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
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.
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 ***** */
46 #include <sys/resource.h>
48 /* Time k repetitions of operation op. */
49 #define M_TimeOperation(op, k) { \
50 double dStart, dNow, dUserTime; \
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++) { \
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); \
75 MP_CHECKOK( testCurve(ecgroup)); \
76 printf("%s passed.\n", name_c); \
80 /* Outputs a floating point double (currently not used) */
82 d_output(const double *u
, int len
, char *name
, const EC_group_fp
* group
)
87 for (i
= 0; i
< len
; i
++) {
88 printf("+ %.2f * 2^%i ", u
[i
] / ecfp_exp
[i
],
89 group
->doubleBitSize
* i
);
94 /* Tests a point p in Jacobian coordinates, comparing against the
95 * expected affine result (x, y). */
97 testJacPoint(ecfp_jac_pt
* p
, mp_int
*x
, mp_int
*y
, ECGroup
*ecgroup
)
101 mp_err res
= MP_OKAY
;
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));
141 /* Tests a point p in Chudnovsky Jacobian coordinates, comparing against
142 * the expected affine result (x, y). */
144 testChudPoint(ecfp_chud_pt
* p
, mp_int
*x
, mp_int
*y
, ECGroup
*ecgroup
)
148 mp_int rx
, ry
, rz
, rz2
, rz3
, test
;
149 mp_err res
= MP_OKAY
;
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");
180 mp_mulmod(&test
, &rz
, &ecgroup
->meth
->irr
, &test
);
181 if (mp_cmp(&test
, &rz3
) != 0) {
182 printf(" Error: rzp2 not valid\n");
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));
216 /* Tests a point p in Modified Jacobian coordinates, comparing against the
217 * expected affine result (x, y). */
219 testJmPoint(ecfp_jm_pt
* r
, mp_int
*x
, mp_int
*y
, ECGroup
*ecgroup
)
223 mp_int rx
, ry
, rz
, raz4
, test
;
224 mp_err res
= MP_OKAY
;
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));
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
);
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));
288 /* Tests point addition of Jacobian + Affine -> Jacobian */
290 testPointAddJacAff(ECGroup
*ecgroup
)
293 mp_int pz
, rx2
, ry2
, rz2
;
296 EC_group_fp
*group
= (EC_group_fp
*) ecgroup
->extra1
;
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));
311 ecfp_i2fp(p
.x
, &ecgroup
->genx
, ecgroup
);
312 ecfp_i2fp(p
.y
, &ecgroup
->geny
, ecgroup
);
313 ecfp_i2fp(p
.z
, &pz
, ecgroup
);
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
));
332 printf(" Test Passed - Point Addition - Jacobian & Affine\n");
334 printf("TEST FAILED - Point Addition - Jacobian & Affine\n");
344 /* Tests point addition in Jacobian coordinates */
346 testPointAddJac(ECGroup
*ecgroup
)
349 mp_int pz
, qz
, qx
, qy
, rx2
, ry2
, rz2
;
351 EC_group_fp
*group
= (EC_group_fp
*) ecgroup
->extra1
;
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));
373 ecfp_i2fp(p
.x
, &ecgroup
->genx
, ecgroup
);
374 ecfp_i2fp(p
.y
, &ecgroup
->geny
, ecgroup
);
375 ecfp_i2fp(p
.z
, &pz
, ecgroup
);
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
,
387 MP_CHECKOK(ec_GFp_pt_add_jac_aff
388 (&ecgroup
->genx
, &ecgroup
->geny
, &pz
, &qx
, &qy
, &rx2
, &ry2
,
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
));
397 printf(" Test Passed - Point Addition - Jacobian\n");
399 printf("TEST FAILED - Point Addition - Jacobian\n");
412 /* Tests point addition in Chudnovsky Jacobian Coordinates */
414 testPointAddChud(ECGroup
*ecgroup
)
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
;
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 */
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
);
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
,
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
));
477 printf(" Test Passed - Point Addition - Chudnovsky Jacobian\n");
479 printf("TEST FAILED - Point Addition - Chudnovsky Jacobian\n");
495 /* Tests point addition in Modified Jacobian + Chudnovsky Jacobian ->
496 * Modified Jacobian coordinates. */
498 testPointAddJmChud(ECGroup
*ecgroup
)
501 mp_int rx2
, ry2
, ix
, iy
, iz
, test
, pz
, paz4
, qx
, qy
, qz
;
504 EC_group_fp
*group
= (EC_group_fp
*) ecgroup
->extra1
;
510 MP_DIGITS(&paz4
) = 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 */
533 ecfp_i2fp(p
.x
, &ecgroup
->genx
, ecgroup
);
534 ecfp_i2fp(p
.y
, &ecgroup
->geny
, ecgroup
);
535 ecfp_i2fp(group
->curvea
, &ecgroup
->curvea
, ecgroup
);
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
);
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
);
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
,
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
));
569 (" Test Passed - Point Addition - Modified & Chudnovsky Jacobian\n");
572 ("TEST FAILED - Point Addition - Modified & Chudnovsky Jacobian\n");
589 /* Tests point doubling in Modified Jacobian coordinates */
591 testPointDoubleJm(ECGroup
*ecgroup
)
594 mp_int pz
, paz4
, rx2
, ry2
, rz2
, raz4
;
596 EC_group_fp
*group
= (EC_group_fp
*) ecgroup
->extra1
;
599 MP_DIGITS(&paz4
) = 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
));
613 ecfp_i2fp(p
.x
, &ecgroup
->genx
, ecgroup
);
614 ecfp_i2fp(p
.y
, &ecgroup
->geny
, ecgroup
);
615 ecfp_i2fp(group
->curvea
, &ecgroup
->curvea
, ecgroup
);
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
,
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
));
640 printf(" Test Passed - Point Doubling - Modified Jacobian\n");
642 printf("TEST FAILED - Point Doubling - Modified Jacobian\n");
654 /* Tests point doubling in Chudnovsky Jacobian coordinates */
656 testPointDoubleChud(ECGroup
*ecgroup
)
659 mp_int px
, py
, pz
, rx2
, ry2
, rz2
;
662 EC_group_fp
*group
= (EC_group_fp
*) ecgroup
->extra1
;
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
));
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
,
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
));
696 printf(" Test Passed - Point Doubling - Chudnovsky Jacobian\n");
698 printf("TEST FAILED - Point Doubling - Chudnovsky Jacobian\n");
710 /* Test point doubling in Jacobian coordinates */
712 testPointDoubleJac(ECGroup
*ecgroup
)
715 mp_int pz
, rx
, ry
, rz
, rx2
, ry2
, rz2
;
717 EC_group_fp
*group
= (EC_group_fp
*) ecgroup
->extra1
;
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));
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
,
749 ec_GFp_pt_jac2aff(&rx2
, &ry2
, &rz2
, &rx2
, &ry2
, ecgroup
);
752 MP_CHECKOK(testJacPoint(&p2
, &rx2
, &ry2
, ecgroup
));
756 printf(" Test Passed - Point Doubling - Jacobian\n");
758 printf("TEST FAILED - Point Doubling - Jacobian\n");
771 /* Tests a point multiplication (various algorithms) */
773 testPointMul(ECGroup
*ecgroup
)
777 mp_int rx
, ry
, order_1
;
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
,
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)) {
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
);
807 ec_GFp_pt_mul_jac_fp(&ecgroup
->order
, &ecgroup
->genx
, &ecgroup
->geny
,
809 if (ec_GFp_pt_is_inf_aff(&rx
, &ry
) != MP_YES
) {
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
);
820 /* Test Algorithm 2: 4-bit Window in Jacobian */
821 ec_GFp_point_mul_jac_4w_fp(&order_1
, &ecgroup
->genx
, &ecgroup
->geny
,
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)) {
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
);
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
) {
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
);
849 /* Test Algorithm 3: wNAF with modified Jacobian coordinates */
850 ec_GFp_point_mul_wNAF_fp(&order_1
, &ecgroup
->genx
, &ecgroup
->geny
, &rx
,
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)) {
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
);
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
) {
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
);
880 printf(" Test Passed - Point Multiplication\n");
882 printf("TEST FAILED - Point Multiplication\n");
890 /* Tests point multiplication with a random scalar repeatedly, comparing
891 * for consistency within different algorithms. */
893 testPointMulRandom(ECGroup
*ecgroup
)
896 mp_int rx
, ry
, rx2
, ry2
, n
;
898 EC_group_fp
*group
= (EC_group_fp
*) ecgroup
->extra1
;
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
) {
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
,
924 ec_GFp_pt_mul_jac_fp(&n
, &ecgroup
->genx
, &ecgroup
->geny
, &rx2
,
927 if ((mp_cmp(&rx
, &rx2
) != 0) || (mp_cmp(&ry
, &ry2
) != 0)) {
929 (" Error: different results for Point Multiplication - Double & Add.\n");
934 ec_GFp_point_mul_wNAF_fp(&n
, &ecgroup
->genx
, &ecgroup
->geny
, &rx
,
936 if ((mp_cmp(&rx
, &rx2
) != 0) || (mp_cmp(&ry
, &ry2
) != 0)) {
938 (" Error: different results for Point Multiplication - wNAF.\n");
943 ec_GFp_point_mul_jac_4w_fp(&n
, &ecgroup
->genx
, &ecgroup
->geny
, &rx
,
945 if ((mp_cmp(&rx
, &rx2
) != 0) || (mp_cmp(&ry
, &ry2
) != 0)) {
947 (" Error: different results for Point Multiplication - 4 bit window.\n");
956 printf(" Test Passed - Point Random Multiplication\n");
958 printf("TEST FAILED - Point Random Multiplication\n");
968 /* Tests the time required for a point multiplication */
970 testPointMulTime(ECGroup
*ecgroup
)
972 mp_err res
= MP_OKAY
;
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
) {
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
,
998 M_TimeOperation(ec_GFp_point_mul_jac_4w_fp
999 (&n
, &ecgroup
->genx
, &ecgroup
->geny
, &rx
, &ry
,
1002 M_TimeOperation(ec_GFp_point_mul_wNAF_fp
1003 (&n
, &ecgroup
->genx
, &ecgroup
->geny
, &rx
, &ry
,
1006 M_TimeOperation(ec_GFp_pt_mul_jac
1007 (&n
, &ecgroup
->genx
, &ecgroup
->geny
, &rx
, &ry
,
1012 printf(" Test Passed - Point Multiplication Timing\n");
1014 printf("TEST FAILED - Point Multiplication Timing\n");
1022 /* Tests pre computation of Chudnovsky Jacobian points used in wNAF form */
1024 testPreCompute(ECGroup
*ecgroup
)
1026 ecfp_chud_pt precomp
[16];
1028 EC_group_fp
*group
= (EC_group_fp
*) ecgroup
->extra1
;
1032 mp_int x
, y
, ny
, x2
, y2
;
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
));
1071 printf(" Test Passed - Precomputation\n");
1073 printf("TEST FAILED - Precomputation\n");
1083 /* Given a curve using floating point arithmetic, test it. This method
1084 * specifies which of the above tests to run. */
1086 testCurve(ECGroup
*ecgroup
)
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
));
1105 /* Tests a number of curves optimized using floating point arithmetic */
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
);
1118 ECGroup_free(ecgroup
);
1119 if (res
!= MP_OKAY
) {
1120 printf("Error: exiting with error value %i\n", res
);