2 * Copyright 2017-2018 The OpenSSL Project Authors. All Rights Reserved.
4 * Licensed under the Apache License 2.0 (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 "crypto/siphash.h"
31 #include "siphash_local.h"
33 #define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
35 #define U32TO8_LE(p, v) \
36 (p)[0] = (uint8_t)((v)); \
37 (p)[1] = (uint8_t)((v) >> 8); \
38 (p)[2] = (uint8_t)((v) >> 16); \
39 (p)[3] = (uint8_t)((v) >> 24);
41 #define U64TO8_LE(p, v) \
42 U32TO8_LE((p), (uint32_t)((v))); \
43 U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
45 #define U8TO64_LE(p) \
46 (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
47 ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
48 ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
49 ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
69 size_t SipHash_ctx_size(void)
71 return sizeof(SIPHASH);
74 size_t SipHash_hash_size(SIPHASH *ctx)
76 return ctx->hash_size;
79 static size_t siphash_adjust_hash_size(size_t hash_size)
82 hash_size = SIPHASH_MAX_DIGEST_SIZE;
86 int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size)
88 hash_size = siphash_adjust_hash_size(hash_size);
89 if (hash_size != SIPHASH_MIN_DIGEST_SIZE
90 && hash_size != SIPHASH_MAX_DIGEST_SIZE)
94 * It's possible that the key was set first. If the hash size changes,
95 * we need to adjust v1 (see SipHash_Init().
98 /* Start by adjusting the stored size, to make things easier */
99 ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
101 /* Now, adjust ctx->v1 if the old and the new size differ */
102 if ((size_t)ctx->hash_size != hash_size) {
104 ctx->hash_size = hash_size;
109 /* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */
110 int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds)
112 uint64_t k0 = U8TO64_LE(k);
113 uint64_t k1 = U8TO64_LE(k + 8);
115 /* If the hash size wasn't set, i.e. is zero */
116 ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
119 drounds = SIPHASH_D_ROUNDS;
121 crounds = SIPHASH_C_ROUNDS;
123 ctx->crounds = crounds;
124 ctx->drounds = drounds;
127 ctx->total_inlen = 0;
129 ctx->v0 = 0x736f6d6570736575ULL ^ k0;
130 ctx->v1 = 0x646f72616e646f6dULL ^ k1;
131 ctx->v2 = 0x6c7967656e657261ULL ^ k0;
132 ctx->v3 = 0x7465646279746573ULL ^ k1;
134 if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
140 void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
146 uint64_t v0 = ctx->v0;
147 uint64_t v1 = ctx->v1;
148 uint64_t v2 = ctx->v2;
149 uint64_t v3 = ctx->v3;
151 ctx->total_inlen += inlen;
154 /* deal with leavings */
155 size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
157 /* not enough to fill leavings */
158 if (inlen < available) {
159 memcpy(&ctx->leavings[ctx->len], in, inlen);
164 /* copy data into leavings and reduce input */
165 memcpy(&ctx->leavings[ctx->len], in, available);
169 /* process leavings */
170 m = U8TO64_LE(ctx->leavings);
172 for (i = 0; i < ctx->crounds; ++i)
176 left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
177 end = in + inlen - left;
179 for (; in != end; in += 8) {
182 for (i = 0; i < ctx->crounds; ++i)
187 /* save leavings and other ctx */
189 memcpy(ctx->leavings, end, left);
198 int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
202 uint64_t b = ctx->total_inlen << 56;
203 uint64_t v0 = ctx->v0;
204 uint64_t v1 = ctx->v1;
205 uint64_t v2 = ctx->v2;
206 uint64_t v3 = ctx->v3;
208 if (outlen != (size_t)ctx->hash_size)
213 b |= ((uint64_t)ctx->leavings[6]) << 48;
216 b |= ((uint64_t)ctx->leavings[5]) << 40;
219 b |= ((uint64_t)ctx->leavings[4]) << 32;
222 b |= ((uint64_t)ctx->leavings[3]) << 24;
225 b |= ((uint64_t)ctx->leavings[2]) << 16;
228 b |= ((uint64_t)ctx->leavings[1]) << 8;
231 b |= ((uint64_t)ctx->leavings[0]);
237 for (i = 0; i < ctx->crounds; ++i)
240 if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
244 for (i = 0; i < ctx->drounds; ++i)
246 b = v0 ^ v1 ^ v2 ^ v3;
248 if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
251 for (i = 0; i < ctx->drounds; ++i)
253 b = v0 ^ v1 ^ v2 ^ v3;
254 U64TO8_LE(out + 8, b);