]> git.ipfire.org Git - thirdparty/openssl.git/blame - crypto/siphash/siphash.c
Update copyright year
[thirdparty/openssl.git] / crypto / siphash / siphash.c
CommitLineData
3f5616d7 1/*
fecb3aae 2 * Copyright 2017-2022 The OpenSSL Project Authors. All Rights Reserved.
3f5616d7 3 *
13414827 4 * Licensed under the Apache License 2.0 (the "License"). You may not use
3f5616d7
TS
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
8 */
9
10/* Based on https://131002.net/siphash C reference implementation */
11/*
12 SipHash reference C implementation
13
14 Copyright (c) 2012-2016 Jean-Philippe Aumasson
e3713c36 15 Copyright (c) 2012-2014 Daniel J. Bernstein
3f5616d7
TS
16
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.
20
21 You should have received a copy of the CC0 Public Domain Dedication along
e3713c36 22 with this software. If not, see
3f5616d7
TS
23 <http://creativecommons.org/publicdomain/zero/1.0/>.
24 */
25
26#include <stdlib.h>
27#include <string.h>
28#include <openssl/crypto.h>
29
25f2138b 30#include "crypto/siphash.h"
3f5616d7 31
3f5616d7
TS
32#define ROTL(x, b) (uint64_t)(((x) << (b)) | ((x) >> (64 - (b))))
33
34#define U32TO8_LE(p, v) \
35 (p)[0] = (uint8_t)((v)); \
36 (p)[1] = (uint8_t)((v) >> 8); \
37 (p)[2] = (uint8_t)((v) >> 16); \
38 (p)[3] = (uint8_t)((v) >> 24);
39
40#define U64TO8_LE(p, v) \
41 U32TO8_LE((p), (uint32_t)((v))); \
42 U32TO8_LE((p) + 4, (uint32_t)((v) >> 32));
43
44#define U8TO64_LE(p) \
45 (((uint64_t)((p)[0])) | ((uint64_t)((p)[1]) << 8) | \
46 ((uint64_t)((p)[2]) << 16) | ((uint64_t)((p)[3]) << 24) | \
47 ((uint64_t)((p)[4]) << 32) | ((uint64_t)((p)[5]) << 40) | \
48 ((uint64_t)((p)[6]) << 48) | ((uint64_t)((p)[7]) << 56))
49
50#define SIPROUND \
51 do { \
52 v0 += v1; \
53 v1 = ROTL(v1, 13); \
54 v1 ^= v0; \
55 v0 = ROTL(v0, 32); \
56 v2 += v3; \
57 v3 = ROTL(v3, 16); \
58 v3 ^= v2; \
59 v0 += v3; \
60 v3 = ROTL(v3, 21); \
61 v3 ^= v0; \
62 v2 += v1; \
63 v1 = ROTL(v1, 17); \
64 v1 ^= v2; \
65 v2 = ROTL(v2, 32); \
66 } while (0)
67
68size_t SipHash_ctx_size(void)
69{
70 return sizeof(SIPHASH);
71}
72
73size_t SipHash_hash_size(SIPHASH *ctx)
74{
75 return ctx->hash_size;
76}
77
d74f23d2
RL
78static size_t siphash_adjust_hash_size(size_t hash_size)
79{
80 if (hash_size == 0)
81 hash_size = SIPHASH_MAX_DIGEST_SIZE;
82 return hash_size;
83}
84
85int SipHash_set_hash_size(SIPHASH *ctx, size_t hash_size)
86{
87 hash_size = siphash_adjust_hash_size(hash_size);
88 if (hash_size != SIPHASH_MIN_DIGEST_SIZE
89 && hash_size != SIPHASH_MAX_DIGEST_SIZE)
90 return 0;
91
42503613
RL
92 /*
93 * It's possible that the key was set first. If the hash size changes,
94 * we need to adjust v1 (see SipHash_Init().
95 */
96
97 /* Start by adjusting the stored size, to make things easier */
98 ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
99
100 /* Now, adjust ctx->v1 if the old and the new size differ */
101 if ((size_t)ctx->hash_size != hash_size) {
102 ctx->v1 ^= 0xee;
103 ctx->hash_size = hash_size;
104 }
d74f23d2
RL
105 return 1;
106}
107
3f5616d7 108/* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */
d74f23d2 109int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds)
3f5616d7
TS
110{
111 uint64_t k0 = U8TO64_LE(k);
112 uint64_t k1 = U8TO64_LE(k + 8);
113
d74f23d2
RL
114 /* If the hash size wasn't set, i.e. is zero */
115 ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
3f5616d7
TS
116
117 if (drounds == 0)
118 drounds = SIPHASH_D_ROUNDS;
119 if (crounds == 0)
120 crounds = SIPHASH_C_ROUNDS;
121
122 ctx->crounds = crounds;
123 ctx->drounds = drounds;
3f5616d7
TS
124
125 ctx->len = 0;
126 ctx->total_inlen = 0;
127
128 ctx->v0 = 0x736f6d6570736575ULL ^ k0;
129 ctx->v1 = 0x646f72616e646f6dULL ^ k1;
130 ctx->v2 = 0x6c7967656e657261ULL ^ k0;
131 ctx->v3 = 0x7465646279746573ULL ^ k1;
132
133 if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
134 ctx->v1 ^= 0xee;
135
136 return 1;
137}
138
139void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
140{
141 uint64_t m;
142 const uint8_t *end;
143 int left;
ae7d90a1 144 unsigned int i;
3f5616d7
TS
145 uint64_t v0 = ctx->v0;
146 uint64_t v1 = ctx->v1;
147 uint64_t v2 = ctx->v2;
148 uint64_t v3 = ctx->v3;
149
150 ctx->total_inlen += inlen;
151
152 if (ctx->len) {
153 /* deal with leavings */
154 size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
155
156 /* not enough to fill leavings */
157 if (inlen < available) {
158 memcpy(&ctx->leavings[ctx->len], in, inlen);
159 ctx->len += inlen;
160 return;
161 }
162
163 /* copy data into leavings and reduce input */
164 memcpy(&ctx->leavings[ctx->len], in, available);
165 inlen -= available;
166 in += available;
167
168 /* process leavings */
169 m = U8TO64_LE(ctx->leavings);
170 v3 ^= m;
171 for (i = 0; i < ctx->crounds; ++i)
172 SIPROUND;
173 v0 ^= m;
174 }
175 left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
176 end = in + inlen - left;
177
178 for (; in != end; in += 8) {
179 m = U8TO64_LE(in);
180 v3 ^= m;
181 for (i = 0; i < ctx->crounds; ++i)
182 SIPROUND;
183 v0 ^= m;
184 }
185
186 /* save leavings and other ctx */
187 if (left)
188 memcpy(ctx->leavings, end, left);
189 ctx->len = left;
190
191 ctx->v0 = v0;
192 ctx->v1 = v1;
193 ctx->v2 = v2;
194 ctx->v3 = v3;
195}
196
197int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
198{
199 /* finalize hash */
ae7d90a1 200 unsigned int i;
3f5616d7
TS
201 uint64_t b = ctx->total_inlen << 56;
202 uint64_t v0 = ctx->v0;
203 uint64_t v1 = ctx->v1;
204 uint64_t v2 = ctx->v2;
205 uint64_t v3 = ctx->v3;
206
650b142c 207 if (ctx->crounds == 0 || outlen == 0 || outlen != (size_t)ctx->hash_size)
3f5616d7
TS
208 return 0;
209
210 switch (ctx->len) {
211 case 7:
212 b |= ((uint64_t)ctx->leavings[6]) << 48;
018fcbec 213 /* fall thru */
3f5616d7
TS
214 case 6:
215 b |= ((uint64_t)ctx->leavings[5]) << 40;
018fcbec 216 /* fall thru */
3f5616d7
TS
217 case 5:
218 b |= ((uint64_t)ctx->leavings[4]) << 32;
018fcbec 219 /* fall thru */
3f5616d7
TS
220 case 4:
221 b |= ((uint64_t)ctx->leavings[3]) << 24;
018fcbec 222 /* fall thru */
3f5616d7
TS
223 case 3:
224 b |= ((uint64_t)ctx->leavings[2]) << 16;
018fcbec 225 /* fall thru */
3f5616d7
TS
226 case 2:
227 b |= ((uint64_t)ctx->leavings[1]) << 8;
018fcbec 228 /* fall thru */
3f5616d7
TS
229 case 1:
230 b |= ((uint64_t)ctx->leavings[0]);
231 case 0:
232 break;
233 }
234
235 v3 ^= b;
236 for (i = 0; i < ctx->crounds; ++i)
237 SIPROUND;
238 v0 ^= b;
239 if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
240 v2 ^= 0xee;
241 else
242 v2 ^= 0xff;
243 for (i = 0; i < ctx->drounds; ++i)
244 SIPROUND;
245 b = v0 ^ v1 ^ v2 ^ v3;
246 U64TO8_LE(out, b);
247 if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
248 return 1;
249 v1 ^= 0xdd;
250 for (i = 0; i < ctx->drounds; ++i)
251 SIPROUND;
252 b = v0 ^ v1 ^ v2 ^ v3;
253 U64TO8_LE(out + 8, b);
254 return 1;
255}