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