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