2 * ec-field-test.c: test harness for elliptic-curve field arithmetic
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.)
9 * This file is Free Software. It was originally written for secnet.
11 * Copyright 2017 Mark Wooding
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
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
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.
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.
40 #define f25519_FESZ 32u
41 #define fgoldi_FESZ 56u
43 #define GLUE(x, y) GLUE_(x, y)
44 #define GLUE_(x, y) x##y
45 #define FIELDOP(op) GLUE(FIELD, _##op)
48 uint8_t fe[FIELDOP(FESZ)];
49 #include "crypto-test.h"
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,
59 static void parse_fe(union regval
*v
, char *p
)
62 size_t sz
= sizeof(v
->fe
);
65 memset(v
->fe
, 0xff, sizeof(v
->fe
));
67 if (sz
> n
/2) sz
= n
/2;
68 parse_hex(v
->fe
, sz
, p
); memset(v
->fe
+ sz
, 0, sizeof(v
->fe
) - sz
);
72 static void dump_fe(FILE *fp
, const union regval
*v
)
73 { dump_hex(fp
, v
->fe
, sizeof(v
->fe
)); }
75 static int eq_fe(const union regval
*v0
, const union regval
*v1
)
76 { return (memcmp(v0
->fe
, v1
->fe
, sizeof(v0
->fe
)) == 0); }
78 static const struct regty regty_fe
= {
87 static void test_##op(struct reg *out, \
88 const struct reg *in, void *ctx) \
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); \
99 static void test_##op(struct reg *out, \
100 const struct reg *in, void *ctx) \
104 FIELDOP(load)(&x, in[RX].v.fe); \
105 FIELDOP(op)(&z, &x); \
106 FIELDOP(store)(out[RZ].v.fe, &z); \
116 static void test_condneg(struct reg
*out
, const struct reg
*in
, void *ctx
)
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
);
125 static void test_mulconst(struct reg
*out
, const struct reg
*in
, void *ctx
)
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
);
134 static void test_condswap(struct reg
*out
, const struct reg
*in
, void *ctx
)
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
);
145 static void test_pick2(struct reg
*out
, const struct reg
*in
, void *ctx
)
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
);
155 static void test_pickn(struct reg
*out
, const struct reg
*in
, void *ctx
)
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
);
166 static void test_quosqrt(struct reg
*out
, const struct reg
*in
, void *ctx
)
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
));
175 FIELDOP(store
)(out
[RZ
].v
.fe
, &z
);
178 static void run_quosqrt(struct test_state
*state
, const struct test
*test
)
180 test
->fn(state
->out
, state
->in
, 0);
182 /* ..._quosqrt returns an arbitrary square root. The test vector
183 * contains both. We win if we match either.
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
);
191 static void test_sub_mulc_add_sub_mul(struct reg
*out
,
192 const struct reg
*in
, void *ctx
)
194 FIELD u
, v
, w
, x
, y
, z
;
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
);
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
);
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 }
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
};
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
},
267 { return run_test_suite(NROUT
, NREG
, sizeof(struct reg
), tests
, stdin
); }