2 * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the OpenSSL license (the "License"). You may not use
5 * this file except in compliance with the License. You can obtain a copy
6 * in the file LICENSE in the source distribution or at
7 * https://www.openssl.org/source/license.html
10 /* Based on https://131002.net/siphash C reference implementation */
12 SipHash reference C implementation
14 Copyright (c) 2012-2016 Jean-Philippe Aumasson
15 <jeanphilippe.aumasson@gmail.com>
16 Copyright (c) 2012-2014 Daniel J. Bernstein <djb@cr.yp.to>
18 To the extent possible under law, the author(s) have dedicated all copyright
19 and related and neighboring rights to this software to the public domain
20 worldwide. This software is distributed without any warranty.
22 You should have received a copy of the CC0 Public Domain Dedication along
24 this software. If not, see
25 <http://creativecommons.org/publicdomain/zero/1.0/>.
30 #include <openssl/crypto.h>
32 #include "internal/siphash.h"
33 #include "siphash_local.h"
35 /* default: SipHash-2-4 */
36 #define SIPHASH_C_ROUNDS 2
37 #define SIPHASH_D_ROUNDS 4
39 #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
41 #define U32TO8_LE(p, v) \
42 (p)[0] = (uint8_t)((v)); \
43 (p)[1] = (uint8_t)((v) >> 8); \
44 (p)[2] = (uint8_t)((v) >> 16); \
45 (p)[3] = (uint8_t)((v) >> 24);
47 #define U64TO8_LE(p, v) \
48 U32TO8_LE((p), (uint32_t)((v))); \
49 U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
51 #define U8TO64_LE(p) \
52 (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
53 ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
54 ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
55 ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
75 size_t SipHash_ctx_size(void)
77 return sizeof(SIPHASH);
80 size_t SipHash_hash_size(SIPHASH *ctx)
82 return ctx->hash_size;
85 /* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */
86 int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int hash_size, int crounds, int drounds)
88 uint64_t k0 = U8TO64_LE(k);
89 uint64_t k1 = U8TO64_LE(k + 8);
92 hash_size = SIPHASH_MAX_DIGEST_SIZE;
93 else if (hash_size != SIPHASH_MIN_DIGEST_SIZE &&
94 hash_size != SIPHASH_MAX_DIGEST_SIZE)
98 drounds = SIPHASH_D_ROUNDS;
100 crounds = SIPHASH_C_ROUNDS;
102 ctx->crounds = crounds;
103 ctx->drounds = drounds;
104 ctx->hash_size = hash_size;
107 ctx->total_inlen = 0;
109 ctx->v0 = 0x736f6d6570736575ULL ^ k0;
110 ctx->v1 = 0x646f72616e646f6dULL ^ k1;
111 ctx->v2 = 0x6c7967656e657261ULL ^ k0;
112 ctx->v3 = 0x7465646279746573ULL ^ k1;
114 if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
120 void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
126 uint64_t v0 = ctx->v0;
127 uint64_t v1 = ctx->v1;
128 uint64_t v2 = ctx->v2;
129 uint64_t v3 = ctx->v3;
131 ctx->total_inlen += inlen;
134 /* deal with leavings */
135 size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
137 /* not enough to fill leavings */
138 if (inlen < available) {
139 memcpy(&ctx->leavings[ctx->len], in, inlen);
144 /* copy data into leavings and reduce input */
145 memcpy(&ctx->leavings[ctx->len], in, available);
149 /* process leavings */
150 m = U8TO64_LE(ctx->leavings);
152 for (i = 0; i < ctx->crounds; ++i)
156 left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
157 end = in + inlen - left;
159 for (; in != end; in += 8) {
162 for (i = 0; i < ctx->crounds; ++i)
167 /* save leavings and other ctx */
169 memcpy(ctx->leavings, end, left);
178 int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
182 uint64_t b = ctx->total_inlen << 56;
183 uint64_t v0 = ctx->v0;
184 uint64_t v1 = ctx->v1;
185 uint64_t v2 = ctx->v2;
186 uint64_t v3 = ctx->v3;
188 if (outlen != (size_t)ctx->hash_size)
193 b |= ((uint64_t)ctx->leavings[6]) << 48;
196 b |= ((uint64_t)ctx->leavings[5]) << 40;
199 b |= ((uint64_t)ctx->leavings[4]) << 32;
202 b |= ((uint64_t)ctx->leavings[3]) << 24;
205 b |= ((uint64_t)ctx->leavings[2]) << 16;
208 b |= ((uint64_t)ctx->leavings[1]) << 8;
211 b |= ((uint64_t)ctx->leavings[0]);
217 for (i = 0; i < ctx->crounds; ++i)
220 if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
224 for (i = 0; i < ctx->drounds; ++i)
226 b = v0 ^ v1 ^ v2 ^ v3;
228 if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
231 for (i = 0; i < ctx->drounds; ++i)
233 b = v0 ^ v1 ^ v2 ^ v3;
234 U64TO8_LE(out + 8, b);