Some deabbreviations
[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     ctx->hash_size = hash_size;
98     return 1;
99 }
100
101 /* hash_size = crounds = drounds = 0 means SipHash24 with 16-byte output */
102 int SipHash_Init(SIPHASH *ctx, const unsigned char *k, int crounds, int drounds)
103 {
104     uint64_t k0 = U8TO64_LE(k);
105     uint64_t k1 = U8TO64_LE(k + 8);
106
107     /* If the hash size wasn't set, i.e. is zero */
108     ctx->hash_size = siphash_adjust_hash_size(ctx->hash_size);
109
110     if (drounds == 0)
111         drounds = SIPHASH_D_ROUNDS;
112     if (crounds == 0)
113         crounds = SIPHASH_C_ROUNDS;
114
115     ctx->crounds = crounds;
116     ctx->drounds = drounds;
117
118     ctx->len = 0;
119     ctx->total_inlen = 0;
120
121     ctx->v0 = 0x736f6d6570736575ULL ^ k0;
122     ctx->v1 = 0x646f72616e646f6dULL ^ k1;
123     ctx->v2 = 0x6c7967656e657261ULL ^ k0;
124     ctx->v3 = 0x7465646279746573ULL ^ k1;
125
126     if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
127         ctx->v1 ^= 0xee;
128
129     return 1;
130 }
131
132 void SipHash_Update(SIPHASH *ctx, const unsigned char *in, size_t inlen)
133 {
134     uint64_t m;
135     const uint8_t *end;
136     int left;
137     int i;
138     uint64_t v0 = ctx->v0;
139     uint64_t v1 = ctx->v1;
140     uint64_t v2 = ctx->v2;
141     uint64_t v3 = ctx->v3;
142
143     ctx->total_inlen += inlen;
144
145     if (ctx->len) {
146         /* deal with leavings */
147         size_t available = SIPHASH_BLOCK_SIZE - ctx->len;
148
149         /* not enough to fill leavings */
150         if (inlen < available) {
151             memcpy(&ctx->leavings[ctx->len], in, inlen);
152             ctx->len += inlen;
153             return;
154         }
155
156         /* copy data into leavings and reduce input */
157         memcpy(&ctx->leavings[ctx->len], in, available);
158         inlen -= available;
159         in += available;
160
161         /* process leavings */
162         m = U8TO64_LE(ctx->leavings);
163         v3 ^= m;
164         for (i = 0; i < ctx->crounds; ++i)
165             SIPROUND;
166         v0 ^= m;
167     }
168     left = inlen & (SIPHASH_BLOCK_SIZE-1); /* gets put into leavings */
169     end = in + inlen - left;
170
171     for (; in != end; in += 8) {
172         m = U8TO64_LE(in);
173         v3 ^= m;
174         for (i = 0; i < ctx->crounds; ++i)
175             SIPROUND;
176         v0 ^= m;
177     }
178
179     /* save leavings and other ctx */
180     if (left)
181         memcpy(ctx->leavings, end, left);
182     ctx->len = left;
183
184     ctx->v0 = v0;
185     ctx->v1 = v1;
186     ctx->v2 = v2;
187     ctx->v3 = v3;
188 }
189
190 int SipHash_Final(SIPHASH *ctx, unsigned char *out, size_t outlen)
191 {
192     /* finalize hash */
193     int i;
194     uint64_t b = ctx->total_inlen << 56;
195     uint64_t v0 = ctx->v0;
196     uint64_t v1 = ctx->v1;
197     uint64_t v2 = ctx->v2;
198     uint64_t v3 = ctx->v3;
199
200     if (outlen != (size_t)ctx->hash_size)
201         return 0;
202
203     switch (ctx->len) {
204     case 7:
205         b |= ((uint64_t)ctx->leavings[6]) << 48;
206         /* fall thru */
207     case 6:
208         b |= ((uint64_t)ctx->leavings[5]) << 40;
209         /* fall thru */
210     case 5:
211         b |= ((uint64_t)ctx->leavings[4]) << 32;
212         /* fall thru */
213     case 4:
214         b |= ((uint64_t)ctx->leavings[3]) << 24;
215         /* fall thru */
216     case 3:
217         b |= ((uint64_t)ctx->leavings[2]) << 16;
218         /* fall thru */
219     case 2:
220         b |= ((uint64_t)ctx->leavings[1]) <<  8;
221         /* fall thru */
222     case 1:
223         b |= ((uint64_t)ctx->leavings[0]);
224     case 0:
225         break;
226     }
227
228     v3 ^= b;
229     for (i = 0; i < ctx->crounds; ++i)
230         SIPROUND;
231     v0 ^= b;
232     if (ctx->hash_size == SIPHASH_MAX_DIGEST_SIZE)
233         v2 ^= 0xee;
234     else
235         v2 ^= 0xff;
236     for (i = 0; i < ctx->drounds; ++i)
237         SIPROUND;
238     b = v0 ^ v1 ^ v2  ^ v3;
239     U64TO8_LE(out, b);
240     if (ctx->hash_size == SIPHASH_MIN_DIGEST_SIZE)
241         return 1;
242     v1 ^= 0xdd;
243     for (i = 0; i < ctx->drounds; ++i)
244         SIPROUND;
245     b = v0 ^ v1 ^ v2  ^ v3;
246     U64TO8_LE(out + 8, b);
247     return 1;
248 }