msgcode-test
msgcode-test.confirm
+f25519-test
+f25519-test.confirm
+f448-test
+f448-test.confirm
+ed25519-test
+ed25519-test.confirm
+ed448-test
+ed448-test.confirm
+keccak1600-test
+keccak1600-test.confirm
+sha3-test
+sha3-test.confirm
+x25519-test
+x25519-test.confirm
+x448-test
+x448-test.confirm
autom4te.cache
hackypar.o
# version.o is handled specially below and in the link rule for secnet.
+CRYPTO_TESTS = keccak1600 sha3 f25519 x25519 ed25519 fgoldi x448 ed448
+
TEST_OBJECTS:=eax-aes-test.o eax-serpent-test.o eax-serpentbe-test.o \
- eax-test.o aes.o
+ eax-test.o aes.o \
+ $(addsuffix -test.o,$(CRYPTO_TESTS))
ifeq (version.o,$(MAKECMDGOALS))
OBJECTS:=version.o
check: eax-aes-test.confirm eax-serpent-test.confirm \
eax-serpentbe-test.confirm check-ipaddrset \
- msgcode-test.confirm
+ msgcode-test.confirm \
+ $(foreach c,$(CRYPTO_TESTS),$c-test.confirm)
version.c: Makefile
echo "#include \"secnet.h\"" >$@.new
./msgcode-test
touch $@
+$(foreach c,$(CRYPTO_TESTS),$c-test): %-test: %-test.o crypto-test.o
+ $(CC) $(LDFLAGS) $(ALL_CFLAGS) -o $@ $^
+
+$(foreach c,$(CRYPTO_TESTS),$c-test.confirm): \
+ %-test.confirm: %-test %-tests.in
+ ./$*-test <$(srcdir)/$*-tests.in
+ touch $@
+
+keccak1600-test: keccak1600.o
+sha3-test: sha3.o keccak1600.o
+f25519-test: f25519.o
+x25519-test: x25519.o f25519.o
+ed25519-test: sha512.o f25519.o scaf.o ed25519.o
+fgoldi-test: fgoldi.o
+x448-test: x448.o fgoldi.o
+ed448-test: keccak1600.o sha3.o fgoldi.o scaf.o ed448.o
+
+f25519-test.o: ec-field-test.c
+ $(CC) $(CPPFLAGS) $(ALL_CFLAGS) -c -DFIELD=f25519 $< -o $@
+fgoldi-test.o: ec-field-test.c
+ $(CC) $(CPPFLAGS) $(ALL_CFLAGS) -c -DFIELD=fgoldi $< -o $@
+x25519-test.o: xdh-test.c
+ $(CC) $(CPPFLAGS) $(ALL_CFLAGS) -c -DXDH=x25519 -DFIELD=f25519 $< -o $@
+x448-test.o: xdh-test.c
+ $(CC) $(CPPFLAGS) $(ALL_CFLAGS) -c -DXDH=x448 -DFIELD=fgoldi $< -o $@
+
check-ipaddrset: ipaddrset-test.py ipaddrset.py ipaddrset-test.expected
$(srcdir)/ipaddrset-test.py >ipaddrset-test.new
diff -u $(srcdir)/ipaddrset-test.expected ipaddrset-test.new
$(RM) -f *.o *.yy.[ch] *.tab.[ch] $(TARGETS) core version.c
$(RM) -f *.d *.pyc *~ eax-*-test.confirm eax-*-test
$(RM) -f msgcode-test.confirm msgcode-test
+ $(RM) -f $(addsuffix -test, $(CRYPTO_TESTS))
+ $(RM) -f $(addsuffix -test.confirm, $(CRYPTO_TESTS))
realclean: clean
$(RM) -f *~ Makefile config.h *.d \
--- /dev/null
+/*
+ * crypto-test.c: common test vector processing
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2017, 2019 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "secnet.h"
+#include "util.h"
+
+#include "crypto-test.h"
+
+/*----- Utilities ---------------------------------------------------------*/
+
+static void *xmalloc(size_t sz)
+{
+ void *p;
+
+ if (!sz) return 0;
+ p = malloc(sz);
+ if (!p) {
+ fprintf(stderr, "out of memory!\n");
+ exit(2);
+ }
+ return p;
+}
+
+static void *xrealloc(void *p, size_t sz)
+{
+ void *q;
+
+ if (!sz) { free(p); return 0; }
+ else if (!p) return xmalloc(sz);
+ q = realloc(p, sz);
+ if (!q) {
+ fprintf(stderr, "out of memory!\n");
+ exit(2);
+ }
+ return q;
+}
+
+static int lno;
+
+void bail(const char *msg, ...)
+{
+ va_list ap;
+ va_start(ap, msg);
+ fprintf(stderr, "unexpected error (line %d): ", lno);
+ vfprintf(stderr, msg, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+ exit(2);
+}
+
+struct linebuf {
+ char *p;
+ size_t sz;
+};
+#define LINEBUF_INIT { 0, 0 };
+
+static int read_line(struct linebuf *b, FILE *fp)
+{
+ size_t n = 0;
+ int ch;
+
+ ch = getc(fp); if (ch == EOF) return EOF;
+ for (;;) {
+ if (n >= b->sz) {
+ b->sz = b->sz ? 2*b->sz : 64;
+ b->p = xrealloc(b->p, b->sz);
+ }
+ if (ch == EOF || ch == '\n') { b->p[n++] = 0; return 0; }
+ b->p[n++] = ch;
+ ch = getc(fp);
+ }
+}
+
+void parse_hex(uint8_t *b, size_t sz, char *p)
+{
+ size_t n = strlen(p);
+ unsigned i;
+ char bb[3];
+
+ if (n%2) bail("bad hex (odd number of nibbles)");
+ else if (n/2 != sz) bail("bad hex (want %zu bytes, found %zu)", sz, n/2);
+ while (sz) {
+ for (i = 0; i < 2; i++) {
+ if (!isxdigit((unsigned char)p[i]))
+ bail("bad hex digit `%c'", p[i]);
+ bb[i] = p[i];
+ }
+ bb[2] = 0;
+ p += 2;
+ *b++ = strtoul(bb, 0, 16); sz--;
+ }
+}
+
+void dump_hex(FILE *fp, const uint8_t *b, size_t sz)
+ { while (sz--) fprintf(fp, "%02x", *b++); fputc('\n', fp); }
+
+void trivial_regty_init(union regval *v) { ; }
+void trivial_regty_release(union regval *v) { ; }
+
+/* Define some global variables we shouldn't need.
+ *
+ * Annoyingly, `secnet.h' declares static pointers and initializes them to
+ * point to some external variables. At `-O0', GCC doesn't optimize these
+ * away, so there's a link-time dependency on these variables. Define them
+ * here, so that `f25519.c' and `f448.c' can find them.
+ *
+ * (Later GCC has `-Og', which optimizes without making debugging a
+ * nightmare, but I'm not running that version here. Note that `serpent.c'
+ * doesn't have this problem because it defines its own word load and store
+ * operations to cope with its endian weirdness, whereas the field arithmetic
+ * uses `unaligned.h' which manages to include `secnet.h'.)
+ */
+uint64_t now_global;
+struct timeval tv_now_global;
+
+/* Bletch. sha512.c wants to drag in the world. */
+void *safe_malloc(size_t size, const char *message) { return xmalloc(size); }
+list_t *new_closure(closure_t *cl) { abort(); }
+void dict_add(dict_t *dict, cstring_t key, list_t *val) { abort(); }
+
+/* Bletch. util.c is a mess of layers. */
+int consttime_memeq(const void *s1in, const void *s2in, size_t n)
+{
+ const uint8_t *s1=s1in, *s2=s2in;
+ register volatile uint8_t accumulator=0;
+
+ while (n-- > 0) {
+ accumulator |= (*s1++ ^ *s2++);
+ }
+ accumulator |= accumulator >> 4; /* constant-time */
+ accumulator |= accumulator >> 2; /* boolean canonicalisation */
+ accumulator |= accumulator >> 1;
+ accumulator &= 1;
+ accumulator ^= 1;
+ return accumulator;
+}
+
+/*----- Built-in types ----------------------------------------------------*/
+
+/* Signed integer. */
+
+static void parse_int(union regval *v, char *p)
+{
+ char *q;
+
+ errno = 0;
+ v->i = strtol(p, &q, 0);
+ if (*q || errno) bail("bad integer `%s'", p);
+}
+
+static void dump_int(FILE *fp, const union regval *v)
+ { fprintf(fp, "%ld\n", v->i); }
+
+static int eq_int(const union regval *v0, const union regval *v1)
+ { return (v0->i == v1->i); }
+
+const struct regty regty_int = {
+ trivial_regty_init,
+ parse_int,
+ dump_int,
+ eq_int,
+ trivial_regty_release
+};
+
+/* Unsigned integer. */
+
+static void parse_uint(union regval *v, char *p)
+{
+ char *q;
+
+ errno = 0;
+ v->u = strtoul(p, &q, 0);
+ if (*q || errno) bail("bad integer `%s'", p);
+}
+
+static void dump_uint(FILE *fp, const union regval *v)
+ { fprintf(fp, "%lu\n", v->u); }
+
+static int eq_uint(const union regval *v0, const union regval *v1)
+ { return (v0->u == v1->u); }
+
+const struct regty regty_uint = {
+ trivial_regty_init,
+ parse_uint,
+ dump_uint,
+ eq_uint,
+ trivial_regty_release
+};
+
+/* Byte string, as hex. */
+
+void allocate_bytes(union regval *v, size_t sz)
+ { v->bytes.p = xmalloc(sz); v->bytes.sz = sz; }
+
+static void init_bytes(union regval *v) { v->bytes.p = 0; v->bytes.sz = 0; }
+
+static void parse_bytes(union regval *v, char *p)
+{
+ size_t n = strlen(p);
+
+ allocate_bytes(v, n/2);
+ parse_hex(v->bytes.p, v->bytes.sz, p);
+}
+
+static void dump_bytes(FILE *fp, const union regval *v)
+ { dump_hex(fp, v->bytes.p, v->bytes.sz); }
+
+static int eq_bytes(const union regval *v0, const union regval *v1)
+{
+ return v0->bytes.sz == v1->bytes.sz &&
+ !memcmp(v0->bytes.p, v1->bytes.p, v0->bytes.sz);
+}
+
+static void release_bytes(union regval *v) { free(v->bytes.p); }
+
+const struct regty regty_bytes = {
+ init_bytes,
+ parse_bytes,
+ dump_bytes,
+ eq_bytes,
+ release_bytes
+};
+
+/* Text strings. Not really intended as an output type. */
+
+void allocate_string(union regval *v, size_t sz)
+ { v->str.p = xmalloc(sz + 1); v->str.sz = sz; }
+
+static void init_string(union regval *v) { v->str.p = 0; v->str.sz = 0; }
+
+static void parse_string(union regval *v, char *p)
+{
+ size_t n = strlen(p);
+
+ allocate_string(v, n);
+ memcpy(v->str.p, p, n + 1);
+}
+
+static void dump_string(FILE *fp, const union regval *v)
+{
+ if (v->str.p) fprintf(fp, "`%s'\n", v->str.p);
+ else fputs("nil\n", fp);
+}
+
+static int eq_string(const union regval *v0, const union regval *v1)
+{
+ size_t n0 = v0->str.sz, n1 = v1->str.sz, n = n0 < n1 ? n0 : n1;
+ return !strncmp(v0->str.p, v1->str.p, n);
+}
+
+static void release_string(union regval *v) { free(v->str.p); }
+
+const struct regty regty_string = {
+ init_string,
+ parse_string,
+ dump_string,
+ eq_string,
+ release_string
+};
+
+/*----- Core test machinery -----------------------------------------------*/
+
+/* Say that a register is `reset' by releasing and then re-initializing it.
+ * While there is a current test, all of that test's registers are
+ * initialized. The input registers are reset at the end of `check', ready
+ * for the next test to load new values. The output registers are reset at
+ * the end of `check_test_output', so that a test runner can run a test
+ * multiple times against the same test input, but with different context
+ * data.
+ */
+
+#define REG(rvec, i) \
+ ((struct reg *)((unsigned char *)state->rvec + (i)*state->regsz))
+
+void check_test_output(struct test_state *state, const struct test *test)
+{
+ const struct regdef *def;
+ struct reg *reg, *in, *out;
+ int ok = 1;
+ int match;
+
+ for (def = test->regs; def->name; def++) {
+ if (def->i >= state->nrout) continue;
+ in = REG(in, def->i); out = REG(out, def->i);
+ if (!def->ty->eq(&in->v, &out->v)) ok = 0;
+ }
+ if (ok)
+ state->win++;
+ else {
+ printf("failed test `%s'\n", test->name);
+ for (def = test->regs; def->name; def++) {
+ in = REG(in, def->i);
+ if (!(in->f®F_LIVE)) continue;
+ if (def->i >= state->nrout) {
+ printf("\t input `%s' = ", def->name);
+ def->ty->dump(stdout, &in->v);
+ } else {
+ out = REG(out, def->i);
+ match = def->ty->eq(&in->v, &out->v);
+ printf("\t%s `%s' = ",
+ match ? " output" : "expected", def->name);
+ def->ty->dump(stdout, &in->v);
+ if (!match) {
+ printf("\tcomputed `%s' = ", def->name);
+ def->ty->dump(stdout, &out->v);
+ }
+ }
+ }
+ state->lose++;
+ }
+
+ for (def = test->regs; def->name; def++) {
+ if (def->i >= state->nrout) continue;
+ reg = REG(out, def->i);
+ def->ty->release(®->v); def->ty->init(®->v);
+ }
+}
+
+void run_test(struct test_state *state, const struct test *test)
+{
+ test->fn(state->out, state->in, 0);
+ check_test_output(state, test);
+}
+
+static void check(struct test_state *state, const struct test *test)
+{
+ const struct regdef *def, *miss = 0;
+ struct reg *reg;
+ int any = 0;
+
+ if (!test) return;
+ for (def = test->regs; def->name; def++) {
+ reg = REG(in, def->i);
+ if (reg->f®F_LIVE) any = 1;
+ else if (!miss && !(def->f®F_OPT)) miss = def;
+ }
+ if (!any) return;
+ if (miss)
+ bail("register `%s' not set in test `%s'", def->name, test->name);
+
+ test->run(state, test);
+
+ for (def = test->regs; def->name; def++) {
+ reg = REG(in, def->i);
+ reg->f = 0; def->ty->release(®->v); def->ty->init(®->v);
+ }
+}
+
+int run_test_suite(unsigned nrout, unsigned nreg, size_t regsz,
+ const struct test *tests, FILE *fp)
+{
+ struct linebuf buf = LINEBUF_INIT;
+ struct test_state state[1];
+ const struct test *test;
+ const struct regdef *def;
+ struct reg *reg;
+ char *p;
+ const char *q;
+ int total;
+ size_t n;
+
+ for (test = tests; test->name; test++)
+ for (def = test->regs; def->name; def++)
+ assert(def->i < nreg);
+
+ state->in = xmalloc(nreg*regsz);
+ state->out = xmalloc(nrout*regsz);
+ state->nrout = nrout;
+ state->nreg = nreg;
+ state->regsz = regsz;
+ state->win = state->lose = 0;
+
+ test = 0;
+ lno = 0;
+ while (!read_line(&buf, fp)) {
+ lno++;
+ p = buf.p; n = strlen(buf.p);
+
+ while (isspace((unsigned char)*p)) p++;
+ if (*p == '#') continue;
+ if (!*p) { check(state, test); continue; }
+
+ q = p;
+ while (*p && !isspace((unsigned char)*p)) p++;
+ if (*p) *p++ = 0;
+
+ if (!strcmp(q, "test")) {
+ if (!*p) bail("missing argument");
+ check(state, test);
+ if (test) {
+ for (def = test->regs; def->name; def++) {
+ def->ty->release(®(in, def->i)->v);
+ if (def->i < state->nrout)
+ def->ty->release(®(out, def->i)->v);
+ }
+ }
+ for (test = tests; test->name; test++)
+ if (!strcmp(p, test->name)) goto found_test;
+ bail("unknown test `%s'", p);
+ found_test:
+ for (def = test->regs; def->name; def++) {
+ reg = REG(in, def->i);
+ reg->f = 0; def->ty->init(®->v);
+ if (def->i < state->nrout) {
+ reg = REG(out, def->i);
+ reg->f = 0; def->ty->init(®->v);
+ }
+ }
+ continue;
+ }
+
+ if (!test) bail("no current test");
+ for (def = test->regs; def->name; def++)
+ if (!strcmp(q, def->name)) goto found_reg;
+ bail("unknown register `%s' in test `%s'", q, test->name);
+ found_reg:
+ reg = REG(in, def->i);
+ if (reg->f®F_LIVE) bail("register `%s' already set", def->name);
+ def->ty->parse(®->v, p); reg->f |= REGF_LIVE;
+ }
+ check(state, test);
+
+ total = state->win + state->lose;
+ if (!state->lose)
+ printf("PASSED all %d test%s\n", state->win, total == 1 ? "" : "s");
+ else
+ printf("FAILED %d of %d test%s\n", state->lose, total,
+ total == 1 ? "" : "s");
+ return state->lose ? 1 : 0;
+}
--- /dev/null
+/*
+ * crypto-test.h: common test vector processing
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2017, 2019 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#ifndef crypto_test_h
+#define crypto_test_h
+
+/* Basic model.
+ *
+ * There is a collection of `registers', each of which can store a value.
+ * Some registers are designated as `input': their values are set while
+ * reading the test vector. Other registers are designated as `output': the
+ * test function is expected to calculate their values, which are then
+ * compared against final values supplied by the test vector. Any
+ * discrepancies are reported.
+ *
+ * While a test suite is running, there is a single vector of registers, and
+ * registers are identified by index, starting from zero. The number of
+ * registers, `nreg', and a threshold `nrout', are defined by the test suite:
+ * registers with index less than `nrout' are for output; other registers up
+ * to, but not including, `nreg' are for input. Finally, the test suite
+ * defines the size of a register. The common test machinery treats
+ * registers as entirely opaque, acting on them only through their defined
+ * types.
+ *
+ * Each kind of test defines a register mapping, which assigns types and
+ * (textual) names to some subset of the registers. A register can be marked
+ * optional; by default, the test vector parser will report an error if a
+ * defined register is not assigned a value.
+ *
+ * The register type is responsible for handling the register on behalf of
+ * the common code. (Test functions can have built-in knowledge of which
+ * registers have which types, and can manipulate registers directly, of
+ * course.)
+ *
+ * Finally, each test defines a test runner, which is responsible for
+ * invoking the test function and checking that the output registers are
+ * correct. There is a generic test runner, but some tests might benefit
+ * from special arrangements.
+ */
+
+union regval {
+ long i; /* signed integer */
+ unsigned long u; /* unsigned integer */
+ struct { unsigned char *p; size_t sz; } bytes; /* buffer of bytes */
+ struct { char *p; size_t sz; } str; /* text string */
+#ifdef REG_MEMBERS
+ REG_MEMBERS /* your members here */
+#endif
+};
+
+struct reg {
+ unsigned f; /* flags */
+#define REGF_LIVE 1u /* input register has a value */
+ union regval v; /* register value */
+};
+
+struct regty {
+ void (*init)(union regval *v); /* set up raw memory */
+ void (*parse)(union regval *v, char *p); /* parse text input as value */
+ void (*dump)(FILE *fp, const union regval *v); /* dump value as text */
+ int (*eq)(const union regval *v0, const union regval *v1); /* equal? */
+ void (*release)(union regval *v); /* release any resources */
+};
+
+struct regdef {
+ const char *name; /* register name (for input files) */
+ unsigned i; /* register index */
+ const struct regty *ty; /* register type descriptor */
+ unsigned f; /* flags */
+#define REGF_OPT 1u /* (input) register is optional */
+};
+#define REGLIST_END { 0 }
+
+struct test_state {
+ struct reg *in, *out; /* vectors of registers */
+ unsigned nrout; /* number of output registers */
+ unsigned nreg; /* total number of registers */
+ size_t regsz; /* size of an individual register */
+ int win, lose; /* number of tests passed/failed */
+};
+
+struct test {
+ const char *name; /* name of the test */
+ void (*run)(struct test_state *state, const struct test *test);
+ /* test runner (`run_test') */
+ const struct regdef *regs; /* register definitions */
+ void (*fn)(struct reg *out, const struct reg *in, void *ctx);
+ /* test function */
+};
+
+/* Utility functions. */
+extern NORETURN(bail(const char *msg, ...))
+ FORMAT(printf, 1, 2);
+extern void parse_hex(uint8_t *b, size_t sz, char *p);
+extern void dump_hex(FILE *fp, const uint8_t *b, size_t sz);
+extern void trivial_regty_init(union regval *v);
+extern void trivial_regty_release(union regval *v);
+extern void allocate_bytes(union regval *v, size_t sz);
+extern void allocate_string(union regval *v, size_t sz);
+
+/* Built-in register types. */
+extern const struct regty
+ regty_int,
+ regty_uint,
+ regty_bytes,
+ regty_string;
+
+/* Running tests. */
+extern void check_test_output(struct test_state *state,
+ const struct test *test);
+extern void run_test(struct test_state *state, const struct test *test);
+extern int run_test_suite(unsigned nrout, unsigned nreg, size_t regsz,
+ const struct test *tests, FILE *fp);
+
+#endif
--- /dev/null
+/*
+ * ec-field-test.c: test harness for elliptic-curve field arithmetic
+ *
+ * (The implementations originally came with different test arrangements,
+ * with complicated external dependencies. This file replicates the original
+ * tests, but without the dependencies.)
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2017 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#include <stdio.h>
+
+#include "secnet.h"
+
+#include "f25519.h"
+#include "fgoldi.h"
+
+#define f25519_FESZ 32u
+#define fgoldi_FESZ 56u
+
+#define GLUE(x, y) GLUE_(x, y)
+#define GLUE_(x, y) x##y
+#define FIELDOP(op) GLUE(FIELD, _##op)
+
+#define REG_MEMBERS \
+ struct { FIELD x; int ok; } fe;
+#include "crypto-test.h"
+
+enum {
+ RZ, RZ0 = RZ, RZ1, RXX = RZ0, RYY = RZ1, NROUT,
+ RM = NROUT, RI = RM, RN = RM,
+ RU, RV, RW, RX, RY, RA,
+ RV0 = RU, RV31 = RV0 + 31,
+ NREG
+};
+
+static void init_fe(union regval *v) { v->fe.ok = 1; }
+
+static void parse_fe(union regval *v, char *p)
+{
+ octet buf[FIELDOP(FESZ)];
+ size_t n = strlen(p);
+ size_t sz = sizeof(buf);
+
+ if (!*p)
+ v->fe.ok = 0;
+ else {
+ if (sz > n/2) sz = n/2;
+ parse_hex(buf, sz, p); memset(buf + sz, 0, sizeof(buf) - sz);
+ FIELDOP(load)(&v->fe.x, buf);
+ }
+}
+
+static void dump_fe(FILE *fp, const union regval *v)
+{
+ octet buf[FIELDOP(FESZ)];
+
+ if (!v->fe.ok)
+ fprintf(fp, "nil\n");
+ else {
+ FIELDOP(store)(buf, &v->fe.x);
+ dump_hex(fp, buf, sizeof(buf));
+ }
+}
+
+static int eq_fe(const union regval *v0, const union regval *v1)
+{
+ octet buf0[FIELDOP(FESZ)], buf1[FIELDOP(FESZ)];
+
+ if (!v0->fe.ok)
+ return (!v1->fe.ok);
+ else if (!v1->fe.ok)
+ return (0);
+ else {
+ FIELDOP(store)(buf0, &v0->fe.x);
+ FIELDOP(store)(buf1, &v1->fe.x);
+ return (memcmp(buf0, buf1, sizeof(buf0)) == 0);
+ }
+}
+
+static const struct regty regty_fe = {
+ init_fe,
+ parse_fe,
+ dump_fe,
+ eq_fe,
+ trivial_regty_release
+};
+
+#define BINOP(op) \
+ static void test_##op(struct reg *out, \
+ const struct reg *in, void *ctx) \
+ { FIELDOP(op)(&out[RZ].v.fe.x, &in[RX].v.fe.x, &in[RY].v.fe.x); }
+
+#define UNOP(op) \
+ static void test_##op(struct reg *out, \
+ const struct reg *in, void *ctx) \
+ { FIELDOP(op)(&out[RZ].v.fe.x, &in[RX].v.fe.x); }
+
+BINOP(add)
+BINOP(sub)
+BINOP(mul)
+UNOP(neg)
+UNOP(sqr)
+UNOP(inv)
+
+static void test_condneg(struct reg *out, const struct reg *in, void *ctx)
+ { FIELDOP(condneg)(&out[RZ].v.fe.x, &in[RX].v.fe.x, in[RM].v.u); }
+
+static void test_mulconst(struct reg *out, const struct reg *in, void *ctx)
+ { FIELDOP(mulconst)(&out[RZ].v.fe.x, &in[RX].v.fe.x, in[RA].v.i); }
+
+static void test_condswap(struct reg *out, const struct reg *in, void *ctx)
+{
+ FIELD *x = &out[RXX].v.fe.x, *y = &out[RYY].v.fe.x;
+ *x = in[RX].v.fe.x; *y = in[RY].v.fe.x;
+ FIELDOP(condswap)(x, y, in[RM].v.u);
+}
+
+static void test_pick2(struct reg *out, const struct reg *in, void *ctx)
+{
+ FIELDOP(pick2)(&out[RZ].v.fe.x,
+ &in[RX].v.fe.x, &in[RY].v.fe.x, in[RM].v.u);
+}
+
+static void test_pickn(struct reg *out, const struct reg *in, void *ctx)
+{
+ FIELD v[32];
+ unsigned n;
+
+ for (n = 0; in[RV0 + n].f®F_LIVE; n++) v[n] = in[RV0 + n].v.fe.x;
+ FIELDOP(pickn)(&out[RZ].v.fe.x, v, n, in[RI].v.u);
+}
+
+static void test_quosqrt(struct reg *out, const struct reg *in, void *ctx)
+{
+ if (FIELDOP(quosqrt)(&out[RZ0].v.fe.x, &in[RX].v.fe.x, &in[RY].v.fe.x))
+ out[RZ0].v.fe.ok = 0;
+}
+
+static void run_quosqrt(struct test_state *state, const struct test *test)
+{
+ test->fn(state->out, state->in, 0);
+
+ /* ..._quosqrt returns an arbitrary square root. The test vector
+ * contains both. We win if we match either.
+ *
+ * So: we always copy the expected Z1 into the computed-Z1 slot. If we
+ * got Z0 wrong, then the test will still fail. If we got Z0 right, then
+ * we'll pass. If our computed Z0 matches the expected Z1, then /also/
+ * pretend we computed Z0 as expected, and then we'll pass.
+ */
+ if (eq_fe(&state->in[RZ1].v, &state->out[RZ].v))
+ state->out[RZ0].v = state->in[RZ0].v;
+ state->out[RZ1].v = state->in[RZ1].v;
+ check_test_output(state, test);
+}
+
+static void test_sub_mulc_add_sub_mul(struct reg *out,
+ const struct reg *in, void *ctx)
+{
+ FIELD t, u;
+
+ FIELDOP(sub)(&t, &in[RU].v.fe.x, &in[RV].v.fe.x);
+ FIELDOP(mulconst)(&t, &t, in[RA].v.i);
+ FIELDOP(add)(&t, &t, &in[RW].v.fe.x);
+ FIELDOP(sub)(&u, &in[RX].v.fe.x, &in[RY].v.fe.x);
+ FIELDOP(mul)(&out[RZ].v.fe.x, &t, &u);
+}
+
+#define REG_U { "u", RU, ®ty_fe, 0 }
+#define REG_V { "v", RV, ®ty_fe, 0 }
+#define REG_W { "w", RW, ®ty_fe, 0 }
+#define REG_X { "x", RX, ®ty_fe, 0 }
+#define REG_Y { "y", RY, ®ty_fe, 0 }
+#define REG_A { "a", RA, ®ty_int, 0 }
+#define REG_M { "m", RM, ®ty_uint, 0 }
+#define REG_I { "i", RI, ®ty_uint, 0 }
+#define REG_XX { "xx", RXX, ®ty_fe, 0 }
+#define REG_YY { "yy", RYY, ®ty_fe, 0 }
+#define REG_Z { "z", RZ, ®ty_fe, 0 }
+#define REG_Z0 { "z0", RZ0, ®ty_fe, 0 }
+#define REG_Z1 { "z1", RZ1, ®ty_fe, 0 }
+#define REG_BIGY { "Y", RY, ®ty_fe, 0 }
+#define REG_BIGZ { "Z", RZ, ®ty_fe, 0 }
+#define REG_N { "n", RN, ®ty_uint, 0 }
+#define REG_Vi(i) { "v[" # i "]", RV0 + i, ®ty_fe, REGF_OPT }
+#define REG_VV \
+ REG_Vi( 0), REG_Vi( 1), REG_Vi( 2), REG_Vi( 3), \
+ REG_Vi( 4), REG_Vi( 5), REG_Vi( 6), REG_Vi( 7), \
+ REG_Vi( 8), REG_Vi( 9), REG_Vi(10), REG_Vi(11), \
+ REG_Vi(12), REG_Vi(13), REG_Vi(14), REG_Vi(15), \
+ REG_Vi(16), REG_Vi(17), REG_Vi(18), REG_Vi(19), \
+ REG_Vi(20), REG_Vi(21), REG_Vi(22), REG_Vi(23), \
+ REG_Vi(24), REG_Vi(25), REG_Vi(26), REG_Vi(27), \
+ REG_Vi(28), REG_Vi(29), REG_Vi(30), REG_Vi(31)
+static const struct regdef
+ unop_regs[] = { REG_X, REG_Z, REGLIST_END },
+ binop_regs[] = { REG_X, REG_Y, REG_Z, REGLIST_END },
+ condneg_regs[] = { REG_X, REG_M, REG_Z, REGLIST_END },
+ mulconst_regs[] = { REG_X, REG_A, REG_Z, REGLIST_END },
+ pick2_regs[] = { REG_X, REG_Y, REG_M, REG_Z, REGLIST_END },
+ pickn_regs[] = { REG_VV, REG_I, REG_Z, REGLIST_END },
+ condswap_regs[] = { REG_X, REG_Y, REG_M, REG_XX, REG_YY, REGLIST_END },
+ quosqrt_regs[] = { REG_X, REG_Y, REG_Z0, REG_Z1, REGLIST_END },
+ sub_mulc_add_sub_mul_regs[] =
+ { REG_U, REG_V, REG_A, REG_W, REG_X, REG_Y, REG_Z, REGLIST_END };
+
+static const struct test tests[] = {
+ { "add", run_test, binop_regs, test_add },
+ { "sub", run_test, binop_regs, test_sub },
+ { "neg", run_test, unop_regs, test_neg },
+ { "condneg", run_test, condneg_regs, test_condneg },
+ { "condswap", run_test, condswap_regs, test_condswap },
+ { "mulconst", run_test, mulconst_regs, test_mulconst },
+ { "mul", run_test, binop_regs, test_mul },
+ { "sqr", run_test, unop_regs, test_sqr },
+ { "inv", run_test, unop_regs, test_inv },
+ { "pick2", run_test, pick2_regs, test_pick2 },
+ { "pickn", run_test, pickn_regs, test_pickn },
+ { "quosqrt", run_quosqrt, quosqrt_regs, test_quosqrt },
+ { "sub-mulc-add-sub-mul", run_test,
+ sub_mulc_add_sub_mul_regs, test_sub_mulc_add_sub_mul },
+ { 0 }
+};
+
+int main(void)
+ { return run_test_suite(NROUT, NREG, sizeof(struct reg), tests, stdin); }
--- /dev/null
+/*
+ * ed25519-test.c: test harness for elliptic curve signatures
+ *
+ * (The implementations originally came with different test arrangements,
+ * with complicated external dependencies. This file replicates the original
+ * tests, but without the dependencies.)
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2019 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#include <stdio.h>
+
+#include "secnet.h"
+
+#include "sha512.h"
+#include "ed25519.h"
+
+#define GLUE(x, y) GLUE_(x, y)
+#define GLUE_(x, y) x##y
+#define XDHOP(op) GLUE(XDH, _##op)
+
+#include "crypto-test.h"
+
+enum {
+ RSIGOUT, RAOUT = RSIGOUT, RRC = RSIGOUT, NROUT,
+ RA = NROUT, RPH, RCTX, RM, RSIGIN, NREG
+};
+
+static void test_pubkey(struct reg *out, const struct reg *in, void *ctx)
+{
+ allocate_bytes(&out[RAOUT].v, ED25519_PUBSZ);
+ ed25519_pubkey(out[RAOUT].v.bytes.p,
+ in[RA].v.bytes.p, in[RA].v.bytes.sz);
+}
+
+static void test_sign(struct reg *out, const struct reg *in, void *ctx)
+{
+ octet K[ED25519_PUBSZ];
+
+ allocate_bytes(&out[RSIGOUT].v, ED25519_SIGSZ);
+ ed25519_pubkey(K, in[RA].v.bytes.p, in[RA].v.bytes.sz);
+ ed25519_sign(out[RSIGOUT].v.bytes.p,
+ in[RA].v.bytes.p, in[RA].v.bytes.sz, K,
+ in[RM].v.bytes.p, in[RM].v.bytes.sz);
+}
+
+static void test_sign_ctx(struct reg *out, const struct reg *in, void *ctx)
+{
+ octet K[ED25519_PUBSZ];
+ const octet *m = in[RM].v.bytes.p; size_t msz = in[RM].v.bytes.sz;
+ octet h[SHA512_DIGEST_SIZE];
+ struct sha512_ctx hctx;
+
+ if (in[RPH].v.i) {
+ sha512_init_ctx(&hctx);
+ sha512_process_bytes(m, msz, &hctx);
+ sha512_finish_ctx(&hctx, h);
+ m = h; msz = sizeof(h);
+ }
+
+ allocate_bytes(&out[RSIGOUT].v, ED25519_SIGSZ);
+ ed25519_pubkey(K, in[RA].v.bytes.p, in[RA].v.bytes.sz);
+ ed25519ctx_sign(out[RSIGOUT].v.bytes.p,
+ in[RA].v.bytes.p, in[RA].v.bytes.sz, K,
+ in[RPH].v.i,
+ in[RCTX].v.bytes.p, in[RCTX].v.bytes.sz,
+ m, msz);
+}
+
+static void test_verify(struct reg *out, const struct reg *in, void *ctx)
+{
+ out[RRC].v.i = ed25519_verify(in[RA].v.bytes.p,
+ in[RM].v.bytes.p, in[RM].v.bytes.sz,
+ in[RSIGIN].v.bytes.p);
+}
+
+static void test_verify_ctx(struct reg *out, const struct reg *in, void *ctx)
+{
+ const octet *m = in[RM].v.bytes.p; size_t msz = in[RM].v.bytes.sz;
+ octet h[SHA512_DIGEST_SIZE];
+ struct sha512_ctx hctx;
+
+ if (in[RPH].v.i) {
+ sha512_init_ctx(&hctx);
+ sha512_process_bytes(m, msz, &hctx);
+ sha512_finish_ctx(&hctx, h);
+ m = h; msz = sizeof(h);
+ }
+
+ out[RRC].v.i = ed25519ctx_verify(in[RA].v.bytes.p,
+ in[RPH].v.i,
+ in[RCTX].v.bytes.p, in[RCTX].v.bytes.sz,
+ m, msz, in[RSIGIN].v.bytes.p);
+}
+
+#define REG_A { "a", RA, ®ty_bytes, 0 }
+#define REG_BIGA { "A", RA, ®ty_bytes, 0 }
+#define REG_PH { "ph", RPH, ®ty_int, 0 }
+#define REG_CTX { "ctx", RCTX, ®ty_bytes, 0 }
+#define REG_M { "m", RM, ®ty_bytes, 0 }
+#define REG_SIGIN { "sig", RSIGIN, ®ty_bytes, 0 }
+
+#define REG_SIGOUT { "sig", RSIGOUT, ®ty_bytes, 0 }
+#define REG_AOUT { "A", RAOUT, ®ty_bytes, 0 }
+#define REG_RC { "rc", RRC, ®ty_int, 0 }
+static const struct regdef
+ pubkey_regs[] = { REG_A, REG_AOUT, REGLIST_END },
+ sign_regs[] = { REG_A, REG_M, REG_SIGOUT, REGLIST_END },
+ sign_ctx_regs[] = { REG_A, REG_PH, REG_CTX,
+ REG_M, REG_SIGOUT, REGLIST_END },
+ verify_regs[] = { REG_BIGA, REG_M, REG_SIGIN, REG_RC, REGLIST_END },
+ verify_ctx_regs[] = { REG_BIGA, REG_PH, REG_CTX,
+ REG_M, REG_SIGIN, REG_RC, REGLIST_END };
+
+static const struct test tests[] = {
+ { "pubkey", run_test, pubkey_regs, test_pubkey },
+ { "sign", run_test, sign_regs, test_sign },
+ { "sign-ctx", run_test, sign_ctx_regs, test_sign_ctx },
+ { "verify", run_test, verify_regs, test_verify },
+ { "verify-ctx", run_test, verify_ctx_regs, test_verify_ctx },
+ { 0 }
+};
+
+int main(void)
+ { return run_test_suite(NROUT, NREG, sizeof(struct reg), tests, stdin); }
--- /dev/null
+/*
+ * ed448-test.c: test harness for elliptic curve signatures
+ *
+ * (The implementations originally came with different test arrangements,
+ * with complicated external dependencies. This file replicates the original
+ * tests, but without the dependencies.)
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2019 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#include <stdio.h>
+
+#include "secnet.h"
+
+#include "sha3.h"
+#include "ed448.h"
+
+#include "crypto-test.h"
+
+enum {
+ RSIGOUT, RAOUT = RSIGOUT, RRC = RSIGOUT, NROUT,
+ RA = NROUT, RPH, RCTX, RM, RSIGIN, NREG
+};
+
+static void test_pubkey(struct reg *out, const struct reg *in, void *ctx)
+{
+ allocate_bytes(&out[RAOUT].v, ED448_PUBSZ);
+ ed448_pubkey(out[RAOUT].v.bytes.p,
+ in[RA].v.bytes.p, in[RA].v.bytes.sz);
+}
+
+static void test_sign(struct reg *out, const struct reg *in, void *ctx)
+{
+ octet K[ED448_PUBSZ];
+ const octet *m = in[RM].v.bytes.p; size_t msz = in[RM].v.bytes.sz;
+ octet h[64];
+ shake_ctx hctx;
+
+ if (in[RPH].v.i) {
+ shake256_init(&hctx);
+ shake_hash(&hctx, m, msz);
+ shake_done(&hctx, h, sizeof(h));
+ m = h; msz = sizeof(h);
+ }
+
+ allocate_bytes(&out[RSIGOUT].v, ED448_SIGSZ);
+ ed448_pubkey(K, in[RA].v.bytes.p, in[RA].v.bytes.sz);
+ ed448_sign(out[RSIGOUT].v.bytes.p,
+ in[RA].v.bytes.p, in[RA].v.bytes.sz, K,
+ in[RPH].v.i,
+ in[RCTX].v.bytes.p, in[RCTX].v.bytes.sz,
+ m, msz);
+}
+
+static void test_verify(struct reg *out, const struct reg *in, void *ctx)
+{
+ const octet *m = in[RM].v.bytes.p; size_t msz = in[RM].v.bytes.sz;
+ octet h[64];
+ shake_ctx hctx;
+
+ if (in[RPH].v.i) {
+ shake256_init(&hctx);
+ shake_hash(&hctx, m, msz);
+ shake_done(&hctx, h, sizeof(h));
+ m = h; msz = sizeof(h);
+ }
+
+ out[RRC].v.i = ed448_verify(in[RA].v.bytes.p,
+ in[RPH].v.i,
+ in[RCTX].v.bytes.p, in[RCTX].v.bytes.sz,
+ m, msz, in[RSIGIN].v.bytes.p);
+}
+
+#define REG_A { "a", RA, ®ty_bytes, 0 }
+#define REG_BIGA { "A", RA, ®ty_bytes, 0 }
+#define REG_PH { "ph", RPH, ®ty_int, 0 }
+#define REG_CTX { "ctx", RCTX, ®ty_bytes, 0 }
+#define REG_M { "m", RM, ®ty_bytes, 0 }
+#define REG_SIGIN { "sig", RSIGIN, ®ty_bytes, 0 }
+
+#define REG_SIGOUT { "sig", RSIGOUT, ®ty_bytes, 0 }
+#define REG_AOUT { "A", RAOUT, ®ty_bytes, 0 }
+#define REG_RC { "rc", RRC, ®ty_int, 0 }
+static const struct regdef
+ pubkey_regs[] = { REG_A, REG_AOUT, REGLIST_END },
+ sign_regs[] = { REG_A, REG_PH, REG_CTX,
+ REG_M, REG_SIGOUT, REGLIST_END },
+ verify_regs[] = { REG_BIGA, REG_PH, REG_CTX,
+ REG_M, REG_SIGIN, REG_RC, REGLIST_END };
+
+static const struct test tests[] = {
+ { "pubkey", run_test, pubkey_regs, test_pubkey },
+ { "sign", run_test, sign_regs, test_sign },
+ { "verify", run_test, verify_regs, test_verify },
+ { 0 }
+};
+
+int main(void)
+ { return run_test_suite(NROUT, NREG, sizeof(struct reg), tests, stdin); }
--- /dev/null
+/*
+ * This file is part of secnet.
+ * See README for full list of copyright holders.
+ *
+ * secnet is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version d of the License, or
+ * (at your option) any later version.
+ *
+ * secnet is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * version 3 along with secnet; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#ifndef fake_mLib_bits_h
+#define fake_mLib_bits_h
+
+/* The <mLib/bits.h> header defines a large number of types and macros for
+ * various kinds of bithacking. Notably, it has machinery for autodetecting
+ * suitable types holding (at least) various numbers of bits -- a service
+ * which C99 provides through other means.
+ *
+ * This file provides a small portion of the <mLib/bits.h> interface, just
+ * enough to make the pieces of code lifted from Catacomb feel at home.
+ */
+
+#include <stdint.h>
+#include "u64.h"
+#include "unaligned.h"
+
+typedef uint8_t octet;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+
+typedef int32_t int32;
+typedef int64_t int64;
+
+#define LOAD32_L(p) (get_uint32_le(p))
+#define LOAD32_B(p) (get_uint32(p))
+#define STORE32_L(p, x) put_uint32_le((p), (x))
+#define STORE32_B(p, x) put_uint32((p), (x))
+#define ROL32(x, n) ((n) ? ((x) << (n) | (x) >> (32 - (n))) : (x))
+
+#define MASK32 0xffffffffu
+#define U32(x) ((uint32)(x) & MASK32)
+
+typedef u64 kludge64;
+#define X64(hi, lo) u64init(0x##hi, 0x##lo)
+#define HI64(x) u64gethi(x)
+#define LO64(x) u64getlo(x)
+#define LOAD64_L_(x, p) do { \
+ const uint8_t *p_ = (const uint8_t *)(p); \
+ uint32_t lo_ = LOAD32_L(p_ + 0), hi_ = LOAD32_L(p_ + 4); \
+ (x) = u64hilo(hi_, lo_); \
+} while (0)
+#define LOAD64_B_(x, p) do { \
+ const uint8_t *p_ = (const uint8_t *)(p); \
+ uint32_t hi_ = LOAD32_B(p_ + 0), lo_ = LOAD32_B(p_ + 4); \
+ (x) = u64hilo(hi_, lo_); \
+} while (0)
+#define STORE64_L_(p, x) do { \
+ uint8_t *p_ = (uint8_t *)(p); \
+ uint32_t lo_ = LO64(x), hi_ = HI64(x); \
+ STORE32_L(p_ + 0, lo_); STORE32_L(p_ + 4, hi_); \
+} while (0)
+#define STORE64_B_(p, x) do { \
+ uint8_t *p_ = (uint8_t *)(p); \
+ uint32_t lo_ = LO64(x), hi_ = HI64(x); \
+ STORE32_B(p_ + 0, hi_); STORE32_B(p_ + 4, lo_); \
+} while (0)
+#define SET64(z, hi, lo) ((z) = u64hilo((hi), (lo)))
+#define AND64(z, x, y) ((z) = u64and((x), (y)))
+#define OR64(z, x, y) ((z) = u64or((x), (y)))
+#define XOR64(z, x, y) ((z) = u64xor((x), (y)))
+#define CPL64(z, x) ((z) = u64not((x)))
+#define ROL64_(z, x, n) ((n) ? (z) = u64rol((x), (n)) : (x))
+
+#endif /* fake_mLib_bits_h */
--- /dev/null
+/*
+ * keccak1600-test.c: test harness for Keccak primitive
+ *
+ * (The implementations originally came with different test arrangements,
+ * with complicated external dependencies. This file replicates the original
+ * tests, but without the dependencies.)
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2019 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#include <stdio.h>
+
+#include "secnet.h"
+
+#include "keccak1600.h"
+#include "crypto-test.h"
+
+enum {
+ RZ, NROUT,
+ RX = NROUT, RN, NREG
+};
+
+static void test_p(struct reg *out, const struct reg *in, void *ctx)
+{
+ keccak1600_state u;
+ kludge64 t[25];
+ unsigned i;
+
+ allocate_bytes(&out[RZ].v, 200);
+ keccak1600_init(&u);
+ for (i = 0; i < 25; i++) LOAD64_L_(t[i], in[RX].v.bytes.p + 8*i);
+ keccak1600_mix(&u, t, 25);
+ keccak1600_p(&u, &u, in[RN].v.u);
+ keccak1600_extract(&u, t, 25);
+ for (i = 0; i < 25; i++) STORE64_L_(out[RZ].v.bytes.p + 8*i, t[i]);
+}
+
+#define REG_X { "x", RX, ®ty_bytes, 0 }
+#define REG_N { "n", RN, ®ty_uint, 0 }
+#define REG_Z { "z", RZ, ®ty_bytes, 0 }
+static const struct regdef
+ p_regs[] = { REG_X, REG_N, REG_Z, REGLIST_END };
+
+static const struct test tests[] = {
+ { "p", run_test, p_regs, test_p },
+ { 0 }
+};
+
+int main(void)
+ { return run_test_suite(NROUT, NREG, sizeof(struct reg), tests, stdin); }
--- /dev/null
+/*
+ * sha3-test.c: test harness for SHA3 and related functions
+ *
+ * (The implementations originally came with different test arrangements,
+ * with complicated external dependencies. This file replicates the original
+ * tests, but without the dependencies.)
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2019 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#include <stdio.h>
+
+#include "secnet.h"
+
+#include "keccak1600.h"
+#include "sha3.h"
+#include "crypto-test.h"
+
+enum {
+ RH, NROUT,
+ RM = NROUT, RN, RFUNC, RPERSO, NREG
+};
+
+struct test_context {
+ size_t step;
+ size_t outsz;
+};
+
+static void run_sha3_kat(struct test_state *state, const struct test *test)
+{
+ static const unsigned steps[] = { 1, 7, 192, -1 };
+ unsigned i = 0;
+ struct test_context ctx;
+
+ ctx.outsz = state->in[RH].v.bytes.sz;
+ do {
+ ctx.step = steps[i];
+ test->fn(state->out, state->in, &ctx);
+ check_test_output(state, test);
+ } while (steps[i++] != (unsigned)-1);
+}
+
+#define SHA3_VARIANTS(_) _(224) _(256) _(384) _(512)
+
+#define SHA3_TESTFUNCS(w) \
+ \
+static void test_sha3_##w##_kat(struct reg *out, \
+ const struct reg *in, void *vctx) \
+{ \
+ struct test_context *ctx = vctx; \
+ sha3_ctx hctx; \
+ const octet *p = in[RM].v.bytes.p; \
+ size_t sz = in[RM].v.bytes.sz, n; \
+ \
+ allocate_bytes(&out[RH].v, SHA3_##w##_HASHSZ); \
+ sha3_##w##_init(&hctx); \
+ while (sz) { \
+ n = ctx->step; if (n > sz) n = sz; \
+ sha3_hash(&hctx, p, n); p += n; sz -= n; \
+ } \
+ sha3_done(&hctx, out[RH].v.bytes.p); \
+} \
+ \
+static void test_sha3_##w##_mct(struct reg *out, \
+ const struct reg *in, void *vctx) \
+{ \
+ sha3_ctx hctx; \
+ octet *p; \
+ unsigned i, n = in[RN].v.u; \
+ \
+ allocate_bytes(&out[RH].v, SHA3_##w##_HASHSZ); \
+ p = out[RH].v.bytes.p; \
+ memcpy(p, in[RM].v.bytes.p, SHA3_##w##_HASHSZ); \
+ for (i = 0; i < n; i++) { \
+ sha3_##w##_init(&hctx); \
+ sha3_hash(&hctx, p, SHA3_##w##_HASHSZ); \
+ sha3_done(&hctx, p); \
+ } \
+}
+
+SHA3_VARIANTS(SHA3_TESTFUNCS)
+
+#define SHAKE_VARIANTS(_) _(128) _(256)
+
+#define SHAKE_TESTFUNCS(w) \
+ \
+static void test_shake##w##_kat(struct reg *out, \
+ const struct reg *in, void *vctx) \
+{ \
+ struct test_context *ctx = vctx; \
+ shake_ctx hctx; \
+ const octet *p = in[RM].v.bytes.p; octet *q; \
+ size_t sz = in[RM].v.bytes.sz, n; \
+ \
+ allocate_bytes(&out[RH].v, ctx->outsz); \
+ shake##w##_init(&hctx); \
+ while (sz) { \
+ n = ctx->step; if (n > sz) n = sz; \
+ shake_hash(&hctx, p, n); p += n; sz -= n; \
+ } \
+ shake_xof(&hctx); \
+ q = out[RH].v.bytes.p; sz = ctx->outsz; \
+ while (sz) { \
+ n = ctx->step; if (n > sz) n = sz; \
+ shake_get(&hctx, q, n); q += n; sz -= n; \
+ } \
+} \
+ \
+static void test_cshake##w##_kat(struct reg *out, \
+ const struct reg *in, void *vctx) \
+{ \
+ struct test_context *ctx = vctx; \
+ shake_ctx hctx; \
+ const octet *p = in[RM].v.bytes.p; octet *q; \
+ size_t sz = in[RM].v.bytes.sz, n; \
+ \
+ allocate_bytes(&out[RH].v, ctx->outsz); \
+ cshake##w##_init(&hctx, \
+ in[RFUNC].v.str.p, in[RFUNC].v.str.sz, \
+ in[RPERSO].v.str.p, in[RPERSO].v.str.sz); \
+ while (sz) { \
+ n = ctx->step; if (n > sz) n = sz; \
+ shake_hash(&hctx, p, n); p += n; sz -= n; \
+ } \
+ shake_xof(&hctx); \
+ q = out[RH].v.bytes.p; sz = ctx->outsz; \
+ while (sz) { \
+ n = ctx->step; if (n > sz) n = sz; \
+ shake_get(&hctx, q, n); q += n; sz -= n; \
+ } \
+}
+
+SHAKE_VARIANTS(SHAKE_TESTFUNCS)
+
+#define REG_M { "m", RM, ®ty_bytes, 0 }
+#define REG_N { "n", RN, ®ty_uint, 0 }
+#define REG_FUNC { "func", RFUNC, ®ty_string, 0 }
+#define REG_PERSO { "perso", RPERSO, ®ty_string, 0 }
+#define REG_H { "h", RH, ®ty_bytes, 0 }
+static const struct regdef
+ hash_kat_regs[] = { REG_M, REG_H, REGLIST_END },
+ hash_mct_regs[] = { REG_M, REG_N, REG_H, REGLIST_END },
+ cshake_regs[] = { REG_M, REG_FUNC, REG_PERSO, REG_H, REGLIST_END };
+
+#define SHA3_TESTDEFS(w) \
+ { "sha3-" #w "-hex", run_sha3_kat, \
+ hash_kat_regs, test_sha3_##w##_kat }, \
+ { "sha3-" #w "-mct", run_test, \
+ hash_mct_regs, test_sha3_##w##_mct },
+#define SHAKE_TESTDEFS(w) \
+ { "shake" #w, run_sha3_kat, \
+ hash_kat_regs, test_shake##w##_kat }, \
+ { "cshake" #w, run_sha3_kat, \
+ cshake_regs, test_cshake##w##_kat },
+static const struct test tests[] = {
+ SHA3_VARIANTS(SHA3_TESTDEFS)
+ SHAKE_VARIANTS(SHAKE_TESTDEFS)
+ { 0 }
+};
+
+int main(void)
+ { return run_test_suite(NROUT, NREG, sizeof(struct reg), tests, stdin); }
# define u64hilo(hi, lo) ((u64) (((u64) (hi) << 32) + (lo)))
# define u64init(hi, lo) u64hilo (hi, lo)
# define u64lo(x) ((u64) (x))
+# define u64getlo(x) ((x)&0xffffffffu)
+# define u64gethi(x) (((u64) (x) >> 32) & 0xffffffffu)
# define u64lt(x, y) ((x) < (y))
# define u64and(x, y) ((x) & (y))
# define u64or(x, y) ((x) | (y))
# define u64xor(x, y) ((x) ^ (y))
+# define u64not(x) (~(x))
# define u64plus(x, y) ((x) + (y))
# define u64shl(x, n) ((x) << (n))
# define u64shr(x, n) ((x) >> (n))
return r;
}
+/* Return the high and low halves of X. */
+# define u64getlo(x) ((x).lo)
+# define u64gethi(x) ((x).hi)
+
/* Return X < Y. */
static inline int
u64lt (u64 x, u64 y)
return r;
}
+/* Return ~X. */
+static inline u64
+u64not (u64 x)
+{
+ u64 r;
+ r.hi = ~x.hi;
+ r.lo = ~x.lo;
+ return r;
+}
+
/* Return X + Y. */
static inline u64
u64plus (u64 x, u64 y)
#define put_uint32(a,v) do { (a)[0]=(v)>>24; (a)[1]=((v)&0xff0000)>>16; \
(a)[2]=((v)&0xff00)>>8; (a)[3]=(v)&0xff; } while(0)
+#define put_uint32_le(a, v) do { (a)[0]=(v)&0xff; (a)[1]=((v)&0xff00)>>8; \
+(a)[2]=((v)&0xff0000)>>16; (a)[3]=(v)>>24; } while(0)
+
#define put_uint16(a,v) do {(a)[0]=((v)&0xff00)>>8; (a)[1]=(v)&0xff;} while(0)
#define put_uint8(a,v) do {(a)[0]=((v)&0xff);} while(0)
(((uint32_t)(a)[0]<<24) | ((uint32_t)(a)[1]<<16) | \
((uint32_t)(a)[2]<<8) | (uint32_t)(a)[3])
+#define get_uint32_le(a) \
+ (((uint32_t)(a)[0]) | ((uint32_t)(a)[1]<<8) | \
+ ((uint32_t)(a)[2]<<16) | (uint32_t)(a)[3]<<24)
+
#define get_uint16(a) (((uint16_t)(a)[0]<<8)|(uint16_t)(a)[1])
#define get_uint8(a) (((uint8_t)(a)[0]))
--- /dev/null
+/*
+ * xdh-test.c: test harness for elliptic-curve Diffie--Hellman
+ *
+ * (The implementations originally came with different test arrangements,
+ * with complicated external dependencies. This file replicates the original
+ * tests, but without the dependencies.)
+ */
+/*
+ * This file is Free Software. It was originally written for secnet.
+ *
+ * Copyright 2017 Mark Wooding
+ *
+ * You may redistribute secnet as a whole and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3, or (at your option) any
+ * later version.
+ *
+ * You may redistribute this file and/or modify it under the terms of
+ * the GNU General Public License as published by the Free Software
+ * Foundation; either version 2, or (at your option) any later
+ * version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this software; if not, see
+ * https://www.gnu.org/licenses/gpl.html.
+ */
+
+#include <stdio.h>
+
+#include "secnet.h"
+
+#include "x25519.h"
+#include "x448.h"
+
+#define x25519_KEYSZ X25519_KEYSZ
+#define x448_KEYSZ X448_KEYSZ
+
+#define GLUE(x, y) GLUE_(x, y)
+#define GLUE_(x, y) x##y
+#define XDHOP(op) GLUE(XDH, _##op)
+
+#define REG_MEMBERS \
+ uint8_t k[XDHOP(KEYSZ)];
+#include "crypto-test.h"
+
+enum {
+ RZ, NROUT,
+ RN = NROUT, RX, RY, NREG
+};
+
+static void parse_key(union regval *v, char *p)
+ { parse_hex(v->k, sizeof(v->k), p); }
+
+static void dump_key(FILE *fp, const union regval *v)
+ { dump_hex(fp, v->k, sizeof(v->k)); }
+
+static int eq_key(const union regval *v0, const union regval *v1)
+ { return (memcmp(v0->k, v1->k, sizeof(v0->k)) == 0); }
+
+static const struct regty regty_key = {
+ trivial_regty_init,
+ parse_key,
+ dump_key,
+ eq_key,
+ trivial_regty_release
+};
+
+static void test_xdh(struct reg *out, const struct reg *in, void *ctx)
+ { XDH(out[RZ].v.k, in[RX].v.k, in[RY].v.k); }
+
+static void test_xdhmct(struct reg *out, const struct reg *in, void *ctx)
+{
+ uint8_t b0[XDHOP(KEYSZ)], b1[XDHOP(KEYSZ)], *x = b0, *y = b1, *t;
+ unsigned long i, n;
+
+ memcpy(b0, in[RX].v.k, sizeof(b0));
+ memcpy(b1, in[RY].v.k, sizeof(b1));
+ n = in[RN].v.u;
+ for (i = 0; i < n; i++) {
+ XDH(y, x, y);
+ t = y; y = x; x = t;
+ }
+ memcpy(out[RZ].v.k, x, sizeof(b0));
+}
+#define REG_X { "x", RX, ®ty_key, 0 }
+#define REG_Y { "Y", RY, ®ty_key, 0 }
+#define REG_Z { "Z", RZ, ®ty_key, 0 }
+#define REG_N { "n", RN, ®ty_uint, 0 }
+static const struct regdef
+ xdh_regs[] = { REG_X, REG_Y, REG_Z, REGLIST_END },
+ xdhmct_regs[] = { REG_X, REG_Y, REG_N, REG_Z, REGLIST_END };
+
+static const struct test tests[] = {
+ { STRING(XDH), run_test, xdh_regs, test_xdh },
+ { STRING(XDH) "-mct", run_test, xdhmct_regs, test_xdhmct },
+ { 0 }
+};
+
+int main(void)
+ { return run_test_suite(NROUT, NREG, sizeof(struct reg), tests, stdin); }