]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/ellipticProj.c
1 /* Copyright (c) 1998,2011,2014 Apple 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, INC. AND THE
6 * ORIGINAL LICENSEE THAT OBTAINED THESE MATERIALS FROM APPLE,
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.
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 perspective," Springer-Verlag, manuscript
61 Solinas J 1998, IEEE P1363 Annex A (draft standard)
63 ***********************************************************/
67 #include "ellipticProj.h"
69 #include "curveParams.h"
74 * convert REC-style smulg to generic imulg
76 #define smulg(s, g) imulg((unsigned)s, g)
78 pointProj
newPointProj(unsigned numDigits
)
82 pt
= (pointProj
) fmalloc(sizeof(pointProjStruct
));
83 pt
->x
= newGiant(numDigits
);
84 pt
->y
= newGiant(numDigits
);
85 pt
->z
= newGiant(numDigits
);
89 void freePointProj(pointProj pt
)
91 clearGiant(pt
->x
); freeGiant(pt
->x
);
92 clearGiant(pt
->y
); freeGiant(pt
->y
);
93 clearGiant(pt
->z
); freeGiant(pt
->z
);
97 void ptopProj(pointProj pt1
, pointProj pt2
)
100 gtog(pt1
->y
, pt2
->y
);
101 gtog(pt1
->z
, pt2
->z
);
104 /**************************************************************
106 * Elliptic curve operations
108 **************************************************************/
110 /* Begin projective-format functions for
114 These are useful in elliptic curve cryptography (ECC).
115 A point is kept as a triple {X,Y,Z}, with the true (x,y)
118 {x,y} = {X/Z^2, Y/Z^3}
120 The function normalizeProj() performs the inverse conversion to get
124 void ellDoubleProj(pointProj pt
, curveParams
*cp
)
125 /* pt := 2 pt on the curve. */
127 giant x
= pt
->x
, y
= pt
->y
, z
= pt
->z
;
132 if(isZero(y
) || isZero(z
)) {
133 int_to_giant(1,x
); int_to_giant(1,y
); int_to_giant(0,z
);
136 t1
= borrowGiant(cp
->maxDigits
);
137 t2
= borrowGiant(cp
->maxDigits
);
138 t3
= borrowGiant(cp
->maxDigits
);
140 if((cp
->a
->sign
>= 0) || (cp
->a
->n
[0] != 3)) { /* Path prior to Apr2001. */
141 gtog(z
,t1
); gsquare(t1
); feemod(cp
, t1
);
142 gsquare(t1
); feemod(cp
, t1
);
143 mulg(cp
->a
, t1
); feemod(cp
, t1
); /* t1 := a z^4. */
144 gtog(x
, t2
); gsquare(t2
); feemod(cp
, t2
);
145 smulg(3, t2
); /* t2 := 3x^2. */
146 addg(t2
, t1
); feemod(cp
, t1
); /* t1 := slope m. */
147 } else { /* New optimization for a = -3 (post Apr 2001). */
148 gtog(z
, t1
); gsquare(t1
); feemod(cp
, t1
); /* t1 := z^2. */
149 gtog(x
, t2
); subg(t1
, t2
); /* t2 := x-z^2. */
150 addg(x
, t1
); smulg(3, t1
); /* t1 := 3(x+z^2). */
151 mulg(t2
, t1
); feemod(cp
, t1
); /* t1 := slope m. */
153 mulg(y
, z
); addg(z
,z
); feemod(cp
, z
); /* z := 2 y z. */
154 gtog(y
, t2
); gsquare(t2
); feemod(cp
, t2
); /* t2 := y^2. */
155 gtog(t2
, t3
); gsquare(t3
); feemod(cp
, t3
); /* t3 := y^4. */
156 gshiftleft(3, t3
); /* t3 := 8 y^4. */
157 mulg(x
, t2
); gshiftleft(2, t2
); feemod(cp
, t2
); /* t2 := 4xy^2. */
158 gtog(t1
, x
); gsquare(x
); feemod(cp
, x
);
159 subg(t2
, x
); subg(t2
, x
); feemod(cp
, x
); /* x done. */
160 gtog(t1
, y
); subg(x
, t2
); mulg(t2
, y
); subg(t3
, y
);
167 void ellAddProj(pointProj pt0
, pointProj pt1
, curveParams
*cp
)
168 /* pt0 := pt0 + pt1 on the curve. */
170 giant x0
= pt0
->x
, y0
= pt0
->y
, z0
= pt0
->z
,
171 x1
= pt1
->x
, y1
= pt1
->y
, z1
= pt1
->z
;
181 gtog(x1
,x0
); gtog(y1
,y0
); gtog(z1
,z0
);
184 if(isZero(z1
)) return;
186 t1
= borrowGiant(cp
->maxDigits
);
187 t2
= borrowGiant(cp
->maxDigits
);
188 t3
= borrowGiant(cp
->maxDigits
);
189 t4
= borrowGiant(cp
->maxDigits
);
190 t5
= borrowGiant(cp
->maxDigits
);
191 t6
= borrowGiant(cp
->maxDigits
);
192 t7
= borrowGiant(cp
->maxDigits
);
194 gtog(x0
, t1
); gtog(y0
,t2
); gtog(z0
, t3
);
195 gtog(x1
, t4
); gtog(y1
, t5
);
198 gtog(t6
, t7
); gsquare(t7
); feemod(cp
, t7
);
199 mulg(t7
, t1
); feemod(cp
, t1
);
200 mulg(t6
, t7
); feemod(cp
, t7
);
201 mulg(t7
, t2
); feemod(cp
, t2
);
203 gtog(t3
, t7
); gsquare(t7
); feemod(cp
, t7
);
204 mulg(t7
, t4
); feemod(cp
, t4
);
205 mulg(t3
, t7
); feemod(cp
, t7
);
206 mulg(t7
, t5
); feemod(cp
, t5
);
207 negg(t4
); addg(t1
, t4
); feemod(cp
, t4
);
208 negg(t5
); addg(t2
, t5
); feemod(cp
, t5
);
211 ellDoubleProj(pt0
, cp
);
213 int_to_giant(1, x0
); int_to_giant(1, y0
);
218 addg(t1
, t1
); subg(t4
, t1
); feemod(cp
, t1
);
219 addg(t2
, t2
); subg(t5
, t2
); feemod(cp
, t2
);
221 mulg(t6
, t3
); feemod(cp
, t3
);
223 mulg(t4
, t3
); feemod(cp
, t3
);
224 gtog(t4
, t7
); gsquare(t7
); feemod(cp
, t7
);
225 mulg(t7
, t4
); feemod(cp
, t4
);
226 mulg(t1
, t7
); feemod(cp
, t7
);
227 gtog(t5
, t1
); gsquare(t1
); feemod(cp
, t1
);
228 subg(t7
, t1
); feemod(cp
, t1
);
229 subg(t1
, t7
); subg(t1
, t7
); feemod(cp
, t7
);
230 mulg(t7
, t5
); feemod(cp
, t5
);
231 mulg(t2
, t4
); feemod(cp
, t4
);
232 gtog(t5
, t2
); subg(t4
,t2
); feemod(cp
, t2
);
233 if(t2
->n
[0] & 1) { /* Test if t2 is odd. */
234 addg(cp
->basePrime
, t2
);
237 gtog(t1
, x0
); gtog(t2
, y0
); gtog(t3
, z0
);
249 void ellNegProj(pointProj pt
, curveParams
*cp
)
250 /* pt := -pt on the curve. */
252 negg(pt
->y
); feemod(cp
, pt
->y
);
255 void ellSubProj(pointProj pt0
, pointProj pt1
, curveParams
*cp
)
256 /* pt0 := pt0 - pt1 on the curve. */
259 ellAddProj(pt0
, pt1
,cp
);
264 * Simple projective multiply.
266 * pt := pt * k, result normalized.
268 void ellMulProjSimple(pointProj pt0
, giant k
, curveParams
*cp
)
270 pointProjStruct pt1
; // local, giants borrowed
272 CKASSERT(isone(pt0
->z
));
273 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
275 /* ellMulProj assumes constant pt0, can't pass as src and dst */
276 pt1
.x
= borrowGiant(cp
->maxDigits
);
277 pt1
.y
= borrowGiant(cp
->maxDigits
);
278 pt1
.z
= borrowGiant(cp
->maxDigits
);
279 ellMulProj(pt0
, &pt1
, k
, cp
);
280 normalizeProj(&pt1
, cp
);
281 CKASSERT(isone(pt1
.z
));
289 void ellMulProj(pointProj pt0
, pointProj pt1
, giant k
, curveParams
*cp
)
290 /* General elliptic multiplication;
291 pt1 := k*pt0 on the curve,
292 with k an arbitrary integer.
295 giant x
= pt0
->x
, y
= pt0
->y
, z
= pt0
->z
,
296 xx
= pt1
->x
, yy
= pt1
->y
, zz
= pt1
->z
;
297 int ksign
, hlen
, klen
, b
, hb
, kb
;
300 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
307 t0
= borrowGiant(cp
->maxDigits
);
309 if(ksign
< 0) negg(k
);
310 gtog(x
,xx
); gtog(y
,yy
); gtog(z
,zz
);
311 gtog(k
, t0
); addg(t0
, t0
); addg(k
, t0
); /* t0 := 3k. */
314 for(b
= hlen
-2; b
> 0; b
--) {
315 ellDoubleProj(pt1
,cp
);
317 if(b
< klen
) kb
= bitval(k
, b
); else kb
= 0;
318 if((hb
!= 0) && (kb
== 0))
319 ellAddProj(pt1
, pt0
, cp
);
320 else if((hb
== 0) && (kb
!=0))
321 ellSubProj(pt1
, pt0
, cp
);
330 void normalizeProj(pointProj pt
, curveParams
*cp
)
331 /* Obtain actual x,y coords via normalization:
332 {x,y,z} := {x/z^2, y/z^3, 1}.
335 { giant x
= pt
->x
, y
= pt
->y
, z
= pt
->z
;
338 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
340 int_to_giant(1,x
); int_to_giant(1,y
);
343 t1
= borrowGiant(cp
->maxDigits
);
344 binvg_cp(cp
, z
); // was binvaux(p, z);
346 gsquare(z
); feemod(cp
, z
);
347 mulg(z
, x
); feemod(cp
, x
);
348 mulg(t1
, z
); mulg(z
, y
); feemod(cp
, y
);
354 jacobi_symbol(giant a
, curveParams
*cp
)
355 /* Standard Jacobi symbol (a/cp->basePrime).
356 basePrime must be odd, positive. */
359 giant t5
= borrowGiant(cp
->maxDigits
);
360 giant t6
= borrowGiant(cp
->maxDigits
);
361 giant t7
= borrowGiant(cp
->maxDigits
);
364 gtog(a
, t5
); feemod(cp
, t5
);
365 gtog(cp
->basePrime
, t6
);
368 while((t5
->n
[0] & 1) == 0) {
370 if((u
==3) || (u
==5)) t
= -t
;
372 gtog(t5
, t7
); gtog(t6
, t5
); gtog(t7
, t6
);
374 if(((t5
->n
[0] & 3) == 3) && ((u
& 3) == 3)) t
= -t
;
391 powFp2(giant a
, giant b
, giant w2
, giant n
, curveParams
*cp
)
392 /* Perform powering in the field F_p^2:
393 a + b w := (a + b w)^n (mod p), where parameter w2 is a quadratic
394 nonresidue (formally equal to w^2).
408 t6
= borrowGiant(cp
->maxDigits
);
409 t7
= borrowGiant(cp
->maxDigits
);
410 t8
= borrowGiant(cp
->maxDigits
);
411 t9
= borrowGiant(cp
->maxDigits
);
412 gtog(a
, t8
); gtog(b
, t9
);
413 for(j
= bitlen(n
)-2; j
>= 0; j
--) {
415 mulg(a
, b
); addg(b
,b
); feemod(cp
, b
); /* b := 2 a b. */
416 gsquare(t6
); feemod(cp
, t6
);
417 mulg(w2
, t6
); feemod(cp
, t6
);
418 gsquare(a
); addg(t6
, a
); feemod(cp
, a
);
419 /* a := a^2 + b^2 w2. */
421 gtog(b
, t6
); mulg(t8
, b
); feemod(cp
, b
);
422 gtog(a
, t7
); mulg(t9
, a
); addg(a
, b
); feemod(cp
, b
);
423 mulg(t9
, t6
); feemod(cp
, t6
);
424 mulg(w2
, t6
); feemod(cp
, t6
);
425 mulg(t8
, a
); addg(t6
, a
); feemod(cp
, a
);
441 /* x becomes x^n (mod basePrime). */
444 giant scratch2
= borrowGiant(cp
->maxDigits
);
452 if (bitval(n
, pos
++))
460 feemod(cp
, scratch2
);
462 returnGiant(scratch2
);
465 static int sqrtmod(giant x
, curveParams
*cp
)
466 /* If Sqrt[x] (mod p) exists, function returns 1, else 0.
467 In either case x is modified, but if 1 is returned,
472 giant t0
= borrowGiant(cp
->maxDigits
);
473 giant t1
= borrowGiant(cp
->maxDigits
);
474 giant t2
= borrowGiant(cp
->maxDigits
);
475 giant t3
= borrowGiant(cp
->maxDigits
);
476 giant t4
= borrowGiant(cp
->maxDigits
);
478 giant p
= cp
->basePrime
;
480 feemod(cp
, x
); /* Justify the argument. */
481 gtog(x
, t0
); /* Store x for eventual validity check on square root. */
482 if((p
->n
[0] & 3) == 3) { /* The case p = 3 (mod 4). */
484 iaddg(1, t1
); gshiftright(2, t1
);
485 powermodg(x
, t1
, cp
);
488 /* Next, handle case p = 5 (mod 8). */
489 if((p
->n
[0] & 7) == 5) {
490 gtog(p
, t1
); int_to_giant(1, t2
);
491 subg(t2
, t1
); gshiftright(2, t1
);
493 powermodg(t2
, t1
, cp
); /* t2 := x^((p-1)/4) % p. */
495 gshiftright(1, t1
); /* t1 := (p+3)/8. */
497 powermodg(x
, t1
, cp
); /* x^((p+3)/8) is root. */
500 int_to_giant(1, t2
); subg(t2
, t1
);
503 powermodg(x
, t1
, cp
);
504 mulg(t0
, x
); addg(x
, x
); feemod(cp
, x
);
505 /* 2x (4x)^((p-5)/8. */
510 /* Next, handle tougher case: p = 1 (mod 8). */
512 while(1) { /* Find appropriate nonresidue. */
514 gsquare(t2
); subg(x
, t2
); feemod(cp
, t2
);
515 if(jacobi_symbol(t2
, cp
) == -1) break;
517 } /* t2 is now w^2 in F_p^2. */
519 gtog(p
, t4
); iaddg(1, t4
); gshiftright(1, t4
);
520 powFp2(t1
, t3
, t2
, t4
, cp
);
524 gtog(x
,t1
); gsquare(t1
); feemod(cp
, t1
);
525 if(gcompg(t0
, t1
) == 0) {
526 rtn
= 1; /* Success. */
529 rtn
= 0; /* no square root */
540 void findPointProj(pointProj pt
, giant seed
, curveParams
*cp
)
541 /* Starting with seed, finds a random (projective) point {x,y,1} on curve.
544 giant x
= pt
->x
, y
= pt
->y
, z
= pt
->z
;
546 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
550 gsquare(x
); feemod(cp
, x
); // x := seed^2
551 addg(cp
->a
, x
); // x := seed^2 + a
552 mulg(seed
,x
); // x := seed^3 + a*seed
554 feemod(cp
, x
); // x := seed^3 + a seed + b.
555 /* test cubic form for having root. */
556 if(sqrtmod(x
, cp
)) break;