blake2b.c raw
1 /*
2 BLAKE2 reference source code package - reference C implementations
3 Copyright 2012, Samuel Neves <sneves@dei.uc.pt>. You may use this under the
4 terms of the CC0, the OpenSSL Licence, or the Apache Public License 2.0, at
5 your option. The terms of these licenses can be found at:
6 - CC0 1.0 Universal : http://creativecommons.org/publicdomain/zero/1.0
7 - OpenSSL license : https://www.openssl.org/source/license.html
8 - Apache 2.0 : http://www.apache.org/licenses/LICENSE-2.0
9
10 More information about the BLAKE2 hash function can be found at
11 https://blake2.net.
12
13 Modified for hash-wasm by Dani BirĂ³
14 */
15
16 #define WITH_BUFFER
17 #include "hash-wasm.h"
18
19 #define BLAKE2_PACKED(x) x __attribute__((packed))
20
21 enum blake2b_constant {
22 BLAKE2B_BLOCKBYTES = 128,
23 BLAKE2B_OUTBYTES = 64,
24 BLAKE2B_KEYBYTES = 64,
25 BLAKE2B_SALTBYTES = 16,
26 BLAKE2B_PERSONALBYTES = 16
27 };
28
29 typedef struct blake2b_state__ {
30 uint64_t h[8];
31 uint64_t t[2];
32 uint64_t f[2];
33 uint8_t buf[BLAKE2B_BLOCKBYTES];
34 int buflen;
35 int outlen;
36 uint8_t last_node;
37 } blake2b_state;
38
39 blake2b_state S[1];
40
41 BLAKE2_PACKED(struct blake2b_param__ {
42 uint8_t digest_length; /* 1 */
43 uint8_t key_length; /* 2 */
44 uint8_t fanout; /* 3 */
45 uint8_t depth; /* 4 */
46 uint32_t leaf_length; /* 8 */
47 uint32_t node_offset; /* 12 */
48 uint32_t xof_length; /* 16 */
49 uint8_t node_depth; /* 17 */
50 uint8_t inner_length; /* 18 */
51 uint8_t reserved[14]; /* 32 */
52 uint8_t salt[BLAKE2B_SALTBYTES]; /* 48 */
53 uint8_t personal[BLAKE2B_PERSONALBYTES]; /* 64 */
54 });
55
56 typedef struct blake2b_param__ blake2b_param;
57
58 blake2b_param P[1];
59
60 static __inline__ uint64_t load64(const void *src) {
61 return *(uint64_t *)src;
62 }
63
64 static __inline__ void store64(void *dst, uint64_t w) {
65 *(uint64_t *)dst = w;
66 }
67
68 static __inline__ uint64_t rotr64(const uint64_t w, const unsigned c) {
69 return (w >> c) | (w << (64 - c));
70 }
71
72 static const uint64_t blake2b_IV[8] = {
73 0x6a09e667f3bcc908ULL, 0xbb67ae8584caa73bULL,
74 0x3c6ef372fe94f82bULL, 0xa54ff53a5f1d36f1ULL,
75 0x510e527fade682d1ULL, 0x9b05688c2b3e6c1fULL,
76 0x1f83d9abfb41bd6bULL, 0x5be0cd19137e2179ULL
77 };
78
79 static const uint8_t blake2b_sigma[12][16] = {
80 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
81 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
82 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 },
83 { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
84 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 },
85 { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
86 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 },
87 { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
88 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 },
89 { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 },
90 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 },
91 { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 }
92 };
93
94 static __inline__ void blake2b_set_lastnode() { S->f[1] = (uint64_t)-1; }
95
96 /* Some helper functions, not necessarily useful */
97 static __inline__ int blake2b_is_lastblock() { return S->f[0] != 0; }
98
99 static __inline__ void blake2b_set_lastblock() {
100 if (S->last_node) blake2b_set_lastnode();
101
102 S->f[0] = (uint64_t)-1;
103 }
104
105 static __inline__ void blake2b_increment_counter(const uint64_t inc) {
106 S->t[0] += inc;
107 S->t[1] += (S->t[0] < inc);
108 }
109
110 #define G(r, i, a, b, c, d) \
111 do { \
112 a = a + b + m[blake2b_sigma[r][2 * i + 0]]; \
113 d = rotr64(d ^ a, 32); \
114 c = c + d; \
115 b = rotr64(b ^ c, 24); \
116 a = a + b + m[blake2b_sigma[r][2 * i + 1]]; \
117 d = rotr64(d ^ a, 16); \
118 c = c + d; \
119 b = rotr64(b ^ c, 63); \
120 } while (0)
121
122 static void round(uint32_t r, uint64_t m[16], uint64_t v[16]) {
123 G(r, 0, v[0], v[4], v[8], v[12]);
124 G(r, 1, v[1], v[5], v[9], v[13]);
125 G(r, 2, v[2], v[6], v[10], v[14]);
126 G(r, 3, v[3], v[7], v[11], v[15]);
127 G(r, 4, v[0], v[5], v[10], v[15]);
128 G(r, 5, v[1], v[6], v[11], v[12]);
129 G(r, 6, v[2], v[7], v[8], v[13]);
130 G(r, 7, v[3], v[4], v[9], v[14]);
131 };
132
133 static void blake2b_compress(const uint8_t block[BLAKE2B_BLOCKBYTES]) {
134 uint64_t m[16];
135 uint64_t v[16];
136
137 #pragma clang loop unroll(full)
138 for (int i = 0; i < 16; ++i) {
139 m[i] = load64(block + i * sizeof(m[i]));
140 }
141
142 #pragma clang loop unroll(full)
143 for (int i = 0; i < 8; ++i) {
144 v[i] = S->h[i];
145 }
146
147 v[8] = blake2b_IV[0];
148 v[9] = blake2b_IV[1];
149 v[10] = blake2b_IV[2];
150 v[11] = blake2b_IV[3];
151 v[12] = blake2b_IV[4] ^ S->t[0];
152 v[13] = blake2b_IV[5] ^ S->t[1];
153 v[14] = blake2b_IV[6] ^ S->f[0];
154 v[15] = blake2b_IV[7] ^ S->f[1];
155
156 #pragma clang loop unroll(full)
157 for (int i = 0; i < 12; ++i) {
158 round(i, m, v);
159 }
160
161 #pragma clang loop unroll(full)
162 for (int i = 0; i < 8; ++i) {
163 S->h[i] = S->h[i] ^ v[i] ^ v[i + 8];
164 }
165 }
166
167 #undef G
168
169 void blake2b_update(const void *pin, int inlen) {
170 const unsigned char *in = (const unsigned char *)pin;
171 if (inlen > 0) {
172 int left = S->buflen;
173 int fill = BLAKE2B_BLOCKBYTES - left;
174 if (inlen > fill) {
175 S->buflen = 0;
176 /* Fill buffer */
177 for (uint8_t i = 0; i < fill; i++) {
178 S->buf[left + i] = in[i];
179 }
180 blake2b_increment_counter(BLAKE2B_BLOCKBYTES);
181 blake2b_compress(S->buf); /* Compress */
182 in += fill;
183 inlen -= fill;
184 while (inlen > BLAKE2B_BLOCKBYTES) {
185 blake2b_increment_counter(BLAKE2B_BLOCKBYTES);
186 blake2b_compress(in);
187 in += BLAKE2B_BLOCKBYTES;
188 inlen -= BLAKE2B_BLOCKBYTES;
189 }
190 }
191 for (uint8_t i = 0; i < inlen; i++) {
192 S->buf[S->buflen + i] = in[i];
193 }
194 S->buflen += inlen;
195 }
196 }
197
198 WASM_EXPORT
199 void Hash_Final() {
200 int outlen = S->outlen;
201 uint8_t buffer[BLAKE2B_OUTBYTES] = {0};
202
203 if (blake2b_is_lastblock()) {
204 return;
205 }
206
207 blake2b_increment_counter(S->buflen);
208 blake2b_set_lastblock();
209 for (int i = 0; i < BLAKE2B_BLOCKBYTES - S->buflen; i++) { /* Padding */
210 (S->buf + S->buflen)[i] = 0;
211 }
212 blake2b_compress(S->buf);
213
214 for (int i = 0; i < 8; ++i) {
215 /* Output full hash to temp buffer */
216 store64(buffer + sizeof(S->h[i]) * i, S->h[i]);
217 }
218
219 for (uint8_t i = 0; i < S->outlen; i++) {
220 main_buffer[i] = buffer[i];
221 }
222 }
223
224 static void blake2b_init0() {
225 memset(S, 0, sizeof(blake2b_state));
226
227 for (int i = 0; i < 8; ++i) {
228 S->h[i] = blake2b_IV[i];
229 }
230 }
231
232 /* init xors IV with input parameter block */
233 void blake2b_init_param() {
234 const uint8_t *p = (const uint8_t *)(P);
235 int i;
236
237 blake2b_init0();
238
239 /* IV XOR ParamBlock */
240 for (i = 0; i < 8; ++i) {
241 S->h[i] ^= load64(p + sizeof(S->h[i]) * i);
242 }
243
244 S->outlen = P->digest_length;
245 }
246
247 void blake2b_init_key(int outlen, const uint8_t *key, int keylen) {
248 P->digest_length = (uint8_t)outlen;
249 P->key_length = (uint8_t)keylen;
250 P->fanout = 1;
251 P->depth = 1;
252 // P->leaf_length = 0;
253 // P->node_offset = 0;
254 // P->xof_length = 0;
255 // P->node_depth = 0;
256 // P->inner_length = 0;
257 // memset(P->reserved, 0, sizeof(P->reserved));
258 // memset(P->salt, 0, sizeof(P->salt));
259 // memset(P->personal, 0, sizeof(P->personal));
260
261 blake2b_init_param();
262
263 if (keylen > 0) {
264 uint8_t block[BLAKE2B_BLOCKBYTES];
265 memset128(block, 0);
266 for (uint8_t i = 0; i < keylen; i++) {
267 block[i] = key[i];
268 }
269 blake2b_update(block, BLAKE2B_BLOCKBYTES);
270 }
271 }
272
273 WASM_EXPORT
274 void Hash_Init(uint32_t bits) {
275 int outlen = bits & 0xFFFF;
276 int keylen = bits >> 16;
277 blake2b_init_key(outlen / 8, main_buffer, keylen);
278 }
279
280 WASM_EXPORT
281 void Hash_Update(uint32_t size) {
282 blake2b_update(main_buffer, size);
283 }
284
285 WASM_EXPORT
286 const uint32_t STATE_SIZE = sizeof(S);
287
288 WASM_EXPORT
289 uint8_t* Hash_GetState() {
290 return (uint8_t*) S;
291 }
292
293 WASM_EXPORT
294 void Hash_Calculate(uint32_t length, uint32_t initParam) {
295 Hash_Init(initParam);
296 Hash_Update(length);
297 Hash_Final();
298 }
299