symm/sha3.[ch]: Add support for SHA3 and related functions based on Keccak.
[catacomb] / progs / rspit.c
CommitLineData
ee33470f 1/* -*-c-*-
2 *
ee33470f 3 * Spit out random numbers
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
45c0fd36 8/*----- Licensing notice --------------------------------------------------*
ee33470f 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.
45c0fd36 16 *
ee33470f 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.
45c0fd36 21 *
ee33470f 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
ee33470f 28/*----- Header files ------------------------------------------------------*/
29
30#include "config.h"
31
bb78535e 32#include <assert.h>
ee33470f 33#include <errno.h>
bb78535e 34#include <math.h>
ee33470f 35#include <signal.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <time.h>
40
41#ifndef PORTABLE
42# include <unistd.h>
15df46bc 43# include <sys/time.h>
ee33470f 44#endif
45
46#include <mLib/darray.h>
47#include <mLib/dstr.h>
48#include <mLib/mdwopt.h>
49#include <mLib/quis.h>
50#include <mLib/report.h>
51#include <mLib/sub.h>
52
bafe8a7b
MW
53#include "mp.h"
54#include "mpint.h"
55#include "mplimits.h"
56#include "mptext.h"
57
bb78535e 58#include "fipstest.h"
ee33470f 59#include "grand.h"
bb78535e 60#include "maurer.h"
87de7c73 61#include "key.h"
ee33470f 62
63#include "lcrand.h"
64#include "fibrand.h"
65#include "rand.h"
66#include "noise.h"
67
68#include "bbs.h"
69#include "mprand.h"
70
965c4e75 71#include "chacha.h"
ee33470f 72#include "rc4.h"
965c4e75
MW
73#include "salsa20.h"
74#include "salsa20-core.h"
bb78535e 75#include "seal.h"
78b4ea88 76#include "sha3.h"
ee33470f 77
78#include "des-ofb.h"
79#include "des3-ofb.h"
bb78535e 80#include "rc2-ofb.h"
ee33470f 81#include "rc5-ofb.h"
b17f4ed5 82#include "mars-ofb.h"
265fb162 83#include "skipjack-ofb.h"
84#include "tea-ofb.h"
85#include "xtea-ofb.h"
ee33470f 86#include "blowfish-ofb.h"
bb78535e 87#include "twofish-ofb.h"
ee33470f 88#include "idea-ofb.h"
bb78535e 89#include "cast128-ofb.h"
90#include "cast256-ofb.h"
0ba18b90 91#include "noekeon-ofb.h"
bb78535e 92#include "rijndael-ofb.h"
2e8eb64a 93#include "rijndael192-ofb.h"
94#include "rijndael256-ofb.h"
b17f4ed5 95#include "safer-ofb.h"
96#include "safersk-ofb.h"
265fb162 97#include "square-ofb.h"
bb78535e 98#include "serpent-ofb.h"
99
100#include "des-counter.h"
101#include "des3-counter.h"
102#include "rc2-counter.h"
103#include "rc5-counter.h"
b17f4ed5 104#include "mars-counter.h"
265fb162 105#include "skipjack-counter.h"
106#include "tea-counter.h"
107#include "xtea-counter.h"
bb78535e 108#include "blowfish-counter.h"
109#include "twofish-counter.h"
110#include "idea-counter.h"
111#include "cast128-counter.h"
112#include "cast256-counter.h"
0ba18b90 113#include "noekeon-counter.h"
bb78535e 114#include "rijndael-counter.h"
2e8eb64a 115#include "rijndael192-counter.h"
116#include "rijndael256-counter.h"
b17f4ed5 117#include "safer-counter.h"
118#include "safersk-counter.h"
265fb162 119#include "square-counter.h"
bb78535e 120#include "serpent-counter.h"
121
d3187d77 122#include "md2-mgf.h"
bb78535e 123#include "md4-mgf.h"
124#include "md5-mgf.h"
125#include "sha-mgf.h"
265fb162 126#include "tiger-mgf.h"
127#include "rmd128-mgf.h"
bb78535e 128#include "rmd160-mgf.h"
265fb162 129#include "rmd256-mgf.h"
130#include "rmd320-mgf.h"
ee33470f 131
132#include "rmd160.h"
133
134/*----- Data structures ---------------------------------------------------*/
135
136typedef struct gen {
137 const char *name;
138 grand *(*seed)(unsigned /*i*/);
139 unsigned i;
140 const char *help;
141} gen;
142
f57c6d85 143extern gen generators[];
ee33470f 144
bb78535e 145#define CIPHERS \
146 E(DES, des) \
147 E(DES3, des3) \
148 E(RC2, rc2) \
149 E(RC5, rc5) \
b17f4ed5 150 E(MARS, mars) \
265fb162 151 E(SKIPJACK, skipjack) \
152 E(TEA, tea) \
153 E(XTEA, xtea) \
bb78535e 154 E(BLOWFISH, blowfish) \
155 E(TWOFISH, twofish) \
156 E(IDEA, idea) \
157 E(CAST128, cast128) \
158 E(CAST256, cast256) \
265fb162 159 E(SQUARE, square) \
b17f4ed5 160 E(SAFER, safer) \
161 E(SAFERSK, safersk) \
0ba18b90 162 E(NOEKEON, noekeon) \
bb78535e 163 E(RIJNDAEL, rijndael) \
2e8eb64a 164 E(RIJNDAEL192, rijndael192) \
165 E(RIJNDAEL256, rijndael256) \
bb78535e 166 E(SERPENT, serpent)
167
168#define HASHES \
d3187d77 169 E(MD2, md2) \
bb78535e 170 E(MD4, md4) \
171 E(MD5, md5) \
172 E(SHA, sha) \
265fb162 173 E(TIGER, tiger) \
174 E(RMD128, rmd128) \
175 E(RMD160, rmd160) \
176 E(RMD256, rmd256) \
177 E(RMD320, rmd320)
bb78535e 178
179#define E(PRE, pre) CIPHER_##PRE,
180enum { CIPHERS CIPHER__bogus };
181#undef E
182
183#define E(PRE, pre) HASH_##PRE,
184enum { HASHES HASH__bogus };
185#undef E
186
cbef819a 187static const struct {
bb78535e 188 const octet *keysz;
189 size_t blksz;
190 grand *(*ofb)(const void */*k*/, size_t /*sz*/);
191 grand *(*counter)(const void */*k*/, size_t /*sz*/);
192} ciphertab[] = {
193#define E(PRE, pre) \
194 { pre##_keysz, PRE##_BLKSZ, pre##_ofbrand, pre##_counterrand },
195 CIPHERS
196#undef E
197};
198
cbef819a 199static const struct {
bb78535e 200 const gchash *h;
201 const octet *keysz;
202 grand *(*mgf)(const void */*k*/, size_t /*sz*/);
203} hashtab[] = {
204#define E(PRE, pre) \
205 { &pre, pre##_mgfkeysz, pre##_mgfrand },
206 HASHES
207#undef E
208};
209
965c4e75
MW
210#define SALSAE \
211 E(salsa20, 20,, SALSA20) \
212 E(salsa20, 12,, SALSA20) \
213 E(salsa20, 8,, SALSA20) \
214 E(xsalsa20, 20, X, SALSA20) \
215 E(xsalsa20, 12, X, SALSA20) \
216 E(xsalsa20, 8, X, SALSA20) \
217 E(chacha, 20,, CHACHA) \
218 E(chacha, 12,, CHACHA) \
219 E(chacha, 8,, CHACHA) \
220 E(xchacha, 20, X, CHACHA) \
221 E(xchacha, 12, X, CHACHA) \
222 E(xchacha, 8, X, CHACHA)
223
224#define E(pre, r, x, BASE) pre##_##r##_INDEX,
225enum { SALSAE BOGUS_SALSA };
226#undef E
227
228#define SALSA20_GEN(pre, r) SALSA20_DECOR(pre, r, _rand)
229#define CHACHA_GEN(pre, r) pre##r##_rand
230
231#define SALSA20_NAME(r) SALSA20_NAME_##r
232#define XSALSA20_NAME(r) "x" SALSA20_NAME_##r
233#define CHACHA_NAME(r) "chacha" #r
234#define XCHACHA_NAME(r) "xchacha" #r
235
d58b0c17 236static const struct {
965c4e75
MW
237 size_t noncesz;
238 grand *(*gen)(const void *, size_t, const void *);
239} salsatab[] = {
240#define E(pre, r, x, BASE) { x##BASE##_NONCESZ, BASE##_GEN(pre, r) },
241 SALSAE
242#undef E
243};
244
78b4ea88
MW
245#define SHAKES E(128) E(256)
246
247enum {
248#define E(sz) SHAKE##sz##_INDEX,
249 SHAKES
250#undef E
251 SHAKE__LIMIT
252};
253
254static const struct {
255 const octet *ksz;
256 grand *(*shake)(const void *, size_t, const void *, size_t,
257 const void *, size_t);
258 grand *(*kmac)(const void *, size_t,
259 const void *, size_t);
260} shaketab[] = {
261#define E(sz) { shake##sz##_keysz, cshake##sz##_rand, kmac##sz##_rand },
262 SHAKES
263#undef E
264};
265
ee33470f 266/*----- Miscellaneous static data -----------------------------------------*/
267
c2181593 268static FILE *outfp;
bafe8a7b 269static mp *outsz = 0;
f0675f8a 270static unsigned maurer_lo = 5, maurer_hi = 8;
ee33470f 271
272static int argc;
273static char **argv;
274
275static unsigned flags = 0;
276
16efd15b 277#define f_progress 1u
278#define f_file 2u
279#define f_fips 4u
280#define f_maurer 8u
281#define f_timer 16u
282#define f_discard 32u
ee33470f 283
284/*----- Help options ------------------------------------------------------*/
285
286static void usage(FILE *fp)
287{
288 pquis(fp, "Usage: $ generator [options]\n");
289}
290
291static void version(FILE *fp)
292{
293 pquis(fp, "$, Catacomb version " VERSION "\n");
294}
295
296static void help(FILE *fp)
297{
298 version(fp);
299 fputc('\n', fp);
300 usage(fp);
301 pquis(fp, "\n\
302Emits a stream of random bytes suitable for, well, all sorts of things.\n\
303The primary objective is to be able to generate streams of input for\n\
304statistical tests, such as Diehard.\n\
305\n\
306Options are specific to the particular generator, although there's a\n\
307common core set:\n\
308\n\
309-h, --help Display this help message.\n\
310-v, --version Display the program's version number.\n\
311-u, --usage Display a useless usage message.\n\
312\n\
313-l, --list Show a list of the supported generators, with\n\
314 their options.\n\
bb78535e 315-f, --fipstest Run the FIPS 140-1 randomness test.\n\
33efa0ae 316-m, --maurer[=LO-HI] Run Maurer's universal statistical test.\n\
ee33470f 317-o, --output FILE Write output to FILE, not stdout.\n\
318-z, --size SIZE Emit SIZE bytes, not an unlimited number.\n\
319-p, --progress Show a little progress meter (on stderr).\n\
04d45209 320-T, --timer Keep track of the CPU time used by the generator.\n\
321-d, --discard Discard the generated output.\n\
ee33470f 322\n\
323(A SIZE may be followed by `g' for gigabytes, `m' for megabytes, or\n\
324`k' for kilobytes. If unqualified, an amount in bytes is assumed.)\n\
325");
326}
327
328/*----- Main options parser -----------------------------------------------*/
329
330static struct option opts[] = {
331
332 /* --- Standard GNU help options --- */
333
334 { "help", 0, 0, 'h' },
335 { "version", 0, 0, 'v' },
336 { "usage", 0, 0, 'u' },
337
338 /* --- Other useful things --- */
339
340 { "list", 0, 0, 'l' },
bb78535e 341 { "fipstest", 0, 0, 'f' },
f0675f8a 342 { "maurer", OPTF_ARGOPT, 0, 'm' },
ee33470f 343 { "output", OPTF_ARGREQ, 0, 'o' },
344 { "size", OPTF_ARGREQ, 0, 'z' },
345 { "progress", 0, 0, 'p' },
04d45209 346 { "timer", 0, 0, 'T' },
347 { "discard", 0, 0, 'd' },
ee33470f 348
349 /* --- End of main table --- */
350
351 { 0, 0, 0, 0 }
352};
353
04d45209 354static const char *sopts = "hvu lfm::o:z:pTd";
ee33470f 355
356#ifndef OPTION_V
357 DA_DECL(option_v, struct option);
358# define OPTION_V
359#endif
360
361static option_v optv = DA_INIT;
362static dstr optd = DSTR_INIT;
363
364/* --- @addopts@ --- *
365 *
366 * Arguments: @const char *s@ = pointer to short options
367 * @struct option *l@ = pointer to long options
368 *
369 * Returns: ---
370 *
371 * Use: Adds a collection of options to the table.
372 */
373
374static void addopts(const char *s, struct option *l)
375{
376 dstr_puts(&optd, s);
377 if (DA_LEN(&optv))
378 DA_SHRINK(&optv, 1);
379 while (l->name)
380 DA_PUSH(&optv, *l++);
381 DA_PUSH(&optv, *l);
382}
383
384/* --- @opt@ --- *
385 *
386 * Arguments: ---
387 *
388 * Returns: Next option from argument array.
389 *
390 * Use: Fetches options, handling the standard ones.
391 */
392
393static int opt(void)
394{
395 for (;;) {
396 int i = mdwopt(argc, argv, optd.buf, DA(&optv), 0, 0, 0);
397 switch (i) {
398 case 'h':
399 help(stdout);
400 exit(0);
401 case 'v':
402 version(stdout);
403 exit(0);
404 case 'u':
405 usage(stdout);
406 exit(0);
407 case 'l': {
408 gen *g;
409 puts("Generators supported:");
410 for (g = generators; g->name; g++)
411 printf(" %s %s\n", g->name, g->help);
412 exit(0);
413 } break;
bb78535e 414 case 'f':
415 flags |= f_fips;
416 break;
417 case 'm':
418 flags |= f_maurer;
f0675f8a 419 if (optarg) {
420 char *p;
421 unsigned long lo, hi;
422 lo = strtoul(optarg, &p, 0);
e3dc2d22 423 if (*p == '-' || *p == ',')
f0675f8a 424 hi = strtoul(p + 1, &p, 0);
425 else
426 hi = lo;
427 if (*p != 0 || hi < lo || lo == 0)
428 die(EXIT_FAILURE, "bad bit range `%s'", optarg);
429 maurer_lo = lo;
430 maurer_hi = hi;
431 }
bb78535e 432 break;
ee33470f 433 case 'o':
434 if (flags & f_file)
435 die(EXIT_FAILURE, "already set an output file");
436 if (strcmp(optarg, "-") == 0)
437 outfp = stdout;
438 else {
439 outfp = fopen(optarg, "w");
440 if (!outfp) {
441 die(EXIT_FAILURE, "couldn't open output file `%s': %s",
bb78535e 442 optarg, strerror(errno));
ee33470f 443 }
444 }
445 flags |= f_file;
446 break;
447 case 'z': {
448 char *p;
bafe8a7b
MW
449 outsz = mp_readstring(outsz, optarg, &p, 0);
450 if (!outsz || MP_NEGP(outsz))
ee33470f 451 die(EXIT_FAILURE, "bad number `%s'", optarg);
452 switch (*p) {
bafe8a7b
MW
453 case 'G': case 'g': outsz = mp_lsl(outsz, outsz, 10);
454 case 'M': case 'm': outsz = mp_lsl(outsz, outsz, 10);
455 case 'K': case 'k': outsz = mp_lsl(outsz, outsz, 10);
ee33470f 456 case 0:
457 break;
458 default:
459 die(EXIT_FAILURE, "bad suffix `%s'", p);
460 break;
461 }
462 if (*p && p[1] != 0)
463 die(EXIT_FAILURE, "bad suffix `%s'", p);
464 } break;
465 case 'p':
466 flags |= f_progress;
467 break;
04d45209 468 case 'T':
469 flags |= f_timer;
470 break;
471 case 'd':
472 flags |= f_discard;
473 break;
ee33470f 474 default:
475 return (i);
476 }
477 }
478}
479
480/*----- Manglers for seed strings -----------------------------------------*/
481
482/* --- @unhex@ --- *
483 *
484 * Arguments: @const char *p@ = pointer to input string
485 * @char **end@ = where the end goes
486 * @dstr *d@ = output buffer
487 *
488 * Returns: ---
489 *
490 * Use: Transforms a hex string into a chunk of binary data.
491 */
492
493static void unhex(const char *p, char **end, dstr *d)
494{
495 while (p[0] && p[1]) {
496 int x = p[0], y = p[1];
497 if ('0' <= x && x <= '9') x -= '0';
498 else if ('A' <= x && x <= 'F') x -= 'A' - 10;
499 else if ('a' <= x && x <= 'f') x -= 'a' - 10;
500 else x = 0;
501 if ('0' <= y && y <= '9') y -= '0';
502 else if ('A' <= y && y <= 'F') y -= 'A' - 10;
503 else if ('a' <= y && y <= 'f') y -= 'a' - 10;
504 else y = 0;
505 DPUTC(d, (x << 4) + y);
506 p += 2;
507 }
508 *end = (char *)p;
509}
510
bb78535e 511/* --- Generate a key --- */
512
513static void textkey(dstr *d, const char *p, const octet *ksz)
514{
515 size_t sz = strlen(p);
516
517 if (!sz)
518 die(EXIT_FAILURE, "zero-length key string");
519 if (keysz(sz, ksz) != sz)
520 DPUTM(d, p, sz);
521 else {
522 rmd160_mgfctx g;
523 rmd160_mgfinit(&g, p, sz);
524 sz = keysz(0, ksz);
525 dstr_ensure(d, sz);
526 rmd160_mgfencrypt(&g, 0, d->buf, sz);
527 d->len += sz;
528 }
529 assert(((void)"I can't seem to choose a good key size",
530 keysz(d->len, ksz) == d->len));
531}
532
533static void hexkey(dstr *d, const char *p, const octet *ksz)
534{
535 char *q;
536 unhex(optarg, &q, d);
537 if (*q)
538 die(EXIT_FAILURE, "bad hex key `%s'", p);
539 if (keysz(d->len, ksz) != d->len)
540 die(EXIT_FAILURE, "bad key length");
541}
542
543static void randkey(dstr *d, const octet *ksz)
544{
545 size_t sz = keysz(0, ksz);
546 dstr_ensure(d, sz);
547 rand_get(RAND_GLOBAL, d->buf, sz);
548 d->len += sz;
549}
550
ee33470f 551/*----- Generators --------------------------------------------------------*/
552
553/* --- Blum-Blum-Shub strong generator --- */
554
ee33470f 555static grand *gen_bbs(unsigned i)
556{
557 /* --- Default modulus --- *
558 *
559 * The factors of this number are
560 *
561 * @p = 1229936431484295969649886203367009966370895964206162032259292413@
45c0fd36 562 * @7754313537966036459299022912838407755462506416274551744201653277@
ee33470f 563 * @313130311731673973886822067@
564 *
565 * @q = 9798171783943489959487301695884963889684294764514008432498259742@
566 * @5374320073594018817245784145742769603334292182227671519041431067@
567 * @61344781426317516045890159@
568 *
bb78535e 569 * Both %$p$% and %$q$% are prime; %$(p - 1)/2$% and %$(q - 1)/2$% have no
ee33470f 570 * common factors. They were found using this program, with random
571 * starting points.
572 *
573 * I hope that, by publishing these factors, I'll dissuade people from
bb78535e 574 * actually using this modulus in an attempt to attain real security. The
575 * program is quite quick at finding Blum numbers, so there's no excuse for
576 * not generating your own.
ee33470f 577 */
578
579 const char *mt =
eaa515d8 580 "12051128439013574251357214209433471144307319411973256935382082"
581 "84356405274180923922403660880355098909699130818163691602989614"
582 "90135716255689660470370755013177656905237112577648090277537209"
583 "93607817155427455344810369808478266925293635284364998010510985"
584 "0503830397166360721262431179505917248447259735253684659338653";
ee33470f 585
586 /* --- Other things --- */
587
588 grand *r;
589 const char *xt = 0;
87de7c73 590 unsigned bits = 1024;
ee33470f 591 mp *m, *x;
592 unsigned show = 0;
87de7c73 593 const char *kfile = 0, *id = 0, *ktype = 0;
ee33470f 594
595 /* --- Parse options --- */
596
597 static struct option opts[] = {
bb78535e 598 { "modulus", OPTF_ARGREQ, 0, 'M' },
ee33470f 599 { "generate", 0, 0, 'g' },
600 { "seed", OPTF_ARGREQ, 0, 's' },
601 { "bits", OPTF_ARGREQ, 0, 'b' },
602 { "show", 0, 0, 'S' },
87de7c73 603 { "keyring", OPTF_ARGREQ, 0, 'k' },
604 { "id", OPTF_ARGREQ, 0, 'i' },
605 { "type", OPTF_ARGREQ, 0, 't' },
ee33470f 606 { 0, 0, 0, 0 }
607 };
608
bb78535e 609 addopts("M:gs:b:Sk:i:t:", opts);
ee33470f 610
611 for (;;) {
612 int o = opt();
613 if (o < 0)
614 break;
615 switch (o) {
bb78535e 616 case 'M':
ee33470f 617 mt = optarg;
618 break;
619 case 'g':
620 mt = 0;
621 break;
622 case 's':
623 xt = optarg;
624 break;
625 case 'b':
626 bits = strtoul(optarg, 0, 0);
627 if (bits == 0)
628 die(EXIT_FAILURE, "bad number of bits `%s'", optarg);
629 break;
630 case 'S':
631 show = 1;
632 break;
87de7c73 633 case 'k':
634 kfile = optarg;
635 mt = 0;
636 break;
637 case 'i':
638 id = optarg;
639 mt = 0;
640 break;
641 case 't':
642 ktype = optarg;
643 mt = 0;
644 break;
ee33470f 645 default:
646 return (0);
647 }
648 }
649
650 /* --- Generate a modulus if one is requested --- */
651
652 if (mt) {
653 char *p;
654 m = mp_readstring(MP_NEW, mt, &p, 0);
87de7c73 655 if (!m || *p || (m->v[0] & 3) != 1)
ee33470f 656 die(EXIT_FAILURE, "bad modulus `%s'", mt);
657 /* Unfortunately I don't know how to test for a Blum integer */
87de7c73 658 } else if (kfile || id || ktype) {
659 key_file kf;
660 key *kk;
661 key_data *kd;
662
663 /* --- Open the key file --- */
664
665 if (!kfile)
666 kfile = "keyring";
667 if (key_open(&kf, kfile, KOPEN_READ, key_moan, 0)) {
668 die(EXIT_FAILURE, "error opening key file `%s': %s",
669 kfile, strerror(errno));
670 }
671
672 /* --- Find the key --- */
673
674 if (id) {
675 if ((kk = key_bytag(&kf, id)) == 0)
676 die(EXIT_FAILURE, "key `%s' not found", id);
677 } else {
678 if (!ktype)
679 ktype = "bbs";
680 if ((kk = key_bytype(&kf, ktype)) == 0)
681 die(EXIT_FAILURE, "no suitable key with type `%s' found", ktype);
682 }
683
684 /* --- Read the key data --- */
685
ef13e9a4 686 if ((kk->k->e & KF_ENCMASK) != KENC_STRUCT)
87de7c73 687 die(EXIT_FAILURE, "key is not structured");
ef13e9a4 688 if ((kd = key_structfind(kk->k, "n")) == 0)
87de7c73 689 die(EXIT_FAILURE, "key has no subkey `n'");
690 if ((kd->e & KF_ENCMASK) != KENC_MP)
e2edda68 691 die(EXIT_FAILURE, "incompatible subkey encoding");
87de7c73 692 m = MP_COPY(kd->u.m);
693 key_close(&kf);
ee33470f 694 } else {
c2181593 695 bbs_priv bp;
ee33470f 696
052b36d0 697 if (bbs_gen(&bp, bits, &rand_global, 0,
698 (flags & f_progress) ? pgen_ev : 0, 0))
87de7c73 699 die(EXIT_FAILURE, "modulus generation failed");
ee33470f 700 m = bp.n;
701
702 if (show) {
703 fputs("p = ", stderr);
704 mp_writefile(bp.p, stderr, 10);
705 fputs("\nq = ", stderr);
706 mp_writefile(bp.q, stderr, 10);
707 fputs("\nn = ", stderr);
708 mp_writefile(bp.n, stderr, 10);
709 fputc('\n', stderr);
710 }
711
ee33470f 712 mp_drop(bp.p);
713 mp_drop(bp.q);
714 }
715
716 /* --- Set up a seed --- */
717
718 if (!xt)
719 x = mprand(MP_NEW, mp_bits(m) - 1, &rand_global, 1);
720 else {
721 char *p;
722 x = mp_readstring(MP_NEW, xt, &p, 0);
723 if (*p)
724 die(EXIT_FAILURE, "bad modulus `%s'", xt);
725 }
726
727 /* --- Right --- */
728
729 r = bbs_rand(m, x);
730
731 mp_drop(m);
732 mp_drop(x);
733 return (r);
734}
735
736/* --- Catacomb's random number generator --- */
737
738static grand *gen_rand(unsigned i)
739{
740 grand *r = rand_create();
741 dstr d = DSTR_INIT;
742
743 static struct option opts[] = {
744 { "key", OPTF_ARGREQ, 0, 'k' },
745 { "text", OPTF_ARGREQ, 0, 't' },
746 { "hex", OPTF_ARGREQ, 0, 'H' },
ee33470f 747 { 0, 0, 0, 0 }
748 };
749
750 addopts("k:t:H:n", opts);
751
bb78535e 752 r->ops->misc(r, RAND_NOISESRC, &noise_source);
753 r->ops->misc(r, RAND_SEED, 160);
754
ee33470f 755 for (;;) {
756 int o = opt();
757 if (o < 0)
758 break;
759 switch (o) {
bb78535e 760 case 'k':
761 DRESET(&d);
1d9ac42f 762 textkey(&d, optarg, rmd160_hmackeysz);
bb78535e 763 r->ops->misc(r, RAND_KEY, d.buf, d.len);
764 break;
ee33470f 765 case 't':
766 r->ops->misc(r, GRAND_SEEDBLOCK, optarg, strlen(optarg));
767 break;
bb78535e 768 case 'H':
ee33470f 769 DRESET(&d);
1d9ac42f 770 hexkey(&d, optarg, rmd160_hmackeysz);
ee33470f 771 r->ops->misc(r, GRAND_SEEDBLOCK, d.buf, d.len);
ee33470f 772 break;
773 }
774 }
775
776 dstr_destroy(&d);
777 return (r);
778}
779
780/* --- RC4 output --- */
781
782static grand *gen_rc4(unsigned i)
783{
784 grand *r;
785 dstr d = DSTR_INIT;
786
787 static struct option opts[] = {
788 { "key", OPTF_ARGREQ, 0, 'k' },
789 { "hex", OPTF_ARGREQ, 0, 'H' },
790 { 0, 0, 0, 0 }
791 };
792
793 addopts("k:H:", opts);
794
795 for (;;) {
796 int o = opt();
797 if (o < 0)
798 break;
799 switch (o) {
bb78535e 800 case 'k':
801 DRESET(&d);
802 textkey(&d, optarg, rc4_keysz);
803 break;
804 case 'H':
805 DRESET(&d);
806 hexkey(&d, optarg, rc4_keysz);
807 break;
ee33470f 808 default:
809 return (0);
810 }
811 }
812
bb78535e 813 if (!d.len)
814 randkey(&d, rc4_keysz);
ee33470f 815 r = rc4_rand(d.buf, d.len);
816 dstr_destroy(&d);
817 return (r);
818}
819
bb78535e 820/* --- SEAL output --- */
ee33470f 821
bb78535e 822static grand *gen_seal(unsigned i)
823{
824 grand *r;
825 dstr d = DSTR_INIT;
826 uint32 n = 0;
ee33470f 827
bb78535e 828 static struct option opts[] = {
829 { "key", OPTF_ARGREQ, 0, 'k' },
830 { "hex", OPTF_ARGREQ, 0, 'H' },
831 { "sequence", OPTF_ARGREQ, 0, 'n' },
832 { 0, 0, 0, 0 }
833 };
ee33470f 834
bb78535e 835 addopts("k:H:n:", opts);
ee33470f 836
bb78535e 837 for (;;) {
838 int o = opt();
839 if (o < 0)
840 break;
841 switch (o) {
842 case 'k':
843 DRESET(&d);
844 textkey(&d, optarg, seal_keysz);
845 break;
846 case 'H':
847 DRESET(&d);
848 hexkey(&d, optarg, seal_keysz);
849 break;
850 case 'n': {
851 char *p;
852 n = strtoul(optarg, &p, 0);
853 if (*p)
854 die(EXIT_FAILURE, "bad number `%s'", optarg);
855 } break;
856 default:
857 return (0);
858 }
859 }
860
861 if (!d.len)
862 randkey(&d, seal_keysz);
863 r = seal_rand(d.buf, d.len, n);
864 dstr_destroy(&d);
865 return (r);
866}
867
965c4e75
MW
868/* --- Salsa20, XSalsa20, ChaCha, and XChaCha --- */
869
870static grand *gen_salsae(unsigned i)
871{
872 grand *r;
873 char *p;
874 dstr d = DSTR_INIT;
875 dstr n = DSTR_INIT;
876 kludge64 pos = { 0 };
877 octet posbuf[8];
878 mp *x;
879
880 static struct option opts[] = {
881 { "key", OPTF_ARGREQ, 0, 'k' },
882 { "hex", OPTF_ARGREQ, 0, 'H' },
883 { "nonce", OPTF_ARGREQ, 0, 'n' },
884 { "seek", OPTF_ARGREQ, 0, 's' },
885 { 0, 0, 0, 0 }
886 };
887
888 addopts("k:H:n:s:", opts);
889
890 for (;;) {
891 int o = opt();
892 if (o < 0)
893 break;
894 switch (o) {
895 case 'k':
896 DRESET(&d);
897 textkey(&d, optarg, salsa20_keysz);
898 break;
899 case 'H':
900 DRESET(&d);
901 hexkey(&d, optarg, salsa20_keysz);
902 break;
903 case 'n':
904 DRESET(&n);
905 unhex(optarg, &p, &n);
906 if (*p)
907 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
908 if (n.len != salsatab[i].noncesz) {
909 die(EXIT_FAILURE, "bad nonce length %lu (must be %lu)",
910 (unsigned long)n.len, (unsigned long)salsatab[i].noncesz);
911 }
912 break;
913 case 's':
914 x = mp_readstring(MP_NEW, optarg, &p, 0);
915 if (*p || MP_NEGP(x) || mp_bits(x) > 64)
916 die(EXIT_FAILURE, "bad position `%s'", optarg);
917 mp_storeb(x, posbuf, sizeof(posbuf));
918 mp_drop(x);
919 LOAD64_(pos, posbuf);
920 break;
921 default:
922 return (0);
923 }
924 }
925
926 if (!d.len)
927 randkey(&d, salsa20_keysz);
928 r = salsatab[i].gen(d.buf, d.len, n.len ? n.buf : 0);
929 r->ops->misc(r, SALSA20_SEEKU64, pos);
930
931 dstr_destroy(&d);
932 dstr_destroy(&n);
933
934 return (r);
935}
936
bb78535e 937/* --- Output feedback generators --- */
ee33470f 938
939static grand *gen_ofb(unsigned i)
940{
941 grand *r;
942 dstr d = DSTR_INIT;
943 dstr iv = DSTR_INIT;
944
945 static struct option opts[] = {
946 { "key", OPTF_ARGREQ, 0, 'k' },
947 { "hex", OPTF_ARGREQ, 0, 'H' },
948 { "iv", OPTF_ARGREQ, 0, 'i' },
949 { 0, 0, 0, 0 }
950 };
951
952 addopts("k:H:i:", opts);
953
954 for (;;) {
955 int o = opt();
956 if (o < 0)
957 break;
958 switch (o) {
bb78535e 959 case 'k':
960 DRESET(&d);
961 textkey(&d, optarg, ciphertab[i].keysz);
962 break;
963 case 'H':
964 DRESET(&d);
965 hexkey(&d, optarg, ciphertab[i].keysz);
966 break;
ee33470f 967 case 'i': {
968 char *p;
1cdc3a62 969 DRESET(&iv);
ee33470f 970 unhex(optarg, &p, &iv);
971 if (*p)
972 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
1cdc3a62
MW
973 if (iv.len != ciphertab[i].blksz) {
974 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
975 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
976 }
ee33470f 977 } break;
978 default:
979 return (0);
980 }
981 }
982
bb78535e 983 if (!d.len)
984 randkey(&d, ciphertab[i].keysz);
985 r = ciphertab[i].ofb(d.buf, d.len);
1cdc3a62 986 if (iv.len)
bb78535e 987 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
ee33470f 988
bb78535e 989 dstr_destroy(&d);
990 dstr_destroy(&iv);
991 return (r);
992}
993
994/* --- Counter generators --- */
995
996static grand *gen_counter(unsigned i)
997{
998 grand *r;
999 dstr d = DSTR_INIT;
1000 dstr iv = DSTR_INIT;
ee33470f 1001
bb78535e 1002 static struct option opts[] = {
1003 { "key", OPTF_ARGREQ, 0, 'k' },
1004 { "hex", OPTF_ARGREQ, 0, 'H' },
1005 { "iv", OPTF_ARGREQ, 0, 'i' },
1006 { 0, 0, 0, 0 }
1007 };
1008
1009 addopts("k:H:i:", opts);
1010
1011 for (;;) {
1012 int o = opt();
1013 if (o < 0)
1014 break;
1015 switch (o) {
1016 case 'k':
1017 DRESET(&d);
1018 textkey(&d, optarg, ciphertab[i].keysz);
1019 break;
1020 case 'H':
1021 DRESET(&d);
1022 hexkey(&d, optarg, ciphertab[i].keysz);
1023 break;
1024 case 'i': {
1025 char *p;
1cdc3a62 1026 DRESET(&iv);
bb78535e 1027 unhex(optarg, &p, &iv);
1028 if (*p)
1029 die(EXIT_FAILURE, "bad hex IV `%s'", optarg);
1cdc3a62
MW
1030 if (iv.len != ciphertab[i].blksz) {
1031 die(EXIT_FAILURE, "bad IV length %lu (must be %lu)",
1032 (unsigned long)iv.len, (unsigned long)ciphertab[i].blksz);
1033 }
bb78535e 1034 } break;
1035 default:
1036 return (0);
1037 }
1038 }
1039
1040 if (!d.len)
1041 randkey(&d, ciphertab[i].keysz);
1042 r = ciphertab[i].counter(d.buf, d.len);
1cdc3a62 1043 if (iv.len)
ee33470f 1044 r->ops->misc(r, GRAND_SEEDBLOCK, iv.buf);
ee33470f 1045
1046 dstr_destroy(&d);
1047 dstr_destroy(&iv);
1048 return (r);
1049}
1050
bb78535e 1051/* --- Mask generators --- */
1052
1053static grand *gen_mgf(unsigned i)
1054{
1055 grand *r;
1056 dstr d = DSTR_INIT;
1057 uint32 c = 0;
1058
1059 static struct option opts[] = {
1060 { "key", OPTF_ARGREQ, 0, 'k' },
1061 { "hex", OPTF_ARGREQ, 0, 'H' },
1062 { "index", OPTF_ARGREQ, 0, 'i' },
1063 { 0, 0, 0, 0 }
1064 };
1065
1066 addopts("k:H:i:", opts);
1067
1068 for (;;) {
1069 int o = opt();
1070 if (o < 0)
1071 break;
1072 switch (o) {
1073 case 'k':
1074 DRESET(&d);
1075 textkey(&d, optarg, hashtab[i].keysz);
1076 break;
1077 case 'H':
1078 DRESET(&d);
1079 hexkey(&d, optarg, hashtab[i].keysz);
1080 break;
1081 case 'i': {
1082 char *p;
1083 c = strtoul(optarg, &p, 0);
1084 if (*p)
1085 die(EXIT_FAILURE, "bad index `%s'", optarg);
1086 } break;
1087 default:
1088 return (0);
1089 }
1090 }
1091
1092 if (!d.len)
1093 randkey(&d, hashtab[i].keysz);
1094
1095 r = hashtab[i].mgf(d.buf, d.len);
1096 if (c)
1097 r->ops->misc(r, GRAND_SEEDUINT32, c);
1098
1099 dstr_destroy(&d);
1100 return (r);
1101}
1102
78b4ea88
MW
1103/* --- SHAKE generators --- */
1104
1105static grand *gen_shake(unsigned i)
1106{
1107 dstr d = DSTR_INIT;
1108 const char *func = 0, *perso = 0;
1109 grand *r;
1110
1111 static struct option opts[] = {
1112 { "function", OPTF_ARGREQ, 0, 'F' },
1113 { "personalization", OPTF_ARGREQ, 0, 'P' },
1114 { "key", OPTF_ARGREQ, 0, 'k' },
1115 { "hex", OPTF_ARGREQ, 0, 'H' },
1116 { 0, 0, 0, 0 }
1117 };
1118
1119 addopts("F:P:k:H:", opts);
1120
1121 for (;;) {
1122 int o = opt();
1123 if (o < 0)
1124 break;
1125 switch (o) {
1126 case 'F':
1127 func = optarg;
1128 break;
1129 case 'P':
1130 perso = optarg;
1131 break;
1132 case 'k':
1133 DRESET(&d);
1134 textkey(&d, optarg, shaketab[i].ksz);
1135 break;
1136 case 'H':
1137 DRESET(&d);
1138 hexkey(&d, optarg, shaketab[i].ksz);
1139 break;
1140 default:
1141 return (0);
1142 }
1143 }
1144
1145 if (!d.len) randkey(&d, shaketab[i].ksz);
1146 r = shaketab[i].shake(func, func ? strlen(func) : 0,
1147 perso, perso ? strlen(perso) : 0,
1148 d.buf, d.len);
1149 dstr_destroy(&d);
1150 return (r);
1151}
1152
1153/* --- KMAC generators --- */
1154
1155static grand *gen_kmac(unsigned i)
1156{
1157 dstr d = DSTR_INIT, m = DSTR_INIT;
1158 const char *perso = 0;
1159 char *q;
1160 grand *r;
1161
1162 static struct option opts[] = {
1163 { "personalization", OPTF_ARGREQ, 0, 'P' },
1164 { "key", OPTF_ARGREQ, 0, 'k' },
1165 { "hex", OPTF_ARGREQ, 0, 'H' },
1166 { "message", OPTF_ARGREQ, 0, 'M' },
1167 { "msghex", OPTF_ARGREQ, 0, 'N' },
1168 { 0, 0, 0, 0 }
1169 };
1170
1171 addopts("P:k:H:M:N:", opts);
1172
1173 for (;;) {
1174 int o = opt();
1175 if (o < 0)
1176 break;
1177 switch (o) {
1178 case 'P':
1179 perso = optarg;
1180 break;
1181 case 'k':
1182 DRESET(&d);
1183 textkey(&d, optarg, shaketab[i].ksz);
1184 break;
1185 case 'H':
1186 DRESET(&d);
1187 hexkey(&d, optarg, shaketab[i].ksz);
1188 break;
1189 case 'M':
1190 DRESET(&m);
1191 DPUTS(&d, optarg);
1192 break;
1193 case 'N':
1194 DRESET(&m);
1195 unhex(optarg, &q, &m);
1196 if (*q) die(EXIT_FAILURE, "bad hex");
1197 break;
1198 default:
1199 return (0);
1200 }
1201 }
1202
1203 if (!d.len) randkey(&d, shaketab[i].ksz);
1204 r = shaketab[i].kmac(perso, perso ? strlen(perso) : 0, d.buf, d.len);
1205 r->ops->misc(r, GRAND_SEEDBLOCK, (void *)m.buf, m.len);
1206 dstr_destroy(&d); dstr_destroy(&m);
1207 return (r);
1208}
1209
ee33470f 1210/* --- Fibonacci generator --- */
1211
1212static grand *gen_fib(unsigned i)
1213{
1214 grand *r;
1215 uint32 s = 0;
1216 char *p;
1217 unsigned set = 0;
1218
1219 static struct option opts[] = {
1220 { "seed", OPTF_ARGREQ, 0, 's' },
1221 { 0, 0, 0, 0 }
1222 };
1223
1224 addopts("s:", opts);
1225
1226 for (;;) {
1227 int o = opt();
1228 if (o < 0)
1229 break;
1230 switch (o) {
1231 case 's':
1232 s = strtoul(optarg, &p, 0);
1233 if (*p)
1234 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1235 set = 1;
1236 break;
1237 default:
1238 return (0);
1239 }
1240 }
1241 r = fibrand_create(s);
1242 if (!set)
1243 r->ops->misc(r, GRAND_SEEDRAND, &rand_global);
1244 return (r);
1245}
1246
1247/* --- LC generator --- */
1248
1249static grand *gen_lc(unsigned i)
1250{
1251 uint32 s = 0;
1252 char *p;
1253 unsigned set = 0;
1254
1255 static struct option opts[] = {
1256 { "seed", OPTF_ARGREQ, 0, 's' },
1257 { 0, 0, 0, 0 }
1258 };
1259
1260 addopts("s:", opts);
1261
1262 for (;;) {
1263 int o = opt();
1264 if (o < 0)
1265 break;
1266 switch (o) {
1267 case 's':
1268 s = strtoul(optarg, &p, 0);
1269 if (*p)
1270 die(EXIT_FAILURE, "bad integer `%s'", optarg);
1271 set = 1;
1272 break;
1273 default:
1274 return (0);
1275 }
1276 }
1277 if (!set) {
1278 do
1279 s = rand_global.ops->range(&rand_global, LCRAND_P);
1280 while (s == LCRAND_FIXEDPT);
1281 }
1282 return (lcrand_create(s));
1283}
1284
1285/* --- Basic options parser -- can't generate output --- */
1286
1287static grand *gen_opts(unsigned i)
1288{
1289 while (opt() >= 0)
1290 ;
1291 return (0);
1292}
1293
1294/*----- Generators table --------------------------------------------------*/
1295
f57c6d85 1296gen generators[] = {
ee33470f 1297 { "fibonacci", gen_fib, 0,
1298 "[-s SEED]" },
1299 { "lc", gen_lc, 0,
1300 "[-s SEED]" },
bb78535e 1301#define E(PRE, pre) \
1302 { #pre "-ofb", gen_ofb, CIPHER_##PRE, \
ee33470f 1303 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
bb78535e 1304 CIPHERS
1305#undef E
1306#define E(PRE, pre) \
1307 { #pre "-counter", gen_counter, CIPHER_##PRE, \
ee33470f 1308 "[-k KEY-PHRASE] [-H HEX-KEY] [-i HEX-IV]" },
bb78535e 1309 CIPHERS
f57c6d85 1310#undef E
bb78535e 1311#define E(PRE, pre) \
1312 { #pre "-mgf", gen_mgf, HASH_##PRE, \
1313 "[-k KEY-PHRASE] [-H HEX-KEY] [-i INDEX]" },
1314 HASHES
f57c6d85 1315#undef E
965c4e75
MW
1316#define E(pre, r, x, BASE) \
1317 { x##BASE##_NAME(r), gen_salsae, pre##_##r##_INDEX, \
1318 "[-k KEY-PHRASE] [-H HEX-KEY] [-n NONCE]" },
1319 SALSAE
1320#undef E
78b4ea88
MW
1321#define E(sz) \
1322 { "shake" #sz, gen_shake, SHAKE##sz##_INDEX, \
1323 "[-k KEY-PHRASE] [-H HEX-KEY]" },
1324 SHAKES
1325#undef E
1326#define E(sz) \
1327 { "kmac" #sz, gen_kmac, SHAKE##sz##_INDEX, \
1328 "[-k KEY-PHRASE] [-H HEX-KEY] [-m MSG]" },
1329 SHAKES
1330#undef E
ee33470f 1331 { "rc4", gen_rc4, 0,
1332 "[-k KEY-PHRASE] [-H HEX-KEY]" },
bb78535e 1333 { "seal", gen_seal, 0,
1334 "[-k KEY-PHRASE] [-H HEX-KEY] [-n SEQ]" },
ee33470f 1335 { "rand", gen_rand, 0,
1336 "[-n] [-k KEY-PHRASE] [-t TEXT-BLOCK] [-H HEX-BLOCK]" },
1337 { "bbs", gen_bbs, 0,
bb78535e 1338 "[-gS] [-s SEED] [-M MODULUS] [-b BITS] [-k KEYRING] [-i TAG] [-t TYPE]"
87de7c73 1339 },
ee33470f 1340 { 0, 0, 0, 0 },
1341};
1342
1343static gen optsg = { "options", gen_opts, 0,
1344 "This message shouldn't be printed." };
1345
f0675f8a 1346/*----- Random number generation ------------------------------------------*/
ee33470f 1347
f0675f8a 1348static int genfile(const void *buf, size_t sz, void *p)
1349{
1350 FILE *fp = p;
1351 if (fwrite(buf, 1, sz, fp) != sz)
1352 die(EXIT_FAILURE, "error writing to file: %s", strerror(errno));
1353 return (0);
1354}
1355
1356static int genbuf(const void *buf, size_t sz, void *p)
1357{
1358 octet **pp = p;
1359 memcpy(*pp, buf, sz);
1360 *pp += sz;
1361 return (0);
1362}
1363
e3dc2d22 1364typedef struct genmaurer_ctx {
1365 size_t n;
1366 maurer_ctx *m;
1367} genmaurer_ctx;
1368
1369static int genmaurer(const void *buf, size_t sz, void *p)
1370{
1371 genmaurer_ctx *g = p;
1372 size_t i;
1373
1374 for (i = 0; i < g->n; i++)
1375 maurer_test(&g->m[i], buf, sz);
1376 return (0);
1377}
1378
15df46bc
MW
1379static double doubletime(void)
1380{
1381#ifdef PORTABLE
1382 static time_t start = (time_t)-1;
1383 time_t now = time(0);
1384
1385 if (start == (time_t)-1) start = now;
1386 return difftime(now, start);
1387#else
1388 struct timeval tv;
1389
1390 gettimeofday(&tv, 0);
1391 return (tv.tv_sec + tv.tv_usec/1000000.0);
1392#endif
1393}
1394
bafe8a7b 1395static int generate(grand *r, mp *outsz,
f0675f8a 1396 int (*func)(const void *buf, size_t sz, void *p),
1397 void *p)
ee33470f 1398{
04d45209 1399 static char kmg[] = { ' ', 'k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 0 };
1400
bb78535e 1401 unsigned percent = 0;
bafe8a7b
MW
1402 mp *kb = MP_ZERO, *t = MP_NEW;
1403 dstr d = DSTR_INIT;
15df46bc 1404 double now, last;
bb78535e 1405 static char baton[] = "-\\|/";
ee33470f 1406 char *bp;
f0675f8a 1407 int rc;
04d45209 1408 clock_t clk = 0;
f0675f8a 1409
1410 /* --- Spit out random data --- */
1411
15df46bc 1412 last = doubletime();
f0675f8a 1413 bp = baton;
1414 if (flags & f_progress) {
1415 char *errbuf = xmalloc(BUFSIZ);
1416 setvbuf(stderr, errbuf, _IOLBF, BUFSIZ);
1417 if (outsz)
1418 fprintf(stderr, "[%*s] 0%% 0\r[/\b", 50, "");
1419 else
1420 fputs("[ ] 0\r[/\b", stderr);
1421 fflush(stderr);
1422 }
1423
1424#ifdef SIGPIPE
1425 signal(SIGPIPE, SIG_IGN);
1426#endif
1427
bafe8a7b 1428 while (!outsz || MP_CMP(kb, <, outsz)) {
f0675f8a 1429 octet buf[BUFSIZ];
bafe8a7b 1430 size_t sz = sizeof(buf), left;
04d45209 1431 clock_t c_start, c_stop;
f0675f8a 1432
1433 /* --- Emit a bufferful (or less) of data --- */
1434
1435 if (outsz) {
bafe8a7b
MW
1436 t = mp_sub(t, outsz, kb);
1437 assert(!MP_NEGP(t));
1438 if (MP_CMP(t, <=, MP_SIZET_MAX)) {
1439 left = mp_tosizet(t);
1440 if (sz > left) sz = left;
1441 }
f0675f8a 1442 }
04d45209 1443 c_start = clock();
f0675f8a 1444 r->ops->fill(r, buf, sz);
04d45209 1445 c_stop = clock();
1446 clk += c_stop - c_start;
1447 if (func && (rc = func(buf, sz, p)) != 0)
f0675f8a 1448 return (rc);
bafe8a7b
MW
1449 t = mp_fromsizet(t, sz);
1450 kb = mp_add(kb, kb, t);
f0675f8a 1451
1452 /* --- Update the display --- */
1453
1454 if (flags & f_progress) {
f0675f8a 1455 unsigned up = 0;
1456
15df46bc
MW
1457 now = doubletime();
1458
f0675f8a 1459 if (percent > 100)
1460 up = 1;
1461
1462 if (!outsz) {
bbde884a 1463 if (now - last > 0.1) {
f0675f8a 1464 up = 1;
1465 }
1466 if (up)
1467 fputs(" ] ", stderr);
1468 } else {
bafe8a7b
MW
1469 unsigned pc;
1470 t = mp_fromulong(t, 100);
1471 t = mp_mul(t, t, kb);
1472 mp_div(&t, 0, t, outsz);
1473 assert(!MP_NEGP(t) && MP_CMP(t, <, MP_UINT_MAX));
1474 pc = mp_touint(t);
bbde884a 1475 if (pc > percent || percent > 100 || now - last > 0.1) {
f0675f8a 1476 if (percent > 100)
1477 percent = 0;
1478 percent &= ~1;
1479 for (; percent < (pc & ~1); percent += 2)
1480 putc('.', stderr);
1481 percent = pc;
1482 for (; pc < 100; pc += 2)
1483 putc(' ', stderr);
1484 fprintf(stderr, "] %3i%% ", percent);
1485 up = 1;
1486 }
1487 }
1488
1489 if (up) {
04d45209 1490 char *kk = kmg;
bafe8a7b
MW
1491 t = mp_add(t, kb, MP_ZERO);
1492 while (mp_bits(t) >= 14) {
1493 t = mp_lsr(t, t, 10);
04d45209 1494 kk++;
f0675f8a 1495 }
bafe8a7b
MW
1496 DRESET(&d);
1497 mp_writedstr(t, &d, 10);
1498 fprintf(stderr, "%4s%c\r[", d.buf, *kk);
f0675f8a 1499 if (outsz) {
1500 unsigned pc;
1501 for (pc = 0; pc < (percent & ~1); pc += 2)
1502 putc('.', stderr);
1503 }
bafe8a7b 1504 last = now;
f0675f8a 1505 }
1506
1507 if (percent > 100)
1508 percent = 0;
1509
bbde884a 1510 if (percent < 100 && up) {
f0675f8a 1511 putc(*bp++, stderr);
1512 putc('\b', stderr);
1513 if (!*bp)
1514 bp = baton;
1515 }
1516 fflush(stderr);
1517 }
bafe8a7b 1518 }
f0675f8a 1519
1520 if (flags & f_progress)
1521 fputc('\n', stderr);
04d45209 1522 if (flags & f_timer) {
bafe8a7b
MW
1523 DRESET(&d);
1524 dstr_puts(&d, "generated ");
1525 mp_writedstr(kb, &d, 10);
1526 dstr_puts(&d, " bytes ");
e3dc2d22 1527 if (!clk)
bafe8a7b 1528 dstr_puts(&d, "too quickly to measure\n");
e3dc2d22 1529 else {
1530 char *kk;
bafe8a7b 1531 double out;
e3dc2d22 1532 double sec = (double)clk/CLOCKS_PER_SEC;
bafe8a7b
MW
1533 unsigned long sh;
1534 double bps;
1535
1536 MP_SHRINK(kb);
1537 switch (MP_LEN(kb)) {
1538 case 0: out = 0; break;
1539 case 1: out = kb->v[0]; break;
1540 default:
1541 sh = mp_bits(kb) - MPW_BITS;
1542 t = mp_lsr(t, kb, sh);
1543 out = ldexp(t->v[0], sh);
1544 break;
1545 }
1546 bps = (8*out)/sec;
e3dc2d22 1547 for (kk = kmg; bps > 1024 && kk[1]; kk++, bps /= 1024)
1548 ;
bafe8a7b
MW
1549 dstr_putf(&d, "in %g secs (%g %cb/s)\n", sec, bps, *kk);
1550 fwrite(d.buf, 1, d.len, stderr);
e3dc2d22 1551 }
04d45209 1552 }
bafe8a7b
MW
1553
1554 mp_drop(t);
1555 DDESTROY(&d);
f0675f8a 1556 return (0);
1557}
1558
1559/*----- Main code ---------------------------------------------------------*/
1560
1561int main(int ac, char *av[])
1562{
1563 gen *g = &optsg;
1564 grand *r;
ee33470f 1565
1566 /* --- Initialize mLib --- */
1567
1568 ego(av[0]);
1569 sub_init();
1570
1571 /* --- Set up the main Catacomb generator --- */
1572
1573 rand_noisesrc(RAND_GLOBAL, &noise_source);
bb78535e 1574 rand_seed(RAND_GLOBAL, 160);
ee33470f 1575
1576 /* --- Initialize the options table --- */
1577
1578 addopts(sopts, opts);
1579 argc = ac;
1580 argv = av;
c2181593 1581 outfp = stdout;
ee33470f 1582
1583 /* --- Read the generator out of the first argument --- */
1584
1585 if (argc > 1 && *argv[1] != '-') {
1586 const char *arg = av[1];
1587 size_t sz = strlen(arg);
bc97f84c 1588 gen *gg;
ee33470f 1589
1590 g = 0;
1591 for (gg = generators; gg->name; gg++) {
1592 if (strncmp(arg, gg->name, sz) == 0) {
1593 if (gg->name[sz] == 0) {
1594 g = gg;
1595 break;
1596 } else if (g)
1597 die(EXIT_FAILURE, "ambiguous generator name `%s'", arg);
1598 else
1599 g = gg;
1600 }
1601 }
1602 if (!g)
1603 die(EXIT_FAILURE, "unknown generator name `%s'", arg);
1604 argc--;
1605 argv++;
1606 }
1607
1608 /* --- Get a generic random number generator --- */
1609
1610 r = g->seed(g->i);
1611 if (!r || optind != ac - 1) {
1612 usage(stderr);
1613 exit(EXIT_FAILURE);
1614 }
1615
bb78535e 1616 /* --- Do the FIPS test --- */
1617
1618 if (flags & f_fips) {
1619 octet buf[FIPSTEST_BUFSZ];
1620 unsigned rc;
bafe8a7b 1621 mp *t;
f0675f8a 1622 octet *p = buf;
bb78535e 1623
bafe8a7b
MW
1624 t = mp_fromsizet(MP_NEW, sizeof(buf));
1625 generate(r, t, genbuf, &p);
1626 mp_drop(t);
bb78535e 1627 rc = fipstest(buf);
1628 if (rc & FIPSTEST_MONOBIT)
1629 moan("failed monobit test");
1630 if (rc & FIPSTEST_POKER)
1631 moan("failed poker test");
1632 if (rc & FIPSTEST_RUNS)
1633 moan("failed runs test");
1634 if (rc & FIPSTEST_LONGRUNS)
1635 moan("failed long runs test");
1636 if (!rc && (flags & f_progress))
04d45209 1637 fputs("test passed\n", stderr);
bb78535e 1638 return (rc ? EXIT_FAILURE : 0);
1639 }
1640
1641 /* --- Do Maurer's test --- */
1642
1643 if (flags & f_maurer) {
f0675f8a 1644 size_t bufsz;
bb78535e 1645 unsigned i;
1646 unsigned rc = 0;
bafe8a7b 1647 mp *t;
e3dc2d22 1648 genmaurer_ctx g;
bb78535e 1649
1650 static struct { double x; const char *sig; } sigtab[] = {
1651 { 3.2905, "1e-3" },
1652 { 3.0902, "2e-3" },
1653 { 2.8070, "5e-3" },
1654 { 2.5758, "1e-2" },
1655 { 0 , 0 }
1656 };
1657
e3dc2d22 1658 g.n = maurer_hi - maurer_lo + 1;
1659 g.m = xmalloc(g.n * sizeof(maurer_ctx));
1660 for (i = 0; i < g.n; i++)
1661 maurer_init(&g.m[i], i + maurer_lo);
f0675f8a 1662 bufsz = (100 * maurer_hi) << maurer_hi;
e3dc2d22 1663
bafe8a7b
MW
1664 t = mp_fromsizet(MP_NEW, bufsz);
1665 generate(r, t, genmaurer, &g);
1666 mp_drop(t);
f0675f8a 1667
1668 for (i = maurer_lo; i <= maurer_hi; i++) {
e3dc2d22 1669 double z = maurer_done(&g.m[i - maurer_lo]);
bb78535e 1670 double zz = fabs(z);
1671 unsigned j;
1672
1673 for (j = 0; sigtab[j].sig; j++) {
1674 if (zz > sigtab[j].x) {
bb78535e 1675 rc = EXIT_FAILURE;
1676 moan("failed, bits = %u, sig = %s, Z_u = %g",
f0675f8a 1677 i, sigtab[j].sig, z);
bb78535e 1678 break;
1679 }
1680 }
1681 if (flags & f_progress)
04d45209 1682 fprintf(stderr, "bits = %u, Z_u = %g\n", i, z);
bb78535e 1683 }
1684
e3dc2d22 1685 xfree(g.m);
bb78535e 1686 return (rc);
1687 }
1688
04d45209 1689 /* --- Discard --- */
1690
1691 if (flags & f_discard) {
1692 generate(r, outsz, 0, 0);
1693 return (0);
1694 }
1695
f0675f8a 1696 /* --- Write to a file --- */
bb78535e 1697
ee33470f 1698#ifndef PORTABLE
1699 if (!(flags & f_file) && isatty(STDOUT_FILENO))
1700 die(EXIT_FAILURE, "writing output to a terminal is a bad idea");
1701#endif
1702
f0675f8a 1703 generate(r, outsz, genfile, outfp);
ee33470f 1704
1705 /* --- Done --- */
1706
1707 r->ops->destroy(r);
ee33470f 1708 return (0);
1709}
1710
1711/*----- That's all, folks -------------------------------------------------*/