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 struct { FIELD x; int ok; } fe;
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 init_fe(union regval
*v
) { v
->fe
.ok
= 1; }
61 static void parse_fe(union regval
*v
, char *p
)
63 octet buf
[FIELDOP(FESZ
)];
65 size_t sz
= sizeof(buf
);
70 if (sz
> n
/2) sz
= n
/2;
71 parse_hex(buf
, sz
, p
); memset(buf
+ sz
, 0, sizeof(buf
) - sz
);
72 FIELDOP(load
)(&v
->fe
.x
, buf
);
76 static void dump_fe(FILE *fp
, const union regval
*v
)
78 octet buf
[FIELDOP(FESZ
)];
83 FIELDOP(store
)(buf
, &v
->fe
.x
);
84 dump_hex(fp
, buf
, sizeof(buf
));
88 static int eq_fe(const union regval
*v0
, const union regval
*v1
)
90 octet buf0
[FIELDOP(FESZ
)], buf1
[FIELDOP(FESZ
)];
97 FIELDOP(store
)(buf0
, &v0
->fe
.x
);
98 FIELDOP(store
)(buf1
, &v1
->fe
.x
);
99 return (memcmp(buf0
, buf1
, sizeof(buf0
)) == 0);
103 static const struct regty regty_fe
= {
108 trivial_regty_release
112 static void test_##op(struct reg *out, \
113 const struct reg *in, void *ctx) \
114 { FIELDOP(op)(&out[RZ].v.fe.x, &in[RX].v.fe.x, &in[RY].v.fe.x); }
117 static void test_##op(struct reg *out, \
118 const struct reg *in, void *ctx) \
119 { FIELDOP(op)(&out[RZ].v.fe.x, &in[RX].v.fe.x); }
128 static void test_condneg(struct reg
*out
, const struct reg
*in
, void *ctx
)
129 { FIELDOP(condneg
)(&out
[RZ
].v
.fe
.x
, &in
[RX
].v
.fe
.x
, in
[RM
].v
.u
); }
131 static void test_mulconst(struct reg
*out
, const struct reg
*in
, void *ctx
)
132 { FIELDOP(mulconst
)(&out
[RZ
].v
.fe
.x
, &in
[RX
].v
.fe
.x
, in
[RA
].v
.i
); }
134 static void test_condswap(struct reg
*out
, const struct reg
*in
, void *ctx
)
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
);
141 static void test_pick2(struct reg
*out
, const struct reg
*in
, void *ctx
)
143 FIELDOP(pick2
)(&out
[RZ
].v
.fe
.x
,
144 &in
[RX
].v
.fe
.x
, &in
[RY
].v
.fe
.x
, in
[RM
].v
.u
);
147 static void test_pickn(struct reg
*out
, const struct reg
*in
, void *ctx
)
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
);
156 static void test_quosqrt(struct reg
*out
, const struct reg
*in
, void *ctx
)
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;
162 static void run_quosqrt(struct test_state
*state
, const struct test
*test
)
164 test
->fn(state
->out
, state
->in
, 0);
166 /* ..._quosqrt returns an arbitrary square root. The test vector
167 * contains both. We win if we match either.
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.
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
);
180 static void test_sub_mulc_add_sub_mul(struct reg
*out
,
181 const struct reg
*in
, void *ctx
)
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
);
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 }
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
};
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
},
249 { return run_test_suite(NROUT
, NREG
, sizeof(struct reg
), tests
, stdin
); }