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);