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