Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / freebl / ecl / tests / ecp_fpt.c
blob538f4d018bf1164feb584f449c5cedc3a10abbeb
1 /*
2 * ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
13 * License.
15 * The Original Code is the elliptic curve math library for prime field curves using floating point operations.
17 * The Initial Developer of the Original Code is
18 * Sun Microsystems, Inc.
19 * Portions created by the Initial Developer are Copyright (C) 2003
20 * the Initial Developer. All Rights Reserved.
22 * Contributor(s):
23 * Stephen Fung <fungstep@hotmail.com> and
24 * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories.
26 * Alternatively, the contents of this file may be used under the terms of
27 * either the GNU General Public License Version 2 or later (the "GPL"), or
28 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 * in which case the provisions of the GPL or the LGPL are applicable instead
30 * of those above. If you wish to allow use of your version of this file only
31 * under the terms of either the GPL or the LGPL, and not to allow others to
32 * use your version of this file under the terms of the MPL, indicate your
33 * decision by deleting the provisions above and replace them with the notice
34 * and other provisions required by the GPL or the LGPL. If you do not delete
35 * the provisions above, a recipient may use your version of this file under
36 * the terms of any one of the MPL, the GPL or the LGPL.
38 * ***** END LICENSE BLOCK ***** */
40 #include "ecp_fp.h"
41 #include "mpprime.h"
43 #include <stdio.h>
44 #include <time.h>
45 #include <sys/time.h>
46 #include <sys/resource.h>
48 /* Time k repetitions of operation op. */
49 #define M_TimeOperation(op, k) { \
50 double dStart, dNow, dUserTime; \
51 struct rusage ru; \
52 int i; \
53 getrusage(RUSAGE_SELF, &ru); \
54 dStart = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \
55 for (i = 0; i < k; i++) { \
56 { op; } \
57 }; \
58 getrusage(RUSAGE_SELF, &ru); \
59 dNow = (double)ru.ru_utime.tv_sec+(double)ru.ru_utime.tv_usec*0.000001; \
60 dUserTime = dNow-dStart; \
61 if (dUserTime) printf(" %-45s\n k: %6i, t: %6.2f sec, k/t: %6.2f ops/sec\n", #op, k, dUserTime, k/dUserTime); \
64 /* Test curve using specific floating point field arithmetic. */
65 #define M_TestCurve(name_c, name) { \
66 printf("Testing %s using specific floating point implementation...\n", name_c); \
67 ECGroup_free(ecgroup); \
68 ecgroup = ECGroup_fromName(name); \
69 if (ecgroup == NULL) { \
70 printf(" Warning: could not construct group.\n"); \
71 printf("%s failed.\n", name_c); \
72 res = MP_NO; \
73 goto CLEANUP; \
74 } else { \
75 MP_CHECKOK( testCurve(ecgroup)); \
76 printf("%s passed.\n", name_c); \
77 } \
80 /* Outputs a floating point double (currently not used) */
81 void
82 d_output(const double *u, int len, char *name, const EC_group_fp * group)
84 int i;
86 printf("%s: ", name);
87 for (i = 0; i < len; i++) {
88 printf("+ %.2f * 2^%i ", u[i] / ecfp_exp[i],
89 group->doubleBitSize * i);
91 printf("\n");
94 /* Tests a point p in Jacobian coordinates, comparing against the
95 * expected affine result (x, y). */
96 mp_err
97 testJacPoint(ecfp_jac_pt * p, mp_int *x, mp_int *y, ECGroup *ecgroup)
99 char s[1000];
100 mp_int rx, ry, rz;
101 mp_err res = MP_OKAY;
103 MP_DIGITS(&rx) = 0;
104 MP_DIGITS(&ry) = 0;
105 MP_DIGITS(&rz) = 0;
107 MP_CHECKOK(mp_init(&rx));
108 MP_CHECKOK(mp_init(&ry));
109 MP_CHECKOK(mp_init(&rz));
111 ecfp_fp2i(&rx, p->x, ecgroup);
112 ecfp_fp2i(&ry, p->y, ecgroup);
113 ecfp_fp2i(&rz, p->z, ecgroup);
115 /* convert result R to affine coordinates */
116 ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup);
118 /* Compare to expected result */
119 if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) {
120 printf(" Error: Jacobian Floating Point Incorrect.\n");
121 MP_CHECKOK(mp_toradix(&rx, s, 16));
122 printf("floating point result\nrx %s\n", s);
123 MP_CHECKOK(mp_toradix(&ry, s, 16));
124 printf("ry %s\n", s);
125 MP_CHECKOK(mp_toradix(x, s, 16));
126 printf("integer result\nx %s\n", s);
127 MP_CHECKOK(mp_toradix(y, s, 16));
128 printf("y %s\n", s);
129 res = MP_NO;
130 goto CLEANUP;
133 CLEANUP:
134 mp_clear(&rx);
135 mp_clear(&ry);
136 mp_clear(&rz);
138 return res;
141 /* Tests a point p in Chudnovsky Jacobian coordinates, comparing against
142 * the expected affine result (x, y). */
143 mp_err
144 testChudPoint(ecfp_chud_pt * p, mp_int *x, mp_int *y, ECGroup *ecgroup)
147 char s[1000];
148 mp_int rx, ry, rz, rz2, rz3, test;
149 mp_err res = MP_OKAY;
151 /* Initialization */
152 MP_DIGITS(&rx) = 0;
153 MP_DIGITS(&ry) = 0;
154 MP_DIGITS(&rz) = 0;
155 MP_DIGITS(&rz2) = 0;
156 MP_DIGITS(&rz3) = 0;
157 MP_DIGITS(&test) = 0;
159 MP_CHECKOK(mp_init(&rx));
160 MP_CHECKOK(mp_init(&ry));
161 MP_CHECKOK(mp_init(&rz));
162 MP_CHECKOK(mp_init(&rz2));
163 MP_CHECKOK(mp_init(&rz3));
164 MP_CHECKOK(mp_init(&test));
166 /* Convert to integers */
167 ecfp_fp2i(&rx, p->x, ecgroup);
168 ecfp_fp2i(&ry, p->y, ecgroup);
169 ecfp_fp2i(&rz, p->z, ecgroup);
170 ecfp_fp2i(&rz2, p->z2, ecgroup);
171 ecfp_fp2i(&rz3, p->z3, ecgroup);
173 /* Verify z2, z3 are valid */
174 mp_sqrmod(&rz, &ecgroup->meth->irr, &test);
175 if (mp_cmp(&test, &rz2) != 0) {
176 printf(" Error: rzp2 not valid\n");
177 res = MP_NO;
178 goto CLEANUP;
180 mp_mulmod(&test, &rz, &ecgroup->meth->irr, &test);
181 if (mp_cmp(&test, &rz3) != 0) {
182 printf(" Error: rzp2 not valid\n");
183 res = MP_NO;
184 goto CLEANUP;
187 /* convert result R to affine coordinates */
188 ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup);
190 /* Compare against expected result */
191 if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) {
192 printf(" Error: Chudnovsky Floating Point Incorrect.\n");
193 MP_CHECKOK(mp_toradix(&rx, s, 16));
194 printf("floating point result\nrx %s\n", s);
195 MP_CHECKOK(mp_toradix(&ry, s, 16));
196 printf("ry %s\n", s);
197 MP_CHECKOK(mp_toradix(x, s, 16));
198 printf("integer result\nx %s\n", s);
199 MP_CHECKOK(mp_toradix(y, s, 16));
200 printf("y %s\n", s);
201 res = MP_NO;
202 goto CLEANUP;
205 CLEANUP:
206 mp_clear(&rx);
207 mp_clear(&ry);
208 mp_clear(&rz);
209 mp_clear(&rz2);
210 mp_clear(&rz3);
211 mp_clear(&test);
213 return res;
216 /* Tests a point p in Modified Jacobian coordinates, comparing against the
217 * expected affine result (x, y). */
218 mp_err
219 testJmPoint(ecfp_jm_pt * r, mp_int *x, mp_int *y, ECGroup *ecgroup)
222 char s[1000];
223 mp_int rx, ry, rz, raz4, test;
224 mp_err res = MP_OKAY;
226 /* Initialization */
227 MP_DIGITS(&rx) = 0;
228 MP_DIGITS(&ry) = 0;
229 MP_DIGITS(&rz) = 0;
230 MP_DIGITS(&raz4) = 0;
231 MP_DIGITS(&test) = 0;
233 MP_CHECKOK(mp_init(&rx));
234 MP_CHECKOK(mp_init(&ry));
235 MP_CHECKOK(mp_init(&rz));
236 MP_CHECKOK(mp_init(&raz4));
237 MP_CHECKOK(mp_init(&test));
239 /* Convert to integer */
240 ecfp_fp2i(&rx, r->x, ecgroup);
241 ecfp_fp2i(&ry, r->y, ecgroup);
242 ecfp_fp2i(&rz, r->z, ecgroup);
243 ecfp_fp2i(&raz4, r->az4, ecgroup);
245 /* Verify raz4 = rz^4 * a */
246 mp_sqrmod(&rz, &ecgroup->meth->irr, &test);
247 mp_sqrmod(&test, &ecgroup->meth->irr, &test);
248 mp_mulmod(&test, &ecgroup->curvea, &ecgroup->meth->irr, &test);
249 if (mp_cmp(&test, &raz4) != 0) {
250 printf(" Error: a*z^4 not valid\n");
251 MP_CHECKOK(mp_toradix(&ecgroup->curvea, s, 16));
252 printf("a %s\n", s);
253 MP_CHECKOK(mp_toradix(&rz, s, 16));
254 printf("rz %s\n", s);
255 MP_CHECKOK(mp_toradix(&raz4, s, 16));
256 printf("raz4 %s\n", s);
257 res = MP_NO;
258 goto CLEANUP;
261 /* convert result R to affine coordinates */
262 ec_GFp_pt_jac2aff(&rx, &ry, &rz, &rx, &ry, ecgroup);
264 /* Compare against expected result */
265 if ((mp_cmp(&rx, x) != 0) || (mp_cmp(&ry, y) != 0)) {
266 printf(" Error: Modified Jacobian Floating Point Incorrect.\n");
267 MP_CHECKOK(mp_toradix(&rx, s, 16));
268 printf("floating point result\nrx %s\n", s);
269 MP_CHECKOK(mp_toradix(&ry, s, 16));
270 printf("ry %s\n", s);
271 MP_CHECKOK(mp_toradix(x, s, 16));
272 printf("integer result\nx %s\n", s);
273 MP_CHECKOK(mp_toradix(y, s, 16));
274 printf("y %s\n", s);
275 res = MP_NO;
276 goto CLEANUP;
278 CLEANUP:
279 mp_clear(&rx);
280 mp_clear(&ry);
281 mp_clear(&rz);
282 mp_clear(&raz4);
283 mp_clear(&test);
285 return res;
288 /* Tests point addition of Jacobian + Affine -> Jacobian */
289 mp_err
290 testPointAddJacAff(ECGroup *ecgroup)
292 mp_err res;
293 mp_int pz, rx2, ry2, rz2;
294 ecfp_jac_pt p, r;
295 ecfp_aff_pt q;
296 EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
298 /* Init */
299 MP_DIGITS(&pz) = 0;
300 MP_DIGITS(&rx2) = 0;
301 MP_DIGITS(&ry2) = 0;
302 MP_DIGITS(&rz2) = 0;
303 MP_CHECKOK(mp_init(&pz));
304 MP_CHECKOK(mp_init(&rx2));
305 MP_CHECKOK(mp_init(&ry2));
306 MP_CHECKOK(mp_init(&rz2));
308 MP_CHECKOK(mp_set_int(&pz, 5));
310 /* Set p */
311 ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
312 ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
313 ecfp_i2fp(p.z, &pz, ecgroup);
314 /* Set q */
315 ecfp_i2fp(q.x, &ecgroup->geny, ecgroup);
316 ecfp_i2fp(q.y, &ecgroup->genx, ecgroup);
318 /* Do calculations */
319 group->pt_add_jac_aff(&p, &q, &r, group);
321 /* Do calculation in integer to compare against */
322 MP_CHECKOK(ec_GFp_pt_add_jac_aff
323 (&ecgroup->genx, &ecgroup->geny, &pz, &ecgroup->geny,
324 &ecgroup->genx, &rx2, &ry2, &rz2, ecgroup));
325 /* convert result R to affine coordinates */
326 ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);
328 MP_CHECKOK(testJacPoint(&r, &rx2, &ry2, ecgroup));
330 CLEANUP:
331 if (res == MP_OKAY)
332 printf(" Test Passed - Point Addition - Jacobian & Affine\n");
333 else
334 printf("TEST FAILED - Point Addition - Jacobian & Affine\n");
336 mp_clear(&pz);
337 mp_clear(&rx2);
338 mp_clear(&ry2);
339 mp_clear(&rz2);
341 return res;
344 /* Tests point addition in Jacobian coordinates */
345 mp_err
346 testPointAddJac(ECGroup *ecgroup)
348 mp_err res;
349 mp_int pz, qz, qx, qy, rx2, ry2, rz2;
350 ecfp_jac_pt p, q, r;
351 EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
353 /* Init */
354 MP_DIGITS(&pz) = 0;
355 MP_DIGITS(&qx) = 0;
356 MP_DIGITS(&qy) = 0;
357 MP_DIGITS(&qz) = 0;
358 MP_DIGITS(&rx2) = 0;
359 MP_DIGITS(&ry2) = 0;
360 MP_DIGITS(&rz2) = 0;
361 MP_CHECKOK(mp_init(&pz));
362 MP_CHECKOK(mp_init(&qx));
363 MP_CHECKOK(mp_init(&qy));
364 MP_CHECKOK(mp_init(&qz));
365 MP_CHECKOK(mp_init(&rx2));
366 MP_CHECKOK(mp_init(&ry2));
367 MP_CHECKOK(mp_init(&rz2));
369 MP_CHECKOK(mp_set_int(&pz, 5));
370 MP_CHECKOK(mp_set_int(&qz, 105));
372 /* Set p */
373 ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
374 ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
375 ecfp_i2fp(p.z, &pz, ecgroup);
376 /* Set q */
377 ecfp_i2fp(q.x, &ecgroup->geny, ecgroup);
378 ecfp_i2fp(q.y, &ecgroup->genx, ecgroup);
379 ecfp_i2fp(q.z, &qz, ecgroup);
381 /* Do calculations */
382 group->pt_add_jac(&p, &q, &r, group);
384 /* Do calculation in integer to compare against */
385 ec_GFp_pt_jac2aff(&ecgroup->geny, &ecgroup->genx, &qz, &qx, &qy,
386 ecgroup);
387 MP_CHECKOK(ec_GFp_pt_add_jac_aff
388 (&ecgroup->genx, &ecgroup->geny, &pz, &qx, &qy, &rx2, &ry2,
389 &rz2, ecgroup));
390 /* convert result R to affine coordinates */
391 ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);
393 MP_CHECKOK(testJacPoint(&r, &rx2, &ry2, ecgroup));
395 CLEANUP:
396 if (res == MP_OKAY)
397 printf(" Test Passed - Point Addition - Jacobian\n");
398 else
399 printf("TEST FAILED - Point Addition - Jacobian\n");
401 mp_clear(&pz);
402 mp_clear(&qx);
403 mp_clear(&qy);
404 mp_clear(&qz);
405 mp_clear(&rx2);
406 mp_clear(&ry2);
407 mp_clear(&rz2);
409 return res;
412 /* Tests point addition in Chudnovsky Jacobian Coordinates */
413 mp_err
414 testPointAddChud(ECGroup *ecgroup)
416 mp_err res;
417 mp_int rx2, ry2, ix, iy, iz, test, pz, qx, qy, qz;
418 ecfp_chud_pt p, q, r;
419 EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
421 MP_DIGITS(&qx) = 0;
422 MP_DIGITS(&qy) = 0;
423 MP_DIGITS(&qz) = 0;
424 MP_DIGITS(&pz) = 0;
425 MP_DIGITS(&rx2) = 0;
426 MP_DIGITS(&ry2) = 0;
427 MP_DIGITS(&ix) = 0;
428 MP_DIGITS(&iy) = 0;
429 MP_DIGITS(&iz) = 0;
430 MP_DIGITS(&test) = 0;
432 MP_CHECKOK(mp_init(&qx));
433 MP_CHECKOK(mp_init(&qy));
434 MP_CHECKOK(mp_init(&qz));
435 MP_CHECKOK(mp_init(&pz));
436 MP_CHECKOK(mp_init(&rx2));
437 MP_CHECKOK(mp_init(&ry2));
438 MP_CHECKOK(mp_init(&ix));
439 MP_CHECKOK(mp_init(&iy));
440 MP_CHECKOK(mp_init(&iz));
441 MP_CHECKOK(mp_init(&test));
443 /* Test Chudnovsky form addition */
444 /* Set p */
445 MP_CHECKOK(mp_set_int(&pz, 5));
446 ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
447 ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
448 ecfp_i2fp(p.z, &pz, ecgroup);
449 mp_sqrmod(&pz, &ecgroup->meth->irr, &test);
450 ecfp_i2fp(p.z2, &test, ecgroup);
451 mp_mulmod(&test, &pz, &ecgroup->meth->irr, &test);
452 ecfp_i2fp(p.z3, &test, ecgroup);
454 /* Set q */
455 MP_CHECKOK(mp_set_int(&qz, 105));
456 ecfp_i2fp(q.x, &ecgroup->geny, ecgroup);
457 ecfp_i2fp(q.y, &ecgroup->genx, ecgroup);
458 ecfp_i2fp(q.z, &qz, ecgroup);
459 mp_sqrmod(&qz, &ecgroup->meth->irr, &test);
460 ecfp_i2fp(q.z2, &test, ecgroup);
461 mp_mulmod(&test, &qz, &ecgroup->meth->irr, &test);
462 ecfp_i2fp(q.z3, &test, ecgroup);
464 group->pt_add_chud(&p, &q, &r, group);
466 /* Calculate addition to compare against */
467 ec_GFp_pt_jac2aff(&ecgroup->geny, &ecgroup->genx, &qz, &qx, &qy,
468 ecgroup);
469 ec_GFp_pt_add_jac_aff(&ecgroup->genx, &ecgroup->geny, &pz, &qx, &qy,
470 &ix, &iy, &iz, ecgroup);
471 ec_GFp_pt_jac2aff(&ix, &iy, &iz, &rx2, &ry2, ecgroup);
473 MP_CHECKOK(testChudPoint(&r, &rx2, &ry2, ecgroup));
475 CLEANUP:
476 if (res == MP_OKAY)
477 printf(" Test Passed - Point Addition - Chudnovsky Jacobian\n");
478 else
479 printf("TEST FAILED - Point Addition - Chudnovsky Jacobian\n");
481 mp_clear(&qx);
482 mp_clear(&qy);
483 mp_clear(&qz);
484 mp_clear(&pz);
485 mp_clear(&rx2);
486 mp_clear(&ry2);
487 mp_clear(&ix);
488 mp_clear(&iy);
489 mp_clear(&iz);
490 mp_clear(&test);
492 return res;
495 /* Tests point addition in Modified Jacobian + Chudnovsky Jacobian ->
496 * Modified Jacobian coordinates. */
497 mp_err
498 testPointAddJmChud(ECGroup *ecgroup)
500 mp_err res;
501 mp_int rx2, ry2, ix, iy, iz, test, pz, paz4, qx, qy, qz;
502 ecfp_chud_pt q;
503 ecfp_jm_pt p, r;
504 EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
506 MP_DIGITS(&qx) = 0;
507 MP_DIGITS(&qy) = 0;
508 MP_DIGITS(&qz) = 0;
509 MP_DIGITS(&pz) = 0;
510 MP_DIGITS(&paz4) = 0;
511 MP_DIGITS(&iz) = 0;
512 MP_DIGITS(&rx2) = 0;
513 MP_DIGITS(&ry2) = 0;
514 MP_DIGITS(&ix) = 0;
515 MP_DIGITS(&iy) = 0;
516 MP_DIGITS(&iz) = 0;
517 MP_DIGITS(&test) = 0;
519 MP_CHECKOK(mp_init(&qx));
520 MP_CHECKOK(mp_init(&qy));
521 MP_CHECKOK(mp_init(&qz));
522 MP_CHECKOK(mp_init(&pz));
523 MP_CHECKOK(mp_init(&paz4));
524 MP_CHECKOK(mp_init(&rx2));
525 MP_CHECKOK(mp_init(&ry2));
526 MP_CHECKOK(mp_init(&ix));
527 MP_CHECKOK(mp_init(&iy));
528 MP_CHECKOK(mp_init(&iz));
529 MP_CHECKOK(mp_init(&test));
531 /* Test Modified Jacobian form addition */
532 /* Set p */
533 ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
534 ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
535 ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);
536 /* paz4 = az^4 */
537 MP_CHECKOK(mp_set_int(&pz, 5));
538 mp_sqrmod(&pz, &ecgroup->meth->irr, &paz4);
539 mp_sqrmod(&paz4, &ecgroup->meth->irr, &paz4);
540 mp_mulmod(&paz4, &ecgroup->curvea, &ecgroup->meth->irr, &paz4);
541 ecfp_i2fp(p.z, &pz, ecgroup);
542 ecfp_i2fp(p.az4, &paz4, ecgroup);
544 /* Set q */
545 MP_CHECKOK(mp_set_int(&qz, 105));
546 ecfp_i2fp(q.x, &ecgroup->geny, ecgroup);
547 ecfp_i2fp(q.y, &ecgroup->genx, ecgroup);
548 ecfp_i2fp(q.z, &qz, ecgroup);
549 mp_sqrmod(&qz, &ecgroup->meth->irr, &test);
550 ecfp_i2fp(q.z2, &test, ecgroup);
551 mp_mulmod(&test, &qz, &ecgroup->meth->irr, &test);
552 ecfp_i2fp(q.z3, &test, ecgroup);
554 /* Do calculation */
555 group->pt_add_jm_chud(&p, &q, &r, group);
557 /* Calculate addition to compare against */
558 ec_GFp_pt_jac2aff(&ecgroup->geny, &ecgroup->genx, &qz, &qx, &qy,
559 ecgroup);
560 ec_GFp_pt_add_jac_aff(&ecgroup->genx, &ecgroup->geny, &pz, &qx, &qy,
561 &ix, &iy, &iz, ecgroup);
562 ec_GFp_pt_jac2aff(&ix, &iy, &iz, &rx2, &ry2, ecgroup);
564 MP_CHECKOK(testJmPoint(&r, &rx2, &ry2, ecgroup));
566 CLEANUP:
567 if (res == MP_OKAY)
568 printf
569 (" Test Passed - Point Addition - Modified & Chudnovsky Jacobian\n");
570 else
571 printf
572 ("TEST FAILED - Point Addition - Modified & Chudnovsky Jacobian\n");
574 mp_clear(&qx);
575 mp_clear(&qy);
576 mp_clear(&qz);
577 mp_clear(&pz);
578 mp_clear(&paz4);
579 mp_clear(&rx2);
580 mp_clear(&ry2);
581 mp_clear(&ix);
582 mp_clear(&iy);
583 mp_clear(&iz);
584 mp_clear(&test);
586 return res;
589 /* Tests point doubling in Modified Jacobian coordinates */
590 mp_err
591 testPointDoubleJm(ECGroup *ecgroup)
593 mp_err res;
594 mp_int pz, paz4, rx2, ry2, rz2, raz4;
595 ecfp_jm_pt p, r;
596 EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
598 MP_DIGITS(&pz) = 0;
599 MP_DIGITS(&paz4) = 0;
600 MP_DIGITS(&rx2) = 0;
601 MP_DIGITS(&ry2) = 0;
602 MP_DIGITS(&rz2) = 0;
603 MP_DIGITS(&raz4) = 0;
605 MP_CHECKOK(mp_init(&pz));
606 MP_CHECKOK(mp_init(&paz4));
607 MP_CHECKOK(mp_init(&rx2));
608 MP_CHECKOK(mp_init(&ry2));
609 MP_CHECKOK(mp_init(&rz2));
610 MP_CHECKOK(mp_init(&raz4));
612 /* Set p */
613 ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
614 ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
615 ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);
617 /* paz4 = az^4 */
618 MP_CHECKOK(mp_set_int(&pz, 5));
619 mp_sqrmod(&pz, &ecgroup->meth->irr, &paz4);
620 mp_sqrmod(&paz4, &ecgroup->meth->irr, &paz4);
621 mp_mulmod(&paz4, &ecgroup->curvea, &ecgroup->meth->irr, &paz4);
623 ecfp_i2fp(p.z, &pz, ecgroup);
624 ecfp_i2fp(p.az4, &paz4, ecgroup);
626 group->pt_dbl_jm(&p, &r, group);
628 M_TimeOperation(group->pt_dbl_jm(&p, &r, group), 100000);
630 /* Calculate doubling to compare against */
631 ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2,
632 &rz2, ecgroup);
633 ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);
635 /* Do comparison and check az^4 */
636 MP_CHECKOK(testJmPoint(&r, &rx2, &ry2, ecgroup));
638 CLEANUP:
639 if (res == MP_OKAY)
640 printf(" Test Passed - Point Doubling - Modified Jacobian\n");
641 else
642 printf("TEST FAILED - Point Doubling - Modified Jacobian\n");
643 mp_clear(&pz);
644 mp_clear(&paz4);
645 mp_clear(&rx2);
646 mp_clear(&ry2);
647 mp_clear(&rz2);
648 mp_clear(&raz4);
650 return res;
654 /* Tests point doubling in Chudnovsky Jacobian coordinates */
655 mp_err
656 testPointDoubleChud(ECGroup *ecgroup)
658 mp_err res;
659 mp_int px, py, pz, rx2, ry2, rz2;
660 ecfp_aff_pt p;
661 ecfp_chud_pt p2;
662 EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
664 MP_DIGITS(&rx2) = 0;
665 MP_DIGITS(&ry2) = 0;
666 MP_DIGITS(&rz2) = 0;
667 MP_DIGITS(&px) = 0;
668 MP_DIGITS(&py) = 0;
669 MP_DIGITS(&pz) = 0;
671 MP_CHECKOK(mp_init(&rx2));
672 MP_CHECKOK(mp_init(&ry2));
673 MP_CHECKOK(mp_init(&rz2));
674 MP_CHECKOK(mp_init(&px));
675 MP_CHECKOK(mp_init(&py));
676 MP_CHECKOK(mp_init(&pz));
678 /* Set p2 = 2P */
679 ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
680 ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
681 ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);
683 group->pt_dbl_aff2chud(&p, &p2, group);
685 /* Calculate doubling to compare against */
686 MP_CHECKOK(mp_set_int(&pz, 1));
687 ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2,
688 &rz2, ecgroup);
689 ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);
691 /* Do comparison and check az^4 */
692 MP_CHECKOK(testChudPoint(&p2, &rx2, &ry2, ecgroup));
694 CLEANUP:
695 if (res == MP_OKAY)
696 printf(" Test Passed - Point Doubling - Chudnovsky Jacobian\n");
697 else
698 printf("TEST FAILED - Point Doubling - Chudnovsky Jacobian\n");
700 mp_clear(&rx2);
701 mp_clear(&ry2);
702 mp_clear(&rz2);
703 mp_clear(&px);
704 mp_clear(&py);
705 mp_clear(&pz);
707 return res;
710 /* Test point doubling in Jacobian coordinates */
711 mp_err
712 testPointDoubleJac(ECGroup *ecgroup)
714 mp_err res;
715 mp_int pz, rx, ry, rz, rx2, ry2, rz2;
716 ecfp_jac_pt p, p2;
717 EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
719 MP_DIGITS(&pz) = 0;
720 MP_DIGITS(&rx) = 0;
721 MP_DIGITS(&ry) = 0;
722 MP_DIGITS(&rz) = 0;
723 MP_DIGITS(&rx2) = 0;
724 MP_DIGITS(&ry2) = 0;
725 MP_DIGITS(&rz2) = 0;
727 MP_CHECKOK(mp_init(&pz));
728 MP_CHECKOK(mp_init(&rx));
729 MP_CHECKOK(mp_init(&ry));
730 MP_CHECKOK(mp_init(&rz));
731 MP_CHECKOK(mp_init(&rx2));
732 MP_CHECKOK(mp_init(&ry2));
733 MP_CHECKOK(mp_init(&rz2));
735 MP_CHECKOK(mp_set_int(&pz, 5));
737 /* Set p2 = 2P */
738 ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
739 ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
740 ecfp_i2fp(p.z, &pz, ecgroup);
741 ecfp_i2fp(group->curvea, &ecgroup->curvea, ecgroup);
743 group->pt_dbl_jac(&p, &p2, group);
744 M_TimeOperation(group->pt_dbl_jac(&p, &p2, group), 100000);
746 /* Calculate doubling to compare against */
747 ec_GFp_pt_dbl_jac(&ecgroup->genx, &ecgroup->geny, &pz, &rx2, &ry2,
748 &rz2, ecgroup);
749 ec_GFp_pt_jac2aff(&rx2, &ry2, &rz2, &rx2, &ry2, ecgroup);
751 /* Do comparison */
752 MP_CHECKOK(testJacPoint(&p2, &rx2, &ry2, ecgroup));
754 CLEANUP:
755 if (res == MP_OKAY)
756 printf(" Test Passed - Point Doubling - Jacobian\n");
757 else
758 printf("TEST FAILED - Point Doubling - Jacobian\n");
760 mp_clear(&pz);
761 mp_clear(&rx);
762 mp_clear(&ry);
763 mp_clear(&rz);
764 mp_clear(&rx2);
765 mp_clear(&ry2);
766 mp_clear(&rz2);
768 return res;
771 /* Tests a point multiplication (various algorithms) */
772 mp_err
773 testPointMul(ECGroup *ecgroup)
775 mp_err res;
776 char s[1000];
777 mp_int rx, ry, order_1;
779 /* Init */
780 MP_DIGITS(&rx) = 0;
781 MP_DIGITS(&ry) = 0;
782 MP_DIGITS(&order_1) = 0;
784 MP_CHECKOK(mp_init(&rx));
785 MP_CHECKOK(mp_init(&ry));
786 MP_CHECKOK(mp_init(&order_1));
788 MP_CHECKOK(mp_set_int(&order_1, 1));
789 MP_CHECKOK(mp_sub(&ecgroup->order, &order_1, &order_1));
791 /* Test Algorithm 1: Jacobian-Affine Double & Add */
792 ec_GFp_pt_mul_jac_fp(&order_1, &ecgroup->genx, &ecgroup->geny, &rx,
793 &ry, ecgroup);
794 MP_CHECKOK(ecgroup->meth->field_neg(&ry, &ry, ecgroup->meth));
795 if ((mp_cmp(&rx, &ecgroup->genx) != 0)
796 || (mp_cmp(&ry, &ecgroup->geny) != 0)) {
797 printf
798 (" Error: ec_GFp_pt_mul_jac_fp invalid result (expected (- base point)).\n");
799 MP_CHECKOK(mp_toradix(&rx, s, 16));
800 printf("rx %s\n", s);
801 MP_CHECKOK(mp_toradix(&ry, s, 16));
802 printf("ry %s\n", s);
803 res = MP_NO;
804 goto CLEANUP;
807 ec_GFp_pt_mul_jac_fp(&ecgroup->order, &ecgroup->genx, &ecgroup->geny,
808 &rx, &ry, ecgroup);
809 if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
810 printf
811 (" Error: ec_GFp_pt_mul_jac_fp invalid result (expected point at infinity.\n");
812 MP_CHECKOK(mp_toradix(&rx, s, 16));
813 printf("rx %s\n", s);
814 MP_CHECKOK(mp_toradix(&ry, s, 16));
815 printf("ry %s\n", s);
816 res = MP_NO;
817 goto CLEANUP;
820 /* Test Algorithm 2: 4-bit Window in Jacobian */
821 ec_GFp_point_mul_jac_4w_fp(&order_1, &ecgroup->genx, &ecgroup->geny,
822 &rx, &ry, ecgroup);
823 MP_CHECKOK(ecgroup->meth->field_neg(&ry, &ry, ecgroup->meth));
824 if ((mp_cmp(&rx, &ecgroup->genx) != 0)
825 || (mp_cmp(&ry, &ecgroup->geny) != 0)) {
826 printf
827 (" Error: ec_GFp_point_mul_jac_4w_fp invalid result (expected (- base point)).\n");
828 MP_CHECKOK(mp_toradix(&rx, s, 16));
829 printf("rx %s\n", s);
830 MP_CHECKOK(mp_toradix(&ry, s, 16));
831 printf("ry %s\n", s);
832 res = MP_NO;
833 goto CLEANUP;
836 ec_GFp_point_mul_jac_4w_fp(&ecgroup->order, &ecgroup->genx,
837 &ecgroup->geny, &rx, &ry, ecgroup);
838 if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
839 printf
840 (" Error: ec_GFp_point_mul_jac_4w_fp invalid result (expected point at infinity.\n");
841 MP_CHECKOK(mp_toradix(&rx, s, 16));
842 printf("rx %s\n", s);
843 MP_CHECKOK(mp_toradix(&ry, s, 16));
844 printf("ry %s\n", s);
845 res = MP_NO;
846 goto CLEANUP;
849 /* Test Algorithm 3: wNAF with modified Jacobian coordinates */
850 ec_GFp_point_mul_wNAF_fp(&order_1, &ecgroup->genx, &ecgroup->geny, &rx,
851 &ry, ecgroup);
852 MP_CHECKOK(ecgroup->meth->field_neg(&ry, &ry, ecgroup->meth));
853 if ((mp_cmp(&rx, &ecgroup->genx) != 0)
854 || (mp_cmp(&ry, &ecgroup->geny) != 0)) {
855 printf
856 (" Error: ec_GFp_pt_mul_wNAF_fp invalid result (expected (- base point)).\n");
857 MP_CHECKOK(mp_toradix(&rx, s, 16));
858 printf("rx %s\n", s);
859 MP_CHECKOK(mp_toradix(&ry, s, 16));
860 printf("ry %s\n", s);
861 res = MP_NO;
862 goto CLEANUP;
865 ec_GFp_point_mul_wNAF_fp(&ecgroup->order, &ecgroup->genx,
866 &ecgroup->geny, &rx, &ry, ecgroup);
867 if (ec_GFp_pt_is_inf_aff(&rx, &ry) != MP_YES) {
868 printf
869 (" Error: ec_GFp_pt_mul_wNAF_fp invalid result (expected point at infinity.\n");
870 MP_CHECKOK(mp_toradix(&rx, s, 16));
871 printf("rx %s\n", s);
872 MP_CHECKOK(mp_toradix(&ry, s, 16));
873 printf("ry %s\n", s);
874 res = MP_NO;
875 goto CLEANUP;
878 CLEANUP:
879 if (res == MP_OKAY)
880 printf(" Test Passed - Point Multiplication\n");
881 else
882 printf("TEST FAILED - Point Multiplication\n");
883 mp_clear(&rx);
884 mp_clear(&ry);
885 mp_clear(&order_1);
887 return res;
890 /* Tests point multiplication with a random scalar repeatedly, comparing
891 * for consistency within different algorithms. */
892 mp_err
893 testPointMulRandom(ECGroup *ecgroup)
895 mp_err res;
896 mp_int rx, ry, rx2, ry2, n;
897 int i, size;
898 EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
900 MP_DIGITS(&rx) = 0;
901 MP_DIGITS(&ry) = 0;
902 MP_DIGITS(&rx2) = 0;
903 MP_DIGITS(&ry2) = 0;
904 MP_DIGITS(&n) = 0;
906 MP_CHECKOK(mp_init(&rx));
907 MP_CHECKOK(mp_init(&ry));
908 MP_CHECKOK(mp_init(&rx2));
909 MP_CHECKOK(mp_init(&ry2));
910 MP_CHECKOK(mp_init(&n));
912 for (i = 0; i < 100; i++) {
913 /* compute random scalar */
914 size = mpl_significant_bits(&ecgroup->meth->irr);
915 if (size < MP_OKAY) {
916 res = MP_NO;
917 goto CLEANUP;
919 MP_CHECKOK(mpp_random_size(&n, group->orderBitSize));
920 MP_CHECKOK(mp_mod(&n, &ecgroup->order, &n));
922 ec_GFp_pt_mul_jac(&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
923 ecgroup);
924 ec_GFp_pt_mul_jac_fp(&n, &ecgroup->genx, &ecgroup->geny, &rx2,
925 &ry2, ecgroup);
927 if ((mp_cmp(&rx, &rx2) != 0) || (mp_cmp(&ry, &ry2) != 0)) {
928 printf
929 (" Error: different results for Point Multiplication - Double & Add.\n");
930 res = MP_NO;
931 goto CLEANUP;
934 ec_GFp_point_mul_wNAF_fp(&n, &ecgroup->genx, &ecgroup->geny, &rx,
935 &ry, ecgroup);
936 if ((mp_cmp(&rx, &rx2) != 0) || (mp_cmp(&ry, &ry2) != 0)) {
937 printf
938 (" Error: different results for Point Multiplication - wNAF.\n");
939 res = MP_NO;
940 goto CLEANUP;
943 ec_GFp_point_mul_jac_4w_fp(&n, &ecgroup->genx, &ecgroup->geny, &rx,
944 &ry, ecgroup);
945 if ((mp_cmp(&rx, &rx2) != 0) || (mp_cmp(&ry, &ry2) != 0)) {
946 printf
947 (" Error: different results for Point Multiplication - 4 bit window.\n");
948 res = MP_NO;
949 goto CLEANUP;
954 CLEANUP:
955 if (res == MP_OKAY)
956 printf(" Test Passed - Point Random Multiplication\n");
957 else
958 printf("TEST FAILED - Point Random Multiplication\n");
959 mp_clear(&rx);
960 mp_clear(&ry);
961 mp_clear(&rx2);
962 mp_clear(&ry2);
963 mp_clear(&n);
965 return res;
968 /* Tests the time required for a point multiplication */
969 mp_err
970 testPointMulTime(ECGroup *ecgroup)
972 mp_err res = MP_OKAY;
973 mp_int rx, ry, n;
974 int size;
976 MP_DIGITS(&rx) = 0;
977 MP_DIGITS(&ry) = 0;
978 MP_DIGITS(&n) = 0;
980 MP_CHECKOK(mp_init(&rx));
981 MP_CHECKOK(mp_init(&ry));
982 MP_CHECKOK(mp_init(&n));
984 /* compute random scalar */
985 size = mpl_significant_bits(&ecgroup->meth->irr);
986 if (size < MP_OKAY) {
987 res = MP_NO;
988 goto CLEANUP;
991 MP_CHECKOK(mpp_random_size(&n, (size + ECL_BITS - 1) / ECL_BITS));
992 MP_CHECKOK(ecgroup->meth->field_mod(&n, &n, ecgroup->meth));
994 M_TimeOperation(ec_GFp_pt_mul_jac_fp
995 (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
996 ecgroup), 1000);
998 M_TimeOperation(ec_GFp_point_mul_jac_4w_fp
999 (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
1000 ecgroup), 1000);
1002 M_TimeOperation(ec_GFp_point_mul_wNAF_fp
1003 (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
1004 ecgroup), 1000);
1006 M_TimeOperation(ec_GFp_pt_mul_jac
1007 (&n, &ecgroup->genx, &ecgroup->geny, &rx, &ry,
1008 ecgroup), 100);
1010 CLEANUP:
1011 if (res == MP_OKAY)
1012 printf(" Test Passed - Point Multiplication Timing\n");
1013 else
1014 printf("TEST FAILED - Point Multiplication Timing\n");
1015 mp_clear(&rx);
1016 mp_clear(&ry);
1017 mp_clear(&n);
1019 return res;
1022 /* Tests pre computation of Chudnovsky Jacobian points used in wNAF form */
1023 mp_err
1024 testPreCompute(ECGroup *ecgroup)
1026 ecfp_chud_pt precomp[16];
1027 ecfp_aff_pt p;
1028 EC_group_fp *group = (EC_group_fp *) ecgroup->extra1;
1029 int i;
1030 mp_err res;
1032 mp_int x, y, ny, x2, y2;
1034 MP_DIGITS(&x) = 0;
1035 MP_DIGITS(&y) = 0;
1036 MP_DIGITS(&ny) = 0;
1037 MP_DIGITS(&x2) = 0;
1038 MP_DIGITS(&y2) = 0;
1040 MP_CHECKOK(mp_init(&x));
1041 MP_CHECKOK(mp_init(&y));
1042 MP_CHECKOK(mp_init(&ny));
1043 MP_CHECKOK(mp_init(&x2));
1044 MP_CHECKOK(mp_init(&y2));
1046 ecfp_i2fp(p.x, &ecgroup->genx, ecgroup);
1047 ecfp_i2fp(p.y, &ecgroup->geny, ecgroup);
1048 ecfp_i2fp(group->curvea, &(ecgroup->curvea), ecgroup);
1050 /* Perform precomputation */
1051 group->precompute_chud(precomp, &p, group);
1053 M_TimeOperation(group->precompute_chud(precomp, &p, group), 10000);
1055 /* Calculate addition to compare against */
1056 MP_CHECKOK(mp_copy(&ecgroup->genx, &x));
1057 MP_CHECKOK(mp_copy(&ecgroup->geny, &y));
1058 MP_CHECKOK(ecgroup->meth->field_neg(&y, &ny, ecgroup->meth));
1060 ec_GFp_pt_dbl_aff(&x, &y, &x2, &y2, ecgroup);
1062 for (i = 0; i < 8; i++) {
1063 MP_CHECKOK(testChudPoint(&precomp[8 + i], &x, &y, ecgroup));
1064 MP_CHECKOK(testChudPoint(&precomp[7 - i], &x, &ny, ecgroup));
1065 ec_GFp_pt_add_aff(&x, &y, &x2, &y2, &x, &y, ecgroup);
1066 MP_CHECKOK(ecgroup->meth->field_neg(&y, &ny, ecgroup->meth));
1069 CLEANUP:
1070 if (res == MP_OKAY)
1071 printf(" Test Passed - Precomputation\n");
1072 else
1073 printf("TEST FAILED - Precomputation\n");
1075 mp_clear(&x);
1076 mp_clear(&y);
1077 mp_clear(&ny);
1078 mp_clear(&x2);
1079 mp_clear(&y2);
1080 return res;
1083 /* Given a curve using floating point arithmetic, test it. This method
1084 * specifies which of the above tests to run. */
1085 mp_err
1086 testCurve(ECGroup *ecgroup)
1088 int res = MP_OKAY;
1090 MP_CHECKOK(testPointAddJacAff(ecgroup));
1091 MP_CHECKOK(testPointAddJac(ecgroup));
1092 MP_CHECKOK(testPointAddChud(ecgroup));
1093 MP_CHECKOK(testPointAddJmChud(ecgroup));
1094 MP_CHECKOK(testPointDoubleJac(ecgroup));
1095 MP_CHECKOK(testPointDoubleChud(ecgroup));
1096 MP_CHECKOK(testPointDoubleJm(ecgroup));
1097 MP_CHECKOK(testPreCompute(ecgroup));
1098 MP_CHECKOK(testPointMul(ecgroup));
1099 MP_CHECKOK(testPointMulRandom(ecgroup));
1100 MP_CHECKOK(testPointMulTime(ecgroup));
1101 CLEANUP:
1102 return res;
1105 /* Tests a number of curves optimized using floating point arithmetic */
1107 main(void)
1109 mp_err res = MP_OKAY;
1110 ECGroup *ecgroup = NULL;
1112 /* specific arithmetic tests */
1113 M_TestCurve("SECG-160R1", ECCurve_SECG_PRIME_160R1);
1114 M_TestCurve("SECG-192R1", ECCurve_SECG_PRIME_192R1);
1115 M_TestCurve("SEGC-224R1", ECCurve_SECG_PRIME_224R1);
1117 CLEANUP:
1118 ECGroup_free(ecgroup);
1119 if (res != MP_OKAY) {
1120 printf("Error: exiting with error value %i\n", res);
1122 return res;