| 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 | |
| 234 | SET64(t, ((n&~(size_t)MASK32) >> 16) >> 16, n&MASK32); |
| 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 | |
| 247 | SET64(t, ((n&~(size_t)MASK32) >> 16) >> 16, n&MASK32); |
| 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); |
| 566 | cc->gc.ops = &shake256_gcops; |
| 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 | |
| 960 | #include <mLib/macros.h> |
| 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 | |
| 983 | if (MEMCMP(d.buf, !=, out->buf, out->len)) { |
| 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 | |
| 1041 | if (MEMCMP(d.buf, !=, want->buf, want->len)) { |
| 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 | |
| 1075 | if (MEMCMP(d.buf, !=, want->buf, want->len)) { |
| 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 | |
| 1135 | if (MEMCMP(d.buf, !=, want->buf, want->len)) { |
| 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 -------------------------------------------------*/ |