1 // SPDX-License-Identifier: BSD-3-Clause 2 /* $OpenBSD: siphash.c,v 1.3 2015/02/20 11:51:03 tedu Exp $ */ 3 4 /*- 5 * Copyright (c) 2013 Andre Oppermann <andre@FreeBSD.org> 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. The name of the author may not be used to endorse or promote 17 * products derived from this software without specific prior written 18 * permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33 /* 34 * SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d 35 * are the number of compression rounds and the number of finalization rounds. 36 * A compression round is identical to a finalization round and this round 37 * function is called SipRound. Given a 128-bit key k and a (possibly empty) 38 * byte string m, SipHash-c-d returns a 64-bit value SipHash-c-d(k; m). 39 * 40 * Implemented from the paper "SipHash: a fast short-input PRF", 2012.09.18, 41 * by Jean-Philippe Aumasson and Daniel J. Bernstein, 42 * Permanent Document ID b9a943a805fbfc6fde808af9fc0ecdfa 43 * https://131002.net/siphash/siphash.pdf 44 * https://131002.net/siphash/ 45 */ 46 47 #include <asm/byteorder.h> 48 #include <linux/unaligned.h> 49 #include <linux/bitops.h> 50 #include <linux/string.h> 51 52 #include "siphash.h" 53 54 static void SipHash_Rounds(SIPHASH_CTX *ctx, int rounds) 55 { 56 while (rounds--) { 57 ctx->v[0] += ctx->v[1]; 58 ctx->v[2] += ctx->v[3]; 59 ctx->v[1] = rol64(ctx->v[1], 13); 60 ctx->v[3] = rol64(ctx->v[3], 16); 61 62 ctx->v[1] ^= ctx->v[0]; 63 ctx->v[3] ^= ctx->v[2]; 64 ctx->v[0] = rol64(ctx->v[0], 32); 65 66 ctx->v[2] += ctx->v[1]; 67 ctx->v[0] += ctx->v[3]; 68 ctx->v[1] = rol64(ctx->v[1], 17); 69 ctx->v[3] = rol64(ctx->v[3], 21); 70 71 ctx->v[1] ^= ctx->v[2]; 72 ctx->v[3] ^= ctx->v[0]; 73 ctx->v[2] = rol64(ctx->v[2], 32); 74 } 75 } 76 77 static void SipHash_CRounds(SIPHASH_CTX *ctx, const void *ptr, int rounds) 78 { 79 u64 m = get_unaligned_le64(ptr); 80 81 ctx->v[3] ^= m; 82 SipHash_Rounds(ctx, rounds); 83 ctx->v[0] ^= m; 84 } 85 86 void SipHash_Init(SIPHASH_CTX *ctx, const SIPHASH_KEY *key) 87 { 88 u64 k0, k1; 89 90 k0 = le64_to_cpu(key->k0); 91 k1 = le64_to_cpu(key->k1); 92 93 ctx->v[0] = 0x736f6d6570736575ULL ^ k0; 94 ctx->v[1] = 0x646f72616e646f6dULL ^ k1; 95 ctx->v[2] = 0x6c7967656e657261ULL ^ k0; 96 ctx->v[3] = 0x7465646279746573ULL ^ k1; 97 98 memset(ctx->buf, 0, sizeof(ctx->buf)); 99 ctx->bytes = 0; 100 } 101 102 void SipHash_Update(SIPHASH_CTX *ctx, int rc, int rf, 103 const void *src, size_t len) 104 { 105 const u8 *ptr = src; 106 size_t left, used; 107 108 if (len == 0) 109 return; 110 111 used = ctx->bytes % sizeof(ctx->buf); 112 ctx->bytes += len; 113 114 if (used > 0) { 115 left = sizeof(ctx->buf) - used; 116 117 if (len >= left) { 118 memcpy(&ctx->buf[used], ptr, left); 119 SipHash_CRounds(ctx, ctx->buf, rc); 120 len -= left; 121 ptr += left; 122 } else { 123 memcpy(&ctx->buf[used], ptr, len); 124 return; 125 } 126 } 127 128 while (len >= sizeof(ctx->buf)) { 129 SipHash_CRounds(ctx, ptr, rc); 130 len -= sizeof(ctx->buf); 131 ptr += sizeof(ctx->buf); 132 } 133 134 if (len > 0) 135 memcpy(&ctx->buf[used], ptr, len); 136 } 137 138 void SipHash_Final(void *dst, SIPHASH_CTX *ctx, int rc, int rf) 139 { 140 u64 r; 141 142 r = SipHash_End(ctx, rc, rf); 143 144 *((__le64 *) dst) = cpu_to_le64(r); 145 } 146 147 u64 SipHash_End(SIPHASH_CTX *ctx, int rc, int rf) 148 { 149 u64 r; 150 size_t left, used; 151 152 used = ctx->bytes % sizeof(ctx->buf); 153 left = sizeof(ctx->buf) - used; 154 memset(&ctx->buf[used], 0, left - 1); 155 ctx->buf[7] = ctx->bytes; 156 157 SipHash_CRounds(ctx, ctx->buf, rc); 158 ctx->v[2] ^= 0xff; 159 SipHash_Rounds(ctx, rf); 160 161 r = (ctx->v[0] ^ ctx->v[1]) ^ (ctx->v[2] ^ ctx->v[3]); 162 memset(ctx, 0, sizeof(*ctx)); 163 return r; 164 } 165 166 u64 SipHash(const SIPHASH_KEY *key, int rc, int rf, const void *src, size_t len) 167 { 168 SIPHASH_CTX ctx; 169 170 SipHash_Init(&ctx, key); 171 SipHash_Update(&ctx, rc, rf, src, len); 172 return SipHash_End(&ctx, rc, rf); 173 } 174