progs/perftest.c: Use from Glibc syscall numbers.
[catacomb] / symm / sha3.c
CommitLineData
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
40static 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
50static void step(sha3_ctx *ctx) { keccak1600_p(&ctx->s, &ctx->s, 24); }
51
52static 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
66static 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
76enum {
77 OP_CSHAKE = 0x04,
78 OP_SHA3 = 0x06,
79 OP_SHAKE = 0x1f
80};
81
82enum { 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
95static 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
101void sha3_224_init(sha3_ctx *ctx) { init_sha3(ctx, 224); }
102void sha3_256_init(sha3_ctx *ctx) { init_sha3(ctx, 256); }
103void sha3_384_init(sha3_ctx *ctx) { init_sha3(ctx, 384); }
104void 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
118void 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
153void 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
183static 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
196void sha3_224_set(sha3_ctx *ctx, const void *buf, unsigned long count)
197 { set(ctx, buf, count, 224); }
198void sha3_256_set(sha3_ctx *ctx, const void *buf, unsigned long count)
199 { set(ctx, buf, count, 256); }
200void sha3_384_set(sha3_ctx *ctx, const void *buf, unsigned long count)
201 { set(ctx, buf, count, 384); }
202void 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
216unsigned 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")
224HASHES(GHASH_DEFX)
225
226/*----- The cSHAKE XOF algorithm ------------------------------------------*/
227
228static 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
241static 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
254static 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
257static void bytepad_before(shake_ctx *ctx)
258 { leftenc_sz(ctx, ctx->h.r); }
259
260static 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
275const 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
293static 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
310void 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
315void 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
330void shake128_init(shake_ctx *ctx) { init_shake(ctx, 128, 0, 0, 0, 0); }
331void 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
345void 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
358void 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
378void 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
423void 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
473void 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
478typedef struct shake_ghctx {
479 ghash h;
480 shake_ctx c;
481 octet hb[SHAKE256_HASHSZ];
482} shake_ghctx;
483
484static const ghash_ops shake128_ghops, shake256_ghops;
485
486static 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
489static 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
497static void shake_ghdestroy(ghash *h)
498 { shake_ghctx *cc = (shake_ghctx *)h; BURN(cc); S_DESTROY(cc); }
499
500static 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
508static 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
516static 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
524const gchash
525 shake128 = { "shake128", SHAKE128_HASHSZ, shake128_ghinit, 168 },
526 shake256 = { "shake256", SHAKE256_HASHSZ, shake256_ghinit, 136 };
527
528static 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
536typedef struct shake_gcctx {
537 gcipher gc;
538 shake_ctx c;
539} shake_gcctx;
540
541static const gcipher_ops shake128_gcops, shake256_gcops;
542
543static 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
546static void shake_gcdestroy(gcipher *c)
547 { shake_gcctx *cc = (shake_gcctx *)c; BURN(*cc); S_DESTROY(cc); }
548
549static 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
555static 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
563static 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
571const 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
577typedef struct shake_grctx {
578 grand gr;
579 shake_ctx c;
580} shake_grctx;
581
582static 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
592static void shake_grdestroy(grand *r)
593 { shake_grctx *cc = (shake_grctx *)r; BURN(cc); S_DESTROY(cc); }
594
595static 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
603static 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
611static void shake_grfill(grand *r, void *p, size_t sz)
612 { shake_grctx *cc = (shake_grctx *)r; shake_get(&cc->c, p, sz); }
613
614static 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
640grand *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
648grand *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
668grand *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
679grand *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
692typedef 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
708static 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
716void 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
720void 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
734void 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
750void 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
755typedef struct kmac_ghctx {
756 ghash h;
757 kmac_ctx c;
758 octet hb[KMAC256_TAGSZ];
759} kmac_ghctx;
760
761typedef struct kmac_gmctx {
762 gmac m;
763 kmac_ctx c;
764 const ghash_ops *hops;
765} kmac_gmctx;
766
767static const ghash_ops kmac128_ghops, kmac256_ghops;
768static const gmac_ops kmac128_gmops, kmac256_gmops;
769
770static 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
773static 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
781static void kmac_ghdestroy(ghash *h)
782 { kmac_ghctx *cc = (kmac_ghctx *)h; BURN(cc); S_DESTROY(cc); }
783
784static 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
792static ghash *kmac_ghinit(void)
793 { assert(((void)"Attempt to instantiate an unkeyed MAC", 0)); return (0); }
794
795static 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
804static void kmac_gmdestroy(gmac *m)
805 { kmac_gmctx *cc = (kmac_gmctx *)m; BURN(cc); S_DESTROY(cc); }
806
807static 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
815static 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
823static const gchash
824 kmac128_ghcls = { "kmac128", KMAC128_TAGSZ, kmac_ghinit, 168 },
825 kmac256_ghcls = { "kmac256", KMAC256_TAGSZ, kmac_ghinit, 136 };
826
827const gcmac
828 kmac128 = { "kmac128", KMAC128_TAGSZ, kmac128_keysz, kmac128_gmkey },
829 kmac256 = { "kmac256", KMAC256_TAGSZ, kmac256_keysz, kmac256_gmkey };
830
831static 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
837static 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
843typedef struct kmac_grctx {
844 grand gr;
845 kmac_ctx k, c;
846} kmac_grctx;
847
848static 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
891static void kmac_grdestroy(grand *r)
892 { kmac_grctx *cc = (kmac_grctx *)r; BURN(cc); S_DESTROY(cc); }
893
894static 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
902static 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
910static void kmac_grfill(grand *r, void *p, size_t sz)
911 { kmac_grctx *cc = (kmac_grctx *)r; kmac_get(&cc->c, p, sz); }
912
913static 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
936grand *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
945grand *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
964HASHES(HASH_VERIFYX)
965
966static 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])); }
1001HASHES(VRF_MCT)
1002#undef VRF_MCT
1003
1004static 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
1093static int vrf_cshake128(dstr *v)
1094{
1095 return (vrf_shaky(cshake128_init, &v[0], &v[1], &v[2], &v[3]));
1096}
1097
1098static int vrf_cshake256(dstr *v)
1099{
1100 return (vrf_shaky(cshake256_init, &v[0], &v[1], &v[2], &v[3]));
1101}
1102
1103static 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
1108static 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
1113static int vrf_shake128(dstr *v)
1114 { return (vrf_shaky(shake128_init_adaptor, 0, 0, &v[0], &v[1])); }
1115
1116static int vrf_shake256(dstr *v)
1117 { return (vrf_shaky(shake256_init_adaptor, 0, 0, &v[0], &v[1])); }
1118
1119static 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
1151static 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
1157static 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
1163static 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
1183int 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 -------------------------------------------------*/