2 * Copyright 2017-2018 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 Copyright (c) 2012-2014 Daniel J. Bernstein
17 To the extent possible under law, the author(s) have dedicated all copyright
18 and related and neighboring rights to this software to the public domain
19 worldwide. This software is distributed without any warranty.
21 You should have received a copy of the CC0 Public Domain Dedication along
22 with this software. If not, see
23 <http://creativecommons.org/publicdomain/zero/1.0/>.
28 #include <openssl/crypto.h>
30 #include "internal/siphash.h"
31 #include "siphash_local.h"
33 /* default: SipHash-2-4 */
34 #define SIPHASH_C_ROUNDS 2
35 #define SIPHASH_D_ROUNDS 4
37 #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
39 #define U32TO8_LE(p, v) \
40 (p)[0] = (uint8_t)((v)); \
41 (p)[1] = (uint8_t)((v) >> 8); \
42 (p)[2] = (uint8_t)((v) >> 16); \
43 (p)[3] = (uint8_t)((v) >> 24);
45 #define U64TO8_LE(p, v) \
46 U32TO8_LE((p), (uint32_t)((v))); \
47 U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
49 #define U8TO64_LE(p) \
50 (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
51 ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
52 ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
53 ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
73 size_t SipHash_ctx_size(void)
75 return sizeof(SIPHASH);
78 size_t SipHash_hash_size(SIPHASH *ctx)
80 return ctx->hash_size;
83 static size_t siphash_adjust_hash_size(size_t hash_size)
86 hash_size = SIPHASH_MAX_DIGEST_SIZE;
90 int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size)
92 hash_size = siphash_adjust_hash_size(hash_size);
93 if (hash_size != SIPHASH_MIN_DIGEST_SIZE
94 && hash_size != SIPHASH_MAX_DIGEST_SIZE)
98 * It's possible that the key was set first. If the hash size changes,
99 * we need to adjust v1 (see SipHash_Init().
102 /* Start by adjusting the stored size, to make things easier */
103 ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
105 /* Now, adjust ctx->v1 if the old and the new size differ */
106 if ((size_t)ctx->hash_size != hash_size) {
108 ctx->hash_size = hash_size;
113 /* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */
114 int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds)
116 uint64_t k0 = U8TO64_LE(k);
117 uint64_t k1 = U8TO64_LE(k + 8);
119 /* If the hash size wasn't set, i.e. is zero */
120 ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
123 drounds = SIPHASH_D_ROUNDS;
125 crounds = SIPHASH_C_ROUNDS;
127 ctx->crounds = crounds;
128 ctx->drounds = drounds;
131 ctx->total_inlen = 0;
133 ctx->v0 = 0x736f6d6570736575ULL ^ k0;
134 ctx->v1 = 0x646f72616e646f6dULL ^ k1;
135 ctx->v2 = 0x6c7967656e657261ULL ^ k0;
136 ctx->v3 = 0x7465646279746573ULL ^ k1;
138 if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
144 void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
150 uint64_t v0 = ctx->v0;
151 uint64_t v1 = ctx->v1;
152 uint64_t v2 = ctx->v2;
153 uint64_t v3 = ctx->v3;
155 ctx->total_inlen += inlen;
158 /* deal with leavings */
159 size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
161 /* not enough to fill leavings */
162 if (inlen < available) {
163 memcpy(&ctx->leavings[ctx->len], in, inlen);
168 /* copy data into leavings and reduce input */
169 memcpy(&ctx->leavings[ctx->len], in, available);
173 /* process leavings */
174 m = U8TO64_LE(ctx->leavings);
176 for (i = 0; i < ctx->crounds; ++i)
180 left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
181 end = in + inlen - left;
183 for (; in != end; in += 8) {
186 for (i = 0; i < ctx->crounds; ++i)
191 /* save leavings and other ctx */
193 memcpy(ctx->leavings, end, left);
202 int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
206 uint64_t b = ctx->total_inlen << 56;
207 uint64_t v0 = ctx->v0;
208 uint64_t v1 = ctx->v1;
209 uint64_t v2 = ctx->v2;
210 uint64_t v3 = ctx->v3;
212 if (outlen != (size_t)ctx->hash_size)
217 b |= ((uint64_t)ctx->leavings[6]) << 48;
220 b |= ((uint64_t)ctx->leavings[5]) << 40;
223 b |= ((uint64_t)ctx->leavings[4]) << 32;
226 b |= ((uint64_t)ctx->leavings[3]) << 24;
229 b |= ((uint64_t)ctx->leavings[2]) << 16;
232 b |= ((uint64_t)ctx->leavings[1]) << 8;
235 b |= ((uint64_t)ctx->leavings[0]);
241 for (i = 0; i < ctx->crounds; ++i)
244 if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
248 for (i = 0; i < ctx->drounds; ++i)
250 b = v0 ^ v1 ^ v2 ^ v3;
252 if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
255 for (i = 0; i < ctx->drounds; ++i)
257 b = v0 ^ v1 ^ v2 ^ v3;
258 U64TO8_LE(out + 8, b);