progs/perftest.c: Rename `c_start', `c_stop' to `c0', c1'.
[catacomb] / progs / perftest.c
1 /* -*-c-*-
2 *
3 * Measure performance of various operations (Unix-specific)
4 *
5 * (c) 2004 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
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.
16 *
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.
21 *
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
28 /*----- Header files ------------------------------------------------------*/
29
30 #define _FILE_OFFSET_BITS 64
31
32 #include "config.h"
33
34 #include <errno.h>
35 #include <limits.h>
36 #include <math.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <time.h>
41
42 #include <sys/types.h>
43 #include <sys/time.h>
44 #include <unistd.h>
45
46 #include <mLib/alloc.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 #include <mLib/tv.h>
53
54 #include "rand.h"
55 #include "mp.h"
56 #include "mprand.h"
57 #include "fibrand.h"
58 #include "rsa.h"
59 #include "mpint.h"
60 #include "mptext.h"
61 #include "mpmont.h"
62 #include "mpbarrett.h"
63 #include "dh.h"
64 #include "pgen.h"
65 #include "ec.h"
66 #include "group.h"
67 #include "x25519.h"
68 #include "x448.h"
69 #include "ed25519.h"
70 #include "ed448.h"
71
72 #include "cc.h"
73 #include "gcipher.h"
74 #include "ghash.h"
75 #include "gmac.h"
76 #include "poly1305.h"
77
78 #include "ectab.h"
79 #include "ptab.h"
80
81 /*----- Options -----------------------------------------------------------*/
82
83 typedef struct opts {
84 const char *name; /* Pre-configured named thing */
85 unsigned fbits; /* Field size bits */
86 unsigned gbits; /* Group size bits */
87 unsigned n; /* Number of factors */
88 unsigned i; /* Number of intervals (or zero) */
89 unsigned k; /* Main loop batch size */
90 double t; /* Time for each interval (secs) */
91 mp *e; /* Public exponent */
92 unsigned f; /* Flags */
93 #define OF_NOCHECK 1u /* Don't do group checking */
94 } opts;
95
96 /*----- Job switch --------------------------------------------------------*/
97
98 /* --- Barrett exponentiation --- */
99
100 typedef struct bar_ctx {
101 size_t n;
102 mpbarrett b;
103 mp_expfactor *e;
104 } bar_ctx;
105
106 static void *bar_init(opts *o)
107 {
108 bar_ctx *c = CREATE(bar_ctx);
109 gprime_param gp;
110 qd_parse qd;
111 size_t i;
112
113 if (o->name) {
114 qd.p = o->name;
115 if (dh_parse(&qd, &gp))
116 die(1, "bad prime group: %s", qd.e);
117 } else {
118 if (!o->fbits) o->fbits = 1024;
119 dh_gen(&gp, o->gbits, o->fbits, 0, &rand_global, pgen_evspin, 0);
120 }
121 mpbarrett_create(&c->b, gp.p);
122 if (!o->n) o->n = 1;
123 c->n = o->n;
124 c->e = xmalloc(c->n * sizeof(group_expfactor));
125 for (i = 0; i < c->n; i++) {
126 c->e[i].base = mprand_range(MP_NEW, gp.p, &rand_global, 0);
127 c->e[i].exp = mprand_range(MP_NEW, gp.q, &rand_global, 0);
128 }
129 dh_paramfree(&gp);
130 return (c);
131 }
132
133 static void bar_run(void *cc)
134 {
135 bar_ctx *c = cc;
136 mp *d = mpbarrett_exp(&c->b, MP_NEW, c->e[0].base, c->e[0].exp);
137 MP_DROP(d);
138 }
139
140 static void barsim_run(void *cc)
141 {
142 bar_ctx *c = cc;
143 mp *d = mpbarrett_mexp(&c->b, MP_NEW, c->e, c->n);
144 MP_DROP(d);
145 }
146
147 /* --- Montgomery exponentiation --- */
148
149 typedef struct mont_ctx {
150 size_t n;
151 mpmont m;
152 mp_expfactor *e;
153 } mont_ctx;
154
155 static void *mont_init(opts *o)
156 {
157 mont_ctx *c = CREATE(mont_ctx);
158 gprime_param gp;
159 qd_parse qd;
160 size_t i;
161
162 if (o->name) {
163 qd.p = o->name;
164 if (dh_parse(&qd, &gp))
165 die(1, "bad prime group: %s", qd.e);
166 } else {
167 if (!o->fbits) o->fbits = 1024;
168 dh_gen(&gp, o->gbits, o->fbits, 0, &rand_global, pgen_evspin, 0);
169 }
170 mpmont_create(&c->m, gp.p);
171 if (!o->n) o->n = 1;
172 c->n = o->n;
173 c->e = xmalloc(c->n * sizeof(mp_expfactor));
174 for (i = 0; i < c->n; i++) {
175 c->e[i].base = mprand_range(MP_NEW, gp.p, &rand_global, 0);
176 c->e[i].exp = mprand_range(MP_NEW, gp.q, &rand_global, 0);
177 }
178 dh_paramfree(&gp);
179 return (c);
180 }
181
182 static void mont_run(void *cc)
183 {
184 mont_ctx *c = cc;
185 mp *d = mpmont_expr(&c->m, MP_NEW, c->e[0].base, c->e[0].exp);
186 MP_DROP(d);
187 }
188
189 static void montsim_run(void *cc)
190 {
191 mont_ctx *c = cc;
192 mp *d = mpmont_mexpr(&c->m, MP_NEW, c->e, c->n);
193 MP_DROP(d);
194 }
195
196 /* --- Group exponentiation --- */
197
198 typedef struct gr_ctx {
199 size_t n;
200 group *g;
201 group_expfactor *e;
202 } gr_ctx;
203
204 static void *grp_init(opts *o)
205 {
206 gr_ctx *c = CREATE(gr_ctx);
207 const char *e;
208 gprime_param gp;
209 qd_parse qd;
210 size_t i;
211
212 if (o->name) {
213 qd.p = o->name;
214 if (dh_parse(&qd, &gp))
215 die(1, "bad prime group: %s", qd.e);
216 } else {
217 if (!o->fbits) o->fbits = 1024;
218 dh_gen(&gp, o->gbits, o->fbits, 0, &rand_global, pgen_evspin, 0);
219 }
220 c->g = group_prime(&gp);
221 if (!(o->f & OF_NOCHECK) && (e = G_CHECK(c->g, &rand_global)) != 0)
222 die(1, "bad group: %s", e);
223 if (!o->n) o->n = 1;
224 c->n = o->n;
225 c->e = xmalloc(c->n * sizeof(group_expfactor));
226 for (i = 0; i < c->n; i++) {
227 c->e[i].base = G_CREATE(c->g);
228 G_FROMINT(c->g, c->e[i].base,
229 mprand_range(MP_NEW, gp.p, &rand_global, 0));
230 c->e[i].exp = mprand_range(MP_NEW, gp.q, &rand_global, 0);
231 }
232 dh_paramfree(&gp);
233 return (c);
234 }
235
236 static void *grec_init(opts *o)
237 {
238 gr_ctx *c = CREATE(gr_ctx);
239 const char *e;
240 ec_info ei;
241 ec p = EC_INIT;
242 size_t i;
243
244 if (!o->name)
245 die(1, "can't generate elliptic curves");
246 if ((e = ec_getinfo(&ei, o->name)) != 0)
247 die(1, "bad curve: %s", e);
248 c->g = group_ec(&ei);
249 if (!(o->f & OF_NOCHECK) && (e = G_CHECK(c->g, &rand_global)) != 0)
250 die(1, "bad group: %s", e);
251 if (!o->n) o->n = 1;
252 c->n = o->n;
253 c->e = xmalloc(c->n * sizeof(group_expfactor));
254 for (i = 0; i < c->n; i++) {
255 c->e[i].base = G_CREATE(c->g);
256 ec_rand(ei.c, &p, &rand_global);
257 G_FROMEC(c->g, c->e[i].base, &p);
258 c->e[i].exp = mprand_range(MP_NEW, ei.r, &rand_global, 0);
259 }
260 EC_DESTROY(&p);
261 return (c);
262 }
263
264 static void gr_run(void *cc)
265 {
266 gr_ctx *c = cc;
267 ge *x = G_CREATE(c->g);
268 G_EXP(c->g, x, c->e[0].base, c->e[0].exp);
269 G_DESTROY(c->g, x);
270 }
271
272 static void grsim_run(void *cc)
273 {
274 gr_ctx *c = cc;
275 ge *x = G_CREATE(c->g);
276 G_MEXP(c->g, x, c->e, c->n);
277 G_DESTROY(c->g, x);
278 }
279
280 /* --- x25519 --- */
281
282 typedef struct x25519_jobctx {
283 octet k[X25519_KEYSZ];
284 octet p[X25519_PUBSZ];
285 } x25519_jobctx;
286
287 static void *x25519_jobinit(opts *o)
288 {
289 x25519_jobctx *c = CREATE(x25519_jobctx);
290 rand_get(RAND_GLOBAL, c->k, sizeof(c->k));
291 rand_get(RAND_GLOBAL, c->p, sizeof(c->p));
292 return (c);
293 }
294
295 static void x25519_jobrun(void *cc)
296 { x25519_jobctx *c = cc; octet z[X25519_OUTSZ]; x25519(z, c->k, c->p); }
297
298 /* --- x448 --- */
299
300 typedef struct x448_jobctx {
301 octet k[X448_KEYSZ];
302 octet p[X448_PUBSZ];
303 } x448_jobctx;
304
305 static void *x448_jobinit(opts *o)
306 {
307 x448_jobctx *c = CREATE(x448_jobctx);
308 rand_get(RAND_GLOBAL, c->k, sizeof(c->k));
309 rand_get(RAND_GLOBAL, c->p, sizeof(c->p));
310 return (c);
311 }
312
313 static void x448_jobrun(void *cc)
314 { x448_jobctx *c = cc; octet z[X448_OUTSZ]; x448(z, c->k, c->p); }
315
316 /* --- Ed25519 --- */
317
318 typedef struct ed25519_signctx {
319 octet k[ED25519_KEYSZ];
320 octet K[ED25519_PUBSZ];
321 octet m[64];
322 } ed25519_signctx;
323
324 typedef struct ed25519_vrfctx {
325 octet K[ED25519_PUBSZ];
326 octet m[64];
327 octet sig[ED25519_SIGSZ];
328 } ed25519_vrfctx;
329
330 static void *ed25519_signinit(opts *o)
331 {
332 ed25519_signctx *c = CREATE(ed25519_signctx);
333
334 rand_get(RAND_GLOBAL, c->k, sizeof(c->k));
335 rand_get(RAND_GLOBAL, c->m, sizeof(c->m));
336 ed25519_pubkey(c->K, c->k, sizeof(c->k));
337 return (c);
338 }
339
340 static void ed25519_signrun(void *cc)
341 {
342 ed25519_signctx *c = cc;
343 octet sig[ED25519_SIGSZ];
344
345 ed25519_sign(sig, c->k, sizeof(c->k), c->K, c->m, sizeof(c->m));
346 }
347
348 static void *ed25519_vrfinit(opts *o)
349 {
350 octet k[ED25519_KEYSZ];
351 ed25519_vrfctx *c = CREATE(ed25519_vrfctx);
352
353 rand_get(RAND_GLOBAL, k, sizeof(k));
354 rand_get(RAND_GLOBAL, c->m, sizeof(c->m));
355 ed25519_pubkey(c->K, k, sizeof(k));
356 ed25519_sign(c->sig, k, sizeof(k), c->K, c->m, sizeof(c->m));
357 return (c);
358 }
359
360 static void ed25519_vrfrun(void *cc)
361 {
362 ed25519_vrfctx *c = cc;
363 ed25519_verify(c->K, c->m, sizeof(c->m), c->sig);
364 }
365
366 /* --- Ed448 --- */
367
368 typedef struct ed448_signctx {
369 octet k[ED448_KEYSZ];
370 octet K[ED448_PUBSZ];
371 octet m[64];
372 } ed448_signctx;
373
374 typedef struct ed448_vrfctx {
375 octet K[ED448_PUBSZ];
376 octet m[64];
377 octet sig[ED448_SIGSZ];
378 } ed448_vrfctx;
379
380 static void *ed448_signinit(opts *o)
381 {
382 ed448_signctx *c = CREATE(ed448_signctx);
383
384 rand_get(RAND_GLOBAL, c->k, sizeof(c->k));
385 rand_get(RAND_GLOBAL, c->m, sizeof(c->m));
386 ed448_pubkey(c->K, c->k, sizeof(c->k));
387 return (c);
388 }
389
390 static void ed448_signrun(void *cc)
391 {
392 ed448_signctx *c = cc;
393 octet sig[ED448_SIGSZ];
394
395 ed448_sign(sig, c->k, sizeof(c->k), c->K, 0, 0, 0, c->m, sizeof(c->m));
396 }
397
398 static void *ed448_vrfinit(opts *o)
399 {
400 octet k[ED448_KEYSZ];
401 ed448_vrfctx *c = CREATE(ed448_vrfctx);
402
403 rand_get(RAND_GLOBAL, k, sizeof(k));
404 rand_get(RAND_GLOBAL, c->m, sizeof(c->m));
405 ed448_pubkey(c->K, k, sizeof(k));
406 ed448_sign(c->sig, k, sizeof(k), c->K, 0, 0, 0, c->m, sizeof(c->m));
407 return (c);
408 }
409
410 static void ed448_vrfrun(void *cc)
411 {
412 ed448_vrfctx *c = cc;
413 ed448_verify(c->K, 0, 0, 0, c->m, sizeof(c->m), c->sig);
414 }
415
416 /* --- RSA --- */
417
418 typedef struct rsapriv_ctx {
419 rsa_priv rp;
420 rsa_privctx rpc;
421 mp *m;
422 } rsapriv_ctx;
423
424 static void *rsapriv_init(opts *o)
425 {
426 rsapriv_ctx *c = CREATE(rsapriv_ctx);
427
428 if (!o->fbits) o->fbits = 1024;
429 if (!o->e) o->e = mp_fromulong(MP_NEW, 65537);
430 rsa_gen_e(&c->rp, o->fbits, o->e, &rand_global, 0, pgen_evspin, 0);
431 rsa_privcreate(&c->rpc, &c->rp, 0);
432 c->m = mprand_range(MP_NEW, c->rp.n, &rand_global, 0);
433 return (c);
434 }
435
436 static void *rsaprivblind_init(opts *o)
437 {
438 rsapriv_ctx *c = CREATE(rsapriv_ctx);
439
440 if (!o->fbits) o->fbits = 1024;
441 if (!o->e) o->e = mp_fromulong(MP_NEW, 65537);
442 rsa_gen_e(&c->rp, o->fbits, o->e, &rand_global, 0, pgen_evspin, 0);
443 rsa_privcreate(&c->rpc, &c->rp, fibrand_create(0));
444 c->m = mprand_range(MP_NEW, c->rp.n, &rand_global, 0);
445 return (c);
446 }
447
448 static void rsapriv_run(void *cc)
449 {
450 rsapriv_ctx *c = cc;
451 mp *d = rsa_privop(&c->rpc, MP_NEW, c->m);
452 MP_DROP(d);
453 }
454
455 typedef struct rsapub_ctx {
456 rsa_pub rp;
457 rsa_pubctx rpc;
458 mp *m;
459 } rsapub_ctx;
460
461 static void *rsapub_init(opts *o)
462 {
463 rsapub_ctx *c = CREATE(rsapub_ctx);
464 rsa_priv rp;
465
466 if (!o->fbits) o->fbits = 1024;
467 if (!o->e) o->e = mp_fromulong(MP_NEW, 65537);
468 rsa_gen_e(&rp, o->fbits, o->e, &rand_global, 0, pgen_evspin, 0);
469 c->rp.n = MP_COPY(rp.n);
470 c->rp.e = MP_COPY(rp.e);
471 rsa_privfree(&rp);
472 rsa_pubcreate(&c->rpc, &c->rp);
473 c->m = mprand_range(MP_NEW, c->rp.n, &rand_global, 0);
474 return (c);
475 }
476
477 static void rsapub_run(void *cc)
478 {
479 rsapub_ctx *c = cc;
480 mp *d = rsa_pubop(&c->rpc, MP_NEW, c->m);
481 MP_DROP(d);
482 }
483
484 /* --- Symmetric encryption --- */
485
486 typedef struct ksched_ctx {
487 const gccipher *c;
488 octet *k;
489 size_t ksz;
490 } ksched_ctx;
491
492 static void *ksched_init(opts *o)
493 {
494 ksched_ctx *c = CREATE(ksched_ctx);
495 if (!o->name)
496 die(1, "must specify encryption scheme name");
497 if ((c->c = gcipher_byname(o->name)) == 0)
498 die(1, "encryption scheme `%s' not known", o->name);
499 c->ksz = keysz(o->gbits/8, c->c->keysz);
500 c->k = xmalloc(c->ksz);
501 rand_get(RAND_GLOBAL, c->k, c->ksz);
502 return (c);
503 }
504
505 static void ksched_run(void *cc)
506 {
507 ksched_ctx *c = cc;
508 gcipher *gc = GC_INIT(c->c, c->k, c->ksz);
509 GC_DESTROY(gc);
510 }
511
512 typedef struct enc_ctx {
513 gcipher *c;
514 octet *m;
515 size_t sz;
516 size_t n;
517 } enc_ctx;
518
519 static void *enc_init(opts *o)
520 {
521 enc_ctx *c = CREATE(enc_ctx);
522 const gccipher *cc;
523 size_t ksz;
524 octet *k;
525 if (!o->name)
526 die(1, "must specify encryption scheme name");
527 if ((cc = gcipher_byname(o->name)) == 0)
528 die(1, "encryption scheme `%s' not known", o->name);
529 ksz = keysz(0, cc->keysz);
530 k = xmalloc(ksz);
531 rand_get(RAND_GLOBAL, k, ksz);
532 c->c = GC_INIT(cc, k, ksz);
533 xfree(k);
534 c->sz = o->gbits ? o->gbits : 65536;
535 c->n = o->n ? o->n : 16;
536 c->m = xmalloc(c->sz);
537 return (c);
538 }
539
540 static void enc_run(void *cc)
541 {
542 enc_ctx *c = cc;
543 size_t i;
544 for (i = 0; i < c->n; i++)
545 GC_ENCRYPT(c->c, c->m, c->m, c->sz);
546 }
547
548 /* --- Hashing --- */
549
550 typedef struct hash_ctx {
551 const gchash *h;
552 octet *m;
553 size_t sz;
554 size_t n;
555 } hash_ctx;
556
557 static void *hash_init(opts *o)
558 {
559 hash_ctx *c = CREATE(hash_ctx);
560 if (!o->name)
561 die(1, "must specify hash function name");
562 if ((c->h = ghash_byname(o->name)) == 0)
563 die(1, "hash function `%s' not known", o->name);
564 c->sz = o->gbits ? o->gbits : 65536;
565 c->n = o->n ? o->n : 16;
566 c->m = xmalloc(c->sz);
567 return (c);
568 }
569
570 static void hash_run(void *cc)
571 {
572 hash_ctx *c = cc;
573 size_t i;
574 ghash *h = GH_INIT(c->h);
575 for (i = 0; i < c->n; i++)
576 GH_HASH(h, c->m, c->sz);
577 GH_DONE(h, 0);
578 GH_DESTROY(h);
579 }
580
581 /* --- Poly1305 --- */
582
583 typedef struct poly1305_jobctx {
584 poly1305_key k;
585 octet s[POLY1305_MASKSZ];
586 octet *m;
587 size_t sz;
588 size_t n;
589 } poly1305_jobctx;
590
591 static void *poly1305_jobinit(opts *o)
592 {
593 octet k[POLY1305_KEYSZ];
594 poly1305_jobctx *c = CREATE(poly1305_jobctx);
595 rand_get(RAND_GLOBAL, k, sizeof(k));
596 poly1305_keyinit(&c->k, k, sizeof(k));
597 rand_get(RAND_GLOBAL, c->s, sizeof(c->s));
598 c->sz = o->gbits ? o->gbits : 65536;
599 c->n = o->n ? o->n : 16;
600 c->m = xmalloc(c->sz);
601 return (c);
602 }
603
604 static void poly1305_jobrun(void *cc)
605 {
606 poly1305_jobctx *c = cc;
607 poly1305_ctx ctx;
608 octet t[POLY1305_TAGSZ];
609 size_t i;
610 poly1305_macinit(&ctx, &c->k, c->s);
611 for (i = 0; i < c->n; i++) poly1305_hash(&ctx, c->m, c->sz);
612 poly1305_done(&ctx, t);
613 }
614
615 /* --- Job table --- */
616
617 typedef struct jobops {
618 const char *name;
619 void *(*init)(opts *);
620 void (*run)(void *);
621 } jobops;
622
623 static const jobops jobtab[] = {
624 { "g-prime-exp", grp_init, gr_run },
625 { "g-ec-mul", grec_init, gr_run },
626 { "g-prime-exp-sim", grp_init, grsim_run },
627 { "g-ec-mul-sim", grec_init, grsim_run },
628 { "barrett-exp", bar_init, bar_run },
629 { "barrett-exp-sim", bar_init, barsim_run },
630 { "mont-exp", mont_init, mont_run },
631 { "mont-exp-sim", mont_init, montsim_run },
632 { "rsa-priv", rsapriv_init, rsapriv_run },
633 { "rsa-priv-blind", rsaprivblind_init, rsapriv_run },
634 { "rsa-pub", rsapub_init, rsapub_run },
635 { "x25519", x25519_jobinit, x25519_jobrun },
636 { "x448", x448_jobinit, x448_jobrun },
637 { "ed25519-sign", ed25519_signinit, ed25519_signrun },
638 { "ed25519-vrf", ed25519_vrfinit, ed25519_vrfrun },
639 { "ed448-sign", ed448_signinit, ed448_signrun },
640 { "ed448-vrf", ed448_vrfinit, ed448_vrfrun },
641 { "ksched", ksched_init, ksched_run },
642 { "enc", enc_init, enc_run },
643 { "hash", hash_init, hash_run },
644 { "poly1305", poly1305_jobinit, poly1305_jobrun },
645 { 0, 0, 0 }
646 };
647
648 /*----- Main code ---------------------------------------------------------*/
649
650 void version(FILE *fp)
651 {
652 pquis(fp, "$, Catacomb " VERSION "\n");
653 }
654
655 static void usage(FILE *fp)
656 {
657 pquis(fp, "Usage: $ [-options] job\n");
658 }
659
660 static void help(FILE *fp)
661 {
662 version(fp);
663 putc('\n', fp);
664 usage(fp);
665 pquis(fp, "\n\
666 Various performance tests.\n\
667 \n\
668 Options:\n\
669 \n\
670 -h, --help Show this help text.\n\
671 -v, --version Show program version number.\n\
672 -u, --usage Show terse usage message.\n\
673 -l, --list [ITEM...] List all the various names of things.\n\
674 \n\
675 -C, --name=NAME Select curve/DH-group/enc/hash name.\n\
676 -b, --field-bits Field size for g-prime and rsa.\n\
677 -q, --no-check Don't check field/group for validity.\n\
678 -B, --group-bits Group size for g-prime; key size for ksched;\n\
679 data size for enc and hash.\n\
680 -n, --factors=COUNT Number of factors for {exp,mul}-sim.\n\
681 -i, --intervals=COUNT Number of intervals to run for. [0; forever]\n\
682 -k, --batch=COUNT Number of operations to batch between timer checks.\n\
683 -t, --time=TIME Length of an interval in seconds. [1]\n\
684 ");
685 }
686
687 #define LISTS(LI) \
688 LI("Lists", list, \
689 listtab[i].name, listtab[i].name) \
690 LI("Jobs", job, \
691 jobtab[i].name, jobtab[i].name) \
692 LI("Elliptic curves", ec, \
693 ectab[i].name, ectab[i].name) \
694 LI("Diffie-Hellman groups", dh, \
695 ptab[i].name, ptab[i].name) \
696 LI("Encryption algorithms", cipher, \
697 gciphertab[i], gciphertab[i]->name) \
698 LI("Hash functions", hash, \
699 ghashtab[i], ghashtab[i]->name)
700
701 MAKELISTTAB(listtab, LISTS)
702
703 static unsigned uarg(const char *what, const char *p)
704 {
705 char *q;
706 unsigned long u;
707 errno = 0;
708 u = strtoul(p, &q, 0);
709 if (*q || u > UINT_MAX || q == p || errno)
710 die(1, "bad %s `%s'", what, p);
711 return (u);
712 }
713
714 static mp *mparg(const char *what, const char *p)
715 {
716 char *q;
717 mp *x = mp_readstring(MP_NEW, p, &q, 0);
718 if (!x || *q) die(1, "bad %s `%s'", what, p);
719 return (x);
720 }
721
722 static double farg(const char *what, const char *p)
723 {
724 char *q;
725 double f;
726 errno = 0;
727 f = strtod(p, &q);
728 if (*q || q == p || errno)
729 die(1, "bad %s `%s'", what, p);
730 return (f);
731 }
732
733 int main(int argc, char *argv[])
734 {
735 int i;
736 opts o = { 0 };
737 const jobops *j;
738 struct timeval tv_next, tv_now;
739 double t, ttot;
740 unsigned n, k;
741 unsigned long ii;
742 clock_t c0, c1;
743 double itot;
744 void *p;
745
746 ego(argv[0]);
747 o.t = 1;
748 for (;;) {
749 static const struct option opts[] = {
750 { "help", 0, 0, 'h' },
751 { "version", 0, 0, 'v' },
752 { "usage", 0, 0, 'u' },
753 { "list", 0, 0, 'l' },
754 { "name", OPTF_ARGREQ, 0, 'C' },
755 { "field-bits", OPTF_ARGREQ, 0, 'b' },
756 { "group-bits", OPTF_ARGREQ, 0, 'B' },
757 { "factors", OPTF_ARGREQ, 0, 'n' },
758 { "intervals", OPTF_ARGREQ, 0, 'i' },
759 { "batch", OPTF_ARGREQ, 0, 'k' },
760 { "public-exponent", OPTF_ARGREQ, 0, 'e' },
761 { "time", OPTF_ARGREQ, 0, 't' },
762 { "no-check", 0, 0, 'q' },
763 { 0, 0, 0, 0 }
764 };
765
766 i = mdwopt(argc, argv, "hvulC:b:B:n:i:k:e:t:q", opts, 0, 0, 0);
767 if (i < 0) break;
768 switch (i) {
769 case 'h': help(stdout); exit(0);
770 case 'v': version(stdout); exit(0);
771 case 'u': usage(stdout); exit(0);
772 case 'l': exit(displaylists(listtab, argv + optind));
773 case 'C': o.name = optarg; break;
774 case 'b': o.fbits = uarg("field bits", optarg); break;
775 case 'B': o.gbits = uarg("subgroup bits", optarg); break;
776 case 'n': o.n = uarg("factor count", optarg); break;
777 case 'e':
778 mp_drop(o.e); o.e = mparg("public exponent", optarg);
779 if (MP_CMP(o.e, <, MP_THREE) || MP_EVENP(o.e))
780 die(1, "invalid public exponent");
781 break;
782 case 'i': o.i = uarg("interval count", optarg); break;
783 case 't': o.t = farg("interval length", optarg); break;
784 case 'k': o.k = uarg("batch size", optarg); break;
785 case 'q': o.f |= OF_NOCHECK; break;
786 default: usage(stderr); exit(1);
787 }
788 }
789 if (optind + 1 != argc) { usage(stderr); exit(1); }
790
791 for (j = jobtab; j->name; j++)
792 if (strcmp(j->name, argv[optind]) == 0) break;
793 if (!j->name) die(1, "unknown job type `%s'", argv[optind]);
794 p = j->init(&o);
795
796 n = 0;
797 ttot = itot = 0;
798 gettimeofday(&tv_now, 0);
799 do {
800 tv_addl(&tv_next, &tv_now, o.t, fmod(o.t * MILLION, MILLION));
801 ii = 0;
802 c0 = clock();
803 do {
804 for (k = 0; k < o.k; k++) { j->run(p); }
805 ii += k;
806 gettimeofday(&tv_now, 0);
807 } while (TV_CMP(&tv_now, <, &tv_next));
808 c1 = clock();
809 printf("%5u: did = %5lu; /sec = %5f; avg /sec = %5f\n",
810 t = (double)(c1 - c0)/CLOCKS_PER_SEC;
811 itot += ii; ttot += t;
812 n, ii, ii/t, itot/ttot);
813 fflush(stdout);
814 n++;
815 } while (!o.i || n < o.i);
816
817 return (0);
818 }
819
820 /*----- That's all, folks -------------------------------------------------*/