+/* --- SHAKE generators --- */
+
+static grand *gen_shake(unsigned i)
+{
+ dstr d = DSTR_INIT;
+ const char *func = 0, *perso = 0;
+ grand *r;
+
+ static struct option opts[] = {
+ { "function", OPTF_ARGREQ, 0, 'F' },
+ { "personalization", OPTF_ARGREQ, 0, 'P' },
+ { "key", OPTF_ARGREQ, 0, 'k' },
+ { "hex", OPTF_ARGREQ, 0, 'H' },
+ { 0, 0, 0, 0 }
+ };
+
+ addopts("F:P:k:H:", opts);
+
+ for (;;) {
+ int o = opt();
+ if (o < 0)
+ break;
+ switch (o) {
+ case 'F':
+ func = optarg;
+ break;
+ case 'P':
+ perso = optarg;
+ break;
+ case 'k':
+ DRESET(&d);
+ textkey(&d, optarg, shaketab[i].ksz);
+ break;
+ case 'H':
+ DRESET(&d);
+ hexkey(&d, optarg, shaketab[i].ksz);
+ break;
+ default:
+ return (0);
+ }
+ }
+
+ if (!d.len) randkey(&d, shaketab[i].ksz);
+ r = shaketab[i].shake(func, func ? strlen(func) : 0,
+ perso, perso ? strlen(perso) : 0,
+ d.buf, d.len);
+ dstr_destroy(&d);
+ return (r);
+}
+
+/* --- KMAC generators --- */
+
+static grand *gen_kmac(unsigned i)
+{
+ dstr d = DSTR_INIT, m = DSTR_INIT;
+ const char *perso = 0;
+ char *q;
+ grand *r;
+
+ static struct option opts[] = {
+ { "personalization", OPTF_ARGREQ, 0, 'P' },
+ { "key", OPTF_ARGREQ, 0, 'k' },
+ { "hex", OPTF_ARGREQ, 0, 'H' },
+ { "message", OPTF_ARGREQ, 0, 'M' },
+ { "msghex", OPTF_ARGREQ, 0, 'N' },
+ { 0, 0, 0, 0 }
+ };
+
+ addopts("P:k:H:M:N:", opts);
+
+ for (;;) {
+ int o = opt();
+ if (o < 0)
+ break;
+ switch (o) {
+ case 'P':
+ perso = optarg;
+ break;
+ case 'k':
+ DRESET(&d);
+ textkey(&d, optarg, shaketab[i].ksz);
+ break;
+ case 'H':
+ DRESET(&d);
+ hexkey(&d, optarg, shaketab[i].ksz);
+ break;
+ case 'M':
+ DRESET(&m);
+ DPUTS(&d, optarg);
+ break;
+ case 'N':
+ DRESET(&m);
+ unhex(optarg, &q, &m);
+ if (*q) die(EXIT_FAILURE, "bad hex");
+ break;
+ default:
+ return (0);
+ }
+ }
+
+ if (!d.len) randkey(&d, shaketab[i].ksz);
+ r = shaketab[i].kmac(perso, perso ? strlen(perso) : 0, d.buf, d.len);
+ r->ops->misc(r, GRAND_SEEDBLOCK, (void *)m.buf, m.len);
+ dstr_destroy(&d); dstr_destroy(&m);
+ return (r);
+}
+