]>
git.saurik.com Git - apple/security.git/blob - libsecurity_cryptkit/lib/ellipticProj.c
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 * ellipticProj.c - elliptic projective algebra routines.
15 * 1 Sep 1998 Doug Mitchell and Richard Crandall at Apple
18 **************************************************************
22 Functions are supplied herein for projective format
23 of points. Alternative formats differ in their
24 range of applicability, efficiency, and so on.
25 Primary advantages of the projective format herein are:
26 -- No explicit inversions (until perhaps one such at the end of
27 an elliptic multiply operation)
28 -- Fairly low operation count (~11 muls for point doubling,
29 ~16 muls for point addition)
31 The elliptic curve is over F_p, with p > 3 prime, and Weierstrass
36 The projective-format coordinates are actually stored in
37 the form {X, Y, Z}, with true x,y
38 coordinates on the curve given by {x,y} = {X/Z^2, Y/Z^3}.
39 The function normalizeProj() performs the
40 transformation from projective->true.
41 (The other direction is trivial, i.e. {x,y} -> {x,y,1} will do.)
42 The basic point multiplication function is
46 which obtains the result k * P for given point P and integer
47 multiplier k. If true {x,y} are required for a multiple, one
48 passes a point P = {X, Y, 1} to ellMulProj(), then afterwards
49 calls normalizeProj(),
51 Projective format is an answer to the typical sluggishness of
52 standard elliptic arithmetic, whose explicit inversion in the
53 field is, depending of course on the machinery and programmer,
54 costly. Projective format is thus especially interesting for
59 Crandall R and Pomerance C 1998, "Prime numbers: a computational
60 perspective," Springer-Verlag, manuscript
62 Solinas J 1998, IEEE P1363 Annex A (draft standard)
64 ***********************************************************/
67 #if CRYPTKIT_ELL_PROJ_ENABLE
69 #include "ellipticProj.h"
71 #include "curveParams.h"
76 * convert REC-style smulg to generic imulg
78 #define smulg(s, g) imulg((unsigned)s, g)
80 pointProj
newPointProj(unsigned numDigits
)
84 pt
= (pointProj
) fmalloc(sizeof(pointProjStruct
));
85 pt
->x
= newGiant(numDigits
);
86 pt
->y
= newGiant(numDigits
);
87 pt
->z
= newGiant(numDigits
);
91 void freePointProj(pointProj pt
)
93 clearGiant(pt
->x
); freeGiant(pt
->x
);
94 clearGiant(pt
->y
); freeGiant(pt
->y
);
95 clearGiant(pt
->z
); freeGiant(pt
->z
);
99 void ptopProj(pointProj pt1
, pointProj pt2
)
101 gtog(pt1
->x
, pt2
->x
);
102 gtog(pt1
->y
, pt2
->y
);
103 gtog(pt1
->z
, pt2
->z
);
106 /**************************************************************
108 * Elliptic curve operations
110 **************************************************************/
112 /* Begin projective-format functions for
116 These are useful in elliptic curve cryptography (ECC).
117 A point is kept as a triple {X,Y,Z}, with the true (x,y)
120 {x,y} = {X/Z^2, Y/Z^3}
122 The function normalizeProj() performs the inverse conversion to get
126 void ellDoubleProj(pointProj pt
, curveParams
*cp
)
127 /* pt := 2 pt on the curve. */
129 giant x
= pt
->x
, y
= pt
->y
, z
= pt
->z
;
134 if(isZero(y
) || isZero(z
)) {
135 int_to_giant(1,x
); int_to_giant(1,y
); int_to_giant(0,z
);
138 t1
= borrowGiant(cp
->maxDigits
);
139 t2
= borrowGiant(cp
->maxDigits
);
140 t3
= borrowGiant(cp
->maxDigits
);
142 if((cp
->a
->sign
>= 0) || (cp
->a
->n
[0] != 3)) { /* Path prior to Apr2001. */
143 gtog(z
,t1
); gsquare(t1
); feemod(cp
, t1
);
144 gsquare(t1
); feemod(cp
, t1
);
145 mulg(cp
->a
, t1
); feemod(cp
, t1
); /* t1 := a z^4. */
146 gtog(x
, t2
); gsquare(t2
); feemod(cp
, t2
);
147 smulg(3, t2
); /* t2 := 3x^2. */
148 addg(t2
, t1
); feemod(cp
, t1
); /* t1 := slope m. */
149 } else { /* New optimization for a = -3 (post Apr 2001). */
150 gtog(z
, t1
); gsquare(t1
); feemod(cp
, t1
); /* t1 := z^2. */
151 gtog(x
, t2
); subg(t1
, t2
); /* t2 := x-z^2. */
152 addg(x
, t1
); smulg(3, t1
); /* t1 := 3(x+z^2). */
153 mulg(t2
, t1
); feemod(cp
, t1
); /* t1 := slope m. */
155 mulg(y
, z
); addg(z
,z
); feemod(cp
, z
); /* z := 2 y z. */
156 gtog(y
, t2
); gsquare(t2
); feemod(cp
, t2
); /* t2 := y^2. */
157 gtog(t2
, t3
); gsquare(t3
); feemod(cp
, t3
); /* t3 := y^4. */
158 gshiftleft(3, t3
); /* t3 := 8 y^4. */
159 mulg(x
, t2
); gshiftleft(2, t2
); feemod(cp
, t2
); /* t2 := 4xy^2. */
160 gtog(t1
, x
); gsquare(x
); feemod(cp
, x
);
161 subg(t2
, x
); subg(t2
, x
); feemod(cp
, x
); /* x done. */
162 gtog(t1
, y
); subg(x
, t2
); mulg(t2
, y
); subg(t3
, y
);
169 void ellAddProj(pointProj pt0
, pointProj pt1
, curveParams
*cp
)
170 /* pt0 := pt0 + pt1 on the curve. */
172 giant x0
= pt0
->x
, y0
= pt0
->y
, z0
= pt0
->z
,
173 x1
= pt1
->x
, y1
= pt1
->y
, z1
= pt1
->z
;
183 gtog(x1
,x0
); gtog(y1
,y0
); gtog(z1
,z0
);
186 if(isZero(z1
)) return;
188 t1
= borrowGiant(cp
->maxDigits
);
189 t2
= borrowGiant(cp
->maxDigits
);
190 t3
= borrowGiant(cp
->maxDigits
);
191 t4
= borrowGiant(cp
->maxDigits
);
192 t5
= borrowGiant(cp
->maxDigits
);
193 t6
= borrowGiant(cp
->maxDigits
);
194 t7
= borrowGiant(cp
->maxDigits
);
196 gtog(x0
, t1
); gtog(y0
,t2
); gtog(z0
, t3
);
197 gtog(x1
, t4
); gtog(y1
, t5
);
200 gtog(t6
, t7
); gsquare(t7
); feemod(cp
, t7
);
201 mulg(t7
, t1
); feemod(cp
, t1
);
202 mulg(t6
, t7
); feemod(cp
, t7
);
203 mulg(t7
, t2
); feemod(cp
, t2
);
205 gtog(t3
, t7
); gsquare(t7
); feemod(cp
, t7
);
206 mulg(t7
, t4
); feemod(cp
, t4
);
207 mulg(t3
, t7
); feemod(cp
, t7
);
208 mulg(t7
, t5
); feemod(cp
, t5
);
209 negg(t4
); addg(t1
, t4
); feemod(cp
, t4
);
210 negg(t5
); addg(t2
, t5
); feemod(cp
, t5
);
213 ellDoubleProj(pt0
, cp
);
215 int_to_giant(1, x0
); int_to_giant(1, y0
);
220 addg(t1
, t1
); subg(t4
, t1
); feemod(cp
, t1
);
221 addg(t2
, t2
); subg(t5
, t2
); feemod(cp
, t2
);
223 mulg(t6
, t3
); feemod(cp
, t3
);
225 mulg(t4
, t3
); feemod(cp
, t3
);
226 gtog(t4
, t7
); gsquare(t7
); feemod(cp
, t7
);
227 mulg(t7
, t4
); feemod(cp
, t4
);
228 mulg(t1
, t7
); feemod(cp
, t7
);
229 gtog(t5
, t1
); gsquare(t1
); feemod(cp
, t1
);
230 subg(t7
, t1
); feemod(cp
, t1
);
231 subg(t1
, t7
); subg(t1
, t7
); feemod(cp
, t7
);
232 mulg(t7
, t5
); feemod(cp
, t5
);
233 mulg(t2
, t4
); feemod(cp
, t4
);
234 gtog(t5
, t2
); subg(t4
,t2
); feemod(cp
, t2
);
235 if(t2
->n
[0] & 1) { /* Test if t2 is odd. */
236 addg(cp
->basePrime
, t2
);
239 gtog(t1
, x0
); gtog(t2
, y0
); gtog(t3
, z0
);
251 void ellNegProj(pointProj pt
, curveParams
*cp
)
252 /* pt := -pt on the curve. */
254 negg(pt
->y
); feemod(cp
, pt
->y
);
257 void ellSubProj(pointProj pt0
, pointProj pt1
, curveParams
*cp
)
258 /* pt0 := pt0 - pt1 on the curve. */
261 ellAddProj(pt0
, pt1
,cp
);
266 * Simple projective multiply.
268 * pt := pt * k, result normalized.
270 void ellMulProjSimple(pointProj pt0
, giant k
, curveParams
*cp
)
272 pointProjStruct pt1
; // local, giants borrowed
274 CKASSERT(isone(pt0
->z
));
275 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
277 /* ellMulProj assumes constant pt0, can't pass as src and dst */
278 pt1
.x
= borrowGiant(cp
->maxDigits
);
279 pt1
.y
= borrowGiant(cp
->maxDigits
);
280 pt1
.z
= borrowGiant(cp
->maxDigits
);
281 ellMulProj(pt0
, &pt1
, k
, cp
);
282 normalizeProj(&pt1
, cp
);
283 CKASSERT(isone(pt1
.z
));
291 void ellMulProj(pointProj pt0
, pointProj pt1
, giant k
, curveParams
*cp
)
292 /* General elliptic multiplication;
293 pt1 := k*pt0 on the curve,
294 with k an arbitrary integer.
297 giant x
= pt0
->x
, y
= pt0
->y
, z
= pt0
->z
,
298 xx
= pt1
->x
, yy
= pt1
->y
, zz
= pt1
->z
;
299 int ksign
, hlen
, klen
, b
, hb
, kb
;
302 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
309 t0
= borrowGiant(cp
->maxDigits
);
311 if(ksign
< 0) negg(k
);
312 gtog(x
,xx
); gtog(y
,yy
); gtog(z
,zz
);
313 gtog(k
, t0
); addg(t0
, t0
); addg(k
, t0
); /* t0 := 3k. */
316 for(b
= hlen
-2; b
> 0; b
--) {
317 ellDoubleProj(pt1
,cp
);
319 if(b
< klen
) kb
= bitval(k
, b
); else kb
= 0;
320 if((hb
!= 0) && (kb
== 0))
321 ellAddProj(pt1
, pt0
, cp
);
322 else if((hb
== 0) && (kb
!=0))
323 ellSubProj(pt1
, pt0
, cp
);
332 void normalizeProj(pointProj pt
, curveParams
*cp
)
333 /* Obtain actual x,y coords via normalization:
334 {x,y,z} := {x/z^2, y/z^3, 1}.
337 { giant x
= pt
->x
, y
= pt
->y
, z
= pt
->z
;
340 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
342 int_to_giant(1,x
); int_to_giant(1,y
);
345 t1
= borrowGiant(cp
->maxDigits
);
346 binvg_cp(cp
, z
); // was binvaux(p, z);
348 gsquare(z
); feemod(cp
, z
);
349 mulg(z
, x
); feemod(cp
, x
);
350 mulg(t1
, z
); mulg(z
, y
); feemod(cp
, y
);
356 jacobi_symbol(giant a
, curveParams
*cp
)
357 /* Standard Jacobi symbol (a/cp->basePrime).
358 basePrime must be odd, positive. */
361 giant t5
= borrowGiant(cp
->maxDigits
);
362 giant t6
= borrowGiant(cp
->maxDigits
);
363 giant t7
= borrowGiant(cp
->maxDigits
);
366 gtog(a
, t5
); feemod(cp
, t5
);
367 gtog(cp
->basePrime
, t6
);
370 while((t5
->n
[0] & 1) == 0) {
372 if((u
==3) || (u
==5)) t
= -t
;
374 gtog(t5
, t7
); gtog(t6
, t5
); gtog(t7
, t6
);
376 if(((t5
->n
[0] & 3) == 3) && ((u
& 3) == 3)) t
= -t
;
393 powFp2(giant a
, giant b
, giant w2
, giant n
, curveParams
*cp
)
394 /* Perform powering in the field F_p^2:
395 a + b w := (a + b w)^n (mod p), where parameter w2 is a quadratic
396 nonresidue (formally equal to w^2).
410 t6
= borrowGiant(cp
->maxDigits
);
411 t7
= borrowGiant(cp
->maxDigits
);
412 t8
= borrowGiant(cp
->maxDigits
);
413 t9
= borrowGiant(cp
->maxDigits
);
414 gtog(a
, t8
); gtog(b
, t9
);
415 for(j
= bitlen(n
)-2; j
>= 0; j
--) {
417 mulg(a
, b
); addg(b
,b
); feemod(cp
, b
); /* b := 2 a b. */
418 gsquare(t6
); feemod(cp
, t6
);
419 mulg(w2
, t6
); feemod(cp
, t6
);
420 gsquare(a
); addg(t6
, a
); feemod(cp
, a
);
421 /* a := a^2 + b^2 w2. */
423 gtog(b
, t6
); mulg(t8
, b
); feemod(cp
, b
);
424 gtog(a
, t7
); mulg(t9
, a
); addg(a
, b
); feemod(cp
, b
);
425 mulg(t9
, t6
); feemod(cp
, t6
);
426 mulg(w2
, t6
); feemod(cp
, t6
);
427 mulg(t8
, a
); addg(t6
, a
); feemod(cp
, a
);
443 /* x becomes x^n (mod basePrime). */
446 giant scratch2
= borrowGiant(cp
->maxDigits
);
454 if (bitval(n
, pos
++))
462 feemod(cp
, scratch2
);
464 returnGiant(scratch2
);
467 static int sqrtmod(giant x
, curveParams
*cp
)
468 /* If Sqrt[x] (mod p) exists, function returns 1, else 0.
469 In either case x is modified, but if 1 is returned,
474 giant t0
= borrowGiant(cp
->maxDigits
);
475 giant t1
= borrowGiant(cp
->maxDigits
);
476 giant t2
= borrowGiant(cp
->maxDigits
);
477 giant t3
= borrowGiant(cp
->maxDigits
);
478 giant t4
= borrowGiant(cp
->maxDigits
);
480 giant p
= cp
->basePrime
;
482 feemod(cp
, x
); /* Justify the argument. */
483 gtog(x
, t0
); /* Store x for eventual validity check on square root. */
484 if((p
->n
[0] & 3) == 3) { /* The case p = 3 (mod 4). */
486 iaddg(1, t1
); gshiftright(2, t1
);
487 powermodg(x
, t1
, cp
);
490 /* Next, handle case p = 5 (mod 8). */
491 if((p
->n
[0] & 7) == 5) {
492 gtog(p
, t1
); int_to_giant(1, t2
);
493 subg(t2
, t1
); gshiftright(2, t1
);
495 powermodg(t2
, t1
, cp
); /* t2 := x^((p-1)/4) % p. */
497 gshiftright(1, t1
); /* t1 := (p+3)/8. */
499 powermodg(x
, t1
, cp
); /* x^((p+3)/8) is root. */
502 int_to_giant(1, t2
); subg(t2
, t1
);
505 powermodg(x
, t1
, cp
);
506 mulg(t0
, x
); addg(x
, x
); feemod(cp
, x
);
507 /* 2x (4x)^((p-5)/8. */
512 /* Next, handle tougher case: p = 1 (mod 8). */
514 while(1) { /* Find appropriate nonresidue. */
516 gsquare(t2
); subg(x
, t2
); feemod(cp
, t2
);
517 if(jacobi_symbol(t2
, cp
) == -1) break;
519 } /* t2 is now w^2 in F_p^2. */
521 gtog(p
, t4
); iaddg(1, t4
); gshiftright(1, t4
);
522 powFp2(t1
, t3
, t2
, t4
, cp
);
526 gtog(x
,t1
); gsquare(t1
); feemod(cp
, t1
);
527 if(gcompg(t0
, t1
) == 0) {
528 rtn
= 1; /* Success. */
531 rtn
= 0; /* no square root */
542 void findPointProj(pointProj pt
, giant seed
, curveParams
*cp
)
543 /* Starting with seed, finds a random (projective) point {x,y,1} on curve.
546 giant x
= pt
->x
, y
= pt
->y
, z
= pt
->z
;
548 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
552 gsquare(x
); feemod(cp
, x
); // x := seed^2
553 addg(cp
->a
, x
); // x := seed^2 + a
554 mulg(seed
,x
); // x := seed^3 + a*seed
556 feemod(cp
, x
); // x := seed^3 + a seed + b.
557 /* test cubic form for having root. */
558 if(sqrtmod(x
, cp
)) break;
566 #endif /* CRYPTKIT_ELL_PROJ_ENABLE */