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 \ | |
f4bf00ab | 48 | struct { FIELD x; int ok; } fe; |
a4c6c9ba MW |
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 | ||
f4bf00ab MW |
59 | static void init_fe(union regval *v) { v->fe.ok = 1; } |
60 | ||
a4c6c9ba MW |
61 | static void parse_fe(union regval *v, char *p) |
62 | { | |
f4bf00ab | 63 | octet buf[FIELDOP(FESZ)]; |
a4c6c9ba | 64 | size_t n = strlen(p); |
f4bf00ab | 65 | size_t sz = sizeof(buf); |
a4c6c9ba MW |
66 | |
67 | if (!*p) | |
f4bf00ab | 68 | v->fe.ok = 0; |
a4c6c9ba MW |
69 | else { |
70 | if (sz > n/2) sz = n/2; | |
f4bf00ab MW |
71 | parse_hex(buf, sz, p); memset(buf + sz, 0, sizeof(buf) - sz); |
72 | FIELDOP(load)(&v->fe.x, buf); | |
a4c6c9ba MW |
73 | } |
74 | } | |
75 | ||
76 | static void dump_fe(FILE *fp, const union regval *v) | |
f4bf00ab MW |
77 | { |
78 | octet buf[FIELDOP(FESZ)]; | |
79 | ||
80 | if (!v->fe.ok) | |
81 | fprintf(fp, "nil\n"); | |
82 | else { | |
83 | FIELDOP(store)(buf, &v->fe.x); | |
84 | dump_hex(fp, buf, sizeof(buf)); | |
85 | } | |
86 | } | |
a4c6c9ba MW |
87 | |
88 | static int eq_fe(const union regval *v0, const union regval *v1) | |
f4bf00ab MW |
89 | { |
90 | octet buf0[FIELDOP(FESZ)], buf1[FIELDOP(FESZ)]; | |
91 | ||
92 | if (!v0->fe.ok) | |
93 | return (!v1->fe.ok); | |
94 | else if (!v1->fe.ok) | |
95 | return (0); | |
96 | else { | |
97 | FIELDOP(store)(buf0, &v0->fe.x); | |
98 | FIELDOP(store)(buf1, &v1->fe.x); | |
99 | return (memcmp(buf0, buf1, sizeof(buf0)) == 0); | |
100 | } | |
101 | } | |
a4c6c9ba MW |
102 | |
103 | static const struct regty regty_fe = { | |
f4bf00ab | 104 | init_fe, |
a4c6c9ba MW |
105 | parse_fe, |
106 | dump_fe, | |
107 | eq_fe, | |
108 | trivial_regty_release | |
109 | }; | |
110 | ||
111 | #define BINOP(op) \ | |
112 | static void test_##op(struct reg *out, \ | |
113 | const struct reg *in, void *ctx) \ | |
f4bf00ab | 114 | { FIELDOP(op)(&out[RZ].v.fe.x, &in[RX].v.fe.x, &in[RY].v.fe.x); } |
a4c6c9ba MW |
115 | |
116 | #define UNOP(op) \ | |
117 | static void test_##op(struct reg *out, \ | |
118 | const struct reg *in, void *ctx) \ | |
f4bf00ab | 119 | { FIELDOP(op)(&out[RZ].v.fe.x, &in[RX].v.fe.x); } |
a4c6c9ba MW |
120 | |
121 | BINOP(add) | |
122 | BINOP(sub) | |
123 | BINOP(mul) | |
124 | UNOP(neg) | |
125 | UNOP(sqr) | |
126 | UNOP(inv) | |
127 | ||
128 | static void test_condneg(struct reg *out, const struct reg *in, void *ctx) | |
f4bf00ab | 129 | { FIELDOP(condneg)(&out[RZ].v.fe.x, &in[RX].v.fe.x, in[RM].v.u); } |
a4c6c9ba MW |
130 | |
131 | static void test_mulconst(struct reg *out, const struct reg *in, void *ctx) | |
f4bf00ab | 132 | { FIELDOP(mulconst)(&out[RZ].v.fe.x, &in[RX].v.fe.x, in[RA].v.i); } |
a4c6c9ba MW |
133 | |
134 | static void test_condswap(struct reg *out, const struct reg *in, void *ctx) | |
135 | { | |
f4bf00ab MW |
136 | FIELD *x = &out[RXX].v.fe.x, *y = &out[RYY].v.fe.x; |
137 | *x = in[RX].v.fe.x; *y = in[RY].v.fe.x; | |
138 | FIELDOP(condswap)(x, y, in[RM].v.u); | |
a4c6c9ba MW |
139 | } |
140 | ||
141 | static void test_pick2(struct reg *out, const struct reg *in, void *ctx) | |
142 | { | |
f4bf00ab MW |
143 | FIELDOP(pick2)(&out[RZ].v.fe.x, |
144 | &in[RX].v.fe.x, &in[RY].v.fe.x, in[RM].v.u); | |
a4c6c9ba MW |
145 | } |
146 | ||
147 | static void test_pickn(struct reg *out, const struct reg *in, void *ctx) | |
148 | { | |
f4bf00ab MW |
149 | FIELD v[32]; |
150 | unsigned n; | |
a4c6c9ba | 151 | |
f4bf00ab MW |
152 | for (n = 0; in[RV0 + n].f®F_LIVE; n++) v[n] = in[RV0 + n].v.fe.x; |
153 | FIELDOP(pickn)(&out[RZ].v.fe.x, v, n, in[RI].v.u); | |
a4c6c9ba MW |
154 | } |
155 | ||
156 | static void test_quosqrt(struct reg *out, const struct reg *in, void *ctx) | |
157 | { | |
f4bf00ab MW |
158 | if (FIELDOP(quosqrt)(&out[RZ0].v.fe.x, &in[RX].v.fe.x, &in[RY].v.fe.x)) |
159 | out[RZ0].v.fe.ok = 0; | |
a4c6c9ba MW |
160 | } |
161 | ||
162 | static void run_quosqrt(struct test_state *state, const struct test *test) | |
163 | { | |
164 | test->fn(state->out, state->in, 0); | |
165 | ||
166 | /* ..._quosqrt returns an arbitrary square root. The test vector | |
167 | * contains both. We win if we match either. | |
f4bf00ab MW |
168 | * |
169 | * So: we always copy the expected Z1 into the computed-Z1 slot. If we | |
170 | * got Z0 wrong, then the test will still fail. If we got Z0 right, then | |
171 | * we'll pass. If our computed Z0 matches the expected Z1, then /also/ | |
172 | * pretend we computed Z0 as expected, and then we'll pass. | |
a4c6c9ba MW |
173 | */ |
174 | if (eq_fe(&state->in[RZ1].v, &state->out[RZ].v)) | |
175 | state->out[RZ0].v = state->in[RZ0].v; | |
176 | state->out[RZ1].v = state->in[RZ1].v; | |
177 | check_test_output(state, test); | |
178 | } | |
179 | ||
180 | static void test_sub_mulc_add_sub_mul(struct reg *out, | |
181 | const struct reg *in, void *ctx) | |
182 | { | |
f4bf00ab MW |
183 | FIELD t, u; |
184 | ||
185 | FIELDOP(sub)(&t, &in[RU].v.fe.x, &in[RV].v.fe.x); | |
186 | FIELDOP(mulconst)(&t, &t, in[RA].v.i); | |
187 | FIELDOP(add)(&t, &t, &in[RW].v.fe.x); | |
188 | FIELDOP(sub)(&u, &in[RX].v.fe.x, &in[RY].v.fe.x); | |
189 | FIELDOP(mul)(&out[RZ].v.fe.x, &t, &u); | |
a4c6c9ba MW |
190 | } |
191 | ||
192 | #define REG_U { "u", RU, ®ty_fe, 0 } | |
193 | #define REG_V { "v", RV, ®ty_fe, 0 } | |
194 | #define REG_W { "w", RW, ®ty_fe, 0 } | |
195 | #define REG_X { "x", RX, ®ty_fe, 0 } | |
196 | #define REG_Y { "y", RY, ®ty_fe, 0 } | |
197 | #define REG_A { "a", RA, ®ty_int, 0 } | |
198 | #define REG_M { "m", RM, ®ty_uint, 0 } | |
199 | #define REG_I { "i", RI, ®ty_uint, 0 } | |
200 | #define REG_XX { "xx", RXX, ®ty_fe, 0 } | |
201 | #define REG_YY { "yy", RYY, ®ty_fe, 0 } | |
202 | #define REG_Z { "z", RZ, ®ty_fe, 0 } | |
203 | #define REG_Z0 { "z0", RZ0, ®ty_fe, 0 } | |
204 | #define REG_Z1 { "z1", RZ1, ®ty_fe, 0 } | |
205 | #define REG_BIGY { "Y", RY, ®ty_fe, 0 } | |
206 | #define REG_BIGZ { "Z", RZ, ®ty_fe, 0 } | |
207 | #define REG_N { "n", RN, ®ty_uint, 0 } | |
208 | #define REG_Vi(i) { "v[" # i "]", RV0 + i, ®ty_fe, REGF_OPT } | |
209 | #define REG_VV \ | |
210 | REG_Vi( 0), REG_Vi( 1), REG_Vi( 2), REG_Vi( 3), \ | |
211 | REG_Vi( 4), REG_Vi( 5), REG_Vi( 6), REG_Vi( 7), \ | |
212 | REG_Vi( 8), REG_Vi( 9), REG_Vi(10), REG_Vi(11), \ | |
213 | REG_Vi(12), REG_Vi(13), REG_Vi(14), REG_Vi(15), \ | |
214 | REG_Vi(16), REG_Vi(17), REG_Vi(18), REG_Vi(19), \ | |
215 | REG_Vi(20), REG_Vi(21), REG_Vi(22), REG_Vi(23), \ | |
216 | REG_Vi(24), REG_Vi(25), REG_Vi(26), REG_Vi(27), \ | |
217 | REG_Vi(28), REG_Vi(29), REG_Vi(30), REG_Vi(31) | |
218 | static const struct regdef | |
219 | unop_regs[] = { REG_X, REG_Z, REGLIST_END }, | |
220 | binop_regs[] = { REG_X, REG_Y, REG_Z, REGLIST_END }, | |
221 | condneg_regs[] = { REG_X, REG_M, REG_Z, REGLIST_END }, | |
222 | mulconst_regs[] = { REG_X, REG_A, REG_Z, REGLIST_END }, | |
223 | pick2_regs[] = { REG_X, REG_Y, REG_M, REG_Z, REGLIST_END }, | |
224 | pickn_regs[] = { REG_VV, REG_I, REG_Z, REGLIST_END }, | |
225 | condswap_regs[] = { REG_X, REG_Y, REG_M, REG_XX, REG_YY, REGLIST_END }, | |
226 | quosqrt_regs[] = { REG_X, REG_Y, REG_Z0, REG_Z1, REGLIST_END }, | |
227 | sub_mulc_add_sub_mul_regs[] = | |
228 | { REG_U, REG_V, REG_A, REG_W, REG_X, REG_Y, REG_Z, REGLIST_END }; | |
229 | ||
230 | static const struct test tests[] = { | |
231 | { "add", run_test, binop_regs, test_add }, | |
232 | { "sub", run_test, binop_regs, test_sub }, | |
233 | { "neg", run_test, unop_regs, test_neg }, | |
234 | { "condneg", run_test, condneg_regs, test_condneg }, | |
235 | { "condswap", run_test, condswap_regs, test_condswap }, | |
236 | { "mulconst", run_test, mulconst_regs, test_mulconst }, | |
237 | { "mul", run_test, binop_regs, test_mul }, | |
238 | { "sqr", run_test, unop_regs, test_sqr }, | |
239 | { "inv", run_test, unop_regs, test_inv }, | |
240 | { "pick2", run_test, pick2_regs, test_pick2 }, | |
241 | { "pickn", run_test, pickn_regs, test_pickn }, | |
242 | { "quosqrt", run_quosqrt, quosqrt_regs, test_quosqrt }, | |
243 | { "sub-mulc-add-sub-mul", run_test, | |
244 | sub_mulc_add_sub_mul_regs, test_sub_mulc_add_sub_mul }, | |
245 | { 0 } | |
246 | }; | |
247 | ||
248 | int main(void) | |
249 | { return run_test_suite(NROUT, NREG, sizeof(struct reg), tests, stdin); } |