@@@ crypto-test
[secnet] / crypto-test.h
diff --git a/crypto-test.h b/crypto-test.h
new file mode 100644 (file)
index 0000000..e7ca777
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * crypto-test.h: common test vector processing
+ */
+/*
+ * 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.
+ */
+
+#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 { void *p; size_t sz; } bytes; /* buffer of bytes */
+#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);
+
+/* Built-in register types. */
+extern const struct regty
+    regty_int,
+    regty_uint,
+    regty_bytes;
+
+/* 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