#include <sys/time.h>
#include <unistd.h>
+#ifdef HAVE_LINUX_PERF_EVENT_H
+# include <sys/syscall.h>
+# include <linux/perf_event.h>
+#endif
+
#include <mLib/alloc.h>
+#include <mLib/bits.h>
#include <mLib/dstr.h>
+#include <mLib/macros.h>
#include <mLib/mdwopt.h>
#include <mLib/quis.h>
#include <mLib/report.h>
#include "ed448.h"
#include "cc.h"
+#include "gaead.h"
#include "gcipher.h"
#include "ghash.h"
#include "gmac.h"
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 */
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);
}
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 {
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);
}
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);
}
{ "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)
\n\
-C, --name=NAME Select curve/DH-group/enc/hash name.\n\
-b, --field-bits Field size for g-prime and rsa;\n\
- key bits for ksched and enc.\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; data size for enc and hash.\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 iterations for enc and hash.\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\
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)
opts o = { 0 };
const jobops *j;
struct timeval tv_next, tv_now;
- double t, ttot;
+ double t, ttot, cy, cytot;
unsigned n, k;
unsigned long ii;
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' },
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;
- c0 = clock();
+ c0 = clock(); cy0 = cyclecount();
do {
for (k = 0; k < o.k; k++) { j->run(p); }
ii += k;
gettimeofday(&tv_now, 0);
} while (TV_CMP(&tv_now, <, &tv_next));
- c1 = clock();
- 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);