1 /* Copyright (c) 1998 Apple Computer, Inc. All rights reserved.
3 * NOTICE: USE OF THE MATERIALS ACCOMPANYING THIS NOTICE IS SUBJECT
4 * TO THE TERMS OF THE SIGNED "FAST ELLIPTIC ENCRYPTION (FEE) REFERENCE
5 * SOURCE CODE EVALUATION AGREEMENT" BETWEEN APPLE COMPUTER, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE COMPUTER,
7 * INC. ANY USE OF THESE MATERIALS NOT PERMITTED BY SUCH AGREEMENT WILL
8 * EXPOSE YOU TO LIABILITY.
9 ***************************************************************************
11 elliptic.c - Library for Apple-proprietary Fast Elliptic
12 Encryption. The algebra in this module ignores elliptic point's
17 FEE is patented, U.S. Patents #5159632 (1992), #5271061 (1993),
18 #5463690 (1994). These patents are implemented
19 in various elliptic algebra functions such as
20 numer/denom_plus/times(), and in the fact of special
21 forms for primes: p = 2^q-k.
23 Digital signature using fast elliptic addition, in
24 U. S. Patent #5581616 (1996), is implemented in the
25 signature_compare() function.
27 FEED (Fast Elliptic Encryption) is patent pending (as of Jan 1998).
28 Various functions such as elliptic_add() implement the patent ideas.
31 Modification history since the U.S. Patent:
32 -------------------------------------------
34 Changed to compile with C++.
35 9 Sep 98 Doug Mitchell at Apple
36 cp->curveType optimizations.
37 Removed code which handled "unknown" curve orders.
38 elliptic() now exported for timing measurements.
39 21 Apr 98 Doug Mitchell at Apple
40 Used inline platform-dependent giant arithmetic.
41 20 Jan 98 Doug Mitchell at Apple
42 feemod now handles PT_MERSENNE, PT_FEE, PT_GENERAL.
43 Added calcGiantSizes(), rewrote giantMinBytes(), giantMaxShorts().
44 Updated heading comments on FEE curve algebra.
45 11 Jan 98 Doug Mitchell and Richard Crandall at Apple
46 Microscopic feemod optimization.
47 10 Jan 98 Doug Mitchell and Richard Crandall at Apple
48 ell_odd, ell_even() Montgomery optimization.
49 09 Jan 98 Doug Mitchell and Richard Crandall at Apple
50 ell_odd, ell_even() Atkin3 optimization.
51 08 Jan 97 Doug Mitchell at Apple
52 Cleaned up some debugging code; added gsquareTime
53 11 Jun 97 Doug Mitchell and Richard Crandall at Apple
54 Mods for modg_via_recip(), divg_via_recip() math
55 Deleted a lot of obsolete code (previously ifdef'd out)
56 Added lesserX1OrderJustify(), x1OrderPlusJustify()
57 Added binvg_cp(), avoiding general modg in favor of feemod
58 05 Feb 97 Doug Mitchell and Richard Crandall at Apple
59 New optimized numer_plus(), denom_double(), and numer_times()
60 All calls to borrowGiant() and newGiant have explicit giant size
61 08 Jan 97 Doug Mitchell and Richard Crandall at NeXT
62 Major mods to accomodate IEEE-style curve parameters.
63 New functions feepowermodg() and curveOrderJustify();
64 elliptic_add(), elliptic(), signature_compare(), and
65 which_curve() completely rewritten.
66 19 Dec 96 Doug Mitchell at NeXT
67 Added mersennePrimes[24..26]
68 08 Aug 96 Doug Mitchell at NeXT
69 Fixed giant leak in elliptic_add()
70 05 Aug 96 Doug Mitchell at NeXT
72 24 Jul 96 Doug Mitchell at NeXT
73 Added ENGINE_127_BITS dependency for use of security engine
74 24 Oct 92 Richard Crandall at NeXT
75 Modified new_public_from_private()
76 1991 Richard Crandall at NeXT
80 FEE curve algebra, Jan 1997.
84 y^2 = x^3 + c x^2 + a x + b
86 where useful parameterizations for practical purposes are:
88 Montgomery: a = 1, b = 0. (The original 1991 FEE system.)
89 Weierstrass: c = 0. (The basic IEEE form.)
93 However, the code is set up to work with any a, b, c.
94 The underlying fields F_{p^m} are of odd characteristic,
95 with all operations are (mod p). The special FEE-class
96 primes p are of the form:
98 p = 2^q - k = 3 (mod 4)
100 where k is single-precision. For such p, the mod operations
101 are especially fast (asymptotically vanishing time with respect
102 to a multiply). Note that the whole system
103 works equally well (except for slower execution) for arbitrary
104 primes p = 3 (mod 4) of the same bit length (q or q+1).
106 The elliptic arithmetic now proceeds on the basis of
107 five fundamental operations that calculate various
108 numerator/denominator parts of the elliptic terms:
110 numer_double(giant x, giant z, giant res, curveParams *par)
111 res := (x^2 - a z^2)^2 - 4 b (2 x + c z) z^3.
113 numer_plus(giant x1, giant x2, giant res, curveParams *par)
114 res = (x1 x2 + a)(x1 + x2) + 2(c x1 x2 + b).
116 denom_double(giant x, giant z, giant res, curveParams *par)
117 res = 4 z (x^3 + c x^2 z + a x z^2 + b z^3).
119 denom_times(giant x1, giant z1, giant x2, giant z2, giant res,
121 res := (x1 z2 - x2 z1)^2
123 numer_times(giant x1, giant z1, giant x2, giant z2, giant res,
125 res := (x1 x2 - a z1 z2)^2 - 4 b(x1 z2 + x2 z1 + c z1 z2) z1 z2
127 If x(+-) represent the sum and difference x-coordinates
128 respectively, then, in pseudocode,
130 For unequal starting coords:
131 x(+) + x(-) = U = 2 numer_plus/denom_times
132 x(+) x(-) = V = numer_times/denom_times
134 and for equal starting coords:
135 x(+) = numer_double/denom_double
137 The elliptic_add() function uses the fact that
139 x(+) = U/2 + s*Sqrt[U^2/4 - V]
141 where the sign s = +-1.
145 #include "ckconfig.h"
149 #include "platform.h"
151 #include "giantIntegers.h"
152 #include "elliptic.h"
153 #include "ellipticProj.h"
154 #include "ckutilities.h"
155 #include "curveParams.h"
156 #include "feeDebug.h"
157 #include "ellipticMeasure.h"
159 #include "giantPortCommon.h"
163 unsigned numerDoubleTime
;
164 unsigned numerPlusTime
;
165 unsigned numerTimesTime
;
166 unsigned denomDoubleTime
;
167 unsigned denomTimesTime
;
168 unsigned ellipticTime
;
169 unsigned sigCompTime
;
170 unsigned powerModTime
;
172 unsigned whichCurveTime
;
175 unsigned binvauxTime
;
176 unsigned gsquareTime
;
205 #endif // FEE_PROFILE
209 unsigned ellEvenTime
;
211 unsigned numEllEvens
;
213 void clearEllProfile()
221 #endif /* ELL_PROFILE */
224 int doEllMeasure
; // gather stats on/off */
231 printf("\nbitlen(n) : %d\n", bitsInN
);
232 printf("feemods : %d\n", numFeeMods
);
233 printf("mulgs : %d\n", numMulgs
);
236 #endif // ELLIPTIC_MEASURE
238 /********** Globals ********************************/
240 static void make_base(curveParams
*par
, giant result
); // result = with 2^q-k
241 static int keys_inconsistent(key pub1
, key pub2
);
242 /* Return non-zero if pub1, pub2 have inconsistent parameters.
246 static void ell_even(giant x1
, giant z1
, giant x2
, giant z2
, curveParams
*par
);
247 static void ell_odd(giant x1
, giant z1
, giant x2
, giant z2
, giant xxor
,
248 giant zor
, curveParams
*par
);
249 static void numer_double(giant x
, giant z
, giant res
, curveParams
*par
);
250 static void numer_plus(giant x1
, giant x2
, giant res
, curveParams
*par
);
251 static void denom_double(giant x
, giant z
, giant res
, curveParams
*par
);
252 static void denom_times(giant x1
, giant z1
, giant x2
, giant z2
, giant res
,
254 static void numer_times(giant x1
, giant z1
, giant x2
, giant z2
, giant res
,
256 static void feepowermodg(curveParams
*par
, giant x
, giant n
);
257 static void curveOrderJustifyWithRecip(giant g
, giant curveOrder
, giant recip
);
260 * Completely rewritten in CryptKit-18, 13 Jan 1997, for new IEEE-style
263 int which_curve(giant x
, curveParams
*par
)
264 /* Returns (+-1) depending on whether x is on curve
265 (+-)y^2 = x^3 + c x^2 + a x + b.
274 t1
= borrowGiant(par
->maxDigits
);
275 t2
= borrowGiant(par
->maxDigits
);
276 t3
= borrowGiant(par
->maxDigits
);
278 /* First, set t2:= x^3 + c x^2 + a x + b. */
279 gtog(x
, t2
); addg(par
->c
, t2
);
280 mulg(x
, t2
); addg(par
->a
, t2
); /* t2 := x^2 + c x + a. */
282 mulg(x
, t2
); addg(par
->b
, t2
);
284 /* Next, test whether t2 is a square. */
286 make_base(par
, t3
); iaddg(1, t3
); gshiftright(1, t3
); /* t3 = (p+1)/2. */
287 feepowermodg(par
, t1
, t3
); /* t1 := t2^((p+1)/2) (mod p). */
288 if(gcompg(t1
, t2
) == 0)
291 result
= CURVE_MINUS
;
295 PROF_END(whichCurveTime
);
299 key
new_public(curveParams
*cp
, int twist
) {
302 k
= (key
) fmalloc(sizeof(keystruct
));
306 k
->x
= newGiant(cp
->maxDigits
);
307 if((twist
== CURVE_PLUS
) && (cp
->curveType
== FCT_Weierstrass
)) {
308 k
->y
= newGiant(cp
->maxDigits
);
312 * no projective algebra. We could optimize and save a few bytes
313 * here by setting y to NULL, but that really complicates things
314 * in may other places. Best to have a real giant.
321 key
new_public_with_key(key old_key
, curveParams
*cp
)
325 result
= new_public(cp
, old_key
->twist
);
326 CKASSERT((old_key
->x
!= NULL
) && (old_key
->y
!= NULL
));
327 CKASSERT((result
->x
!= NULL
) && (result
->y
!= NULL
));
328 gtog(old_key
->x
, result
->x
);
329 gtog(old_key
->y
, result
->y
);
333 void free_key(key pub
) {
347 * Specify private data for key created by new_public().
350 void set_priv_key_giant(key k
, giant privGiant
)
352 curveParams
*cp
= k
->cp
;
354 /* elliptiy multiply of initial public point times private key */
355 #if CRYPTKIT_ELL_PROJ_ENABLE
356 if((k
->twist
== CURVE_PLUS
) && (cp
->curveType
== FCT_Weierstrass
)) {
359 pointProj pt1
= newPointProj(cp
->maxDigits
);
361 CKASSERT((cp
->y1Plus
!= NULL
) && (!isZero(cp
->y1Plus
)));
362 CKASSERT(k
->y
!= NULL
);
364 /* pt1 := {x1Plus, y1Plus, 1} */
365 gtog(cp
->x1Plus
, pt1
->x
);
366 gtog(cp
->y1Plus
, pt1
->y
);
367 int_to_giant(1, pt1
->z
);
369 /* pt1 := pt1 * privateKey */
370 ellMulProjSimple(pt1
, privGiant
, cp
);
372 /* result back to {k->x, k->y} */
375 freePointProj(pt1
); // FIXME - clear the giants
380 #endif /* CRYPTKIT_ELL_PROJ_ENABLE */
382 if(k
->twist
== CURVE_PLUS
) {
383 gtog(cp
->x1Plus
, k
->x
);
386 gtog(cp
->x1Minus
, k
->x
);
388 elliptic_simple(k
->x
, privGiant
, k
->cp
);
392 int key_equal(key one
, key two
) {
393 if (keys_inconsistent(one
, two
)) return 0;
394 return !gcompg(one
->x
, two
->x
);
397 static void make_base(curveParams
*par
, giant result
)
398 /* Jams result with 2^q-k. */
400 gtog(par
->basePrime
, result
);
403 void make_base_prim(curveParams
*cp
)
404 /* Jams cp->basePrime with 2^q-k. Assumes valid maxDigits, q, k. */
406 giant tmp
= borrowGiant(cp
->maxDigits
);
408 CKASSERT(cp
->primeType
!= FPT_General
);
409 int_to_giant(1, cp
->basePrime
);
410 gshiftleft((int)cp
->q
, cp
->basePrime
);
411 int_to_giant(cp
->k
, tmp
);
412 subg(tmp
, cp
->basePrime
);
416 static int sequalg(int n
, giant g
) {
417 if((g
->sign
== 1) && (g
->n
[0] == n
)) return(1);
423 * Elliptic multiply: x := n * {x, 1}
425 void elliptic_simple(giant x
, giant n
, curveParams
*par
) {
426 giant ztmp
= borrowGiant(par
->maxDigits
);
427 giant cur_n
= borrowGiant(par
->maxDigits
);
429 START_ELL_MEASURE(n
);
430 int_to_giant(1, ztmp
);
431 elliptic(x
, ztmp
, n
, par
);
442 * General elliptic multiply.
444 * {xx, zz} := k * {xx, zz}
446 void elliptic(giant xx
, giant zz
, giant k
, curveParams
*par
) {
455 if(sequalg(1,k
)) return;
457 ell_even(xx
, zz
, xx
, zz
, par
);
460 zs
= borrowGiant(par
->maxDigits
);
461 xs
= borrowGiant(par
->maxDigits
);
462 zorg
= borrowGiant(par
->maxDigits
);
463 xorg
= borrowGiant(par
->maxDigits
);
464 gtog(xx
, xorg
); gtog(zz
, zorg
);
465 ell_even(xx
, zz
, xs
, zs
, par
);
467 if(bitval(k
, pos
--)) {
468 ell_odd(xs
, zs
, xx
, zz
, xorg
, zorg
, par
);
469 ell_even(xs
, zs
, xs
, zs
, par
);
471 ell_odd(xx
, zz
, xs
, zs
, xorg
, zorg
, par
);
472 ell_even(xx
, zz
, xx
, zz
, par
);
474 } while (pos
>= 0); // REC fix 9/23/94
480 PROF_END(ellipticTime
);
484 * Completely rewritten in CryptKit-18, 13 Jan 1997, for new IEEE-style
487 void elliptic_add(giant x1
, giant x2
, giant x3
, curveParams
*par
, int s
) {
489 /* Addition algorithm for x3 = x1 + x2 on the curve, with sign ambiguity s.
490 From theory, we know that if {x1,1} and {x2,1} are on a curve, then
491 their elliptic sum (x1,1} + {x2,1} = {x3,1} must have x3 as one of two
494 x3 = U/2 + s*Sqrt[U^2/4 - V]
496 where sign s = +-1, and U,V are functions of x1,x2. Tho present function
497 is called a maximum of twice, to settle which of +- is s. When a call
498 is made, it is guaranteed already that x1, x2 both lie on the same curve
499 (+- curve); i.e., which curve (+-) is not connected at all with sign s of
511 cur_n
= borrowGiant(par
->maxDigits
);
512 t1
= borrowGiant(par
->maxDigits
);
513 t2
= borrowGiant(par
->maxDigits
);
514 t3
= borrowGiant(par
->maxDigits
);
515 t4
= borrowGiant(par
->maxDigits
);
516 t5
= borrowGiant(par
->maxDigits
);
518 if(gcompg(x1
, x2
)==0) {
520 numer_double(x1
, t1
, x3
, par
);
521 denom_double(x1
, t1
, t2
, par
);
523 mulg(t2
, x3
); feemod(par
, x3
);
526 numer_plus(x1
, x2
, t1
, par
);
528 numer_times(x1
, t3
, x2
, t3
, t2
, par
);
529 int_to_giant(1, t4
); int_to_giant(1, t5
);
530 denom_times(x1
, t4
, x2
, t5
, t3
, par
);
532 mulg(t3
, t1
); feemod(par
, t1
); /* t1 := U/2. */
533 mulg(t3
, t2
); feemod(par
, t2
); /* t2 := V. */
534 /* Now x3 will be t1 +- Sqrt[t1^2 - t2]. */
535 gtog(t1
, t4
); gsquare(t4
); feemod(par
, t4
);
537 make_base(par
, cur_n
); iaddg(1, cur_n
); gshiftright(2, cur_n
);
538 /* cur_n := (p+1)/4. */
539 feepowermodg(par
, t4
, cur_n
); /* t4 := t2^((p+1)/4) (mod p). */
541 if(s
!= SIGN_PLUS
) negg(t4
);
553 PROF_END(ellAddTime
);
559 giant
make_pad(giant privGiant
, key publicKey
) {
560 curveParams
*par
= publicKey
->cp
;
561 giant result
= newGiant(par
->maxDigits
);
563 gtog(publicKey
->x
, result
);
564 elliptic_simple(result
, privGiant
, par
);
568 static void ell_even(giant x1
, giant z1
, giant x2
, giant z2
, curveParams
*par
) {
575 t1
= borrowGiant(par
->maxDigits
);
576 t2
= borrowGiant(par
->maxDigits
);
577 t3
= borrowGiant(par
->maxDigits
);
579 if(par
->curveType
== FCT_Montgomery
) {
580 /* Begin Montgomery OPT: 10 Jan 98 REC. */
581 gtog(x1
, t1
); gsquare(t1
); feemod(par
, t1
); /* t1 := x1^2. */
582 gtog(z1
, t2
); gsquare(t2
); feemod(par
, t2
); /* t2 := z1^2. */
584 gtog(x1
, t3
); mulg(z1
, t3
); feemod(par
, t3
);
585 gtog(t3
, z2
); mulg(par
->c
, z2
); feemod(par
, z2
);
586 addg(t1
, z2
); addg(t2
, z2
); mulg(t3
, z2
); gshiftleft(2, z2
);
587 feemod(par
, z2
); /* z2 := 4 x1 z1 (x1^2 + c x1 z1 + z1^2). */
588 gtog(t1
, x2
); subg(t2
, x2
); gsquare(x2
); feemod(par
, x2
);
589 /* x2 := (x1^2 - z1^2)^2. */
590 /* End OPT: 10 Jan 98 REC. */
592 else if((par
->curveType
== FCT_Weierstrass
) && isZero(par
->a
)) {
593 /* Begin Atkin3 OPT: 9 Jan 98 REC. */
595 gsquare(t1
); feemod(par
, t1
);
596 mulg(x1
, t1
); feemod(par
, t1
); /* t1 := x^3. */
598 gsquare(t2
); feemod(par
, t2
);
599 mulg(z1
, t2
); feemod(par
, t2
); /* t2 := z1^3 */
600 mulg(par
->b
, t2
); feemod(par
, t2
); /* t2 := b z1^3. */
601 gtog(t1
, t3
); addg(t2
, t3
); /* t3 := x^3 + b z1^3 */
602 mulg(z1
, t3
); feemod(par
, t3
); /* t3 *= z1
603 * = z1 ( x^3 + b z1^3 ) */
604 gshiftleft(2, t3
); feemod(par
, t3
); /* t3 = 4 z1 (x1^3 + b z1^3) */
606 gshiftleft(3, t2
); /* t2 = 8 b z1^3 */
607 subg(t2
, t1
); /* t1 = x^3 - 8 b z1^3 */
608 mulg(x1
, t1
); feemod(par
, t1
); /* t1 = x1 (x1^3 - 8 b z1^3) */
612 /* End OPT: 9 Jan 98 REC. */
615 numer_double(x1
, z1
, t1
, par
);
616 denom_double(x1
, z1
, t2
, par
);
617 gtog(t1
, x2
); gtog(t2
, z2
);
623 EPROF_END(ellEvenTime
);
624 EPROF_INCR(numEllEvens
);
627 printf("ell_even end\n");
628 printf(" x1 : "); printGiant(x1);
629 printf(" z1 : "); printGiant(z1);
630 printf(" x2 : "); printGiant(x2);
631 printf(" z2 : "); printGiant(z2);
635 static void ell_odd(giant x1
, giant z1
, giant x2
, giant z2
, giant xxor
,
636 giant zor
, curveParams
*par
)
643 t1
= borrowGiant(par
->maxDigits
);
644 t2
= borrowGiant(par
->maxDigits
);
646 if(par
->curveType
== FCT_Montgomery
) {
647 /* Begin Montgomery OPT: 10 Jan 98 REC. */
648 giant t3
= borrowGiant(par
->maxDigits
);
649 giant t4
= borrowGiant(par
->maxDigits
);
651 gtog(x1
, t1
); addg(z1
, t1
); /* t1 := x1 + z1. */
652 gtog(x2
, t2
); subg(z2
, t2
); /* t2 := x2 - z2. */
653 gtog(x1
, t3
); subg(z1
, t3
); /* t3 := x1 - z1. */
654 gtog(x2
, t4
); addg(z2
, t4
); /* t4 := x2 + z2. */
655 mulg(t2
, t1
); feemod(par
, t1
); /* t1 := (x1 + z1)(x2 - z2) */
656 mulg(t4
, t3
); feemod(par
, t3
); /* t4 := (x2 + z2)(x1 - z1) */
657 gtog(t1
, z2
); subg(t3
, z2
); /*???gshiftright(1, z2);*/
658 /* z2 := ((x1 + z1)(x2 - z2) - x2)/2 */
659 gsquare(z2
); feemod(par
, z2
);
660 mulg(xxor
, z2
); feemod(par
, z2
);
661 gtog(t1
, x2
); addg(t3
, x2
); /*????gshiftright(1, x2);*/
662 gsquare(x2
); feemod(par
, x2
);
663 mulg(zor
, x2
); feemod(par
, x2
);
668 else if((par
->curveType
== FCT_Weierstrass
) && isZero(par
->a
)) {
669 /* Begin Atkin3 OPT: 9 Jan 98 REC. */
671 giant t3
= borrowGiant(par
->maxDigits
);
672 giant t4
= borrowGiant(par
->maxDigits
);
674 gtog(x1
, t1
); mulg(x2
, t1
); feemod(par
, t1
); /* t1 := x1 x2. */
675 gtog(z1
, t2
); mulg(z2
, t2
); feemod(par
, t2
); /* t2 := z1 z2. */
676 gtog(x1
, t3
); mulg(z2
, t3
); feemod(par
, t3
); /* t3 := x1 z2. */
677 gtog(z1
, t4
); mulg(x2
, t4
); feemod(par
, t4
); /* t4 := x2 z1. */
678 gtog(t3
, z2
); subg(t4
, z2
); gsquare(z2
); feemod(par
, z2
);
679 mulg(xxor
, z2
); feemod(par
, z2
);
680 gtog(t1
, x2
); gsquare(x2
); feemod(par
, x2
);
681 addg(t4
, t3
); mulg(t2
, t3
); feemod(par
, t3
);
682 mulg(par
->b
, t3
); feemod(par
, t3
);
683 addg(t3
, t3
); addg(t3
, t3
);
684 subg(t3
, x2
); mulg(zor
, x2
); feemod(par
, x2
);
688 /* End OPT: 9 Jan 98 REC. */
691 numer_times(x1
, z1
, x2
, z2
, t1
, par
);
692 mulg(zor
, t1
); feemod(par
, t1
);
693 denom_times(x1
, z1
, x2
, z2
, t2
, par
);
694 mulg(xxor
, t2
); feemod(par
, t2
);
696 gtog(t1
, x2
); gtog(t2
, z2
);
702 EPROF_END(ellOddTime
);
703 EPROF_INCR(numEllOdds
);
706 printf("ell_odd end\n");
707 printf(" x2 : "); printGiant(x2);
708 printf(" z2 : "); printGiant(z2);
713 * return codes from keys_inconsistent() and signature_compare(). The actual
714 * values are not public; they are defined here for debugging.
716 #define CURVE_PARAM_MISMATCH 1
717 #define TWIST_PARAM_MISMATCH 2
718 #define SIGNATURE_INVALID 3
722 * Determine whether two keystructs have compatible parameters (i.e., same
723 * twist and curveParams). Return 0 if compatible, else non-zero.
725 static int keys_inconsistent(key pub1
, key pub2
){
726 if(!curveParamsEquivalent(pub1
->cp
, pub2
->cp
)) {
727 return CURVE_PARAM_MISMATCH
;
729 if(pub1
->twist
!= pub2
->twist
) {
730 return TWIST_PARAM_MISMATCH
;
735 int signature_compare(giant p0x
, giant p1x
, giant p2x
, curveParams
*par
)
736 /* Returns non-zero iff p0x cannot be the x-coordinate of the sum of two points whose respective x-coordinates are p1x, p2x. */
747 t1
= borrowGiant(par
->maxDigits
);
748 t2
= borrowGiant(par
->maxDigits
);
749 t3
= borrowGiant(par
->maxDigits
);
750 t4
= borrowGiant(par
->maxDigits
);
751 t5
= borrowGiant(par
->maxDigits
);
753 if(gcompg(p1x
, p2x
) == 0) {
755 numer_double(p1x
, t1
, t2
, par
);
756 denom_double(p1x
, t1
, t3
, par
);
757 mulg(p0x
, t3
); subg(t3
, t2
);
760 numer_plus(p1x
, p2x
, t1
, par
);
761 gshiftleft(1, t1
); feemod(par
, t1
);
763 numer_times(p1x
, t3
, p2x
, t3
, t2
, par
);
764 int_to_giant(1, t4
); int_to_giant(1, t5
);
765 denom_times(p1x
, t4
, p2x
, t5
, t3
, par
);
766 /* Now we require t3 x0^2 - t1 x0 + t2 == 0. */
767 mulg(p0x
, t3
); feemod(par
, t3
);
768 subg(t1
, t3
); mulg(p0x
, t3
);
774 if(!isZero(t2
)) ret
= SIGNATURE_INVALID
;
780 PROF_END(sigCompTime
);
785 static void numer_double(giant x
, giant z
, giant res
, curveParams
*par
)
786 /* Numerator algebra.
787 res := (x^2 - a z^2)^2 - 4 b (2 x + c z) z^3.
794 t1
= borrowGiant(par
->maxDigits
);
795 t2
= borrowGiant(par
->maxDigits
);
797 gtog(x
, t1
); gsquare(t1
); feemod(par
, t1
);
798 gtog(z
, res
); gsquare(res
); feemod(par
, res
);
800 if(!isZero(par
->a
) ) {
801 if(!isone(par
->a
)) { /* Speedup - REC 17 Jan 1997. */
802 mulg(par
->a
, res
); feemod(par
, res
);
804 subg(res
, t1
); feemod(par
, t1
);
806 gsquare(t1
); feemod(par
, t1
);
807 /* t1 := (x^2 - a z^2)^2. */
808 if(isZero(par
->b
)) { /* Speedup - REC 17 Jan 1997. */
812 if(par
->curveType
!= FCT_Weierstrass
) { // i.e., !isZero(par->c)
813 // Speedup - REC 17 Jan 1997.
814 gtog(z
, res
); mulg(par
->c
, res
); feemod(par
, res
);
816 int_to_giant(0, res
);
818 addg(x
, res
); addg(x
, res
); mulg(par
->b
, res
);
820 gshiftleft(2, res
); mulg(z
, res
); feemod(par
, res
);
821 mulg(t2
, res
); feemod(par
, res
);
822 negg(res
); addg(t1
, res
);
828 PROF_END(numerDoubleTime
);
831 static void numer_plus(giant x1
, giant x2
, giant res
, curveParams
*par
)
832 /* Numerator algebra.
833 res = (x1 x2 + a)(x1 + x2) + 2(c x1 x2 + b).
840 t1
= borrowGiant(par
->maxDigits
);
841 t2
= borrowGiant(par
->maxDigits
);
843 gtog(x1
, t1
); mulg(x2
, t1
); feemod(par
, t1
);
844 gtog(x2
, t2
); addg(x1
, t2
); feemod(par
, t2
);
848 mulg(t2
, res
); feemod(par
, res
);
849 if(par
->curveType
== FCT_Weierstrass
) { // i.e., isZero(par->c)
853 mulg(par
->c
, t1
); feemod(par
, t1
);
858 addg(t1
, res
); feemod(par
, res
);
862 PROF_END(numerPlusTime
);
865 static void denom_double(giant x
, giant z
, giant res
, curveParams
*par
)
866 /* Denominator algebra.
867 res = 4 z (x^3 + c x^2 z + a x z^2 + b z^3). */
873 t1
= borrowGiant(par
->maxDigits
);
874 t2
= borrowGiant(par
->maxDigits
);
876 gtog(x
, res
); gtog(z
, t1
);
877 if(par
->curveType
!= FCT_Weierstrass
) { // i.e., !isZero(par->c)
878 gtog(par
->c
, t2
); mulg(t1
, t2
); feemod(par
, t2
);
881 mulg(x
, res
); feemod(par
, res
);
882 gsquare(t1
); feemod(par
, t1
);
883 if(!isZero(par
->a
)) {
885 mulg(par
->a
, t2
); feemod(par
, t2
);
888 mulg(x
, res
); feemod(par
, res
);
889 if(!isZero(par
->b
)) {
890 mulg(z
, t1
); feemod(par
, t1
);
891 mulg(par
->b
, t1
); feemod(par
, t1
);
894 mulg(z
, res
); gshiftleft(2, res
);
899 PROF_END(denomDoubleTime
);
904 static void denom_times(giant x1
, giant z1
, giant x2
, giant z2
, giant res
,
906 /* Denominator algebra.
907 res := (x1 z2 - x2 z1)^2
913 t1
= borrowGiant(par
->maxDigits
);
915 gtog(x1
, res
); mulg(z2
, res
); feemod(par
, res
);
916 gtog(z1
, t1
); mulg(x2
, t1
); feemod(par
, t1
);
917 subg(t1
, res
); gsquare(res
); feemod(par
, res
);
920 PROF_END(denomTimesTime
);
923 static void numer_times(giant x1
, giant z1
, giant x2
, giant z2
, giant res
,
925 /* Numerator algebra.
926 res := (x1 x2 - a z1 z2)^2 -
927 4 b(x1 z2 + x2 z1 + c z1 z2) z1 z2
936 t1
= borrowGiant(par
->maxDigits
);
937 t2
= borrowGiant(par
->maxDigits
);
938 t3
= borrowGiant(par
->maxDigits
);
939 t4
= borrowGiant(par
->maxDigits
);
941 gtog(x1
, t1
); mulg(x2
, t1
); feemod(par
, t1
);
942 gtog(z1
, t2
); mulg(z2
, t2
); feemod(par
, t2
);
944 if(!isZero(par
->a
)) {
946 mulg(t2
, t3
); feemod(par
, t3
);
949 gsquare(res
); feemod(par
, res
);
952 if(par
->curveType
!= FCT_Weierstrass
) { // i.e., !isZero(par->c)
954 mulg(t2
, t3
); feemod(par
, t3
);
955 } else int_to_giant(0, t3
);
956 gtog(z1
, t4
); mulg(x2
, t4
); feemod(par
, t4
);
958 gtog(x1
, t4
); mulg(z2
, t4
); feemod(par
, t4
);
959 addg(t4
, t3
); mulg(par
->b
, t3
); feemod(par
, t3
);
960 mulg(t2
, t3
); gshiftleft(2, t3
); feemod(par
, t3
);
969 PROF_END(numerTimesTime
);
975 static void feepowermodg(curveParams
*par
, giant x
, giant n
)
984 t1
= borrowGiant(par
->maxDigits
);
990 if(bitval(n
, pos
++)) {
999 PROF_END(powerModTime
);
1003 * Set g := g mod curveOrder;
1004 * force g to be between 2 and (curveOrder-2), inclusive.
1006 * Tolerates zero curve orders (indicating "not known").
1010 * This version is not normally used; it's for when the reciprocal of
1011 * curveOrder is not known and won't be used again.
1013 void curveOrderJustify(giant g
, giant curveOrder
)
1017 CKASSERT(!isZero(curveOrder
));
1019 recip
= borrowGiant(2 * abs(g
->sign
));
1020 make_recip(curveOrder
, recip
);
1021 curveOrderJustifyWithRecip(g
, curveOrder
, recip
);
1026 * New optimzation of curveOrderJustify using known reciprocal, 11 June 1997.
1027 * g is set to be within [2, curveOrder-2].
1029 static void curveOrderJustifyWithRecip(giant g
, giant curveOrder
, giant recip
)
1033 CKASSERT(!isZero(curveOrder
));
1035 modg_via_recip(curveOrder
, recip
, g
); // g now in [0, curveOrder-1]
1039 * First degenerate case - (g == 0) : set g := 2
1041 dbgLog(("curveOrderJustify: case 1\n"));
1047 * Second case - (g == 1) : set g := 2
1049 dbgLog(("curveOrderJustify: case 2\n"));
1053 tmp
= borrowGiant(g
->capacity
);
1056 if(gcompg(tmp
, curveOrder
) == 0) {
1058 * Third degenerate case - (g == (curveOrder-1)) : set g -= 1
1060 dbgLog(("curveOrderJustify: case 3\n"));
1061 int_to_giant(1, tmp
);
1068 #define RECIP_DEBUG 0
1070 #define recipLog(x) printf x
1071 #else // RECIP_DEBUG
1073 #endif // RECIP_DEBUG
1076 * curveOrderJustify routines with specific orders, using (and possibly
1077 * generating) associated reciprocals.
1079 void lesserX1OrderJustify(giant g
, curveParams
*cp
)
1082 * Note this is a pointer to a giant in *cp, not a newly
1085 giant lesserX1Ord
= lesserX1Order(cp
);
1087 if(isZero(lesserX1Ord
)) {
1092 * Calculate reciprocal if we don't have it
1094 if(isZero(cp
->lesserX1OrderRecip
)) {
1095 if((lesserX1Ord
== cp
->x1OrderPlus
) &&
1096 (!isZero(cp
->x1OrderPlusRecip
))) {
1098 * lesserX1Ord happens to be x1OrderPlus, and we
1099 * have a reciprocal for x1OrderPlus. Copy it over.
1102 "x1OrderPlusRecip --> lesserX1OrderRecip\n"));
1103 gtog(cp
->x1OrderPlusRecip
, cp
->lesserX1OrderRecip
);
1106 /* Calculate the reciprocal. */
1107 recipLog(("calc lesserX1OrderRecip\n"));
1108 make_recip(lesserX1Ord
, cp
->lesserX1OrderRecip
);
1112 recipLog(("using existing lesserX1OrderRecip\n"));
1114 curveOrderJustifyWithRecip(g
, lesserX1Ord
, cp
->lesserX1OrderRecip
);
1118 * Common code used by x1OrderPlusJustify() and x1OrderPlusMod() to generate
1119 * reciprocal of x1OrderPlus.
1120 * 8 Sep 1998 - also used by feeSigSign().
1122 void calcX1OrderPlusRecip(curveParams
*cp
)
1124 if(isZero(cp
->x1OrderPlusRecip
)) {
1125 if((cp
->x1OrderPlus
== lesserX1Order(cp
)) &&
1126 (!isZero(cp
->lesserX1OrderRecip
))) {
1128 * lesserX1Order happens to be x1OrderPlus, and we
1129 * have a reciprocal for lesserX1Order. Copy it over.
1132 "lesserX1OrderRecip --> x1OrderPlusRecip\n"));
1133 gtog(cp
->lesserX1OrderRecip
, cp
->x1OrderPlusRecip
);
1136 /* Calculate the reciprocal. */
1137 recipLog(("calc x1OrderPlusRecip\n"));
1138 make_recip(cp
->x1OrderPlus
, cp
->x1OrderPlusRecip
);
1142 recipLog(("using existing x1OrderPlusRecip\n"));
1146 void x1OrderPlusJustify(giant g
, curveParams
*cp
)
1148 CKASSERT(!isZero(cp
->x1OrderPlus
));
1151 * Calculate reciprocal if we don't have it
1153 calcX1OrderPlusRecip(cp
);
1154 curveOrderJustifyWithRecip(g
, cp
->x1OrderPlus
, cp
->x1OrderPlusRecip
);
1158 * g := g mod x1OrderPlus. Result may be zero.
1160 void x1OrderPlusMod(giant g
, curveParams
*cp
)
1162 CKASSERT(!isZero(cp
->x1OrderPlus
));
1165 * Calculate reciprocal if we don't have it
1167 calcX1OrderPlusRecip(cp
);
1168 modg_via_recip(cp
->x1OrderPlus
, cp
->x1OrderPlusRecip
, g
);
1172 * New general-purpose giant mod routine, 8 Jan 97.
1173 * x := x mod basePrime.
1177 * This stuff is used to analyze the critical loop behavior inside feemod().
1179 #define FEEMOD_LOOP_TEST 0
1180 #if FEEMOD_LOOP_TEST
1182 * these two are only examined via debugger
1184 unsigned feemodCalls
= 0; // calls to feemod()
1185 unsigned feemodMultLoops
= 0; // times while() loop runs > once
1186 #define FEEMOD_LOOP_INCR feemodLoops++
1187 #define FEEMOD_CALL_INCR feemodCalls++
1188 #else // FEEMOD_LOOP_TEST
1189 #define FEEMOD_LOOP_INCR
1190 #define FEEMOD_CALL_INCR
1191 #endif // FEEMOD_LOOP_TEST
1195 feemod(curveParams
*par
, giant x
)
1202 #if FEEMOD_LOOP_TEST
1203 unsigned feemodLoops
= 0;
1204 #endif // FEEMOD_LOOP_TEST
1206 FEEMOD_CALL_INCR
; // for FEEMOD_LOOP_TEST
1207 INCR_FEEMODS
; // for ellipticMeasure
1208 PROF_INCR(numFeemod
); // for general profiling
1210 switch(par
->primeType
) {
1213 * Super-optimized Mersenne prime modulus case
1215 gmersennemod(par
->q
, x
);
1220 * General 2**q-k case
1222 sign
= (x
->sign
< 0) ? -1 : 1;
1224 x
->sign
= abs(x
->sign
);
1225 if(gcompg(par
->basePrime
, x
) >= 0) {
1228 t1
= borrowGiant(par
->maxDigits
);
1229 t3
= borrowGiant(par
->maxDigits
);
1230 t4
= borrowGiant(par
->maxDigits
);
1231 t5
= borrowGiant(par
->maxDigits
);
1233 /* Begin OPT: 11 Jan 98 REC. */
1234 if( ((par
->q
& (GIANT_BITS_PER_DIGIT
- 1)) == 0) &&
1236 (par
->k
< GIANT_DIGIT_MASK
)) {
1239 * Microscopic mod for certain regions of {q,k}
1242 int j
, digits
, excess
, max
;
1244 giantDigit termHi
; // double precision
1246 giantDigit
*p1
, *p2
;
1248 digits
= par
->q
>> GIANT_LOG2_BITS_PER_DIGIT
;
1249 while(bitlen(x
) > par
->q
) {
1250 excess
= (x
->sign
) - digits
;
1251 max
= (excess
> digits
) ? excess
: digits
;
1257 if(excess
<= digits
) {
1258 carry
= VectorMultiply(par
->k
,
1263 /* propagate final carry */
1265 for(j
= excess
; j
< digits
; j
++) {
1268 * term = *p1 + carry;
1269 * *p1++ = term & 65535;
1270 * carry = term >> 16;
1272 termLo
= giantAddDigits(*p1
, carry
, &carry
);
1276 carry
= VectorMultiply(par
->k
,
1282 for(j
= digits
; j
< excess
; j
++) {
1284 * term = (par->k)*(*p2++) + carry;
1286 giantMulDigits(par
->k
,
1290 giantAddDouble(&termLo
, &termHi
, carry
);
1293 * *p1++ = term & 65535;
1294 * carry = term >> 16;
1305 if(x
->n
[max
] != 0) break;
1311 } else { /* Macroscopic mod for general PT_FEE case. */
1312 int_to_giant(par
->k
, t4
);
1313 while(bitlen(x
) > par
->q
) {
1314 /* Enter fast loop, as in FEE patent. */
1315 int_to_giant(1, t5
);
1317 extractbits(par
->q
, t3
, x
);
1318 while(bitlen(t3
) > par
->q
) {
1319 gshiftright(par
->q
, t3
);
1320 extractbits(par
->q
, t3
, t1
);
1330 /* End OPT: 11 Jan 98 REC. */
1332 sign2
= (x
->sign
< 0)? -1: 1;
1333 x
->sign
= abs(x
->sign
);
1339 if(gcompg(x
, par
->basePrime
) >=0) subg(par
->basePrime
, x
);
1341 giant t2
= borrowGiant(par
->maxDigits
);
1342 gtog(par
->basePrime
, t2
);
1348 /* end case PT_FEE */
1352 * Use brute-force modg.
1355 if(par
->basePrimeRecip
== NULL
) {
1356 CKRaise("feemod(PT_GENERAL): No basePrimeRecip!\n");
1358 #endif /* FEE_DEBUG */
1359 modg_via_recip(par
->basePrime
, par
->basePrimeRecip
, x
);
1363 /* never appears here */
1366 } /* switch primeType */
1368 #if FEEMOD_LOOP_TEST
1369 if(feemodLoops
> 1) {
1371 if(feemodLoops
> 2) {
1372 printf("feemod while loop executed %d times\n", feemodLoops
);
1375 #endif // FEEMOD_LOOP_TEST
1381 * For a given curveParams, calculate minBytes and maxDigits.
1382 * Assumes valid primeType, and also a valid basePrime for PT_GENERAL.
1384 void calcGiantSizes(curveParams
*cp
)
1387 if(cp
->primeType
== FPT_General
) {
1388 cp
->minBytes
= (bitlen(cp
->basePrime
) + 7) / 8;
1391 cp
->minBytes
= giantMinBytes(cp
->q
, cp
->k
);
1393 cp
->maxDigits
= giantMaxDigits(cp
->minBytes
);
1396 unsigned giantMinBytes(unsigned q
, int k
)
1398 unsigned kIsNeg
= (k
< 0) ? 1 : 0;
1400 return (q
+ 7 + kIsNeg
) / 8;
1404 * min value for "extra" bytes. Derived from the fact that during sig verify,
1405 * we have to multiply a giant representing a digest - which may be
1406 * 20 bytes for SHA1 - by a giant of minBytes.
1408 #define MIN_EXTRA_BYTES 20
1410 unsigned giantMaxDigits(unsigned minBytes
)
1412 unsigned maxBytes
= 4 * minBytes
;
1414 if((maxBytes
- minBytes
) < MIN_EXTRA_BYTES
) {
1415 maxBytes
= minBytes
+ MIN_EXTRA_BYTES
;
1417 return BYTES_TO_GIANT_DIGITS(maxBytes
);
1422 * Optimized binvg(basePrime, x). Avoids the general modg() in favor of
1425 int binvg_cp(curveParams
*cp
, giant x
)
1428 return(binvaux(cp
->basePrime
, x
));
1432 * Optimized binvg(x1OrderPlus, x). Uses x1OrderPlusMod().
1434 int binvg_x1OrderPlus(curveParams
*cp
, giant x
)
1436 x1OrderPlusMod(x
, cp
);
1437 return(binvaux(cp
->x1OrderPlus
, x
));