X-Git-Url: https://git.distorted.org.uk/~mdw/catacomb/blobdiff_plain/ef7cf21d686245593220769a5f80a9bb75d62769..HEAD:/progs/perftest.c diff --git a/progs/perftest.c b/progs/perftest.c index e6f7ddf0..7c4a1331 100644 --- a/progs/perftest.c +++ b/progs/perftest.c @@ -43,8 +43,15 @@ #include #include +#ifdef HAVE_LINUX_PERF_EVENT_H +# include +# include +#endif + #include +#include #include +#include #include #include #include @@ -56,14 +63,21 @@ #include "mprand.h" #include "fibrand.h" #include "rsa.h" +#include "mpint.h" +#include "mptext.h" #include "mpmont.h" #include "mpbarrett.h" #include "dh.h" #include "pgen.h" #include "ec.h" #include "group.h" +#include "x25519.h" +#include "x448.h" +#include "ed25519.h" +#include "ed448.h" #include "cc.h" +#include "gaead.h" #include "gcipher.h" #include "ghash.h" #include "gmac.h" @@ -76,11 +90,15 @@ typedef struct opts { const char *name; /* Pre-configured named thing */ + const char *opwhat; /* What to call operations */ unsigned fbits; /* Field size bits */ unsigned gbits; /* Group size bits */ unsigned n; /* Number of factors */ unsigned i; /* Number of intervals (or zero) */ + unsigned k; /* Main loop batch size */ + unsigned long sc; /* Scale factor */ double t; /* Time for each interval (secs) */ + mp *e; /* Public exponent */ unsigned f; /* Flags */ #define OF_NOCHECK 1u /* Don't do group checking */ } opts; @@ -269,6 +287,142 @@ static void grsim_run(void *cc) G_DESTROY(c->g, x); } +/* --- x25519 --- */ + +typedef struct x25519_jobctx { + octet k[X25519_KEYSZ]; + octet p[X25519_PUBSZ]; +} x25519_jobctx; + +static void *x25519_jobinit(opts *o) +{ + x25519_jobctx *c = CREATE(x25519_jobctx); + rand_get(RAND_GLOBAL, c->k, sizeof(c->k)); + rand_get(RAND_GLOBAL, c->p, sizeof(c->p)); + return (c); +} + +static void x25519_jobrun(void *cc) + { x25519_jobctx *c = cc; octet z[X25519_OUTSZ]; x25519(z, c->k, c->p); } + +/* --- x448 --- */ + +typedef struct x448_jobctx { + octet k[X448_KEYSZ]; + octet p[X448_PUBSZ]; +} x448_jobctx; + +static void *x448_jobinit(opts *o) +{ + x448_jobctx *c = CREATE(x448_jobctx); + rand_get(RAND_GLOBAL, c->k, sizeof(c->k)); + rand_get(RAND_GLOBAL, c->p, sizeof(c->p)); + return (c); +} + +static void x448_jobrun(void *cc) + { x448_jobctx *c = cc; octet z[X448_OUTSZ]; x448(z, c->k, c->p); } + +/* --- Ed25519 --- */ + +typedef struct ed25519_signctx { + octet k[ED25519_KEYSZ]; + octet K[ED25519_PUBSZ]; + octet m[64]; +} ed25519_signctx; + +typedef struct ed25519_vrfctx { + octet K[ED25519_PUBSZ]; + octet m[64]; + octet sig[ED25519_SIGSZ]; +} ed25519_vrfctx; + +static void *ed25519_signinit(opts *o) +{ + ed25519_signctx *c = CREATE(ed25519_signctx); + + rand_get(RAND_GLOBAL, c->k, sizeof(c->k)); + rand_get(RAND_GLOBAL, c->m, sizeof(c->m)); + ed25519_pubkey(c->K, c->k, sizeof(c->k)); + return (c); +} + +static void ed25519_signrun(void *cc) +{ + ed25519_signctx *c = cc; + octet sig[ED25519_SIGSZ]; + + ed25519_sign(sig, c->k, sizeof(c->k), c->K, c->m, sizeof(c->m)); +} + +static void *ed25519_vrfinit(opts *o) +{ + octet k[ED25519_KEYSZ]; + ed25519_vrfctx *c = CREATE(ed25519_vrfctx); + + rand_get(RAND_GLOBAL, k, sizeof(k)); + rand_get(RAND_GLOBAL, c->m, sizeof(c->m)); + ed25519_pubkey(c->K, k, sizeof(k)); + ed25519_sign(c->sig, k, sizeof(k), c->K, c->m, sizeof(c->m)); + return (c); +} + +static void ed25519_vrfrun(void *cc) +{ + ed25519_vrfctx *c = cc; + ed25519_verify(c->K, c->m, sizeof(c->m), c->sig); +} + +/* --- Ed448 --- */ + +typedef struct ed448_signctx { + octet k[ED448_KEYSZ]; + octet K[ED448_PUBSZ]; + octet m[64]; +} ed448_signctx; + +typedef struct ed448_vrfctx { + octet K[ED448_PUBSZ]; + octet m[64]; + octet sig[ED448_SIGSZ]; +} ed448_vrfctx; + +static void *ed448_signinit(opts *o) +{ + ed448_signctx *c = CREATE(ed448_signctx); + + rand_get(RAND_GLOBAL, c->k, sizeof(c->k)); + rand_get(RAND_GLOBAL, c->m, sizeof(c->m)); + ed448_pubkey(c->K, c->k, sizeof(c->k)); + return (c); +} + +static void ed448_signrun(void *cc) +{ + ed448_signctx *c = cc; + octet sig[ED448_SIGSZ]; + + ed448_sign(sig, c->k, sizeof(c->k), c->K, 0, 0, 0, c->m, sizeof(c->m)); +} + +static void *ed448_vrfinit(opts *o) +{ + octet k[ED448_KEYSZ]; + ed448_vrfctx *c = CREATE(ed448_vrfctx); + + rand_get(RAND_GLOBAL, k, sizeof(k)); + rand_get(RAND_GLOBAL, c->m, sizeof(c->m)); + ed448_pubkey(c->K, k, sizeof(k)); + ed448_sign(c->sig, k, sizeof(k), c->K, 0, 0, 0, c->m, sizeof(c->m)); + return (c); +} + +static void ed448_vrfrun(void *cc) +{ + ed448_vrfctx *c = cc; + ed448_verify(c->K, 0, 0, 0, c->m, sizeof(c->m), c->sig); +} + /* --- RSA --- */ typedef struct rsapriv_ctx { @@ -282,7 +436,8 @@ static void *rsapriv_init(opts *o) rsapriv_ctx *c = CREATE(rsapriv_ctx); if (!o->fbits) o->fbits = 1024; - rsa_gen(&c->rp, o->fbits, &rand_global, 0, pgen_evspin, 0); + if (!o->e) o->e = mp_fromulong(MP_NEW, 65537); + rsa_gen_e(&c->rp, o->fbits, o->e, &rand_global, 0, pgen_evspin, 0); rsa_privcreate(&c->rpc, &c->rp, 0); c->m = mprand_range(MP_NEW, c->rp.n, &rand_global, 0); return (c); @@ -293,7 +448,8 @@ static void *rsaprivblind_init(opts *o) rsapriv_ctx *c = CREATE(rsapriv_ctx); if (!o->fbits) o->fbits = 1024; - rsa_gen(&c->rp, o->fbits, &rand_global, 0, pgen_evspin, 0); + if (!o->e) o->e = mp_fromulong(MP_NEW, 65537); + rsa_gen_e(&c->rp, o->fbits, o->e, &rand_global, 0, pgen_evspin, 0); rsa_privcreate(&c->rpc, &c->rp, fibrand_create(0)); c->m = mprand_range(MP_NEW, c->rp.n, &rand_global, 0); return (c); @@ -318,7 +474,8 @@ static void *rsapub_init(opts *o) rsa_priv rp; if (!o->fbits) o->fbits = 1024; - rsa_gen(&rp, o->fbits, &rand_global, 0, pgen_evspin, 0); + if (!o->e) o->e = mp_fromulong(MP_NEW, 65537); + rsa_gen_e(&rp, o->fbits, o->e, &rand_global, 0, pgen_evspin, 0); c->rp.n = MP_COPY(rp.n); c->rp.e = MP_COPY(rp.e); rsa_privfree(&rp); @@ -349,7 +506,9 @@ static void *ksched_init(opts *o) die(1, "must specify encryption scheme name"); if ((c->c = gcipher_byname(o->name)) == 0) die(1, "encryption scheme `%s' not known", o->name); - c->ksz = keysz(o->gbits/8, c->c->keysz); + c->ksz = keysz(o->fbits/8, c->c->keysz); + if (o->fbits%8 || (o->fbits && c->ksz != o->fbits/8)) + die(1, "bad key size %u for %s", o->fbits, o->name); c->k = xmalloc(c->ksz); rand_get(RAND_GLOBAL, c->k, c->ksz); return (c); @@ -379,13 +538,16 @@ static void *enc_init(opts *o) die(1, "must specify encryption scheme name"); if ((cc = gcipher_byname(o->name)) == 0) die(1, "encryption scheme `%s' not known", o->name); - ksz = keysz(0, cc->keysz); + ksz = keysz(o->fbits/8, cc->keysz); + if (o->fbits%8 || (o->fbits && ksz != o->fbits/8)) + die(1, "bad key size %u for %s", o->fbits, o->name); k = xmalloc(ksz); rand_get(RAND_GLOBAL, k, ksz); c->c = GC_INIT(cc, k, ksz); xfree(k); c->sz = o->gbits ? o->gbits : 65536; c->n = o->n ? o->n : 16; + o->opwhat = "byte"; o->sc = c->n*c->sz; c->m = xmalloc(c->sz); return (c); } @@ -398,6 +560,105 @@ static void enc_run(void *cc) GC_ENCRYPT(c->c, c->m, c->m, c->sz); } +/* --- Authenticated encryption --- */ + +typedef struct aeadsetup_ctx { + const gcaead *aec; + octet *k; size_t ksz; + octet *n; size_t nsz; + size_t tsz; +} aeadsetup_ctx; + +static void *aeadsetup_init(opts *o) +{ + aeadsetup_ctx *c = CREATE(aeadsetup_ctx); + if (!o->name) + die(1, "must specify encryption scheme name"); + if ((c->aec = gaead_byname(o->name)) == 0) + die(1, "aead scheme `%s' not known", o->name); + c->ksz = keysz(o->fbits/8, c->aec->keysz); + c->nsz = keysz_pad(o->gbits/8, c->aec->noncesz); + c->tsz = keysz(0, c->aec->tagsz); + if (o->fbits%8 || (o->fbits && c->ksz != o->fbits/8)) + die(1, "bad key size %u for %s", o->fbits, o->name); + if (o->gbits%8 || (o->gbits && c->nsz != o->gbits/8)) + die(1, "bad nonce size %u for %s", o->gbits, o->name); + c->k = xmalloc(c->ksz); rand_get(RAND_GLOBAL, c->k, c->ksz); + c->n = xmalloc(c->nsz); rand_get(RAND_GLOBAL, c->n, c->nsz); + return (c); +} + +static void aeadsetup_run(void *cc) +{ + aeadsetup_ctx *c = cc; + gaead_key *k = GAEAD_KEY(c->aec, c->k, c->ksz); + gaead_enc *e = GAEAD_ENC(k, c->n, c->nsz, 0, 0, c->tsz); + GAEAD_DESTROY(e); GAEAD_DESTROY(k); +} + +typedef struct aeadenc_ctx { + gaead_enc *enc; + octet *n; size_t nsz; + octet *p, *q; size_t sz; size_t nn; + size_t tsz; +} aeadenc_ctx; + +static void *aeadenc_init(opts *o) +{ + aeadenc_ctx *c = CREATE(aeadenc_ctx); + const gcaead *aec; + gaead_key *key; + octet *k; size_t ksz; + + if (!o->name) + die(1, "must specify encryption scheme name"); + if ((aec = gaead_byname(o->name)) == 0) + die(1, "aead scheme `%s' not known", o->name); + c->sz = o->gbits ? o->gbits : 65536; + c->nn = o->n ? o->n : 16; + ksz = keysz(o->fbits/8, aec->keysz); + c->nsz = keysz(0, aec->noncesz); + c->tsz = keysz(0, aec->tagsz); + if (o->fbits%8 || (o->fbits && ksz != o->fbits/8)) + die(1, "bad key size %u for %s", o->fbits, o->name); + + k = xmalloc(ksz); rand_get(RAND_GLOBAL, k, ksz); + c->n = xmalloc(c->nsz); rand_get(RAND_GLOBAL, c->n, c->nsz); + c->p = xmalloc(c->sz); c->q = xmalloc(c->sz + aec->bufsz); + + key = GAEAD_KEY(aec, k, ksz); + c->enc = GAEAD_ENC(key, c->n, c->nsz, 0, 0, c->tsz); + GAEAD_DESTROY(key); xfree(k); + + o->opwhat = "byte"; o->sc = c->nn*c->sz; + return (c); +} + +static void aeadaad_run(void *cc) +{ + aeadenc_ctx *c = cc; + gaead_aad *a; + size_t i; + + GAEAD_REINIT(c->enc, c->n, c->nsz, c->nn*c->sz, 0, c->tsz); + a = GAEAD_AAD(c->enc); + for (i = 0; i < c->nn; i++) GAEAD_HASH(a, c->p, c->sz); + GAEAD_DESTROY(a); +} + +static void aeadenc_run(void *cc) +{ + aeadenc_ctx *c = cc; + buf b; + size_t i; + + GAEAD_REINIT(c->enc, c->n, c->nsz, 0, c->nn*c->sz, c->tsz); + for (i = 0; i < c->nn; i++) { + buf_init(&b, c->q, c->sz + c->enc->ops->c->bufsz); + GAEAD_ENCRYPT(c->enc, c->p, c->sz, &b); + } +} + /* --- Hashing --- */ typedef struct hash_ctx { @@ -416,6 +677,7 @@ static void *hash_init(opts *o) die(1, "hash function `%s' not known", o->name); c->sz = o->gbits ? o->gbits : 65536; c->n = o->n ? o->n : 16; + o->opwhat = "byte"; o->sc = c->n*c->sz; c->m = xmalloc(c->sz); return (c); } @@ -450,6 +712,7 @@ static void *poly1305_jobinit(opts *o) rand_get(RAND_GLOBAL, c->s, sizeof(c->s)); c->sz = o->gbits ? o->gbits : 65536; c->n = o->n ? o->n : 16; + o->opwhat = "byte"; o->sc = c->n*c->sz; c->m = xmalloc(c->sz); return (c); } @@ -485,13 +748,89 @@ static const jobops jobtab[] = { { "rsa-priv", rsapriv_init, rsapriv_run }, { "rsa-priv-blind", rsaprivblind_init, rsapriv_run }, { "rsa-pub", rsapub_init, rsapub_run }, + { "x25519", x25519_jobinit, x25519_jobrun }, + { "x448", x448_jobinit, x448_jobrun }, + { "ed25519-sign", ed25519_signinit, ed25519_signrun }, + { "ed25519-vrf", ed25519_vrfinit, ed25519_vrfrun }, + { "ed448-sign", ed448_signinit, ed448_signrun }, + { "ed448-vrf", ed448_vrfinit, ed448_vrfrun }, { "ksched", ksched_init, ksched_run }, { "enc", enc_init, enc_run }, + { "aead-setup", aeadsetup_init, aeadsetup_run }, + { "aead-aad", aeadenc_init, aeadaad_run }, + { "aead-enc", aeadenc_init, aeadenc_run }, { "hash", hash_init, hash_run }, { "poly1305", poly1305_jobinit, poly1305_jobrun }, { 0, 0, 0 } }; +/*----- Cycle counting ----------------------------------------------------*/ + +typedef kludge64 cycles; +static int cyclecount_active_p = 0; + +#if defined(__GNUC__) && (CPUFAM_X86 || CPUFAM_AMD64) + +static void init_cyclecount(void) { cyclecount_active_p = 1; } + +static cycles cyclecount(void) +{ + uint32 lo, hi; + kludge64 cy; + + __asm__("rdtsc" : "=a"(lo), "=d"(hi)); + SET64(cy, hi, lo); + return cy; +} + +#elif defined(HAVE_LINUX_PERF_EVENT_H) && defined(HAVE_UINT64) + +static int perf_fd = -1; + +static void init_cyclecount(void) +{ + struct perf_event_attr attr = { 0 }; + + attr.type = PERF_TYPE_HARDWARE; + attr.size = sizeof(attr); + attr.config = PERF_COUNT_HW_CPU_CYCLES; + attr.disabled = 0; + attr.exclude_kernel = 1; + attr.exclude_hv = 1; + + if ((perf_fd = syscall(SYS_perf_event_open, &attr, 0, -1, -1, 0)) < 0) + moan("failed to open perf event: %s", strerror(errno)); + else + cyclecount_active_p = 1; +} + +static cycles cyclecount(void) +{ + kludge64 cy; + ssize_t n; + + if (!cyclecount_active_p) + goto fail; + else if ((n = read(perf_fd, &cy.i, sizeof(cy.i))) != sizeof(cy.i)) { + if (n < 0) moan("error reading perf event: %s", strerror(errno)); + else moan("unexpected short read from perf event"); + cyclecount_active_p = 0; close(perf_fd); perf_fd = -1; + goto fail; + } +end: + return (cy); +fail: + SET64(cy, 0, 0); + goto end; +} + +#else + +static void init_cyclecount(void) { cyclecount_active_p = 0; } +static cycles cyclecount(void) { kludge64 cy; SET64(cy, 0, 0); return (cy); } + +#endif + /*----- Main code ---------------------------------------------------------*/ void version(FILE *fp) @@ -520,12 +859,15 @@ Options:\n\ -l, --list [ITEM...] List all the various names of things.\n\ \n\ -C, --name=NAME Select curve/DH-group/enc/hash name.\n\ --b, --field-bits Field size for g-prime and rsa.\n\ +-b, --field-bits Field size for g-prime and rsa;\n\ + key bits for ksched, enc, aead-setup, aead-enc.\n\ -q, --no-check Don't check field/group for validity.\n\ --B, --group-bits Group size for g-prime; key size for ksched;\n\ - data size for enc and hash.\n\ --n, --factors=COUNT Number of factors for {exp,mul}-sim.\n\ +-B, --group-bits Group size for g-prime; nonce bits for aead-setup;\n\ + data size for enc, aead-aad, aead-enc, and hash.\n\ +-n, --factors=COUNT Number of factors for {exp,mul}-sim;\n\ + inner iters for enc, aead-aad, aead-enc, hash.\n\ -i, --intervals=COUNT Number of intervals to run for. [0; forever]\n\ +-k, --batch=COUNT Number of operations to batch between timer checks.\n\ -t, --time=TIME Length of an interval in seconds. [1]\n\ "); } @@ -541,6 +883,8 @@ Options:\n\ ptab[i].name, ptab[i].name) \ LI("Encryption algorithms", cipher, \ gciphertab[i], gciphertab[i]->name) \ + LI("Authenticated encryption schemes", aead, \ + gaeadtab[i], gaeadtab[i]->name) \ LI("Hash functions", hash, \ ghashtab[i], ghashtab[i]->name) @@ -557,6 +901,14 @@ static unsigned uarg(const char *what, const char *p) return (u); } +static mp *mparg(const char *what, const char *p) +{ + char *q; + mp *x = mp_readstring(MP_NEW, p, &q, 0); + if (!x || *q) die(1, "bad %s `%s'", what, p); + return (x); +} + static double farg(const char *what, const char *p) { char *q; @@ -574,15 +926,16 @@ int main(int argc, char *argv[]) opts o = { 0 }; const jobops *j; struct timeval tv_next, tv_now; - double t, ttot; - unsigned n; + double t, ttot, cy, cytot; + unsigned n, k; unsigned long ii; - clock_t c_start, c_stop; + clock_t c0, c1; + kludge64 cy0, cy1, cydiff; double itot; void *p; ego(argv[0]); - o.t = 1; + o.t = 1; o.k = 1; o.sc = 1; o.opwhat = "op"; for (;;) { static const struct option opts[] = { { "help", 0, 0, 'h' }, @@ -594,12 +947,14 @@ int main(int argc, char *argv[]) { "group-bits", OPTF_ARGREQ, 0, 'B' }, { "factors", OPTF_ARGREQ, 0, 'n' }, { "intervals", OPTF_ARGREQ, 0, 'i' }, + { "batch", OPTF_ARGREQ, 0, 'k' }, + { "public-exponent", OPTF_ARGREQ, 0, 'e' }, { "time", OPTF_ARGREQ, 0, 't' }, { "no-check", 0, 0, 'q' }, { 0, 0, 0, 0 } }; - i = mdwopt(argc, argv, "hvulC:b:B:n:i:t:q", opts, 0, 0, 0); + i = mdwopt(argc, argv, "hvulC:b:B:n:i:k:e:t:q", opts, 0, 0, 0); if (i < 0) break; switch (i) { case 'h': help(stdout); exit(0); @@ -610,8 +965,14 @@ int main(int argc, char *argv[]) case 'b': o.fbits = uarg("field bits", optarg); break; case 'B': o.gbits = uarg("subgroup bits", optarg); break; case 'n': o.n = uarg("factor count", optarg); break; + case 'e': + mp_drop(o.e); o.e = mparg("public exponent", optarg); + if (MP_CMP(o.e, <, MP_THREE) || MP_EVENP(o.e)) + die(1, "invalid public exponent"); + break; case 'i': o.i = uarg("interval count", optarg); break; case 't': o.t = farg("interval length", optarg); break; + case 'k': o.k = uarg("batch size", optarg); break; case 'q': o.f |= OF_NOCHECK; break; default: usage(stderr); exit(1); } @@ -619,28 +980,34 @@ int main(int argc, char *argv[]) if (optind + 1 != argc) { usage(stderr); exit(1); } for (j = jobtab; j->name; j++) - if (strcmp(j->name, argv[optind]) == 0) break; + if (STRCMP(j->name, ==, argv[optind])) break; if (!j->name) die(1, "unknown job type `%s'", argv[optind]); p = j->init(&o); n = 0; - ttot = itot = 0; + ttot = itot = 0; cytot = 0; init_cyclecount(); gettimeofday(&tv_now, 0); do { tv_addl(&tv_next, &tv_now, o.t, fmod(o.t * MILLION, MILLION)); ii = 0; - c_start = clock(); + c0 = clock(); cy0 = cyclecount(); do { - j->run(p); - ii++; + for (k = 0; k < o.k; k++) { j->run(p); } + ii += k; gettimeofday(&tv_now, 0); } while (TV_CMP(&tv_now, <, &tv_next)); - c_stop = clock(); - t = (double)(c_stop - c_start)/CLOCKS_PER_SEC; - itot += ii; - ttot += t; - printf("%5u: did = %5lu; /sec = %5f; avg /sec = %5f\n", + cy1 = cyclecount(); c1 = clock(); + t = (double)(c1 - c0)/CLOCKS_PER_SEC; + itot += ii; ttot += t; + printf("%5u: did = %5lu; /sec = %5f; avg /sec = %5f", n, ii, ii/t, itot/ttot); + if (cyclecount_active_p) { + SUB64(cydiff, cy1, cy0); cy = LO64(cydiff) + ldexp(HI64(cydiff), 32); + cytot += cy; + printf(" (cy/%s = %3f; avg cy/%s = %3f)", + o.opwhat, cy/ii/o.sc, o.opwhat, cytot/itot/o.sc); + } + putchar('\n'); fflush(stdout); n++; } while (!o.i || n < o.i);