X-Git-Url: https://git.distorted.org.uk/~mdw/secnet/blobdiff_plain/b0c1f00ce101fa475c51e26f3824ccd8864f649c..a4c6c9bad5c2965cf970071de0cb2f3179c22b50:/ec-field-test.c diff --git a/ec-field-test.c b/ec-field-test.c new file mode 100644 index 0000000..5c29704 --- /dev/null +++ b/ec-field-test.c @@ -0,0 +1,267 @@ +/* + * 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 + +#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 \ + uint8_t fe[FIELDOP(FESZ)]; +#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 parse_fe(union regval *v, char *p) +{ + size_t n = strlen(p); + size_t sz = sizeof(v->fe); + + if (!*p) + memset(v->fe, 0xff, sizeof(v->fe)); + else { + if (sz > n/2) sz = n/2; + parse_hex(v->fe, sz, p); memset(v->fe + sz, 0, sizeof(v->fe) - sz); + } +} + +static void dump_fe(FILE *fp, const union regval *v) + { dump_hex(fp, v->fe, sizeof(v->fe)); } + +static int eq_fe(const union regval *v0, const union regval *v1) + { return (memcmp(v0->fe, v1->fe, sizeof(v0->fe)) == 0); } + +static const struct regty regty_fe = { + trivial_regty_init, + 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) \ + { \ + FIELD x, y, z; \ + \ + FIELDOP(load)(&x, in[RX].v.fe); \ + FIELDOP(load)(&y, in[RY].v.fe); \ + FIELDOP(op)(&z, &x, &y); \ + FIELDOP(store)(out[RZ].v.fe, &z); \ + } + +#define UNOP(op) \ + static void test_##op(struct reg *out, \ + const struct reg *in, void *ctx) \ + { \ + FIELD x, z; \ + \ + FIELDOP(load)(&x, in[RX].v.fe); \ + FIELDOP(op)(&z, &x); \ + FIELDOP(store)(out[RZ].v.fe, &z); \ + } + +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) +{ + FIELD x, z; + + FIELDOP(load)(&x, in[RX].v.fe); + FIELDOP(condneg)(&z, &x, in[RM].v.u); + FIELDOP(store)(out[RZ].v.fe, &z); +} + +static void test_mulconst(struct reg *out, const struct reg *in, void *ctx) +{ + FIELD x, z; + + FIELDOP(load)(&x, in[RX].v.fe); + FIELDOP(mulconst)(&z, &x, in[RA].v.i); + FIELDOP(store)(out[RZ].v.fe, &z); +} + +static void test_condswap(struct reg *out, const struct reg *in, void *ctx) +{ + FIELD x, y; + + FIELDOP(load)(&x, in[RX].v.fe); + FIELDOP(load)(&y, in[RY].v.fe); + FIELDOP(condswap)(&x, &y, in[RM].v.u); + FIELDOP(store)(out[RXX].v.fe, &x); + FIELDOP(store)(out[RYY].v.fe, &y); +} + +static void test_pick2(struct reg *out, const struct reg *in, void *ctx) +{ + FIELD x, y, z; + + FIELDOP(load)(&x, in[RX].v.fe); + FIELDOP(load)(&y, in[RY].v.fe); + FIELDOP(pick2)(&z, &x, &y, in[RM].v.u); + FIELDOP(store)(out[RZ].v.fe, &z); +} + +static void test_pickn(struct reg *out, const struct reg *in, void *ctx) +{ + FIELD v[32], z; + unsigned i; + + for (i = 0; in[RV0 + i].f®F_LIVE; i++) + FIELDOP(load)(&v[i], in[RV0 + i].v.fe); + FIELDOP(pickn)(&z, v, i, in[RI].v.u); + FIELDOP(store)(out[RZ].v.fe, &z); +} + +static void test_quosqrt(struct reg *out, const struct reg *in, void *ctx) +{ + FIELD x, y, z; + + FIELDOP(load)(&x, in[RX].v.fe); + FIELDOP(load)(&y, in[RY].v.fe); + if (FIELDOP(quosqrt)(&z, &x, &y)) + memset(out[RZ0].v.fe, 0xff, sizeof(out[RZ].v.fe)); + else + FIELDOP(store)(out[RZ].v.fe, &z); +} + +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. + */ + 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 u, v, w, x, y, z; + + FIELDOP(load)(&u, in[RU].v.fe); + FIELDOP(load)(&v, in[RV].v.fe); + FIELDOP(load)(&w, in[RW].v.fe); + FIELDOP(load)(&x, in[RX].v.fe); + FIELDOP(load)(&y, in[RY].v.fe); + + FIELDOP(sub)(&z, &u, &v); + FIELDOP(mulconst)(&z, &z, in[RA].v.i); + FIELDOP(add)(&z, &z, &w); + FIELDOP(sub)(&x, &x, &y); + FIELDOP(mul)(&z, &z, &x); + FIELDOP(store)(out[RZ].v.fe, &z); +} + +#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); }