X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/b0c1f00ce101fa475c51e26f3824ccd8864f649c..a4c6c9bad5c2965cf970071de0cb2f3179c22b50:/crypto-test.h diff --git a/crypto-test.h b/crypto-test.h new file mode 100644 index 0000000..e7ca777 --- /dev/null +++ b/crypto-test.h @@ -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