|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "mpi.h" |
|
6 #include "mplogic.h" |
|
7 #include "mpprime.h" |
|
8 #include "ecl.h" |
|
9 #include "ecl-curve.h" |
|
10 #include "ecp.h" |
|
11 #include <stdio.h> |
|
12 #include <strings.h> |
|
13 #include <assert.h> |
|
14 |
|
15 #include <time.h> |
|
16 #include <sys/time.h> |
|
17 #include <sys/resource.h> |
|
18 |
|
19 /* Time k repetitions of operation op. */ |
|
20 #define M_TimeOperation(op, k) { \ |
|
21 double dStart, dNow, dUserTime; \ |
|
22 struct rusage ru; \ |
|
23 int i; \ |
|
24 getrusage(RUSAGE_SELF, &ru); \ |
|
25 dStart = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \ |
|
26 for (i = 0; i < k; i++) { \ |
|
27 { op; } \ |
|
28 }; \ |
|
29 getrusage(RUSAGE_SELF, &ru); \ |
|
30 dNow = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \ |
|
31 dUserTime = dNow-dStart; \ |
|
32 if (dUserTime) printf(" %-45s k: %6i, t: %6.2f sec\n", #op, k, dUserTime); \ |
|
33 } |
|
34 |
|
35 /* Test curve using generic field arithmetic. */ |
|
36 #define ECTEST_GENERIC_GFP(name_c, name) \ |
|
37 printf("Testing %s using generic implementation...\n", name_c); \ |
|
38 params = EC_GetNamedCurveParams(name); \ |
|
39 if (params == NULL) { \ |
|
40 printf(" Error: could not construct params.\n"); \ |
|
41 res = MP_NO; \ |
|
42 goto CLEANUP; \ |
|
43 } \ |
|
44 ECGroup_free(group); \ |
|
45 group = ECGroup_fromHex(params); \ |
|
46 if (group == NULL) { \ |
|
47 printf(" Error: could not construct group.\n"); \ |
|
48 res = MP_NO; \ |
|
49 goto CLEANUP; \ |
|
50 } \ |
|
51 MP_CHECKOK( ectest_curve_GFp(group, ectestPrint, ectestTime, 1) ); \ |
|
52 printf("... okay.\n"); |
|
53 |
|
54 /* Test curve using specific field arithmetic. */ |
|
55 #define ECTEST_NAMED_GFP(name_c, name) \ |
|
56 printf("Testing %s using specific implementation...\n", name_c); \ |
|
57 ECGroup_free(group); \ |
|
58 group = ECGroup_fromName(name); \ |
|
59 if (group == NULL) { \ |
|
60 printf(" Warning: could not construct group.\n"); \ |
|
61 printf("... failed; continuing with remaining tests.\n"); \ |
|
62 } else { \ |
|
63 MP_CHECKOK( ectest_curve_GFp(group, ectestPrint, ectestTime, 0) ); \ |
|
64 printf("... okay.\n"); \ |
|
65 } |
|
66 |
|
67 /* Performs basic tests of elliptic curve cryptography over prime fields. |
|
68 * If tests fail, then it prints an error message, aborts, and returns an |
|
69 * error code. Otherwise, returns 0. */ |
|
70 int |
|
71 ectest_curve_GFp(ECGroup *group, int ectestPrint, int ectestTime, |
|
72 int generic) |
|
73 { |
|
74 |
|
75 mp_int one, order_1, gx, gy, rx, ry, n; |
|
76 int size; |
|
77 mp_err res; |
|
78 char s[1000]; |
|
79 |
|
80 /* initialize values */ |
|
81 MP_CHECKOK(mp_init(&one)); |
|
82 MP_CHECKOK(mp_init(&order_1)); |
|
83 MP_CHECKOK(mp_init(&gx)); |
|
84 MP_CHECKOK(mp_init(&gy)); |
|
85 MP_CHECKOK(mp_init(&rx)); |
|
86 MP_CHECKOK(mp_init(&ry)); |
|
87 MP_CHECKOK(mp_init(&n)); |
|
88 |
|
89 MP_CHECKOK(mp_set_int(&one, 1)); |
|
90 MP_CHECKOK(mp_sub(&group->order, &one, &order_1)); |
|
91 |
|
92 /* encode base point */ |
|
93 if (group->meth->field_dec) { |
|
94 MP_CHECKOK(group->meth->field_dec(&group->genx, &gx, group->meth)); |
|
95 MP_CHECKOK(group->meth->field_dec(&group->geny, &gy, group->meth)); |
|
96 } else { |
|
97 MP_CHECKOK(mp_copy(&group->genx, &gx)); |
|
98 MP_CHECKOK(mp_copy(&group->geny, &gy)); |
|
99 } |
|
100 if (ectestPrint) { |
|
101 /* output base point */ |
|
102 printf(" base point P:\n"); |
|
103 MP_CHECKOK(mp_toradix(&gx, s, 16)); |
|
104 printf(" %s\n", s); |
|
105 MP_CHECKOK(mp_toradix(&gy, s, 16)); |
|
106 printf(" %s\n", s); |
|
107 if (group->meth->field_enc) { |
|
108 printf(" base point P (encoded):\n"); |
|
109 MP_CHECKOK(mp_toradix(&group->genx, s, 16)); |
|
110 printf(" %s\n", s); |
|
111 MP_CHECKOK(mp_toradix(&group->geny, s, 16)); |
|
112 printf(" %s\n", s); |
|
113 } |
|
114 } |
|
115 |
|
116 #ifdef ECL_ENABLE_GFP_PT_MUL_AFF |
|
117 /* multiply base point by order - 1 and check for negative of base |
|
118 * point */ |
|
119 MP_CHECKOK(ec_GFp_pt_mul_aff |
|
120 (&order_1, &group->genx, &group->geny, &rx, &ry, group)); |
|
121 if (ectestPrint) { |
|
122 printf(" (order-1)*P (affine):\n"); |
|
123 MP_CHECKOK(mp_toradix(&rx, s, 16)); |
|
124 printf(" %s\n", s); |
|
125 MP_CHECKOK(mp_toradix(&ry, s, 16)); |
|
126 printf(" %s\n", s); |
|
127 } |
|
128 MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth)); |
|
129 if ((mp_cmp(&rx, &group->genx) != 0) |
|
130 || (mp_cmp(&ry, &group->geny) != 0)) { |
|
131 printf(" Error: invalid result (expected (- base point)).\n"); |
|
132 res = MP_NO; |
|
133 goto CLEANUP; |
|
134 } |
|
135 #endif |
|
136 |
|
137 #ifdef ECL_ENABLE_GFP_PT_MUL_AFF |
|
138 /* multiply base point by order - 1 and check for negative of base |
|
139 * point */ |
|
140 MP_CHECKOK(ec_GFp_pt_mul_jac |
|
141 (&order_1, &group->genx, &group->geny, &rx, &ry, group)); |
|
142 if (ectestPrint) { |
|
143 printf(" (order-1)*P (jacobian):\n"); |
|
144 MP_CHECKOK(mp_toradix(&rx, s, 16)); |
|
145 printf(" %s\n", s); |
|
146 MP_CHECKOK(mp_toradix(&ry, s, 16)); |
|
147 printf(" %s\n", s); |
|
148 } |
|
149 MP_CHECKOK(group->meth->field_neg(&ry, &ry, group->meth)); |
|
150 if ((mp_cmp(&rx, &group->genx) != 0) |
|
151 || (mp_cmp(&ry, &group->geny) != 0)) { |
|
152 printf(" Error: invalid result (expected (- base point)).\n"); |
|
153 res = MP_NO; |
|
154 goto CLEANUP; |
|
155 } |
|
156 #endif |
|
157 |
|
158 /* multiply base point by order - 1 and check for negative of base |
|
159 * point */ |
|
160 MP_CHECKOK(ECPoint_mul(group, &order_1, NULL, NULL, &rx, &ry)); |
|
161 if (ectestPrint) { |
|
162 printf(" (order-1)*P (ECPoint_mul):\n"); |
|
163 MP_CHECKOK(mp_toradix(&rx, s, 16)); |
|
164 printf(" %s\n", s); |
|
165 MP_CHECKOK(mp_toradix(&ry, s, 16)); |
|
166 printf(" %s\n", s); |
|
167 } |
|
168 MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry)); |
|
169 if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) { |
|
170 printf(" Error: invalid result (expected (- base point)).\n"); |
|
171 res = MP_NO; |
|
172 goto CLEANUP; |
|
173 } |
|
174 |
|
175 /* multiply base point by order - 1 and check for negative of base |
|
176 * point */ |
|
177 MP_CHECKOK(ECPoint_mul(group, &order_1, &gx, &gy, &rx, &ry)); |
|
178 if (ectestPrint) { |
|
179 printf(" (order-1)*P (ECPoint_mul):\n"); |
|
180 MP_CHECKOK(mp_toradix(&rx, s, 16)); |
|
181 printf(" %s\n", s); |
|
182 MP_CHECKOK(mp_toradix(&ry, s, 16)); |
|
183 printf(" %s\n", s); |
|
184 } |
|
185 MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry)); |
|
186 if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) { |
|
187 printf(" Error: invalid result (expected (- base point)).\n"); |
|
188 res = MP_NO; |
|
189 goto CLEANUP; |
|
190 } |
|
191 |
|
192 #ifdef ECL_ENABLE_GFP_PT_MUL_AFF |
|
193 /* multiply base point by order and check for point at infinity */ |
|
194 MP_CHECKOK(ec_GFp_pt_mul_aff |
|
195 (&group->order, &group->genx, &group->geny, &rx, &ry, |
|
196 group)); |
|
197 if (ectestPrint) { |
|
198 printf(" (order)*P (affine):\n"); |
|
199 MP_CHECKOK(mp_toradix(&rx, s, 16)); |
|
200 printf(" %s\n", s); |
|
201 MP_CHECKOK(mp_toradix(&ry, s, 16)); |
|
202 printf(" %s\n", s); |
|
203 } |
|
204 if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { |
|
205 printf(" Error: invalid result (expected point at infinity).\n"); |
|
206 res = MP_NO; |
|
207 goto CLEANUP; |
|
208 } |
|
209 #endif |
|
210 |
|
211 #ifdef ECL_ENABLE_GFP_PT_MUL_JAC |
|
212 /* multiply base point by order and check for point at infinity */ |
|
213 MP_CHECKOK(ec_GFp_pt_mul_jac |
|
214 (&group->order, &group->genx, &group->geny, &rx, &ry, |
|
215 group)); |
|
216 if (ectestPrint) { |
|
217 printf(" (order)*P (jacobian):\n"); |
|
218 MP_CHECKOK(mp_toradix(&rx, s, 16)); |
|
219 printf(" %s\n", s); |
|
220 MP_CHECKOK(mp_toradix(&ry, s, 16)); |
|
221 printf(" %s\n", s); |
|
222 } |
|
223 if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { |
|
224 printf(" Error: invalid result (expected point at infinity).\n"); |
|
225 res = MP_NO; |
|
226 goto CLEANUP; |
|
227 } |
|
228 #endif |
|
229 |
|
230 /* multiply base point by order and check for point at infinity */ |
|
231 MP_CHECKOK(ECPoint_mul(group, &group->order, NULL, NULL, &rx, &ry)); |
|
232 if (ectestPrint) { |
|
233 printf(" (order)*P (ECPoint_mul):\n"); |
|
234 MP_CHECKOK(mp_toradix(&rx, s, 16)); |
|
235 printf(" %s\n", s); |
|
236 MP_CHECKOK(mp_toradix(&ry, s, 16)); |
|
237 printf(" %s\n", s); |
|
238 } |
|
239 if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { |
|
240 printf(" Error: invalid result (expected point at infinity).\n"); |
|
241 res = MP_NO; |
|
242 goto CLEANUP; |
|
243 } |
|
244 |
|
245 /* multiply base point by order and check for point at infinity */ |
|
246 MP_CHECKOK(ECPoint_mul(group, &group->order, &gx, &gy, &rx, &ry)); |
|
247 if (ectestPrint) { |
|
248 printf(" (order)*P (ECPoint_mul):\n"); |
|
249 MP_CHECKOK(mp_toradix(&rx, s, 16)); |
|
250 printf(" %s\n", s); |
|
251 MP_CHECKOK(mp_toradix(&ry, s, 16)); |
|
252 printf(" %s\n", s); |
|
253 } |
|
254 if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) { |
|
255 printf(" Error: invalid result (expected point at infinity).\n"); |
|
256 res = MP_NO; |
|
257 goto CLEANUP; |
|
258 } |
|
259 |
|
260 /* check that (order-1)P + (order-1)P + P == (order-1)P */ |
|
261 MP_CHECKOK(ECPoints_mul |
|
262 (group, &order_1, &order_1, &gx, &gy, &rx, &ry)); |
|
263 MP_CHECKOK(ECPoints_mul(group, &one, &one, &rx, &ry, &rx, &ry)); |
|
264 if (ectestPrint) { |
|
265 printf |
|
266 (" (order-1)*P + (order-1)*P + P == (order-1)*P (ECPoints_mul):\n"); |
|
267 MP_CHECKOK(mp_toradix(&rx, s, 16)); |
|
268 printf(" %s\n", s); |
|
269 MP_CHECKOK(mp_toradix(&ry, s, 16)); |
|
270 printf(" %s\n", s); |
|
271 } |
|
272 MP_CHECKOK(mp_submod(&group->meth->irr, &ry, &group->meth->irr, &ry)); |
|
273 if ((mp_cmp(&rx, &gx) != 0) || (mp_cmp(&ry, &gy) != 0)) { |
|
274 printf(" Error: invalid result (expected (- base point)).\n"); |
|
275 res = MP_NO; |
|
276 goto CLEANUP; |
|
277 } |
|
278 |
|
279 /* test validate_point function */ |
|
280 if (ECPoint_validate(group, &gx, &gy) != MP_YES) { |
|
281 printf(" Error: validate point on base point failed.\n"); |
|
282 res = MP_NO; |
|
283 goto CLEANUP; |
|
284 } |
|
285 MP_CHECKOK(mp_add_d(&gy, 1, &ry)); |
|
286 if (ECPoint_validate(group, &gx, &ry) != MP_NO) { |
|
287 printf(" Error: validate point on invalid point passed.\n"); |
|
288 res = MP_NO; |
|
289 goto CLEANUP; |
|
290 } |
|
291 |
|
292 if (ectestTime) { |
|
293 /* compute random scalar */ |
|
294 size = mpl_significant_bits(&group->meth->irr); |
|
295 if (size < MP_OKAY) { |
|
296 goto CLEANUP; |
|
297 } |
|
298 MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS)); |
|
299 MP_CHECKOK(group->meth->field_mod(&n, &n, group->meth)); |
|
300 /* timed test */ |
|
301 if (generic) { |
|
302 #ifdef ECL_ENABLE_GFP_PT_MUL_AFF |
|
303 M_TimeOperation(MP_CHECKOK |
|
304 (ec_GFp_pt_mul_aff |
|
305 (&n, &group->genx, &group->geny, &rx, &ry, |
|
306 group)), 100); |
|
307 #endif |
|
308 M_TimeOperation(MP_CHECKOK |
|
309 (ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)), |
|
310 100); |
|
311 M_TimeOperation(MP_CHECKOK |
|
312 (ECPoints_mul |
|
313 (group, &n, &n, &gx, &gy, &rx, &ry)), 100); |
|
314 } else { |
|
315 M_TimeOperation(MP_CHECKOK |
|
316 (ECPoint_mul(group, &n, NULL, NULL, &rx, &ry)), |
|
317 100); |
|
318 M_TimeOperation(MP_CHECKOK |
|
319 (ECPoint_mul(group, &n, &gx, &gy, &rx, &ry)), |
|
320 100); |
|
321 M_TimeOperation(MP_CHECKOK |
|
322 (ECPoints_mul |
|
323 (group, &n, &n, &gx, &gy, &rx, &ry)), 100); |
|
324 } |
|
325 } |
|
326 |
|
327 CLEANUP: |
|
328 mp_clear(&one); |
|
329 mp_clear(&order_1); |
|
330 mp_clear(&gx); |
|
331 mp_clear(&gy); |
|
332 mp_clear(&rx); |
|
333 mp_clear(&ry); |
|
334 mp_clear(&n); |
|
335 if (res != MP_OKAY) { |
|
336 printf(" Error: exiting with error value %i\n", res); |
|
337 } |
|
338 return res; |
|
339 } |
|
340 |
|
341 /* Prints help information. */ |
|
342 void |
|
343 printUsage() |
|
344 { |
|
345 printf("Usage: ecp_test [--print] [--time]\n"); |
|
346 printf |
|
347 (" --print Print out results of each point arithmetic test.\n"); |
|
348 printf |
|
349 (" --time Benchmark point operations and print results.\n"); |
|
350 } |
|
351 |
|
352 /* Performs tests of elliptic curve cryptography over prime fields If |
|
353 * tests fail, then it prints an error message, aborts, and returns an |
|
354 * error code. Otherwise, returns 0. */ |
|
355 int |
|
356 main(int argv, char **argc) |
|
357 { |
|
358 |
|
359 int ectestTime = 0; |
|
360 int ectestPrint = 0; |
|
361 int i; |
|
362 ECGroup *group = NULL; |
|
363 ECCurveParams *params = NULL; |
|
364 mp_err res; |
|
365 |
|
366 /* read command-line arguments */ |
|
367 for (i = 1; i < argv; i++) { |
|
368 if ((strcasecmp(argc[i], "time") == 0) |
|
369 || (strcasecmp(argc[i], "-time") == 0) |
|
370 || (strcasecmp(argc[i], "--time") == 0)) { |
|
371 ectestTime = 1; |
|
372 } else if ((strcasecmp(argc[i], "print") == 0) |
|
373 || (strcasecmp(argc[i], "-print") == 0) |
|
374 || (strcasecmp(argc[i], "--print") == 0)) { |
|
375 ectestPrint = 1; |
|
376 } else { |
|
377 printUsage(); |
|
378 return 0; |
|
379 } |
|
380 } |
|
381 |
|
382 /* generic arithmetic tests */ |
|
383 ECTEST_GENERIC_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); |
|
384 |
|
385 /* specific arithmetic tests */ |
|
386 ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192); |
|
387 ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224); |
|
388 ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256); |
|
389 ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384); |
|
390 ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521); |
|
391 ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1); |
|
392 ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2); |
|
393 ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3); |
|
394 ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1); |
|
395 ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2); |
|
396 ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3); |
|
397 ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1); |
|
398 ECTEST_NAMED_GFP("SECP-112R1", ECCurve_SECG_PRIME_112R1); |
|
399 ECTEST_NAMED_GFP("SECP-112R2", ECCurve_SECG_PRIME_112R2); |
|
400 ECTEST_NAMED_GFP("SECP-128R1", ECCurve_SECG_PRIME_128R1); |
|
401 ECTEST_NAMED_GFP("SECP-128R2", ECCurve_SECG_PRIME_128R2); |
|
402 ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1); |
|
403 ECTEST_NAMED_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); |
|
404 ECTEST_NAMED_GFP("SECP-160R2", ECCurve_SECG_PRIME_160R2); |
|
405 ECTEST_NAMED_GFP("SECP-192K1", ECCurve_SECG_PRIME_192K1); |
|
406 ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1); |
|
407 ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1); |
|
408 ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1); |
|
409 ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1); |
|
410 ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1); |
|
411 ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1); |
|
412 ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1); |
|
413 ECTEST_NAMED_GFP("WTLS-6 (112)", ECCurve_WTLS_6); |
|
414 ECTEST_NAMED_GFP("WTLS-7 (160)", ECCurve_WTLS_7); |
|
415 ECTEST_NAMED_GFP("WTLS-8 (112)", ECCurve_WTLS_8); |
|
416 ECTEST_NAMED_GFP("WTLS-9 (160)", ECCurve_WTLS_9); |
|
417 ECTEST_NAMED_GFP("WTLS-12 (224)", ECCurve_WTLS_12); |
|
418 |
|
419 CLEANUP: |
|
420 EC_FreeCurveParams(params); |
|
421 ECGroup_free(group); |
|
422 if (res != MP_OKAY) { |
|
423 printf("Error: exiting with error value %i\n", res); |
|
424 } |
|
425 return res; |
|
426 } |