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
stir(struct entpool * P)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
entpool_enter(struct entpool * P,const void * buf,size_t len)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
entpool_enter_nostir(struct entpool * P,const void * buf,size_t len)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
entpool_stir(struct entpool * P)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
entpool_extract(struct entpool * P,secret void * buf,size_t len)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
entpool_selftest(void)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
main(void)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
compute(uint8_t output[KATLEN],const struct event * events)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
main(void)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