Commit | Line | Data |
---|---|---|
a4c6c9ba MW |
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); } |