1 /* $NetBSD: entpool.c,v 1.1 2020/04/30 03:28:19 riastradh Exp $ */ 2 3 /*- 4 * Copyright (c) 2019 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Taylor R. Campbell. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * Entropy pool (`reseedable pseudorandom number generator') based on a 34 * sponge duplex, following the design described and analyzed in 35 * 36 * Guido Bertoni, Joan Daemen, Michaël Peeters, and Gilles Van 37 * Assche, `Sponge-Based Pseudo-Random Number Generators', in 38 * Stefan Mangard and François-Xavier Standaert, eds., 39 * Cryptographic Hardware and Embedded Systems—CHES 2010, Springer 40 * LNCS 6225, pp. 33–47. 41 * https://link.springer.com/chapter/10.1007/978-3-642-15031-9_3 42 * https://keccak.team/files/SpongePRNG.pdf 43 * 44 * Guido Bertoni, Joan Daemen, Michaël Peeters, and Gilles Van 45 * Assche, `Duplexing the Sponge: Single-Pass Authenticated 46 * Encryption and Other Applications', in Ali Miri and Serge 47 * Vaudenay, eds., Selected Areas in Cryptography—SAC 2011, 48 * Springer LNCS 7118, pp. 320–337. 49 * https://link.springer.com/chapter/10.1007/978-3-642-28496-0_19 50 * https://keccak.team/files/SpongeDuplex.pdf 51 * 52 * We make the following tweaks that don't affect security: 53 * 54 * - Samples are length-delimited 7-bit variable-length encoding. 55 * The encoding is still injective, so the security theorems 56 * continue to apply. 57 * 58 * - Output is not buffered -- callers should draw 32 bytes and 59 * expand with a stream cipher. In effect, every output draws 60 * the full rate, and we just discard whatever the caller didn't 61 * ask for; the impact is only on performance, not security. 62 * 63 * On top of the underlying sponge state, an entropy pool maintains an 64 * integer i in [0, RATE-1] indicating where to write the next byte in 65 * the input buffer. Zeroing an entropy pool initializes it. 66 */ 67 68 #if defined(_KERNEL) || defined(_STANDALONE) 69 #include <sys/cdefs.h> 70 __KERNEL_RCSID(0, "$NetBSD: entpool.c,v 1.1 2020/04/30 03:28:19 riastradh Exp $"); 71 #endif 72 73 #include "entpool.h" 74 #include ENTPOOL_HEADER 75 76 #if defined(_KERNEL) || defined(_STANDALONE) 77 #include <sys/types.h> 78 #include <lib/libkern/libkern.h> 79 #define ASSERT KASSERT 80 #else 81 #include <sys/cdefs.h> 82 #include <assert.h> 83 #include <stdbool.h> 84 #include <stdint.h> 85 #include <string.h> 86 #define ASSERT assert 87 #define CTASSERT __CTASSERT 88 #endif 89 90 #define secret /* must not use in variable-time operations; should zero */ 91 #define arraycount(A) (sizeof(A)/sizeof((A)[0])) 92 #define MIN(X,Y) ((X) < (Y) ? (X) : (Y)) 93 94 #define RATE ENTPOOL_RATE 95 96 /* 97 * stir(P) 98 * 99 * Internal subroutine to apply the sponge permutation to the 100 * state in P. Resets P->i to 0 to indicate that the input buffer 101 * is empty. 102 */ 103 static void 104 stir(struct entpool *P) 105 { 106 size_t i; 107 108 /* 109 * Switch to the permutation's byte order, if necessary, apply 110 * permutation, and then switch back. This way we can data in 111 * and out byte by byte, but get the same answers out of test 112 * vectors. 113 */ 114 for (i = 0; i < arraycount(P->s.w); i++) 115 P->s.w[i] = ENTPOOL_WTOH(P->s.w[i]); 116 ENTPOOL_PERMUTE(P->s.w); 117 for (i = 0; i < arraycount(P->s.w); i++) 118 P->s.w[i] = ENTPOOL_HTOW(P->s.w[i]); 119 120 /* Reset the input buffer. */ 121 P->i = 0; 122 } 123 124 /* 125 * entpool_enter(P, buf, len) 126 * 127 * Enter len bytes from buf into the entropy pool P, stirring as 128 * needed. Corresponds to P.feed in the paper. 129 */ 130 void 131 entpool_enter(struct entpool *P, const void *buf, size_t len) 132 { 133 const uint8_t *p = buf; 134 size_t n = len, n1 = n; 135 136 /* Sanity-check P->i. */ 137 ASSERT(P->i <= RATE-1); 138 139 /* Encode the length, stirring as needed. */ 140 while (n1) { 141 if (P->i == RATE-1) 142 stir(P); 143 ASSERT(P->i < RATE-1); 144 P->s.u8[P->i++] ^= (n1 >= 0x80 ? 0x80 : 0) | (n1 & 0x7f); 145 n1 >>= 7; 146 } 147 148 /* Enter the sample, stirring as needed. */ 149 while (n --> 0) { 150 if (P->i == RATE-1) 151 stir(P); 152 ASSERT(P->i < RATE-1); 153 P->s.u8[P->i++] ^= *p++; 154 } 155 156 /* If we filled the input buffer exactly, stir once more. */ 157 if (P->i == RATE-1) 158 stir(P); 159 ASSERT(P->i < RATE-1); 160 } 161 162 /* 163 * entpool_enter_nostir(P, buf, len) 164 * 165 * Enter as many bytes as possible, up to len, from buf into the 166 * entropy pool P. Roughly corresponds to P.feed in the paper, 167 * but we stop if we would have run the permutation. 168 * 169 * Return true if the sample was consumed in its entirety, or true 170 * if the sample was truncated so the caller should arrange to 171 * call entpool_stir when it is next convenient to do so. 172 * 173 * This function is cheap -- it only xors the input into the 174 * state, and never calls the underlying permutation, but it may 175 * truncate samples. 176 */ 177 bool 178 entpool_enter_nostir(struct entpool *P, const void *buf, size_t len) 179 { 180 const uint8_t *p = buf; 181 size_t n0, n; 182 183 /* Sanity-check P->i. */ 184 ASSERT(P->i <= RATE-1); 185 186 /* If the input buffer is full, fail. */ 187 if (P->i == RATE-1) 188 return false; 189 ASSERT(P->i < RATE-1); 190 191 /* 192 * Truncate the sample and enter it with 1-byte length encoding 193 * -- don't bother with variable-length encoding, not worth the 194 * trouble. 195 */ 196 n = n0 = MIN(127, MIN(len, RATE-1 - P->i - 1)); 197 P->s.u8[P->i++] ^= n; 198 while (n --> 0) 199 P->s.u8[P->i++] ^= *p++; 200 201 /* Can't guarantee anything better than 0 <= i <= RATE-1. */ 202 ASSERT(P->i <= RATE-1); 203 204 /* Return true if all done, false if truncated and in need of stir. */ 205 return (n0 == len); 206 } 207 208 /* 209 * entpool_stir(P) 210 * 211 * Stir the entropy pool after entpool_enter_nostir fails. If it 212 * has already been stirred already, this has no effect. 213 */ 214 void 215 entpool_stir(struct entpool *P) 216 { 217 218 /* Sanity-check P->i. */ 219 ASSERT(P->i <= RATE-1); 220 221 /* If the input buffer is full, stir. */ 222 if (P->i == RATE-1) 223 stir(P); 224 ASSERT(P->i < RATE-1); 225 } 226 227 /* 228 * entpool_extract(P, buf, len) 229 * 230 * Extract len bytes from the entropy pool P into buf. 231 * Corresponds to iterating P.fetch/P.forget in the paper. 232 * (Feeding the output back in -- as P.forget does -- is the same 233 * as zeroing what we just read out.) 234 */ 235 void 236 entpool_extract(struct entpool *P, secret void *buf, size_t len) 237 { 238 uint8_t *p = buf; 239 size_t n = len; 240 241 /* Sanity-check P->i. */ 242 ASSERT(P->i <= RATE-1); 243 244 /* If input buffer is not empty, stir. */ 245 if (P->i != 0) 246 stir(P); 247 ASSERT(P->i == 0); 248 249 /* 250 * Copy out and zero (RATE-1)-sized chunks at a time, stirring 251 * with a bit set to distinguish this from inputs. 252 */ 253 while (n >= RATE-1) { 254 memcpy(p, P->s.u8, RATE-1); 255 memset(P->s.u8, 0, RATE-1); 256 P->s.u8[RATE-1] ^= 0x80; 257 stir(P); 258 p += RATE-1; 259 n -= RATE-1; 260 } 261 262 /* 263 * If there's anything left, copy out a partial rate's worth 264 * and zero the entire rate's worth, stirring with a bit set to 265 * distinguish this from inputs. 266 */ 267 if (n) { 268 ASSERT(n < RATE-1); 269 memcpy(p, P->s.u8, n); /* Copy part of it. */ 270 memset(P->s.u8, 0, RATE-1); /* Zero all of it. */ 271 P->s.u8[RATE-1] ^= 0x80; 272 stir(P); 273 } 274 } 275 276 /* 277 * Known-answer tests 278 */ 279 280 #if ENTPOOL_SMALL 281 282 #define KATLEN 15 283 284 /* Gimli */ 285 static const uint8_t known_answers[][KATLEN] = { 286 [0] = { 287 0x69,0xb8,0x49,0x0d,0x39,0xfb,0x42,0x61, 288 0xf7,0x66,0xdf,0x04,0xb6,0xed,0x11, 289 }, 290 [1] = { 291 0x74,0x15,0x16,0x49,0x31,0x07,0x77,0xa1, 292 0x3b,0x4d,0x78,0xc6,0x5d,0xef,0x87, 293 }, 294 [2] = { 295 0xae,0xfd,0x7d,0xc4,0x3b,0xce,0x09,0x25, 296 0xbf,0x60,0x21,0x6e,0x3c,0x3a,0x84, 297 }, 298 [3] = { 299 0xae,0xfd,0x7d,0xc4,0x3b,0xce,0x09,0x25, 300 0xbf,0x60,0x21,0x6e,0x3c,0x3a,0x84, 301 }, 302 [4] = { 303 0x69,0xb8,0x49,0x0d,0x39,0xfb,0x42,0x61, 304 0xf7,0x66,0xdf,0x04,0xb6,0xed,0x11, 305 }, 306 [5] = { 307 0xa9,0x3c,0x3c,0xac,0x5f,0x6d,0x80,0xdc, 308 0x33,0x0c,0xb2,0xe3,0xdd,0x55,0x31, 309 }, 310 [6] = { 311 0x2e,0x69,0x1a,0x2a,0x2d,0x09,0xd4,0x5e, 312 0x49,0xcc,0x8c,0xb2,0x0b,0xcc,0x42, 313 }, 314 [7] = { 315 0xae,0xfd,0x7d,0xc4,0x3b,0xce,0x09,0x25, 316 0xbf,0x60,0x21,0x6e,0x3c,0x3a,0x84, 317 }, 318 [8] = { 319 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 320 0x00,0x00,0x00,0x00,0x00,0x00,0x00, 321 }, 322 [9] = { 323 0x69,0xb8,0x49,0x0d,0x39,0xfb,0x42,0x61, 324 0xf7,0x66,0xdf,0x04,0xb6,0xed,0x11, 325 }, 326 [10] = { 327 0x2e,0x69,0x1a,0x2a,0x2d,0x09,0xd4,0x5e, 328 0x49,0xcc,0x8c,0xb2,0x0b,0xcc,0x42, 329 }, 330 [11] = { 331 0x6f,0xfd,0xd2,0x29,0x78,0x46,0xc0,0x7d, 332 0xc7,0xf2,0x0a,0x2b,0x72,0xd6,0xc6, 333 }, 334 [12] = { 335 0x86,0xf0,0xc1,0xf9,0x95,0x0f,0xc9,0x12, 336 0xde,0x38,0x39,0x10,0x1f,0x8c,0xc4, 337 }, 338 }; 339 340 #else /* !ENTPOOL_SMALL */ 341 342 #define KATLEN 16 343 344 /* Keccak-p[1600, 24] */ 345 static const uint8_t known_answers[][KATLEN] = { 346 [0] = { 347 0x3b,0x20,0xf0,0xe9,0xce,0x94,0x48,0x07, 348 0x97,0xb6,0x16,0xb5,0xb5,0x05,0x1a,0xce, 349 }, 350 [1] = { 351 0x57,0x49,0x6e,0x28,0x7f,0xaa,0xee,0x6c, 352 0xa8,0xb0,0xf5,0x0b,0x87,0xae,0xd6,0xd6, 353 }, 354 [2] = { 355 0x51,0x72,0x0f,0x59,0x54,0xe1,0xaf,0xa8, 356 0x16,0x67,0xfa,0x3f,0x8a,0x19,0x52,0x50, 357 }, 358 [3] = { 359 0x51,0x72,0x0f,0x59,0x54,0xe1,0xaf,0xa8, 360 0x16,0x67,0xfa,0x3f,0x8a,0x19,0x52,0x50, 361 }, 362 [4] = { 363 0x3b,0x20,0xf0,0xe9,0xce,0x94,0x48,0x07, 364 0x97,0xb6,0x16,0xb5,0xb5,0x05,0x1a,0xce, 365 }, 366 [5] = { 367 0x95,0x23,0x77,0xe4,0x84,0xeb,0xaa,0x2e, 368 0x6a,0x99,0xc2,0x52,0x06,0x6d,0xdf,0xea, 369 }, 370 [6] = { 371 0x8c,0xdd,0x1b,0xaf,0x0e,0xf6,0xe9,0x1d, 372 0x51,0x33,0x68,0x38,0x8d,0xad,0x55,0x84, 373 }, 374 [7] = { 375 0x51,0x72,0x0f,0x59,0x54,0xe1,0xaf,0xa8, 376 0x16,0x67,0xfa,0x3f,0x8a,0x19,0x52,0x50, 377 }, 378 [8] = { 379 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 380 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 381 }, 382 [9] = { 383 0x3b,0x20,0xf0,0xe9,0xce,0x94,0x48,0x07, 384 0x97,0xb6,0x16,0xb5,0xb5,0x05,0x1a,0xce, 385 }, 386 [10] = { 387 0x8c,0xdd,0x1b,0xaf,0x0e,0xf6,0xe9,0x1d, 388 0x51,0x33,0x68,0x38,0x8d,0xad,0x55,0x84, 389 }, 390 [11] = { 391 0xf6,0xc1,0x14,0xbb,0x13,0x0a,0xaf,0xed, 392 0xca,0x0b,0x35,0x2c,0xf1,0x2b,0x1a,0x85, 393 }, 394 [12] = { 395 0xf9,0x4b,0x05,0xd1,0x8b,0xcd,0xb3,0xd0, 396 0x77,0x27,0xfe,0x46,0xf9,0x33,0xb2,0xa2, 397 }, 398 }; 399 400 #endif 401 402 #define KAT_BEGIN(P, n) memset(P, 0, sizeof(*(P))) 403 #define KAT_ERROR() return -1 404 #define KAT_END(P, n) do \ 405 { \ 406 uint8_t KAT_ACTUAL[KATLEN]; \ 407 entpool_extract(P, KAT_ACTUAL, KATLEN); \ 408 if (memcmp(KAT_ACTUAL, known_answers[n], KATLEN)) \ 409 return -1; \ 410 } while (0) 411 412 int 413 entpool_selftest(void) 414 { 415 struct entpool pool, *P = &pool; 416 uint8_t sample[1] = {0xff}; 417 uint8_t scratch[RATE]; 418 const uint8_t zero[RATE] = {0}; 419 420 /* Test entpool_enter with empty buffer. */ 421 KAT_BEGIN(P, 0); 422 entpool_stir(P); /* noop */ 423 entpool_enter(P, sample, 1); 424 entpool_stir(P); /* noop */ 425 KAT_END(P, 0); 426 427 /* Test entpool_enter with partial buffer. */ 428 KAT_BEGIN(P, 1); 429 entpool_stir(P); /* noop */ 430 #if ENTPOOL_SMALL 431 entpool_enter(P, zero, RATE-3); 432 #else 433 entpool_enter(P, zero, RATE-4); 434 #endif 435 entpool_stir(P); /* noop */ 436 entpool_enter(P, sample, 1); 437 entpool_stir(P); /* noop */ 438 KAT_END(P, 1); 439 440 /* Test entpool_enter with full buffer. */ 441 KAT_BEGIN(P, 2); 442 entpool_stir(P); /* noop */ 443 #if ENTPOOL_SMALL 444 if (!entpool_enter_nostir(P, zero, RATE-2)) 445 KAT_ERROR(); 446 #else 447 if (!entpool_enter_nostir(P, zero, 127)) 448 KAT_ERROR(); 449 if (!entpool_enter_nostir(P, zero, RATE-2 - 127 - 1)) 450 KAT_ERROR(); 451 #endif 452 entpool_enter(P, sample, 1); 453 entpool_stir(P); /* noop */ 454 KAT_END(P, 2); 455 456 /* Test entpool_enter with full buffer after stir. */ 457 KAT_BEGIN(P, 3); 458 entpool_stir(P); /* noop */ 459 #if ENTPOOL_SMALL 460 if (!entpool_enter_nostir(P, zero, RATE-2)) 461 KAT_ERROR(); 462 #else 463 CTASSERT(127 <= RATE-2); 464 if (!entpool_enter_nostir(P, zero, 127)) 465 KAT_ERROR(); 466 if (!entpool_enter_nostir(P, zero, RATE-2 - 127 - 1)) 467 KAT_ERROR(); 468 #endif 469 entpool_stir(P); 470 entpool_enter(P, sample, 1); 471 entpool_stir(P); /* noop */ 472 KAT_END(P, 3); 473 474 /* Test entpool_enter_nostir with empty buffer. */ 475 KAT_BEGIN(P, 4); 476 entpool_stir(P); /* noop */ 477 if (!entpool_enter_nostir(P, sample, 1)) 478 KAT_ERROR(); 479 entpool_stir(P); /* noop */ 480 KAT_END(P, 4); 481 482 /* Test entpool_enter_nostir with partial buffer. */ 483 KAT_BEGIN(P, 5); 484 entpool_stir(P); /* noop */ 485 #if ENTPOOL_SMALL 486 entpool_enter(P, zero, RATE-3); 487 #else 488 entpool_enter(P, zero, RATE-4); 489 #endif 490 entpool_stir(P); /* noop */ 491 if (entpool_enter_nostir(P, sample, 1)) 492 KAT_ERROR(); 493 entpool_stir(P); 494 KAT_END(P, 5); 495 496 /* Test entpool_enter_nostir with full buffer. */ 497 KAT_BEGIN(P, 6); 498 entpool_stir(P); /* noop */ 499 #if ENTPOOL_SMALL 500 if (!entpool_enter_nostir(P, zero, RATE-2)) 501 KAT_ERROR(); 502 #else 503 CTASSERT(127 <= RATE-2); 504 if (!entpool_enter_nostir(P, zero, 127)) 505 KAT_ERROR(); 506 if (!entpool_enter_nostir(P, zero, RATE-2 - 127 - 1)) 507 KAT_ERROR(); 508 #endif 509 if (entpool_enter_nostir(P, sample, 1)) 510 KAT_ERROR(); 511 entpool_stir(P); 512 KAT_END(P, 6); 513 514 /* Test entpool_enter_nostir with full buffer after stir. */ 515 KAT_BEGIN(P, 7); 516 entpool_stir(P); /* noop */ 517 #if ENTPOOL_SMALL 518 if (!entpool_enter_nostir(P, zero, RATE-2)) 519 KAT_ERROR(); 520 #else 521 CTASSERT(127 <= RATE-2); 522 if (!entpool_enter_nostir(P, zero, 127)) 523 KAT_ERROR(); 524 if (!entpool_enter_nostir(P, zero, RATE-2 - 127 - 1)) 525 KAT_ERROR(); 526 #endif 527 entpool_stir(P); 528 if (!entpool_enter_nostir(P, sample, 1)) 529 KAT_ERROR(); 530 entpool_stir(P); /* noop */ 531 KAT_END(P, 7); 532 533 /* Test entpool_extract with empty input buffer. */ 534 KAT_BEGIN(P, 8); 535 entpool_stir(P); /* noop */ 536 KAT_END(P, 8); 537 538 /* Test entpool_extract with nonempty input buffer. */ 539 KAT_BEGIN(P, 9); 540 entpool_stir(P); /* noop */ 541 entpool_enter(P, sample, 1); 542 entpool_stir(P); /* noop */ 543 KAT_END(P, 9); 544 545 /* Test entpool_extract with full input buffer. */ 546 KAT_BEGIN(P, 10); 547 entpool_stir(P); /* noop */ 548 #if ENTPOOL_SMALL 549 if (!entpool_enter_nostir(P, zero, RATE-2)) 550 KAT_ERROR(); 551 #else 552 CTASSERT(127 <= RATE-2); 553 if (!entpool_enter_nostir(P, zero, 127)) 554 KAT_ERROR(); 555 if (!entpool_enter_nostir(P, zero, RATE-2 - 127 - 1)) 556 KAT_ERROR(); 557 #endif 558 KAT_END(P, 10); 559 560 /* Test entpool_extract with iterated output. */ 561 KAT_BEGIN(P, 11); 562 entpool_stir(P); /* noop */ 563 entpool_extract(P, scratch, RATE-1 + 1); 564 entpool_stir(P); /* noop */ 565 KAT_END(P, 11); 566 567 /* Test extract, enter, extract. */ 568 KAT_BEGIN(P, 12); 569 entpool_stir(P); /* noop */ 570 entpool_extract(P, scratch, 1); 571 entpool_stir(P); /* noop */ 572 entpool_enter(P, sample, 1); 573 entpool_stir(P); /* noop */ 574 KAT_END(P, 12); 575 576 return 0; 577 } 578 579 #if ENTPOOL_TEST 580 int 581 main(void) 582 { 583 return entpool_selftest(); 584 } 585 #endif 586 587 /* 588 * Known-answer test generation 589 * 590 * This generates the known-answer test vectors from explicitly 591 * specified duplex inputs that correspond to what entpool_enter 592 * &c. induce, to confirm the encoding of inputs works as 593 * intended. 594 */ 595 596 #if ENTPOOL_GENKAT 597 598 #include <stdio.h> 599 600 struct event { 601 enum { IN, OUT, STOP } t; 602 uint8_t b[RATE-1]; 603 }; 604 605 /* Cases correspond to entpool_selftest above. */ 606 static const struct event *const cases[] = { 607 [0] = (const struct event[]) { 608 {IN, {1, 0xff}}, 609 {STOP, {0}}, 610 }, 611 [1] = (const struct event[]) { 612 #if ENTPOOL_SMALL 613 {IN, {RATE-3, [RATE-2] = 1}}, 614 #else 615 {IN, {0x80|((RATE-4)&0x7f), (RATE-4)>>7, [RATE-2] = 1}}, 616 #endif 617 {IN, {0xff}}, 618 {STOP, {0}}, 619 }, 620 [2] = (const struct event[]) { 621 #if ENTPOOL_SMALL 622 {IN, {RATE-2}}, 623 #else 624 {IN, {127, [128] = RATE-2 - 127 - 1}}, 625 #endif 626 {IN, {1, 0xff}}, 627 {STOP, {0}}, 628 }, 629 [3] = (const struct event[]) { 630 #if ENTPOOL_SMALL 631 {IN, {RATE-2}}, 632 #else 633 {IN, {127, [128] = RATE-2 - 127 - 1}}, 634 #endif 635 {IN, {1, 0xff}}, 636 {STOP, {0}}, 637 }, 638 [4] = (const struct event[]) { 639 {IN, {1, 0xff}}, 640 {STOP, {0}}, 641 }, 642 643 [5] = (const struct event[]) { 644 #if ENTPOOL_SMALL 645 {IN, {RATE-3, [RATE-2] = 0 /* truncated length */}}, 646 #else 647 {IN, {0x80|((RATE-4)&0x7f), (RATE-4)>>7, 648 [RATE-2] = 0 /* truncated length */}}, 649 #endif 650 {STOP, {0}}, 651 }, 652 [6] = (const struct event[]) { 653 #if ENTPOOL_SMALL 654 {IN, {RATE-2}}, 655 #else 656 {IN, {127, [128] = RATE-2 - 127 - 1}}, 657 #endif 658 {STOP, {0}}, 659 }, 660 [7] = (const struct event[]) { 661 #if ENTPOOL_SMALL 662 {IN, {RATE-2}}, 663 #else 664 {IN, {127, [128] = RATE-2 - 127 - 1}}, 665 #endif 666 {IN, {1, 0xff}}, 667 {STOP, {0}}, 668 }, 669 [8] = (const struct event[]) { 670 {STOP, {0}}, 671 }, 672 [9] = (const struct event[]) { 673 {IN, {1, 0xff}}, 674 {STOP, {0}}, 675 }, 676 [10] = (const struct event[]) { 677 #if ENTPOOL_SMALL 678 {IN, {RATE-2}}, 679 #else 680 {IN, {127, [128] = RATE-2 - 127 - 1}}, 681 #endif 682 {STOP, {0}}, 683 }, 684 [11] = (const struct event[]) { 685 {OUT, {0}}, 686 {OUT, {0}}, 687 {STOP, {0}}, 688 }, 689 [12] = (const struct event[]) { 690 {OUT, {0}}, 691 {IN, {1, 0xff}}, 692 {STOP, {0}}, 693 }, 694 }; 695 696 static void 697 compute(uint8_t output[KATLEN], const struct event *events) 698 { 699 union { 700 uint8_t b[ENTPOOL_SIZE]; 701 ENTPOOL_WORD w[ENTPOOL_SIZE/sizeof(ENTPOOL_WORD)]; 702 } u; 703 unsigned i, j, k; 704 705 memset(&u.b, 0, sizeof u.b); 706 for (i = 0;; i++) { 707 if (events[i].t == STOP) 708 break; 709 for (j = 0; j < sizeof(events[i].b); j++) 710 u.b[j] ^= events[i].b[j]; 711 if (events[i].t == OUT) { 712 memset(u.b, 0, RATE-1); 713 u.b[RATE-1] ^= 0x80; 714 } 715 716 for (k = 0; k < arraycount(u.w); k++) 717 u.w[k] = ENTPOOL_WTOH(u.w[k]); 718 ENTPOOL_PERMUTE(u.w); 719 for (k = 0; k < arraycount(u.w); k++) 720 u.w[k] = ENTPOOL_HTOW(u.w[k]); 721 } 722 723 for (j = 0; j < KATLEN; j++) 724 output[j] = u.b[j]; 725 } 726 727 int 728 main(void) 729 { 730 uint8_t output[KATLEN]; 731 unsigned i, j; 732 733 printf("static const uint8_t known_answers[][KATLEN] = {\n"); 734 for (i = 0; i < arraycount(cases); i++) { 735 printf("\t[%u] = {\n", i); 736 compute(output, cases[i]); 737 for (j = 0; j < KATLEN; j++) { 738 if (j % 8 == 0) 739 printf("\t\t"); 740 printf("0x%02hhx,", output[j]); 741 if (j % 8 == 7) 742 printf("\n"); 743 } 744 if ((KATLEN % 8) != 0) 745 printf("\n"); 746 printf("\t},\n"); 747 } 748 printf("};\n"); 749 750 fflush(stdout); 751 return ferror(stdout); 752 } 753 754 #endif 755