]>
git.saurik.com Git - apple/security.git/blob - Security/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 ***********************************************************/
66 #if CRYPTKIT_ELL_PROJ_ENABLE
68 #include "ellipticProj.h"
70 #include "curveParams.h"
75 * convert REC-style smulg to generic imulg
77 #define smulg(s, g) imulg((unsigned)s, g)
79 pointProj
newPointProj(unsigned numDigits
)
83 pt
= (pointProj
) fmalloc(sizeof(pointProjStruct
));
84 pt
->x
= newGiant(numDigits
);
85 pt
->y
= newGiant(numDigits
);
86 pt
->z
= newGiant(numDigits
);
90 void freePointProj(pointProj pt
)
92 clearGiant(pt
->x
); freeGiant(pt
->x
);
93 clearGiant(pt
->y
); freeGiant(pt
->y
);
94 clearGiant(pt
->z
); freeGiant(pt
->z
);
98 void ptopProj(pointProj pt1
, pointProj pt2
)
100 gtog(pt1
->x
, pt2
->x
);
101 gtog(pt1
->y
, pt2
->y
);
102 gtog(pt1
->z
, pt2
->z
);
105 /**************************************************************
107 * Elliptic curve operations
109 **************************************************************/
111 /* Begin projective-format functions for
115 These are useful in elliptic curve cryptography (ECC).
116 A point is kept as a triple {X,Y,Z}, with the true (x,y)
119 {x,y} = {X/Z^2, Y/Z^3}
121 The function normalizeProj() performs the inverse conversion to get
125 void ellDoubleProj(pointProj pt
, curveParams
*cp
)
126 /* pt := 2 pt on the curve. */
128 giant x
= pt
->x
, y
= pt
->y
, z
= pt
->z
;
133 if(isZero(y
) || isZero(z
)) {
134 int_to_giant(1,x
); int_to_giant(1,y
); int_to_giant(0,z
);
137 t1
= borrowGiant(cp
->maxDigits
);
138 t2
= borrowGiant(cp
->maxDigits
);
139 t3
= borrowGiant(cp
->maxDigits
);
141 if((cp
->a
->sign
>= 0) || (cp
->a
->n
[0] != 3)) { /* Path prior to Apr2001. */
142 gtog(z
,t1
); gsquare(t1
); feemod(cp
, t1
);
143 gsquare(t1
); feemod(cp
, t1
);
144 mulg(cp
->a
, t1
); feemod(cp
, t1
); /* t1 := a z^4. */
145 gtog(x
, t2
); gsquare(t2
); feemod(cp
, t2
);
146 smulg(3, t2
); /* t2 := 3x^2. */
147 addg(t2
, t1
); feemod(cp
, t1
); /* t1 := slope m. */
148 } else { /* New optimization for a = -3 (post Apr 2001). */
149 gtog(z
, t1
); gsquare(t1
); feemod(cp
, t1
); /* t1 := z^2. */
150 gtog(x
, t2
); subg(t1
, t2
); /* t2 := x-z^2. */
151 addg(x
, t1
); smulg(3, t1
); /* t1 := 3(x+z^2). */
152 mulg(t2
, t1
); feemod(cp
, t1
); /* t1 := slope m. */
154 mulg(y
, z
); addg(z
,z
); feemod(cp
, z
); /* z := 2 y z. */
155 gtog(y
, t2
); gsquare(t2
); feemod(cp
, t2
); /* t2 := y^2. */
156 gtog(t2
, t3
); gsquare(t3
); feemod(cp
, t3
); /* t3 := y^4. */
157 gshiftleft(3, t3
); /* t3 := 8 y^4. */
158 mulg(x
, t2
); gshiftleft(2, t2
); feemod(cp
, t2
); /* t2 := 4xy^2. */
159 gtog(t1
, x
); gsquare(x
); feemod(cp
, x
);
160 subg(t2
, x
); subg(t2
, x
); feemod(cp
, x
); /* x done. */
161 gtog(t1
, y
); subg(x
, t2
); mulg(t2
, y
); subg(t3
, y
);
168 void ellAddProj(pointProj pt0
, pointProj pt1
, curveParams
*cp
)
169 /* pt0 := pt0 + pt1 on the curve. */
171 giant x0
= pt0
->x
, y0
= pt0
->y
, z0
= pt0
->z
,
172 x1
= pt1
->x
, y1
= pt1
->y
, z1
= pt1
->z
;
182 gtog(x1
,x0
); gtog(y1
,y0
); gtog(z1
,z0
);
185 if(isZero(z1
)) return;
187 t1
= borrowGiant(cp
->maxDigits
);
188 t2
= borrowGiant(cp
->maxDigits
);
189 t3
= borrowGiant(cp
->maxDigits
);
190 t4
= borrowGiant(cp
->maxDigits
);
191 t5
= borrowGiant(cp
->maxDigits
);
192 t6
= borrowGiant(cp
->maxDigits
);
193 t7
= borrowGiant(cp
->maxDigits
);
195 gtog(x0
, t1
); gtog(y0
,t2
); gtog(z0
, t3
);
196 gtog(x1
, t4
); gtog(y1
, t5
);
199 gtog(t6
, t7
); gsquare(t7
); feemod(cp
, t7
);
200 mulg(t7
, t1
); feemod(cp
, t1
);
201 mulg(t6
, t7
); feemod(cp
, t7
);
202 mulg(t7
, t2
); feemod(cp
, t2
);
204 gtog(t3
, t7
); gsquare(t7
); feemod(cp
, t7
);
205 mulg(t7
, t4
); feemod(cp
, t4
);
206 mulg(t3
, t7
); feemod(cp
, t7
);
207 mulg(t7
, t5
); feemod(cp
, t5
);
208 negg(t4
); addg(t1
, t4
); feemod(cp
, t4
);
209 negg(t5
); addg(t2
, t5
); feemod(cp
, t5
);
212 ellDoubleProj(pt0
, cp
);
214 int_to_giant(1, x0
); int_to_giant(1, y0
);
219 addg(t1
, t1
); subg(t4
, t1
); feemod(cp
, t1
);
220 addg(t2
, t2
); subg(t5
, t2
); feemod(cp
, t2
);
222 mulg(t6
, t3
); feemod(cp
, t3
);
224 mulg(t4
, t3
); feemod(cp
, t3
);
225 gtog(t4
, t7
); gsquare(t7
); feemod(cp
, t7
);
226 mulg(t7
, t4
); feemod(cp
, t4
);
227 mulg(t1
, t7
); feemod(cp
, t7
);
228 gtog(t5
, t1
); gsquare(t1
); feemod(cp
, t1
);
229 subg(t7
, t1
); feemod(cp
, t1
);
230 subg(t1
, t7
); subg(t1
, t7
); feemod(cp
, t7
);
231 mulg(t7
, t5
); feemod(cp
, t5
);
232 mulg(t2
, t4
); feemod(cp
, t4
);
233 gtog(t5
, t2
); subg(t4
,t2
); feemod(cp
, t2
);
234 if(t2
->n
[0] & 1) { /* Test if t2 is odd. */
235 addg(cp
->basePrime
, t2
);
238 gtog(t1
, x0
); gtog(t2
, y0
); gtog(t3
, z0
);
250 void ellNegProj(pointProj pt
, curveParams
*cp
)
251 /* pt := -pt on the curve. */
253 negg(pt
->y
); feemod(cp
, pt
->y
);
256 void ellSubProj(pointProj pt0
, pointProj pt1
, curveParams
*cp
)
257 /* pt0 := pt0 - pt1 on the curve. */
260 ellAddProj(pt0
, pt1
,cp
);
265 * Simple projective multiply.
267 * pt := pt * k, result normalized.
269 void ellMulProjSimple(pointProj pt0
, giant k
, curveParams
*cp
)
271 pointProjStruct pt1
; // local, giants borrowed
273 CKASSERT(isone(pt0
->z
));
274 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
276 /* ellMulProj assumes constant pt0, can't pass as src and dst */
277 pt1
.x
= borrowGiant(cp
->maxDigits
);
278 pt1
.y
= borrowGiant(cp
->maxDigits
);
279 pt1
.z
= borrowGiant(cp
->maxDigits
);
280 ellMulProj(pt0
, &pt1
, k
, cp
);
281 normalizeProj(&pt1
, cp
);
282 CKASSERT(isone(pt1
.z
));
290 void ellMulProj(pointProj pt0
, pointProj pt1
, giant k
, curveParams
*cp
)
291 /* General elliptic multiplication;
292 pt1 := k*pt0 on the curve,
293 with k an arbitrary integer.
296 giant x
= pt0
->x
, y
= pt0
->y
, z
= pt0
->z
,
297 xx
= pt1
->x
, yy
= pt1
->y
, zz
= pt1
->z
;
298 int ksign
, hlen
, klen
, b
, hb
, kb
;
301 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
308 t0
= borrowGiant(cp
->maxDigits
);
310 if(ksign
< 0) negg(k
);
311 gtog(x
,xx
); gtog(y
,yy
); gtog(z
,zz
);
312 gtog(k
, t0
); addg(t0
, t0
); addg(k
, t0
); /* t0 := 3k. */
315 for(b
= hlen
-2; b
> 0; b
--) {
316 ellDoubleProj(pt1
,cp
);
318 if(b
< klen
) kb
= bitval(k
, b
); else kb
= 0;
319 if((hb
!= 0) && (kb
== 0))
320 ellAddProj(pt1
, pt0
, cp
);
321 else if((hb
== 0) && (kb
!=0))
322 ellSubProj(pt1
, pt0
, cp
);
331 void normalizeProj(pointProj pt
, curveParams
*cp
)
332 /* Obtain actual x,y coords via normalization:
333 {x,y,z} := {x/z^2, y/z^3, 1}.
336 { giant x
= pt
->x
, y
= pt
->y
, z
= pt
->z
;
339 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
341 int_to_giant(1,x
); int_to_giant(1,y
);
344 t1
= borrowGiant(cp
->maxDigits
);
345 binvg_cp(cp
, z
); // was binvaux(p, z);
347 gsquare(z
); feemod(cp
, z
);
348 mulg(z
, x
); feemod(cp
, x
);
349 mulg(t1
, z
); mulg(z
, y
); feemod(cp
, y
);
355 jacobi_symbol(giant a
, curveParams
*cp
)
356 /* Standard Jacobi symbol (a/cp->basePrime).
357 basePrime must be odd, positive. */
360 giant t5
= borrowGiant(cp
->maxDigits
);
361 giant t6
= borrowGiant(cp
->maxDigits
);
362 giant t7
= borrowGiant(cp
->maxDigits
);
365 gtog(a
, t5
); feemod(cp
, t5
);
366 gtog(cp
->basePrime
, t6
);
369 while((t5
->n
[0] & 1) == 0) {
371 if((u
==3) || (u
==5)) t
= -t
;
373 gtog(t5
, t7
); gtog(t6
, t5
); gtog(t7
, t6
);
375 if(((t5
->n
[0] & 3) == 3) && ((u
& 3) == 3)) t
= -t
;
392 powFp2(giant a
, giant b
, giant w2
, giant n
, curveParams
*cp
)
393 /* Perform powering in the field F_p^2:
394 a + b w := (a + b w)^n (mod p), where parameter w2 is a quadratic
395 nonresidue (formally equal to w^2).
409 t6
= borrowGiant(cp
->maxDigits
);
410 t7
= borrowGiant(cp
->maxDigits
);
411 t8
= borrowGiant(cp
->maxDigits
);
412 t9
= borrowGiant(cp
->maxDigits
);
413 gtog(a
, t8
); gtog(b
, t9
);
414 for(j
= bitlen(n
)-2; j
>= 0; j
--) {
416 mulg(a
, b
); addg(b
,b
); feemod(cp
, b
); /* b := 2 a b. */
417 gsquare(t6
); feemod(cp
, t6
);
418 mulg(w2
, t6
); feemod(cp
, t6
);
419 gsquare(a
); addg(t6
, a
); feemod(cp
, a
);
420 /* a := a^2 + b^2 w2. */
422 gtog(b
, t6
); mulg(t8
, b
); feemod(cp
, b
);
423 gtog(a
, t7
); mulg(t9
, a
); addg(a
, b
); feemod(cp
, b
);
424 mulg(t9
, t6
); feemod(cp
, t6
);
425 mulg(w2
, t6
); feemod(cp
, t6
);
426 mulg(t8
, a
); addg(t6
, a
); feemod(cp
, a
);
442 /* x becomes x^n (mod basePrime). */
445 giant scratch2
= borrowGiant(cp
->maxDigits
);
453 if (bitval(n
, pos
++))
461 feemod(cp
, scratch2
);
463 returnGiant(scratch2
);
466 static int sqrtmod(giant x
, curveParams
*cp
)
467 /* If Sqrt[x] (mod p) exists, function returns 1, else 0.
468 In either case x is modified, but if 1 is returned,
473 giant t0
= borrowGiant(cp
->maxDigits
);
474 giant t1
= borrowGiant(cp
->maxDigits
);
475 giant t2
= borrowGiant(cp
->maxDigits
);
476 giant t3
= borrowGiant(cp
->maxDigits
);
477 giant t4
= borrowGiant(cp
->maxDigits
);
479 giant p
= cp
->basePrime
;
481 feemod(cp
, x
); /* Justify the argument. */
482 gtog(x
, t0
); /* Store x for eventual validity check on square root. */
483 if((p
->n
[0] & 3) == 3) { /* The case p = 3 (mod 4). */
485 iaddg(1, t1
); gshiftright(2, t1
);
486 powermodg(x
, t1
, cp
);
489 /* Next, handle case p = 5 (mod 8). */
490 if((p
->n
[0] & 7) == 5) {
491 gtog(p
, t1
); int_to_giant(1, t2
);
492 subg(t2
, t1
); gshiftright(2, t1
);
494 powermodg(t2
, t1
, cp
); /* t2 := x^((p-1)/4) % p. */
496 gshiftright(1, t1
); /* t1 := (p+3)/8. */
498 powermodg(x
, t1
, cp
); /* x^((p+3)/8) is root. */
501 int_to_giant(1, t2
); subg(t2
, t1
);
504 powermodg(x
, t1
, cp
);
505 mulg(t0
, x
); addg(x
, x
); feemod(cp
, x
);
506 /* 2x (4x)^((p-5)/8. */
511 /* Next, handle tougher case: p = 1 (mod 8). */
513 while(1) { /* Find appropriate nonresidue. */
515 gsquare(t2
); subg(x
, t2
); feemod(cp
, t2
);
516 if(jacobi_symbol(t2
, cp
) == -1) break;
518 } /* t2 is now w^2 in F_p^2. */
520 gtog(p
, t4
); iaddg(1, t4
); gshiftright(1, t4
);
521 powFp2(t1
, t3
, t2
, t4
, cp
);
525 gtog(x
,t1
); gsquare(t1
); feemod(cp
, t1
);
526 if(gcompg(t0
, t1
) == 0) {
527 rtn
= 1; /* Success. */
530 rtn
= 0; /* no square root */
541 void findPointProj(pointProj pt
, giant seed
, curveParams
*cp
)
542 /* Starting with seed, finds a random (projective) point {x,y,1} on curve.
545 giant x
= pt
->x
, y
= pt
->y
, z
= pt
->z
;
547 CKASSERT(cp
->curveType
== FCT_Weierstrass
);
551 gsquare(x
); feemod(cp
, x
); // x := seed^2
552 addg(cp
->a
, x
); // x := seed^2 + a
553 mulg(seed
,x
); // x := seed^3 + a*seed
555 feemod(cp
, x
); // x := seed^3 + a seed + b.
556 /* test cubic form for having root. */
557 if(sqrtmod(x
, cp
)) break;
565 #endif /* CRYPTKIT_ELL_PROJ_ENABLE */