Commit | Line | Data |
---|---|---|
78b4ea88 MW |
1 | /* -*-c-*- |
2 | * | |
3 | * The SHA3 algorithm family | |
4 | * | |
5 | * (c) 2017 Straylight/Edgeware | |
6 | */ | |
7 | ||
8 | /*----- Licensing notice --------------------------------------------------* | |
9 | * | |
10 | * This file is part of Catacomb. | |
11 | * | |
12 | * Catacomb is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU Library General Public License as | |
14 | * published by the Free Software Foundation; either version 2 of the | |
15 | * License, or (at your option) any later version. | |
16 | * | |
17 | * Catacomb is distributed in the hope that it will be useful, | |
18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | * GNU Library General Public License for more details. | |
21 | * | |
22 | * You should have received a copy of the GNU Library General Public | |
23 | * License along with Catacomb; if not, write to the Free | |
24 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, | |
25 | * MA 02111-1307, USA. | |
26 | */ | |
27 | ||
28 | /*----- Header files ------------------------------------------------------*/ | |
29 | ||
30 | #include <assert.h> | |
31 | #include <stdarg.h> | |
32 | #include <string.h> | |
33 | ||
34 | #include "hash.h" | |
35 | #include "ghash-def.h" | |
36 | #include "sha3.h" | |
37 | ||
38 | /*----- General utilities -------------------------------------------------*/ | |
39 | ||
40 | static void absorb(sha3_ctx *ctx, const octet *p, unsigned r) | |
41 | { | |
42 | kludge64 t[25]; | |
43 | unsigned i; | |
44 | ||
45 | /* memdump("absorb", p, 8*r, 0); */ | |
46 | for (i = 0; i < r; i++) { LOAD64_L_(t[i], p); p += 8; } | |
47 | keccak1600_mix(&ctx->s, t, r); | |
48 | } | |
49 | ||
50 | static void step(sha3_ctx *ctx) { keccak1600_p(&ctx->s, &ctx->s, 24); } | |
51 | ||
52 | static void pad(sha3_ctx *ctx, unsigned lo, unsigned hi) | |
53 | { | |
54 | size_t spare = ctx->r - ctx->n; | |
55 | ||
56 | if (spare == 1) | |
57 | ctx->buf[ctx->n] = lo | hi; | |
58 | else { | |
59 | ctx->buf[ctx->n] = lo; | |
60 | ctx->buf[ctx->r - 1] = hi; | |
61 | memset(ctx->buf + ctx->n + 1, 0, spare - 2); | |
62 | } | |
63 | absorb(ctx, ctx->buf, ctx->r/8); | |
64 | } | |
65 | ||
66 | static void squeeze(sha3_ctx *ctx, octet *p, unsigned r) | |
67 | { | |
68 | kludge64 t[25]; | |
69 | unsigned i; | |
70 | ||
71 | keccak1600_extract(&ctx->s, t, r); | |
72 | for (i = 0; i < r; i++) { STORE64_L_(p, t[i]); p += 8; } | |
73 | /* memdump("squeeze", p - 8*r, 8*r, 0); */ | |
74 | } | |
75 | ||
76 | enum { | |
77 | OP_CSHAKE = 0x04, | |
78 | OP_SHA3 = 0x06, | |
79 | OP_SHAKE = 0x1f | |
80 | }; | |
81 | ||
82 | enum { ST_ABSORB, ST_SQUEEZE, ST_DEAD }; | |
83 | ||
84 | /*----- The SHA3 algorithms -----------------------------------------------*/ | |
85 | ||
86 | /* --- @sha3_{224,256,384,512}_init@ --- * | |
87 | * | |
88 | * Arguments: @sha3_ctx *ctx@ = pointer to context block to initialize | |
89 | * | |
90 | * Returns: --- | |
91 | * | |
92 | * Use: Initializes a SHA3 hashing context for use. | |
93 | */ | |
94 | ||
95 | static void init_sha3(sha3_ctx *ctx, unsigned w) | |
96 | { | |
97 | keccak1600_init(&ctx->s); | |
98 | ctx->w = w/8; ctx->r = (1600 - 2*w)/8; ctx->n = 0; | |
99 | } | |
100 | ||
101 | void sha3_224_init(sha3_ctx *ctx) { init_sha3(ctx, 224); } | |
102 | void sha3_256_init(sha3_ctx *ctx) { init_sha3(ctx, 256); } | |
103 | void sha3_384_init(sha3_ctx *ctx) { init_sha3(ctx, 384); } | |
104 | void sha3_512_init(sha3_ctx *ctx) { init_sha3(ctx, 512); } | |
105 | ||
106 | /* --- @sha3_hash@ --- * | |
107 | * | |
108 | * Arguments: @sha3_ctx *ctx@ = pointer to context bock | |
109 | * @const void *p@ = pointer to data to hash | |
110 | * @size_t sz@ = size of buffer to hash | |
111 | * | |
112 | * Returns: --- | |
113 | * | |
114 | * Use: Hashes a buffer of data. The buffer may be of any size and | |
115 | * alignment. | |
116 | */ | |
117 | ||
118 | void sha3_hash(sha3_ctx *ctx, const void *p, size_t sz) | |
119 | { | |
120 | const octet *q = p; | |
121 | size_t spare = ctx->r - ctx->n; | |
122 | ||
123 | if (sz < spare) { | |
124 | memcpy(ctx->buf + ctx->n, q, sz); | |
125 | ctx->n += sz; | |
126 | return; | |
127 | } | |
128 | if (ctx->n) { | |
129 | memcpy(ctx->buf + ctx->n, q, spare); | |
130 | absorb(ctx, ctx->buf, ctx->r/8); | |
131 | step(ctx); | |
132 | q += spare; sz -= spare; | |
133 | } | |
134 | while (sz >= ctx->r) { | |
135 | absorb(ctx, q, ctx->r/8); | |
136 | step(ctx); | |
137 | q += ctx->r; sz -= ctx->r; | |
138 | } | |
139 | if (sz) memcpy(ctx->buf, q, sz); | |
140 | ctx->n = sz; | |
141 | } | |
142 | ||
143 | /* --- @sha3_done@ --- * | |
144 | * | |
145 | * Arguments: @sha3_ctx *ctx@ = pointer to context block | |
146 | * @void *hash@ = pointer to output buffer | |
147 | * | |
148 | * Returns: --- | |
149 | * | |
150 | * Use: Returns the hash of the data read so far. | |
151 | */ | |
152 | ||
153 | void sha3_done(sha3_ctx *ctx, void *hash) | |
154 | { | |
155 | pad(ctx, OP_SHA3, 0x80); | |
156 | step(ctx); | |
157 | ||
158 | if (ctx->w%8 == 0) | |
159 | squeeze(ctx, hash, ctx->w/8); | |
160 | else { | |
161 | squeeze(ctx, ctx->buf, (ctx->w + 7)/8); | |
162 | memcpy(hash, ctx->buf, ctx->w); | |
163 | } | |
164 | } | |
165 | ||
166 | /* --- @sha3_{224,256,384,512}_set@ --- * | |
167 | * | |
168 | * Arguments: @sha3_ctx *ctx@ = pointer to context block | |
169 | * @const void *buf@ = pointer to state buffer | |
170 | * @unsigned long count@ = current count of bytes processed | |
171 | * | |
172 | * Returns: --- | |
173 | * | |
174 | * Use: Initializes a context block from a given state. This is | |
175 | * something of a kludge for the benefit of HMAC, but there are | |
176 | * better ways to use SHA3 as a MAC. | |
177 | * | |
178 | * Furthermore, the @count@ argument is expected to be zero or | |
179 | * be the output of @sha3_state@ below. Doing anything else | |
180 | * won't work properly. | |
181 | */ | |
182 | ||
183 | static void set(sha3_ctx *ctx, const void *buf, | |
184 | unsigned long count, unsigned w) | |
185 | { | |
186 | if (count) | |
187 | memcpy(ctx, buf, sizeof(*ctx)); | |
188 | else { | |
189 | static const char *prefix = "Catacomb SHA3 NMAC kludge"; | |
190 | init_sha3(ctx, w); | |
191 | sha3_hash(ctx, prefix, sizeof(prefix)); | |
192 | sha3_hash(ctx, buf, SHA3_STATESZ); | |
193 | } | |
194 | } | |
195 | ||
196 | void sha3_224_set(sha3_ctx *ctx, const void *buf, unsigned long count) | |
197 | { set(ctx, buf, count, 224); } | |
198 | void sha3_256_set(sha3_ctx *ctx, const void *buf, unsigned long count) | |
199 | { set(ctx, buf, count, 256); } | |
200 | void sha3_384_set(sha3_ctx *ctx, const void *buf, unsigned long count) | |
201 | { set(ctx, buf, count, 384); } | |
202 | void sha3_512_set(sha3_ctx *ctx, const void *buf, unsigned long count) | |
203 | { set(ctx, buf, count, 512); } | |
204 | ||
205 | /* --- @sha3_state@ --- * | |
206 | * | |
207 | * Arguments: @sha3_ctx *ctx@ = pointer to context block | |
208 | * @void *state@ = pointer to buffer for current state | |
209 | * | |
210 | * Returns: A value which is meaningful to @sha3_..._set@. | |
211 | * | |
212 | * Use: Returns the current state of the hash function such that it | |
213 | * can be passed to @sha3_..._set@. | |
214 | */ | |
215 | ||
216 | unsigned long sha3_state(sha3_ctx *ctx, void *state) | |
217 | { memcpy(state, ctx, sizeof(*ctx)); return (1); } | |
218 | ||
219 | #define HASHES(_) \ | |
220 | _(SHA3_224, sha3_224, "sha3-224") \ | |
221 | _(SHA3_256, sha3_256, "sha3-256") \ | |
222 | _(SHA3_384, sha3_384, "sha3-384") \ | |
223 | _(SHA3_512, sha3_512, "sha3-512") | |
224 | HASHES(GHASH_DEFX) | |
225 | ||
226 | /*----- The cSHAKE XOF algorithm ------------------------------------------*/ | |
227 | ||
228 | static void leftenc_sz(shake_ctx *ctx, size_t n) | |
229 | { | |
230 | kludge64 t; | |
231 | octet b[9]; | |
232 | unsigned i; | |
233 | ||
e91d142c | 234 | SET64(t, ((n&~(size_t)MASK32) >> 16) >> 16, n&MASK32); |
78b4ea88 MW |
235 | STORE64_B_(b + 1, t); |
236 | for (i = 1; i < 8 && !b[i]; i++); | |
237 | i--; b[i] = 8 - i; | |
238 | shake_hash(ctx, b + i, 9 - i); | |
239 | } | |
240 | ||
241 | static void rightenc_sz(shake_ctx *ctx, size_t n) | |
242 | { | |
243 | kludge64 t; | |
244 | octet b[9]; | |
245 | unsigned i; | |
246 | ||
e91d142c | 247 | SET64(t, ((n&~(size_t)MASK32) >> 16) >> 16, n&MASK32); |
78b4ea88 MW |
248 | STORE64_B_(b, t); |
249 | for (i = 0; i < 7 && !b[i]; i++); | |
250 | b[8] = 8 - i; | |
251 | shake_hash(ctx, b + i, 9 - i); | |
252 | } | |
253 | ||
254 | static void stringenc(shake_ctx *ctx, const void *p, size_t sz) | |
255 | { leftenc_sz(ctx, 8*sz); if (sz) shake_hash(ctx, p, sz); } | |
256 | ||
257 | static void bytepad_before(shake_ctx *ctx) | |
258 | { leftenc_sz(ctx, ctx->h.r); } | |
259 | ||
260 | static void bytepad_after(shake_ctx *ctx) | |
261 | { | |
262 | unsigned pad; | |
263 | ||
264 | if (ctx->h.n%8) { | |
265 | pad = 8 - ctx->h.n%8; | |
266 | memset(ctx->h.buf + ctx->h.n, 0, pad); | |
267 | ctx->h.n += pad; | |
268 | } | |
269 | if (ctx->h.n) { | |
270 | absorb(&ctx->h, ctx->h.buf, ctx->h.n/8); | |
271 | step(&ctx->h); ctx->h.n = 0; | |
272 | } | |
273 | } | |
274 | ||
275 | const octet | |
276 | shake128_keysz[] = { KSZ_ANY, SHAKE128_KEYSZ }, | |
277 | shake256_keysz[] = { KSZ_ANY, SHAKE256_KEYSZ }; | |
278 | ||
279 | /* --- @cshake{128,256}_init@ --- * | |
280 | * | |
281 | * Arguments: @shake_ctx *ctx@ = pointer to context to initialize | |
282 | * @const void *func@ = NIST-allocated function name | |
283 | * @size_t fsz@ = length of function name | |
284 | * @const void *perso@ = user personalization string | |
285 | * @size_t psz@ = length of personalization string | |
286 | * | |
287 | * Returns: --- | |
288 | * | |
289 | * Use: Initializes a cSHAKE context. The context is initially in | |
290 | * the `absorbing' state: feed it data with @shake_hash@. | |
291 | */ | |
292 | ||
293 | static void init_shake(shake_ctx *ctx, unsigned c0, | |
294 | const void *func, size_t fsz, | |
295 | const void *perso, size_t psz) | |
296 | { | |
297 | keccak1600_init(&ctx->h.s); ctx->st = ST_ABSORB; | |
298 | ctx->h.r = (1600 - 2*c0)/8; ctx->h.w = 0; ctx->h.n = 0; | |
299 | if (!fsz && !psz) | |
300 | ctx->op = OP_SHAKE; | |
301 | else { | |
302 | bytepad_before(ctx); | |
303 | stringenc(ctx, func, fsz); | |
304 | stringenc(ctx, perso, psz); | |
305 | bytepad_after(ctx); | |
306 | ctx->op = OP_CSHAKE; | |
307 | } | |
308 | } | |
309 | ||
310 | void cshake128_init(shake_ctx *ctx, | |
311 | const void *func, size_t fsz, | |
312 | const void *perso, size_t psz) | |
313 | { init_shake(ctx, 128, func, fsz, perso, psz); } | |
314 | ||
315 | void cshake256_init(shake_ctx *ctx, | |
316 | const void *func, size_t fsz, | |
317 | const void *perso, size_t psz) | |
318 | { init_shake(ctx, 256, func, fsz, perso, psz); } | |
319 | ||
320 | /* --- @shake{128,256}_init@ --- * | |
321 | * | |
322 | * Arguments: @sha3_ctx *ctx@ = pointer to context to initialize | |
323 | * | |
324 | * Returns: --- | |
325 | * | |
326 | * Use: Initializes a SHAKE context. The context is initially in | |
327 | * the `absorbing' state: feed it data with @shake_hash@. | |
328 | */ | |
329 | ||
330 | void shake128_init(shake_ctx *ctx) { init_shake(ctx, 128, 0, 0, 0, 0); } | |
331 | void shake256_init(shake_ctx *ctx) { init_shake(ctx, 256, 0, 0, 0, 0); } | |
332 | ||
333 | /* --- @shake_hash@ --- * | |
334 | * | |
335 | * Arguments: @shake_ctx *ctx@ = context to update | |
336 | * @const void *p@ = input buffer | |
337 | * @size_t sz@ = size of input | |
338 | * | |
339 | * Returns: --- | |
340 | * | |
341 | * Use: Feeds input data into a SHAKE context. The context must be | |
342 | * in `absorbing' state. | |
343 | */ | |
344 | ||
345 | void shake_hash(shake_ctx *ctx, const void *p, size_t sz) | |
346 | { assert(ctx->st == ST_ABSORB); sha3_hash(&ctx->h, p, sz); } | |
347 | ||
348 | /* --- @shake_xof@ --- * | |
349 | * | |
350 | * Arguments: @shake_ctx *ctx@ = context to update | |
351 | * | |
352 | * Returns: --- | |
353 | * | |
354 | * Use: Switches the context into `squeezing' state. Use @shake_get@ | |
355 | * or @shake_mask@ to extract data. | |
356 | */ | |
357 | ||
358 | void shake_xof(shake_ctx *ctx) | |
359 | { | |
360 | assert(ctx->st == ST_ABSORB); | |
361 | pad(&ctx->h, ctx->op, 0x80); | |
362 | ctx->st = ST_SQUEEZE; | |
363 | ctx->h.n = ctx->h.r; | |
364 | } | |
365 | ||
366 | /* --- @shake_get@ --- * | |
367 | * | |
368 | * Arguments: @shake_ctx *ctx@ = context to update | |
369 | * @void *p@ = output buffer | |
370 | * @size_t sz@ = size of output | |
371 | * | |
372 | * Returns: --- | |
373 | * | |
374 | * Use: Extracts output from a SHAKE context. The context must be | |
375 | * in `squeezing' state. | |
376 | */ | |
377 | ||
378 | void shake_get(shake_ctx *ctx, void *p, size_t sz) | |
379 | { | |
380 | octet *q = p; | |
381 | size_t left = ctx->h.r - ctx->h.n; | |
382 | ||
383 | assert(ctx->st == ST_SQUEEZE); | |
384 | if (left >= sz) { | |
385 | memcpy(q, ctx->h.buf + ctx->h.n, sz); | |
386 | ctx->h.n += sz; | |
387 | return; | |
388 | } | |
389 | if (left) { | |
390 | memcpy(q, ctx->h.buf + ctx->h.n, left); | |
391 | q += left; sz -= left; | |
392 | } | |
393 | while (sz >= ctx->h.r) { | |
394 | step(&ctx->h); | |
395 | squeeze(&ctx->h, q, ctx->h.r/8); | |
396 | q += ctx->h.r; sz -= ctx->h.r; | |
397 | } | |
398 | if (!sz) | |
399 | ctx->h.n = ctx->h.r; | |
400 | else { | |
401 | step(&ctx->h); | |
402 | squeeze(&ctx->h, ctx->h.buf, ctx->h.r/8); | |
403 | memcpy(q, ctx->h.buf, sz); | |
404 | ctx->h.n = sz; | |
405 | } | |
406 | } | |
407 | ||
408 | /* --- @shake_mask@ --- * | |
409 | * | |
410 | * Arguments: @shake_ctx *ctx@ = context to update | |
411 | * @const void *src@ = pointer to source data, or null | |
412 | * @void *dest@ = output buffer | |
413 | * @size_t sz@ = size of output | |
414 | * | |
415 | * Returns: --- | |
416 | * | |
417 | * Use: Mask the @src@ data by XORing it with output from the SHAKE | |
418 | * context, writing the result to @dest@. The @src@ and @dest | |
419 | * buffers may be equal but must not otherwise overlap. The | |
420 | * context must be in `squeezing' state. | |
421 | */ | |
422 | ||
423 | void shake_mask(shake_ctx *ctx, const void *src, void *dest, size_t sz) | |
424 | { | |
425 | const octet *p = src, *pp, *l; | |
426 | octet *q = dest; | |
427 | size_t left = ctx->h.r - ctx->h.n; | |
428 | ||
429 | if (!src) { shake_get(ctx, dest, sz); return; } | |
430 | ||
431 | assert(ctx->st == ST_SQUEEZE); | |
432 | if (left >= sz) { | |
433 | pp = ctx->h.buf + ctx->h.n; l = q + sz; | |
434 | while (q < l) *q++ = *p++ ^ *pp++; | |
435 | ctx->h.n += sz; | |
436 | return; | |
437 | } | |
438 | if (left) { | |
439 | pp = ctx->h.buf + ctx->h.n; l = q + left; | |
440 | while (q < l) *q++ = *p++ ^ *pp++; | |
441 | sz -= left; | |
442 | } | |
443 | while (sz >= ctx->h.r) { | |
444 | step(&ctx->h); | |
445 | squeeze(&ctx->h, ctx->h.buf, ctx->h.r/8); | |
446 | pp = ctx->h.buf; l = pp + ctx->h.r; | |
447 | while (pp < l) *q++ = *p++ ^ *pp++; | |
448 | sz -= ctx->h.r; | |
449 | } | |
450 | if (!sz) | |
451 | ctx->h.n = ctx->h.r; | |
452 | else { | |
453 | step(&ctx->h); | |
454 | squeeze(&ctx->h, ctx->h.buf, ctx->h.r/8); | |
455 | pp = ctx->h.buf; l = q + sz; | |
456 | while (q < l) *q++ = *p++ ^ *pp++; | |
457 | ctx->h.n = sz; | |
458 | } | |
459 | } | |
460 | ||
461 | /* --- @shake_done@ --- * | |
462 | * | |
463 | * Arguments: @shake_ctx *ctx@ = context to update | |
464 | * @void *h@ = where to write the hash | |
465 | * @size_t hsz@ = size of the hash to make | |
466 | * | |
467 | * Returns: --- | |
468 | * | |
469 | * Use: Switches the context into `squeezing' state. Use @shake_get@ | |
470 | * or @shake_mask@ to extract data. | |
471 | */ | |
472 | ||
473 | void shake_done(shake_ctx *ctx, void *h, size_t hsz) | |
474 | { shake_xof(ctx); shake_get(ctx, h, hsz); ctx->st = ST_DEAD; } | |
475 | ||
476 | /* --- Hash interface --- */ | |
477 | ||
478 | typedef struct shake_ghctx { | |
479 | ghash h; | |
480 | shake_ctx c; | |
481 | octet hb[SHAKE256_HASHSZ]; | |
482 | } shake_ghctx; | |
483 | ||
484 | static const ghash_ops shake128_ghops, shake256_ghops; | |
485 | ||
486 | static void shake_ghhash(ghash *h, const void *p, size_t sz) | |
487 | { shake_ghctx *cc = (shake_ghctx *)h; shake_hash(&cc->c, p, sz); } | |
488 | ||
489 | static octet *shake_ghdone(ghash *h, void *buf) | |
490 | { | |
491 | shake_ghctx *cc = (shake_ghctx *)h; | |
492 | if (!buf) buf = cc->hb; | |
493 | shake_done(&cc->c, buf, h->ops->c->hashsz); | |
494 | return (buf); | |
495 | } | |
496 | ||
497 | static void shake_ghdestroy(ghash *h) | |
498 | { shake_ghctx *cc = (shake_ghctx *)h; BURN(cc); S_DESTROY(cc); } | |
499 | ||
500 | static ghash *shake_ghcopy(ghash *h) | |
501 | { | |
502 | shake_ghctx *cc = (shake_ghctx *)h; | |
503 | shake_ghctx *hc = S_CREATE(shake_ghctx); | |
504 | *hc = *cc; | |
505 | return (&hc->h); | |
506 | } | |
507 | ||
508 | static ghash *shake128_ghinit(void) | |
509 | { | |
510 | shake_ghctx *cc = S_CREATE(shake_ghctx); | |
511 | cc->h.ops = &shake128_ghops; | |
512 | shake128_init(&cc->c); | |
513 | return (&cc->h); | |
514 | } | |
515 | ||
516 | static ghash *shake256_ghinit(void) | |
517 | { | |
518 | shake_ghctx *cc = S_CREATE(shake_ghctx); | |
519 | cc->h.ops = &shake256_ghops; | |
520 | shake256_init(&cc->c); | |
521 | return (&cc->h); | |
522 | } | |
523 | ||
524 | const gchash | |
525 | shake128 = { "shake128", SHAKE128_HASHSZ, shake128_ghinit, 168 }, | |
526 | shake256 = { "shake256", SHAKE256_HASHSZ, shake256_ghinit, 136 }; | |
527 | ||
528 | static const ghash_ops | |
529 | shake128_ghops = { &shake128, shake_ghhash, shake_ghdone, | |
530 | shake_ghdestroy, shake_ghcopy }, | |
531 | shake256_ghops = { &shake256, shake_ghhash, shake_ghdone, | |
532 | shake_ghdestroy, shake_ghcopy }; | |
533 | ||
534 | /* --- Cipher interface --- */ | |
535 | ||
536 | typedef struct shake_gcctx { | |
537 | gcipher gc; | |
538 | shake_ctx c; | |
539 | } shake_gcctx; | |
540 | ||
541 | static const gcipher_ops shake128_gcops, shake256_gcops; | |
542 | ||
543 | static void shake_gcencdec(gcipher *c, const void *s, void *d, size_t sz) | |
544 | { shake_gcctx *cc = (shake_gcctx *)c; shake_mask(&cc->c, s, d, sz); } | |
545 | ||
546 | static void shake_gcdestroy(gcipher *c) | |
547 | { shake_gcctx *cc = (shake_gcctx *)c; BURN(*cc); S_DESTROY(cc); } | |
548 | ||
549 | static const gcipher_ops | |
550 | shake128_gcops = { &shake128_xof, shake_gcencdec, shake_gcencdec, | |
551 | shake_gcdestroy, 0, 0 }, | |
552 | shake256_gcops = { &shake256_xof, shake_gcencdec, shake_gcencdec, | |
553 | shake_gcdestroy, 0, 0 }; | |
554 | ||
555 | static gcipher *shake128_gcinit(const void *k, size_t sz) | |
556 | { | |
557 | shake_gcctx *cc = S_CREATE(shake_gcctx); | |
558 | cc->gc.ops = &shake128_gcops; | |
559 | shake128_init(&cc->c); shake_hash(&cc->c, k, sz); shake_xof(&cc->c); | |
560 | return (&cc->gc); | |
561 | } | |
562 | ||
563 | static gcipher *shake256_gcinit(const void *k, size_t sz) | |
564 | { | |
565 | shake_gcctx *cc = S_CREATE(shake_gcctx); | |
b7715b9a | 566 | cc->gc.ops = &shake256_gcops; |
78b4ea88 MW |
567 | shake256_init(&cc->c); shake_hash(&cc->c, k, sz); shake_xof(&cc->c); |
568 | return (&cc->gc); | |
569 | } | |
570 | ||
571 | const gccipher | |
572 | shake128_xof = { "shake128-xof", shake128_keysz, 0, shake128_gcinit }, | |
573 | shake256_xof = { "shake256-xof", shake256_keysz, 0, shake256_gcinit }; | |
574 | ||
575 | /* --- Random generator interface --- */ | |
576 | ||
577 | typedef struct shake_grctx { | |
578 | grand gr; | |
579 | shake_ctx c; | |
580 | } shake_grctx; | |
581 | ||
582 | static int shake_grmisc(grand *r, unsigned op, ...) | |
583 | { | |
584 | int rc = 0; | |
585 | switch (op) { | |
586 | case GRAND_CHECK: rc = 0; break; | |
587 | default: GRAND_BADOP; break; | |
588 | } | |
589 | return (rc); | |
590 | } | |
591 | ||
592 | static void shake_grdestroy(grand *r) | |
593 | { shake_grctx *cc = (shake_grctx *)r; BURN(cc); S_DESTROY(cc); } | |
594 | ||
595 | static octet shake_grbyte(grand *r) | |
596 | { | |
597 | shake_grctx *cc = (shake_grctx *)r; | |
598 | octet o; | |
599 | shake_get(&cc->c, &o, 1); | |
600 | return (o); | |
601 | } | |
602 | ||
603 | static uint32 shake_grword(grand *r) | |
604 | { | |
605 | shake_grctx *cc = (shake_grctx *)r; | |
606 | octet b[4]; | |
607 | shake_get(&cc->c, &b, 4); | |
608 | return (LOAD32(b)); | |
609 | } | |
610 | ||
611 | static void shake_grfill(grand *r, void *p, size_t sz) | |
612 | { shake_grctx *cc = (shake_grctx *)r; shake_get(&cc->c, p, sz); } | |
613 | ||
614 | static const grand_ops | |
615 | shake128_grops = { "shake128", GRAND_CRYPTO, 0, | |
616 | shake_grmisc, shake_grdestroy, shake_grword, | |
617 | shake_grbyte, shake_grword, grand_defaultrange, | |
618 | shake_grfill }, | |
619 | shake256_grops = { "shake256", GRAND_CRYPTO, 0, | |
620 | shake_grmisc, shake_grdestroy, shake_grword, | |
621 | shake_grbyte, shake_grword, grand_defaultrange, | |
622 | shake_grfill }, | |
623 | cshake128_grops = { "cshake128", GRAND_CRYPTO, 0, | |
624 | shake_grmisc, shake_grdestroy, shake_grword, | |
625 | shake_grbyte, shake_grword, grand_defaultrange, | |
626 | shake_grfill }, | |
627 | cshake256_grops = { "cshake256", GRAND_CRYPTO, 0, | |
628 | shake_grmisc, shake_grdestroy, shake_grword, | |
629 | shake_grbyte, shake_grword, grand_defaultrange, | |
630 | shake_grfill }; | |
631 | ||
632 | /* --- @shake{128,256}_rand@ --- * | |
633 | * | |
634 | * Arguments: @const void *k@ = pointer to seed material | |
635 | * @size_t sz@ = size of the seed | |
636 | * | |
637 | * Returns: A pseudorandom generator with the given seed. | |
638 | */ | |
639 | ||
640 | grand *shake128_rand(const void *k, size_t sz) | |
641 | { | |
642 | shake_grctx *cc = S_CREATE(shake_grctx); | |
643 | cc->gr.ops = &shake128_grops; | |
644 | shake128_init(&cc->c); shake_hash(&cc->c, k, sz); shake_xof(&cc->c); | |
645 | return (&cc->gr); | |
646 | } | |
647 | ||
648 | grand *shake256_rand(const void *k, size_t sz) | |
649 | { | |
650 | shake_grctx *cc = S_CREATE(shake_grctx); | |
651 | cc->gr.ops = &shake256_grops; | |
652 | shake256_init(&cc->c); shake_hash(&cc->c, k, sz); shake_xof(&cc->c); | |
653 | return (&cc->gr); | |
654 | } | |
655 | ||
656 | /* --- @cshake{128,256}_rand@ --- * | |
657 | * | |
658 | * Arguments: @const void *func@ = function name | |
659 | * @size_t fsz@ = length of function name | |
660 | * @const void *perso@ = personalization string | |
661 | * @size_t psz@ = length of personalization string | |
662 | * @const void *k@ = pointer to seed material | |
663 | * @size_t sz@ = size of the seed | |
664 | * | |
665 | * Returns: A pseudorandom generator with the given seed. | |
666 | */ | |
667 | ||
668 | grand *cshake128_rand(const void *func, size_t fsz, | |
669 | const void *perso, size_t psz, | |
670 | const void *k, size_t sz) | |
671 | { | |
672 | shake_grctx *cc = S_CREATE(shake_grctx); | |
673 | cc->gr.ops = &cshake128_grops; | |
674 | cshake128_init(&cc->c, func, fsz, perso, psz); | |
675 | shake_hash(&cc->c, k, sz); shake_xof(&cc->c); | |
676 | return (&cc->gr); | |
677 | } | |
678 | ||
679 | grand *cshake256_rand(const void *func, size_t fsz, | |
680 | const void *perso, size_t psz, | |
681 | const void *k, size_t sz) | |
682 | { | |
683 | shake_grctx *cc = S_CREATE(shake_grctx); | |
684 | cc->gr.ops = &cshake256_grops; | |
685 | cshake256_init(&cc->c, func, fsz, perso, psz); | |
686 | shake_hash(&cc->c, k, sz); shake_xof(&cc->c); | |
687 | return (&cc->gr); | |
688 | } | |
689 | ||
690 | /*----- The KMAC variable-length PRF --------------------------------------*/ | |
691 | ||
692 | typedef shake_ctx kmac_ctx; | |
693 | ||
694 | /* --- @kmac{128,256}_init@ --- * | |
695 | * | |
696 | * Arguments: @kmac_ctx *ctx@ = pointer to context to fill in | |
697 | * @const char *perso@ = personalization string, or null | |
698 | * @size_t psz@ = length of personalization string | |
699 | * @const void *k@ = pointer to key material | |
700 | * @size_t sz@ = size of key material | |
701 | * | |
702 | * Returns: --- | |
703 | * | |
704 | * Use: Sets up a KMAC context. Use @kmac_hash@ to feed in the input | |
705 | * message. | |
706 | */ | |
707 | ||
708 | static void init_kmac(kmac_ctx *ctx, | |
709 | unsigned c0, const void *perso, size_t psz, | |
710 | const void *k, size_t sz) | |
711 | { | |
712 | init_shake(ctx, c0, "KMAC", 4, perso, psz); | |
713 | bytepad_before(ctx); stringenc(ctx, k, sz); bytepad_after(ctx); | |
714 | } | |
715 | ||
716 | void kmac128_init(kmac_ctx *ctx, const void *perso, size_t psz, | |
717 | const void *k, size_t sz) | |
718 | { init_kmac(ctx, 128, perso, psz, k, sz); } | |
719 | ||
720 | void kmac256_init(kmac_ctx *ctx, const void *perso, size_t psz, | |
721 | const void *k, size_t sz) | |
722 | { init_kmac(ctx, 256, perso, psz, k, sz); } | |
723 | ||
724 | /* --- @kmac_xof@ --- * | |
725 | * | |
726 | * Arguments: @kmac_ctx *ctx@ = pointer to context | |
727 | * | |
728 | * Returns: --- | |
729 | * | |
730 | * Use: Marks the end of the message to be processed. The output can | |
731 | * be read using @kmac_get@. | |
732 | */ | |
733 | ||
734 | void kmac_xof(kmac_ctx *ctx) | |
735 | { rightenc_sz(ctx, 0); shake_xof(ctx); } | |
736 | ||
737 | /* --- @kmac_done@ --- * | |
738 | * | |
739 | * Arguments: @kmac_ctx *ctx@ = pointer to context | |
740 | * @void *h@ = where to put the tag | |
741 | * @size_t hsz@ = size of tag to produce | |
742 | * | |
743 | * Returns: --- | |
744 | * | |
745 | * Use: Marks the end of the message to be processed and returns a | |
746 | * tag. Note that the tag value is dependent on the output | |
747 | * size. | |
748 | */ | |
749 | ||
750 | void kmac_done(kmac_ctx *ctx, void *h, size_t hsz) | |
751 | { rightenc_sz(ctx, 8*hsz); shake_done(ctx, h, hsz); } | |
752 | ||
753 | /* --- MAC interface --- */ | |
754 | ||
755 | typedef struct kmac_ghctx { | |
756 | ghash h; | |
757 | kmac_ctx c; | |
758 | octet hb[KMAC256_TAGSZ]; | |
759 | } kmac_ghctx; | |
760 | ||
761 | typedef struct kmac_gmctx { | |
762 | gmac m; | |
763 | kmac_ctx c; | |
764 | const ghash_ops *hops; | |
765 | } kmac_gmctx; | |
766 | ||
767 | static const ghash_ops kmac128_ghops, kmac256_ghops; | |
768 | static const gmac_ops kmac128_gmops, kmac256_gmops; | |
769 | ||
770 | static void kmac_ghhash(ghash *h, const void *p, size_t sz) | |
771 | { kmac_ghctx *cc = (kmac_ghctx *)h; kmac_hash(&cc->c, p, sz); } | |
772 | ||
773 | static octet *kmac_ghdone(ghash *h, void *buf) | |
774 | { | |
775 | kmac_ghctx *cc = (kmac_ghctx *)h; | |
776 | if (!buf) buf = cc->hb; | |
777 | kmac_done(&cc->c, buf, cc->h.ops->c->hashsz); | |
778 | return (buf); | |
779 | } | |
780 | ||
781 | static void kmac_ghdestroy(ghash *h) | |
782 | { kmac_ghctx *cc = (kmac_ghctx *)h; BURN(cc); S_DESTROY(cc); } | |
783 | ||
784 | static ghash *kmac_ghcopy(ghash *h) | |
785 | { | |
786 | kmac_ghctx *cc = (kmac_ghctx *)h; | |
787 | kmac_ghctx *hc = S_CREATE(kmac_ghctx); | |
788 | *hc = *cc; | |
789 | return (&hc->h); | |
790 | } | |
791 | ||
792 | static ghash *kmac_ghinit(void) | |
793 | { assert(((void)"Attempt to instantiate an unkeyed MAC", 0)); return (0); } | |
794 | ||
795 | static ghash *kmac_gminit(gmac *m) | |
796 | { | |
797 | kmac_gmctx *cc = (kmac_gmctx *)m; | |
798 | kmac_ghctx *hc = S_CREATE(kmac_ghctx); | |
799 | hc->h.ops = cc->hops; | |
800 | hc->c = cc->c; | |
801 | return (&hc->h); | |
802 | } | |
803 | ||
804 | static void kmac_gmdestroy(gmac *m) | |
805 | { kmac_gmctx *cc = (kmac_gmctx *)m; BURN(cc); S_DESTROY(cc); } | |
806 | ||
807 | static gmac *kmac128_gmkey(const void *k, size_t sz) | |
808 | { | |
809 | kmac_gmctx *cc = S_CREATE(kmac_gmctx); | |
810 | cc->m.ops = &kmac128_gmops; cc->hops = &kmac128_ghops; | |
811 | kmac128_init(&cc->c, 0, 0, k, sz); | |
812 | return (&cc->m); | |
813 | } | |
814 | ||
815 | static gmac *kmac256_gmkey(const void *k, size_t sz) | |
816 | { | |
817 | kmac_gmctx *cc = S_CREATE(kmac_gmctx); | |
818 | cc->m.ops = &kmac256_gmops; cc->hops = &kmac256_ghops; | |
819 | kmac256_init(&cc->c, 0, 0, k, sz); | |
820 | return (&cc->m); | |
821 | } | |
822 | ||
823 | static const gchash | |
824 | kmac128_ghcls = { "kmac128", KMAC128_TAGSZ, kmac_ghinit, 168 }, | |
825 | kmac256_ghcls = { "kmac256", KMAC256_TAGSZ, kmac_ghinit, 136 }; | |
826 | ||
827 | const gcmac | |
828 | kmac128 = { "kmac128", KMAC128_TAGSZ, kmac128_keysz, kmac128_gmkey }, | |
829 | kmac256 = { "kmac256", KMAC256_TAGSZ, kmac256_keysz, kmac256_gmkey }; | |
830 | ||
831 | static const ghash_ops | |
832 | kmac128_ghops = { &kmac128_ghcls, kmac_ghhash, kmac_ghdone, | |
833 | kmac_ghdestroy, kmac_ghcopy }, | |
834 | kmac256_ghops = { &kmac256_ghcls, kmac_ghhash, kmac_ghdone, | |
835 | kmac_ghdestroy, kmac_ghcopy }; | |
836 | ||
837 | static const gmac_ops | |
838 | kmac128_gmops = { &kmac128, kmac_gminit, kmac_gmdestroy }, | |
839 | kmac256_gmops = { &kmac256, kmac_gminit, kmac_gmdestroy }; | |
840 | ||
841 | /* --- Random generator XOF interface --- */ | |
842 | ||
843 | typedef struct kmac_grctx { | |
844 | grand gr; | |
845 | kmac_ctx k, c; | |
846 | } kmac_grctx; | |
847 | ||
848 | static int kmac_grmisc(grand *r, unsigned op, ...) | |
849 | { | |
850 | kmac_grctx *cc = (kmac_grctx *)r; | |
851 | int rc = 0; | |
852 | octet buf[64]; | |
853 | va_list ap; | |
854 | int i; | |
855 | uint32 u; | |
856 | grand *rr; | |
857 | const void *p; | |
858 | size_t sz; | |
859 | ||
860 | va_start(ap, op); | |
861 | switch (op) { | |
862 | case GRAND_CHECK: | |
863 | op = va_arg(ap, unsigned); | |
864 | switch (op) { | |
865 | case GRAND_SEEDINT: case GRAND_SEEDUINT32: | |
866 | case GRAND_SEEDBLOCK: case GRAND_SEEDRAND: | |
867 | rc = 1; break; | |
868 | default: | |
869 | rc = 0; break; | |
870 | } | |
871 | break; | |
872 | case GRAND_SEEDINT: | |
873 | i = va_arg(ap, int); STORE32_L(buf, i); p = buf; sz = 4; goto seed; | |
874 | case GRAND_SEEDUINT32: | |
875 | u = va_arg(ap, uint32); STORE32_L(buf, u); p = buf; sz = 4; goto seed; | |
876 | case GRAND_SEEDRAND: | |
877 | rr = va_arg(ap, grand *); | |
878 | p = buf; sz = (200 - cc->c.h.r)/2; GR_FILL(rr, buf, sz); goto seed; | |
879 | case GRAND_SEEDBLOCK: | |
880 | p = va_arg(ap, const void *); sz = va_arg(ap, size_t); | |
881 | seed: | |
882 | cc->c = cc->k; | |
883 | kmac_hash(&cc->c, p, sz); | |
884 | kmac_xof(&cc->c); | |
885 | break; | |
886 | default: GRAND_BADOP; break; | |
887 | } | |
888 | return (rc); | |
889 | } | |
890 | ||
891 | static void kmac_grdestroy(grand *r) | |
892 | { kmac_grctx *cc = (kmac_grctx *)r; BURN(cc); S_DESTROY(cc); } | |
893 | ||
894 | static octet kmac_grbyte(grand *r) | |
895 | { | |
896 | kmac_grctx *cc = (kmac_grctx *)r; | |
897 | octet o; | |
898 | kmac_get(&cc->c, &o, 1); | |
899 | return (o); | |
900 | } | |
901 | ||
902 | static uint32 kmac_grword(grand *r) | |
903 | { | |
904 | kmac_grctx *cc = (kmac_grctx *)r; | |
905 | octet b[4]; | |
906 | kmac_get(&cc->c, &b, 4); | |
907 | return (LOAD32(b)); | |
908 | } | |
909 | ||
910 | static void kmac_grfill(grand *r, void *p, size_t sz) | |
911 | { kmac_grctx *cc = (kmac_grctx *)r; kmac_get(&cc->c, p, sz); } | |
912 | ||
913 | static const grand_ops | |
914 | kmac128_grops = { "kmac128", GRAND_CRYPTO, 0, | |
915 | kmac_grmisc, kmac_grdestroy, kmac_grword, | |
916 | kmac_grbyte, kmac_grword, grand_defaultrange, | |
917 | kmac_grfill }, | |
918 | kmac256_grops = { "kmac256", GRAND_CRYPTO, 0, | |
919 | kmac_grmisc, kmac_grdestroy, kmac_grword, | |
920 | kmac_grbyte, kmac_grword, grand_defaultrange, | |
921 | kmac_grfill }; | |
922 | ||
923 | /* --- @kmac{128,256}_rand@ --- * | |
924 | * | |
925 | * Arguments: @const void *perso@ = personalization string, or null | |
926 | * @size_t psz@ = length of personalization string | |
927 | * @const void *k@ = pointer to seed material | |
928 | * @size_t sz@ = size of the seed | |
929 | * | |
930 | * Returns: A pseudorandom generator with the given key. | |
931 | * | |
932 | * Use: The generator processes an empty message by default, but this | |
933 | * can be changed by seeding it. | |
934 | */ | |
935 | ||
936 | grand *kmac128_rand(const void *perso, size_t psz, const void *k, size_t sz) | |
937 | { | |
938 | kmac_grctx *cc = S_CREATE(kmac_grctx); | |
939 | cc->gr.ops = &kmac128_grops; | |
940 | kmac128_init(&cc->k, perso, psz, k, sz); | |
941 | cc->c = cc->k; kmac_xof(&cc->c); | |
942 | return (&cc->gr); | |
943 | } | |
944 | ||
945 | grand *kmac256_rand(const void *perso, size_t psz, const void *k, size_t sz) | |
946 | { | |
947 | kmac_grctx *cc = S_CREATE(kmac_grctx); | |
948 | cc->gr.ops = &kmac256_grops; | |
949 | kmac256_init(&cc->k, perso, psz, k, sz); | |
950 | cc->c = cc->k; kmac_xof(&cc->c); | |
951 | return (&cc->gr); | |
952 | } | |
953 | ||
954 | /*----- Test rig ----------------------------------------------------------*/ | |
955 | ||
956 | #ifdef TEST_RIG | |
957 | ||
958 | #include <stdio.h> | |
959 | ||
141c1284 | 960 | #include <mLib/macros.h> |
78b4ea88 MW |
961 | #include <mLib/report.h> |
962 | #include <mLib/testrig.h> | |
963 | ||
964 | HASHES(HASH_VERIFYX) | |
965 | ||
966 | static int vrf_sha3_mct(void (*initfn)(sha3_ctx *), | |
967 | int n, dstr *in, dstr *out) | |
968 | { | |
969 | sha3_ctx ctx; | |
970 | dstr d = DSTR_INIT; | |
971 | int ok = 1; | |
972 | int i; | |
973 | ||
974 | if (in->len != out->len) die(1, "inconsistent lengths"); | |
975 | dstr_ensure(&d, out->len); d.len = out->len; | |
976 | memcpy(d.buf, in->buf, in->len); | |
977 | for (i = 0; i < n; i++) { | |
978 | initfn(&ctx); | |
979 | sha3_hash(&ctx, d.buf, d.len); | |
980 | sha3_done(&ctx, d.buf); | |
981 | } | |
982 | ||
141c1284 | 983 | if (MEMCMP(d.buf, !=, out->buf, out->len)) { |
78b4ea88 MW |
984 | ok = 0; |
985 | printf("\nfail\n\tsteps = %d\n\tinput = ", n); | |
986 | type_hex.dump(in, stdout); | |
987 | printf("\n\texpected = "); | |
988 | type_hex.dump(out, stdout); | |
989 | fputs("\n\tcomputed = ", stdout); | |
990 | type_hex.dump(&d, stdout); | |
991 | putchar('\n'); | |
992 | } | |
993 | ||
994 | dstr_destroy(&d); | |
995 | return (ok); | |
996 | } | |
997 | ||
998 | #define VRF_MCT(PRE, pre, name) \ | |
999 | static int vrf_##pre##_mct(dstr *v) \ | |
1000 | { return (vrf_sha3_mct(pre##_init, *(int *)v[0].buf, &v[1], &v[2])); } | |
1001 | HASHES(VRF_MCT) | |
1002 | #undef VRF_MCT | |
1003 | ||
1004 | static int vrf_shaky(void (*initfn)(shake_ctx *, | |
1005 | const void *, size_t, | |
1006 | const void *, size_t), | |
1007 | dstr *func, dstr *perso, | |
1008 | dstr *m, dstr *want) | |
1009 | { | |
1010 | shake_ctx ctx; | |
1011 | dstr d = DSTR_INIT; | |
1012 | int ok = 1; | |
1013 | int i; | |
1014 | const int *ip; | |
1015 | size_t sz; | |
1016 | octet *p; | |
1017 | static const int szs[] = { 1, 7, 192, -1, 0 }; | |
1018 | ||
1019 | dstr_ensure(&d, want->len); d.len = want->len; | |
1020 | for (ip = szs; *ip; ip++) { | |
1021 | initfn(&ctx, | |
1022 | func ? func->buf : 0, func ? func->len : 0, | |
1023 | perso ? perso->buf : 0, perso ? perso->len : 0); | |
1024 | p = (octet *)m->buf; sz = m->len; | |
1025 | i = (*ip == -1 || *ip > sz) ? sz : *ip; | |
1026 | while (sz) { | |
1027 | if (i > sz) i = sz; | |
1028 | shake_hash(&ctx, p, i); | |
1029 | p += i; sz -= i; | |
1030 | } | |
1031 | shake_xof(&ctx); | |
1032 | ||
1033 | p = (octet *)d.buf; sz = d.len; | |
1034 | i = (*ip == -1 || *ip > sz) ? sz : *ip; | |
1035 | while (sz) { | |
1036 | if (i > sz) i = sz; | |
1037 | shake_get(&ctx, p, i); | |
1038 | p += i; sz -= i; | |
1039 | } | |
1040 | ||
141c1284 | 1041 | if (MEMCMP(d.buf, !=, want->buf, want->len)) { |
78b4ea88 MW |
1042 | ok = 0; |
1043 | printf("\nfail (get):\n\tstep = %i\n\tinput = ", *ip); | |
1044 | type_hex.dump(m, stdout); | |
1045 | if (func) printf("\n\tfunction = `%s'", func->buf); | |
1046 | if (perso) printf("\n\tperso = `%s'", perso->buf); | |
1047 | printf("\n\texpected = "); | |
1048 | type_hex.dump(want, stdout); | |
1049 | fputs("\n\tcomputed = ", stdout); | |
1050 | type_hex.dump(&d, stdout); | |
1051 | putchar('\n'); | |
1052 | } | |
1053 | ||
1054 | initfn(&ctx, | |
1055 | func ? func->buf : 0, func ? func->len : 0, | |
1056 | perso ? perso->buf : 0, perso ? perso->len : 0); | |
1057 | p = (octet *)m->buf; sz = m->len; | |
1058 | i = (*ip == -1 || *ip > sz) ? sz : *ip; | |
1059 | while (sz) { | |
1060 | if (i > sz) i = sz; | |
1061 | shake_hash(&ctx, p, i); | |
1062 | p += i; sz -= i; | |
1063 | } | |
1064 | shake_xof(&ctx); | |
1065 | ||
1066 | memset(d.buf, 0, d.len); | |
1067 | p = (octet *)d.buf; sz = d.len; | |
1068 | i = (*ip == -1 || *ip > sz) ? sz : *ip; | |
1069 | while (sz) { | |
1070 | if (i > sz) i = sz; | |
1071 | shake_mask(&ctx, p, p, i); | |
1072 | p += i; sz -= i; | |
1073 | } | |
1074 | ||
141c1284 | 1075 | if (MEMCMP(d.buf, !=, want->buf, want->len)) { |
78b4ea88 MW |
1076 | ok = 0; |
1077 | printf("\nfail (mask):\n\tstep = %i\n\tinput = ", *ip); | |
1078 | type_hex.dump(m, stdout); | |
1079 | if (func) printf("\n\tfunction = `%s'", func->buf); | |
1080 | if (perso) printf("\n\tperso = `%s'", perso->buf); | |
1081 | printf("\n\texpected = "); | |
1082 | type_hex.dump(want, stdout); | |
1083 | fputs("\n\tcomputed = ", stdout); | |
1084 | type_hex.dump(&d, stdout); | |
1085 | putchar('\n'); | |
1086 | } | |
1087 | } | |
1088 | ||
1089 | dstr_destroy(&d); | |
1090 | return (ok); | |
1091 | } | |
1092 | ||
1093 | static int vrf_cshake128(dstr *v) | |
1094 | { | |
1095 | return (vrf_shaky(cshake128_init, &v[0], &v[1], &v[2], &v[3])); | |
1096 | } | |
1097 | ||
1098 | static int vrf_cshake256(dstr *v) | |
1099 | { | |
1100 | return (vrf_shaky(cshake256_init, &v[0], &v[1], &v[2], &v[3])); | |
1101 | } | |
1102 | ||
1103 | static void shake128_init_adaptor(shake_ctx *ctx, | |
1104 | const void *func, size_t fsz, | |
1105 | const void *perso, size_t psz) | |
1106 | { assert(!fsz); assert(!psz); shake128_init(ctx);} | |
1107 | ||
1108 | static void shake256_init_adaptor(shake_ctx *ctx, | |
1109 | const void *func, size_t fsz, | |
1110 | const void *perso, size_t psz) | |
1111 | { assert(!fsz); assert(!psz); shake256_init(ctx);} | |
1112 | ||
1113 | static int vrf_shake128(dstr *v) | |
1114 | { return (vrf_shaky(shake128_init_adaptor, 0, 0, &v[0], &v[1])); } | |
1115 | ||
1116 | static int vrf_shake256(dstr *v) | |
1117 | { return (vrf_shaky(shake256_init_adaptor, 0, 0, &v[0], &v[1])); } | |
1118 | ||
1119 | static int vrf_kmac(void (*initfn)(kmac_ctx *, const void *, size_t, | |
1120 | const void *, size_t), | |
1121 | dstr *perso, int tsz, | |
1122 | dstr *k, dstr *m, dstr *want) | |
1123 | { | |
1124 | kmac_ctx ctx; | |
1125 | dstr d = DSTR_INIT; | |
1126 | int ok = 1; | |
1127 | ||
1128 | if (tsz && tsz != want->len) die(1, "inconsistent tag length request"); | |
1129 | dstr_ensure(&d, want->len); d.len = want->len; | |
1130 | initfn(&ctx, perso->buf, perso->len, k->buf, k->len); | |
1131 | kmac_hash(&ctx, m->buf, m->len); | |
1132 | if (tsz) kmac_done(&ctx, d.buf, tsz); | |
1133 | else { kmac_xof(&ctx); kmac_get(&ctx, d.buf, d.len); } | |
1134 | ||
141c1284 | 1135 | if (MEMCMP(d.buf, !=, want->buf, want->len)) { |
78b4ea88 MW |
1136 | ok = 0; |
1137 | printf("\nfail"); | |
1138 | printf("\n\tperso = `%s'", perso->buf); | |
1139 | printf("\n\ttag size = %d", tsz); | |
1140 | printf("\n\tkey = "); type_hex.dump(k, stdout); | |
1141 | printf("\n\tinput = "); type_hex.dump(m, stdout); | |
1142 | printf("\n\texpected = "); type_hex.dump(want, stdout); | |
1143 | fputs("\n\tcomputed = ", stdout); type_hex.dump(&d, stdout); | |
1144 | putchar('\n'); | |
1145 | } | |
1146 | ||
1147 | dstr_destroy(&d); | |
1148 | return (ok); | |
1149 | } | |
1150 | ||
1151 | static int vrf_kmac128(dstr *v) | |
1152 | { | |
1153 | return (vrf_kmac(kmac128_init, &v[0], *(int *)v[1].buf, | |
1154 | &v[2], &v[3], &v[4])); | |
1155 | } | |
1156 | ||
1157 | static int vrf_kmac256(dstr *v) | |
1158 | { | |
1159 | return (vrf_kmac(kmac256_init, &v[0], *(int *)v[1].buf, | |
1160 | &v[2], &v[3], &v[4])); | |
1161 | } | |
1162 | ||
1163 | static const test_chunk defs[] = { | |
1164 | HASHES(HASH_TESTDEFSX) | |
1165 | #define VRF_MCTDEF(PRE, pre, name) \ | |
1166 | { name "-mct", vrf_##pre##_mct, \ | |
1167 | { &type_int, &type_hex, &type_hex, 0 } }, | |
1168 | HASHES(VRF_MCTDEF) | |
1169 | #undef VRF_MCTDEF | |
1170 | { "shake128", vrf_shake128, { &type_hex, &type_hex, 0 } }, | |
1171 | { "shake256", vrf_shake256, { &type_hex, &type_hex, 0 } }, | |
1172 | { "cshake128", vrf_cshake128, | |
1173 | { &type_string, &type_string, &type_hex, &type_hex, 0 } }, | |
1174 | { "cshake256", vrf_cshake256, | |
1175 | { &type_string, &type_string, &type_hex, &type_hex, 0 } }, | |
1176 | { "kmac128", vrf_kmac128, | |
1177 | { &type_string, &type_int, &type_hex, &type_hex, &type_hex, 0 } }, | |
1178 | { "kmac256", vrf_kmac256, | |
1179 | { &type_string, &type_int, &type_hex, &type_hex, &type_hex, 0 } }, | |
1180 | { 0, 0, { 0 } } | |
1181 | }; | |
1182 | ||
1183 | int main(int argc, char *argv[]) | |
1184 | { | |
1185 | test_run(argc, argv, defs, SRCDIR"/t/sha3"); | |
1186 | return (0); | |
1187 | } | |
1188 | ||
1189 | #endif | |
1190 | ||
1191 | /*----- That's all, folks -------------------------------------------------*/ |