| 1 | /* |
| 2 | * ec-field-test.c: test harness for elliptic-curve field arithmetic |
| 3 | * |
| 4 | * (The implementations originally came with different test arrangements, |
| 5 | * with complicated external dependencies. This file replicates the original |
| 6 | * tests, but without the dependencies.) |
| 7 | */ |
| 8 | /* |
| 9 | * This file is Free Software. It was originally written for secnet. |
| 10 | * |
| 11 | * Copyright 2017 Mark Wooding |
| 12 | * |
| 13 | * You may redistribute secnet as a whole and/or modify it under the |
| 14 | * terms of the GNU General Public License as published by the Free |
| 15 | * Software Foundation; either version 3, or (at your option) any |
| 16 | * later version. |
| 17 | * |
| 18 | * You may redistribute this file and/or modify it under the terms of |
| 19 | * the GNU General Public License as published by the Free Software |
| 20 | * Foundation; either version 2, or (at your option) any later |
| 21 | * version. |
| 22 | * |
| 23 | * This software is distributed in the hope that it will be useful, |
| 24 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 25 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 26 | * GNU General Public License for more details. |
| 27 | * |
| 28 | * You should have received a copy of the GNU General Public License |
| 29 | * along with this software; if not, see |
| 30 | * https://www.gnu.org/licenses/gpl.html. |
| 31 | */ |
| 32 | |
| 33 | #include <stdio.h> |
| 34 | |
| 35 | #include "secnet.h" |
| 36 | |
| 37 | #include "f25519.h" |
| 38 | #include "fgoldi.h" |
| 39 | |
| 40 | #define f25519_FESZ 32u |
| 41 | #define fgoldi_FESZ 56u |
| 42 | |
| 43 | #define GLUE(x, y) GLUE_(x, y) |
| 44 | #define GLUE_(x, y) x##y |
| 45 | #define FIELDOP(op) GLUE(FIELD, _##op) |
| 46 | |
| 47 | #define REG_MEMBERS \ |
| 48 | uint8_t fe[FIELDOP(FESZ)]; |
| 49 | #include "crypto-test.h" |
| 50 | |
| 51 | enum { |
| 52 | RZ, RZ0 = RZ, RZ1, RXX = RZ0, RYY = RZ1, NROUT, |
| 53 | RM = NROUT, RI = RM, RN = RM, |
| 54 | RU, RV, RW, RX, RY, RA, |
| 55 | RV0 = RU, RV31 = RV0 + 31, |
| 56 | NREG |
| 57 | }; |
| 58 | |
| 59 | static void parse_fe(union regval *v, char *p) |
| 60 | { |
| 61 | size_t n = strlen(p); |
| 62 | size_t sz = sizeof(v->fe); |
| 63 | |
| 64 | if (!*p) |
| 65 | memset(v->fe, 0xff, sizeof(v->fe)); |
| 66 | else { |
| 67 | if (sz > n/2) sz = n/2; |
| 68 | parse_hex(v->fe, sz, p); memset(v->fe + sz, 0, sizeof(v->fe) - sz); |
| 69 | } |
| 70 | } |
| 71 | |
| 72 | static void dump_fe(FILE *fp, const union regval *v) |
| 73 | { dump_hex(fp, v->fe, sizeof(v->fe)); } |
| 74 | |
| 75 | static int eq_fe(const union regval *v0, const union regval *v1) |
| 76 | { return (memcmp(v0->fe, v1->fe, sizeof(v0->fe)) == 0); } |
| 77 | |
| 78 | static const struct regty regty_fe = { |
| 79 | trivial_regty_init, |
| 80 | parse_fe, |
| 81 | dump_fe, |
| 82 | eq_fe, |
| 83 | trivial_regty_release |
| 84 | }; |
| 85 | |
| 86 | #define BINOP(op) \ |
| 87 | static void test_##op(struct reg *out, \ |
| 88 | const struct reg *in, void *ctx) \ |
| 89 | { \ |
| 90 | FIELD x, y, z; \ |
| 91 | \ |
| 92 | FIELDOP(load)(&x, in[RX].v.fe); \ |
| 93 | FIELDOP(load)(&y, in[RY].v.fe); \ |
| 94 | FIELDOP(op)(&z, &x, &y); \ |
| 95 | FIELDOP(store)(out[RZ].v.fe, &z); \ |
| 96 | } |
| 97 | |
| 98 | #define UNOP(op) \ |
| 99 | static void test_##op(struct reg *out, \ |
| 100 | const struct reg *in, void *ctx) \ |
| 101 | { \ |
| 102 | FIELD x, z; \ |
| 103 | \ |
| 104 | FIELDOP(load)(&x, in[RX].v.fe); \ |
| 105 | FIELDOP(op)(&z, &x); \ |
| 106 | FIELDOP(store)(out[RZ].v.fe, &z); \ |
| 107 | } |
| 108 | |
| 109 | BINOP(add) |
| 110 | BINOP(sub) |
| 111 | BINOP(mul) |
| 112 | UNOP(neg) |
| 113 | UNOP(sqr) |
| 114 | UNOP(inv) |
| 115 | |
| 116 | static void test_condneg(struct reg *out, const struct reg *in, void *ctx) |
| 117 | { |
| 118 | FIELD x, z; |
| 119 | |
| 120 | FIELDOP(load)(&x, in[RX].v.fe); |
| 121 | FIELDOP(condneg)(&z, &x, in[RM].v.u); |
| 122 | FIELDOP(store)(out[RZ].v.fe, &z); |
| 123 | } |
| 124 | |
| 125 | static void test_mulconst(struct reg *out, const struct reg *in, void *ctx) |
| 126 | { |
| 127 | FIELD x, z; |
| 128 | |
| 129 | FIELDOP(load)(&x, in[RX].v.fe); |
| 130 | FIELDOP(mulconst)(&z, &x, in[RA].v.i); |
| 131 | FIELDOP(store)(out[RZ].v.fe, &z); |
| 132 | } |
| 133 | |
| 134 | static void test_condswap(struct reg *out, const struct reg *in, void *ctx) |
| 135 | { |
| 136 | FIELD x, y; |
| 137 | |
| 138 | FIELDOP(load)(&x, in[RX].v.fe); |
| 139 | FIELDOP(load)(&y, in[RY].v.fe); |
| 140 | FIELDOP(condswap)(&x, &y, in[RM].v.u); |
| 141 | FIELDOP(store)(out[RXX].v.fe, &x); |
| 142 | FIELDOP(store)(out[RYY].v.fe, &y); |
| 143 | } |
| 144 | |
| 145 | static void test_pick2(struct reg *out, const struct reg *in, void *ctx) |
| 146 | { |
| 147 | FIELD x, y, z; |
| 148 | |
| 149 | FIELDOP(load)(&x, in[RX].v.fe); |
| 150 | FIELDOP(load)(&y, in[RY].v.fe); |
| 151 | FIELDOP(pick2)(&z, &x, &y, in[RM].v.u); |
| 152 | FIELDOP(store)(out[RZ].v.fe, &z); |
| 153 | } |
| 154 | |
| 155 | static void test_pickn(struct reg *out, const struct reg *in, void *ctx) |
| 156 | { |
| 157 | FIELD v[32], z; |
| 158 | unsigned i; |
| 159 | |
| 160 | for (i = 0; in[RV0 + i].f®F_LIVE; i++) |
| 161 | FIELDOP(load)(&v[i], in[RV0 + i].v.fe); |
| 162 | FIELDOP(pickn)(&z, v, i, in[RI].v.u); |
| 163 | FIELDOP(store)(out[RZ].v.fe, &z); |
| 164 | } |
| 165 | |
| 166 | static void test_quosqrt(struct reg *out, const struct reg *in, void *ctx) |
| 167 | { |
| 168 | FIELD x, y, z; |
| 169 | |
| 170 | FIELDOP(load)(&x, in[RX].v.fe); |
| 171 | FIELDOP(load)(&y, in[RY].v.fe); |
| 172 | if (FIELDOP(quosqrt)(&z, &x, &y)) |
| 173 | memset(out[RZ0].v.fe, 0xff, sizeof(out[RZ].v.fe)); |
| 174 | else |
| 175 | FIELDOP(store)(out[RZ].v.fe, &z); |
| 176 | } |
| 177 | |
| 178 | static void run_quosqrt(struct test_state *state, const struct test *test) |
| 179 | { |
| 180 | test->fn(state->out, state->in, 0); |
| 181 | |
| 182 | /* ..._quosqrt returns an arbitrary square root. The test vector |
| 183 | * contains both. We win if we match either. |
| 184 | */ |
| 185 | if (eq_fe(&state->in[RZ1].v, &state->out[RZ].v)) |
| 186 | state->out[RZ0].v = state->in[RZ0].v; |
| 187 | state->out[RZ1].v = state->in[RZ1].v; |
| 188 | check_test_output(state, test); |
| 189 | } |
| 190 | |
| 191 | static void test_sub_mulc_add_sub_mul(struct reg *out, |
| 192 | const struct reg *in, void *ctx) |
| 193 | { |
| 194 | FIELD u, v, w, x, y, z; |
| 195 | |
| 196 | FIELDOP(load)(&u, in[RU].v.fe); |
| 197 | FIELDOP(load)(&v, in[RV].v.fe); |
| 198 | FIELDOP(load)(&w, in[RW].v.fe); |
| 199 | FIELDOP(load)(&x, in[RX].v.fe); |
| 200 | FIELDOP(load)(&y, in[RY].v.fe); |
| 201 | |
| 202 | FIELDOP(sub)(&z, &u, &v); |
| 203 | FIELDOP(mulconst)(&z, &z, in[RA].v.i); |
| 204 | FIELDOP(add)(&z, &z, &w); |
| 205 | FIELDOP(sub)(&x, &x, &y); |
| 206 | FIELDOP(mul)(&z, &z, &x); |
| 207 | FIELDOP(store)(out[RZ].v.fe, &z); |
| 208 | } |
| 209 | |
| 210 | #define REG_U { "u", RU, ®ty_fe, 0 } |
| 211 | #define REG_V { "v", RV, ®ty_fe, 0 } |
| 212 | #define REG_W { "w", RW, ®ty_fe, 0 } |
| 213 | #define REG_X { "x", RX, ®ty_fe, 0 } |
| 214 | #define REG_Y { "y", RY, ®ty_fe, 0 } |
| 215 | #define REG_A { "a", RA, ®ty_int, 0 } |
| 216 | #define REG_M { "m", RM, ®ty_uint, 0 } |
| 217 | #define REG_I { "i", RI, ®ty_uint, 0 } |
| 218 | #define REG_XX { "xx", RXX, ®ty_fe, 0 } |
| 219 | #define REG_YY { "yy", RYY, ®ty_fe, 0 } |
| 220 | #define REG_Z { "z", RZ, ®ty_fe, 0 } |
| 221 | #define REG_Z0 { "z0", RZ0, ®ty_fe, 0 } |
| 222 | #define REG_Z1 { "z1", RZ1, ®ty_fe, 0 } |
| 223 | #define REG_BIGY { "Y", RY, ®ty_fe, 0 } |
| 224 | #define REG_BIGZ { "Z", RZ, ®ty_fe, 0 } |
| 225 | #define REG_N { "n", RN, ®ty_uint, 0 } |
| 226 | #define REG_Vi(i) { "v[" # i "]", RV0 + i, ®ty_fe, REGF_OPT } |
| 227 | #define REG_VV \ |
| 228 | REG_Vi( 0), REG_Vi( 1), REG_Vi( 2), REG_Vi( 3), \ |
| 229 | REG_Vi( 4), REG_Vi( 5), REG_Vi( 6), REG_Vi( 7), \ |
| 230 | REG_Vi( 8), REG_Vi( 9), REG_Vi(10), REG_Vi(11), \ |
| 231 | REG_Vi(12), REG_Vi(13), REG_Vi(14), REG_Vi(15), \ |
| 232 | REG_Vi(16), REG_Vi(17), REG_Vi(18), REG_Vi(19), \ |
| 233 | REG_Vi(20), REG_Vi(21), REG_Vi(22), REG_Vi(23), \ |
| 234 | REG_Vi(24), REG_Vi(25), REG_Vi(26), REG_Vi(27), \ |
| 235 | REG_Vi(28), REG_Vi(29), REG_Vi(30), REG_Vi(31) |
| 236 | static const struct regdef |
| 237 | unop_regs[] = { REG_X, REG_Z, REGLIST_END }, |
| 238 | binop_regs[] = { REG_X, REG_Y, REG_Z, REGLIST_END }, |
| 239 | condneg_regs[] = { REG_X, REG_M, REG_Z, REGLIST_END }, |
| 240 | mulconst_regs[] = { REG_X, REG_A, REG_Z, REGLIST_END }, |
| 241 | pick2_regs[] = { REG_X, REG_Y, REG_M, REG_Z, REGLIST_END }, |
| 242 | pickn_regs[] = { REG_VV, REG_I, REG_Z, REGLIST_END }, |
| 243 | condswap_regs[] = { REG_X, REG_Y, REG_M, REG_XX, REG_YY, REGLIST_END }, |
| 244 | quosqrt_regs[] = { REG_X, REG_Y, REG_Z0, REG_Z1, REGLIST_END }, |
| 245 | sub_mulc_add_sub_mul_regs[] = |
| 246 | { REG_U, REG_V, REG_A, REG_W, REG_X, REG_Y, REG_Z, REGLIST_END }; |
| 247 | |
| 248 | static const struct test tests[] = { |
| 249 | { "add", run_test, binop_regs, test_add }, |
| 250 | { "sub", run_test, binop_regs, test_sub }, |
| 251 | { "neg", run_test, unop_regs, test_neg }, |
| 252 | { "condneg", run_test, condneg_regs, test_condneg }, |
| 253 | { "condswap", run_test, condswap_regs, test_condswap }, |
| 254 | { "mulconst", run_test, mulconst_regs, test_mulconst }, |
| 255 | { "mul", run_test, binop_regs, test_mul }, |
| 256 | { "sqr", run_test, unop_regs, test_sqr }, |
| 257 | { "inv", run_test, unop_regs, test_inv }, |
| 258 | { "pick2", run_test, pick2_regs, test_pick2 }, |
| 259 | { "pickn", run_test, pickn_regs, test_pickn }, |
| 260 | { "quosqrt", run_quosqrt, quosqrt_regs, test_quosqrt }, |
| 261 | { "sub-mulc-add-sub-mul", run_test, |
| 262 | sub_mulc_add_sub_mul_regs, test_sub_mulc_add_sub_mul }, |
| 263 | { 0 } |
| 264 | }; |
| 265 | |
| 266 | int main(void) |
| 267 | { return run_test_suite(NROUT, NREG, sizeof(struct reg), tests, stdin); } |