]>
git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/CurveParamDocs/schoof.c
3 Elliptic curve order calculator, for
5 y^2 = x^3 + a x + b (mod p)
9 % cc -O schoof.c giants.c tools.c ellproj.c -lm -o schoof
11 and run, entering p and the a,b parameters.
12 Eventually the curve order o is reported, together with
13 the twist order o'. The sum of these two orders is always
14 2p + 2. A final check is performed to verify that a
15 random point (x,y,z) enjoys the annihilation
16 o * (x,y,z) = point-at-infinity. This is not absolutely
17 definitive, rather it is a necessary condition on the oder o
18 (i.e. it is a sanity check of sorts).
22 18 Nov 99 REC fixed M. Scott bug (MAX_DIGS bumped by 2)
23 5 Jul 99 REC Installed improved (base-4) power ladder
24 5 Jul 99 REC Made use of binary segmentation square (per se)
25 5 Jul 99 REC Improved memory usage
26 2 May 99 REC Added initial primality check
27 30 Apr 99 REC Added actual order-annihilation test
28 29 Apr 99 REC Improvements due to A. Powell
29 2 Feb 99 REC Added explicit CRT result
30 12 Jan 99 REC Removed (hopefully) last of memory crashes
31 20 Jan 98 REC Creation
33 * c. 1998 Perfectly Scientific, Inc.
34 * All Rights Reserved.
37 *************************************************************/
51 #define bzero(D, n) memset(D, 0x00, n)
52 #define bcopy(S, D, n) memcpy(D, S, n)
55 #define Q_MAX 256 /* Bits in largest primes handled. */
56 #define L_CEIL 100 /* Bound on Schoof L values (not all needed in general). */
64 typedef polystruct
*poly
;
69 static int MAX_DIGS
, MAX_COEFFS
;
71 static giant
*mcand
, coe
, tmp
, err
, aux
, aux2
, globx
, globy
, t1
, t2
,
73 static poly qscratch
, rscratch
, sscratch
, tscratch
, pbuff
,
74 pbuff2
, precip
, cubic
, powx
, powy
, kxn
, kyn
, kxd
, kyd
,
75 txn
, txd
, tyn
, tyd
, txn1
, txd1
, tyn1
, tyd1
,
76 nx
, dx
, ny
, dy
, mn
, md
, tmp1
, tmp2
, tmp3
, tmp4
;
77 static poly s
[L_CEIL
+2], smonic
;
81 void quickmodg(giant g
, giant x
)
86 if(gcompg(x
, g
) >= 0) subg(g
, x
);
106 for(j
= x
->deg
; j
>= 0; j
--) {
107 if(!is0(x
->coe
[j
])) break;
109 x
->deg
= (j
>0)? j
: 0;
115 for(j
=0; j
<= x
->deg
; j
++) {
124 giant
*p
= (giant
*)malloc(n
*sizeof(giant
));
127 p
[j
] = newgiant(MAX_DIGS
);
133 newpoly(int coeffs
) {
135 pol
= (poly
) malloc(sizeof(polystruct
));
136 pol
->coe
= (giant
*)newa(coeffs
);
144 j
= (2*Q
+ log_2(MAX_COEFFS
) + 32 + 15)/16;
148 s
[0] = newpoly(MAX_COEFFS
);
150 for(j
=1; j
<=L_MAX
+1; j
++) {
151 s
[j
] = newpoly(j
*(j
+1));
153 smonic
= newpoly(MAX_COEFFS
);
154 powx
= newpoly(MAX_COEFFS
);
155 powy
= newpoly(MAX_COEFFS
);
156 kxn
= newpoly(MAX_COEFFS
);
157 kxd
= newpoly(MAX_COEFFS
);
158 kyn
= newpoly(MAX_COEFFS
);
159 kyd
= newpoly(MAX_COEFFS
);
160 txn
= newpoly(MAX_COEFFS
);
161 txd
= newpoly(MAX_COEFFS
);
162 tyn
= newpoly(MAX_COEFFS
);
163 tyd
= newpoly(MAX_COEFFS
);
164 txn1
= newpoly(MAX_COEFFS
);
165 txd1
= newpoly(MAX_COEFFS
);
166 tyn1
= newpoly(MAX_COEFFS
);
167 tyd1
= newpoly(MAX_COEFFS
);
168 nx
= newpoly(MAX_COEFFS
);
169 ny
= newpoly(MAX_COEFFS
);
170 dx
= newpoly(MAX_COEFFS
);
171 dy
= newpoly(MAX_COEFFS
);
172 mn
= newpoly(MAX_COEFFS
);
173 md
= newpoly(MAX_COEFFS
);
174 tmp1
= newpoly(MAX_COEFFS
);
175 tmp2
= newpoly(MAX_COEFFS
);
176 tmp3
= newpoly(MAX_COEFFS
);
177 tmp4
= newpoly(MAX_COEFFS
);
178 mcand
= (giant
*)newa(MAX_COEFFS
);
179 /* The next three need extra space for remaindering routines. */
180 qscratch
= newpoly(2*MAX_COEFFS
);
181 rscratch
= newpoly(2*MAX_COEFFS
);
182 pbuff
= newpoly(2*MAX_COEFFS
);
183 pbuff2
= newpoly(MAX_COEFFS
);
184 sscratch
= newpoly(MAX_COEFFS
);
185 tscratch
= newpoly(MAX_COEFFS
);
186 tmp
= newgiant(MAX_DIGS
);
187 err
= newgiant(MAX_DIGS
);
188 coe
= newgiant(MAX_DIGS
);
189 aux
= newgiant(MAX_DIGS
);
190 aux2
= newgiant(MAX_DIGS
);
191 t3
= newgiant(MAX_DIGS
);
192 t4
= newgiant(MAX_DIGS
);
193 t5
= newgiant(MAX_DIGS
);
195 precip
= newpoly(MAX_COEFFS
);
199 atoa(giant
*a
, giant
*b
, int n
) {
201 for(j
=0; j
<n
; j
++) gtog(a
[j
], b
[j
]);
209 atoa(x
->coe
, y
->coe
, y
->deg
+1);
216 for(j
=0; j
<= y
->deg
; j
++) {
218 quickmodg(p
, y
->coe
[j
]);
225 if(a
->sign
== 0) return(1);
232 if(x
->deg
== 0 && iszer(x
->coe
[0])) return 1;
253 if(y
->deg
> d
) d
= y
->deg
;
254 for(j
= 0; j
<= d
; j
++) {
255 if((j
<= x
->deg
) && (j
<= y
->deg
)) {
256 addg(x
->coe
[j
], y
->coe
[j
]);
257 quickmodg(p
, y
->coe
[j
]);
260 if((j
<= x
->deg
) && (j
> y
->deg
)) {
261 gtog(x
->coe
[j
], y
->coe
[j
]);
262 quickmodg(p
, y
->coe
[j
]);
276 if(y
->deg
> d
) d
= y
->deg
;
277 for(j
= 0; j
<= d
; j
++) {
278 if((j
<= x
->deg
) && (j
<= y
->deg
)) {
279 subg(x
->coe
[j
], y
->coe
[j
]);
280 quickmodg(p
, y
->coe
[j
]);
283 if((j
<= x
->deg
) && (j
> y
->deg
)) {
284 gtog(x
->coe
[j
], y
->coe
[j
]);
286 quickmodg(p
, y
->coe
[j
]);
296 grammarmulp(poly a
, poly b
)
299 int dega
= a
->deg
, degb
= b
->deg
, deg
= dega
+ degb
;
300 register int d
, kk
, first
, diffa
;
302 for(d
=deg
; d
>=0; d
--) {
305 for(kk
=0; kk
<=d
; kk
++) {
306 if((kk
>degb
)||(kk
<diffa
)) continue;
307 gtog(b
->coe
[kk
], tmp
);
308 mulg(a
->coe
[d
-kk
], tmp
);
315 atoa(mcand
, b
->coe
, deg
+1);
321 atop(giant
*a
, poly x
, int deg
)
322 /* Copy array to poly, with monic option. */
326 atoa(a
, x
->coe
, adeg
);
328 itog(1, x
->coe
[adeg
]);
330 gtog(a
[adeg
], x
->coe
[adeg
]);
336 while((g
->n
[g
->sign
-1] == 0) && (g
->sign
> 0)) --g
->sign
;
340 unstuff_partial(giant g
, poly y
, int words
){
342 for(j
=0; j
< y
->deg
; j
++) {
343 bcopy((g
->n
) + j
*words
, y
->coe
[j
]->n
, words
*sizeof(short));
344 y
->coe
[j
]->sign
= words
;
350 stuff(poly x
, giant g
, int words
) {
351 int deg
= x
->deg
, j
, coedigs
;
353 g
->sign
= words
*(1 + deg
);
354 for(j
=0; j
<= deg
; j
++) {
355 coedigs
= (x
->coe
[j
])->sign
;
356 bcopy(x
->coe
[j
]->n
, (g
->n
) + j
*words
, coedigs
*sizeof(short));
357 bzero((g
->n
) + (j
*words
+coedigs
),
358 sizeof(short)*(words
-coedigs
));
366 binarysegmul(poly x
, poly y
) {
367 int bits
= bitlen(p
), xwords
, ywords
, words
;
369 xwords
= (2*bits
+ log_2(x
->deg
+1) + 32 + 15)/16;
370 ywords
= (2*bits
+ log_2(y
->deg
+1) + 32 + 15)/16;
371 if(xwords
> ywords
) words
= xwords
; else words
= ywords
;
372 stuff(x
, globx
, words
);
373 stuff(y
, globy
, words
);
375 gtog(y
->coe
[y
->deg
], globx
); /* Save high coeff. */
377 gtog(globx
, y
->coe
[y
->deg
]); /* Move high coeff. */
378 unstuff_partial(globy
, y
, words
);
379 mulg(x
->coe
[x
->deg
], y
->coe
[y
->deg
]); /* resolve high coeff. */
383 binarysegsquare(poly y
) {
384 int bits
= bitlen(p
), words
;
385 words
= (2*bits
+ log_2(y
->deg
+1) + 32 + 15)/16;
386 stuff(y
, globy
, words
);
388 gtog(y
->coe
[y
->deg
], globx
); /* Save high coeff. */
390 gtog(globx
, y
->coe
[y
->deg
]); /* Move high coeff. */
391 unstuff_partial(globy
, y
, words
);
392 mulg(y
->coe
[y
->deg
], y
->coe
[y
->deg
]); /* resolve high coeff. */
397 assess(poly x
, poly y
){
399 for(j
=0; j
<= x
->deg
; j
++) {
400 if(bitlen(x
->coe
[j
]) > max
) max
= bitlen(x
->coe
[j
]);
403 for(j
=0; j
<= y
->deg
; j
++) {
404 if(bitlen(y
->coe
[j
]) > max
) max
= bitlen(y
->coe
[j
]);
409 pcompp(poly x
, poly y
) {
411 if(x
->deg
!= y
->deg
) return 1;
412 for(j
=0; j
<= x
->deg
; j
++) {
413 if(gcompg(x
->coe
[j
], y
->coe
[j
])) return 1;
426 int n
, degx
= x
->deg
, degy
= y
->deg
;
430 max_deg = degx; printf("xdeg: %d\n", degx);
434 max_deg = degy; printf("ydeg: %d\n", degy);
437 if((degx
< P_BREAK
) || (degy
< P_BREAK
)) {
442 if(x
==y
) binarysegsquare(y
);
443 else binarysegmul(x
, y
);
448 /* Reverse the coefficients of x. */
449 { int j
, deg
= x
->deg
;
451 for(j
=0; j
<= deg
/2; j
++) {
452 gtog(x
->coe
[deg
-j
], tmp
);
453 gtog(x
->coe
[j
], x
->coe
[deg
-j
]);
454 gtog(tmp
, x
->coe
[j
]);
460 recipp(poly f
, int deg
)
461 /* f := 1/f, via newton method. */
463 int lim
= deg
+ 1, prec
= 1;
465 sscratch
->deg
= 0; itog(1, sscratch
->coe
[0]);
469 if(prec
> lim
) prec
= lim
;
471 ptop(sscratch
, tscratch
);
473 tscratch
->deg
= prec
-1;
475 subg(aux
, tscratch
->coe
[0]);
476 quickmodg(p
, tscratch
->coe
[0]);
477 mulp(sscratch
, tscratch
);
478 tscratch
->deg
= prec
-1;
480 subp(tscratch
, sscratch
);
481 sscratch
->deg
= prec
-1;
489 left_justifyp(poly x
, int start
)
490 /* Left-justify the polynomial, checking from position "start." */
494 for(j
= start
; j
<= x
->deg
; j
++) {
495 if(!is0(x
->coe
[j
])) {
501 for(j
=0; j
<= x
->deg
; j
++) {
502 gtog(x
->coe
[j
+shift
], x
->coe
[j
]);
508 remp(poly x
, poly y
, int mode
)
510 mode = 0 is normal operation,
511 = 1 jams a fixed reciprocal,
512 = 2 uses the fixed reciprocal.
515 int degx
= x
->deg
, degy
= y
->deg
, d
, shift
;
530 case 0: recipp(rscratch
, d
);
532 case 1: recipp(rscratch
, degy
); /* degy -1. */
533 ptop(rscratch
, precip
);
534 rscratch
->deg
= d
; justifyp(rscratch
);
536 case 2: ptop(precip
, rscratch
);
537 rscratch
->deg
= d
; justifyp(rscratch
);
540 /* Next, a limited-precision multiply. */
541 if(d
< degx
) { x
->deg
= d
; justifyp(x
);}
546 x
->deg
= degx
; justifyp(x
);
550 shift
= left_justifyp(y
, d
+1);
551 for(d
= y
->deg
+1; d
<= degx
-shift
; d
++) itog(0, y
->coe
[d
]);
552 y
->deg
= degx
- shift
;
565 scalarmul(giant s
, poly x
) {
567 for(j
=0; j
<= x
->deg
; j
++) {
578 itog(0, s
[0]->coe
[0]);
581 itog(1, s
[1]->coe
[0]);
583 itog(2, s
[2]->coe
[0]);
586 gtog(a
, aux
); mulg(a
, aux
); negg(aux
);
587 gtog(aux
, s
[3]->coe
[0]);
588 gtog(b
, aux
); smulg(12, aux
);
589 gtog(aux
, s
[3]->coe
[1]);
590 gtog(a
, aux
); smulg(6, aux
);
591 gtog(aux
, s
[3]->coe
[2]);
592 itog(0, s
[3]->coe
[3]);
593 itog(3, s
[3]->coe
[4]);
596 gtog(a
, aux
); mulg(a
, aux
); mulg(a
, aux
);
597 gtog(b
, tmp
); mulg(b
, tmp
); smulg(8, tmp
); addg(tmp
, aux
);
599 gtog(aux
, s
[4]->coe
[0]);
600 gtog(b
, aux
); mulg(a
, aux
); smulg(4, aux
); negg(aux
);
601 gtog(aux
, s
[4]->coe
[1]);
602 gtog(a
, aux
); mulg(a
, aux
); smulg(5, aux
); negg(aux
);
603 gtog(aux
, s
[4]->coe
[2]);
604 gtog(b
, aux
); smulg(20, aux
);
605 gtog(aux
, s
[4]->coe
[3]);
606 gtog(a
, aux
); smulg(5, aux
);
607 gtog(aux
, s
[4]->coe
[4]);
608 itog(0, s
[4]->coe
[5]);
609 itog(1, s
[4]->coe
[6]);
611 scalarmul(aux
, s
[4]);
613 itog(1, cubic
->coe
[3]);
614 itog(0, cubic
->coe
[2]);
615 gtog(a
, cubic
->coe
[1]);
616 gtog(b
, cubic
->coe
[0]);
617 for(j
=5; j
<= el
; j
++) {
619 ptop(s
[j
/2 + 2], s
[j
]); mulp(s
[j
/2-1], s
[j
]);
620 polyrem(s
[j
]); mulp(s
[j
/2-1], s
[j
]); polyrem(s
[j
]);
621 ptop(s
[j
/2-2], s
[0]); mulp(s
[j
/2+1], s
[0]); polyrem(s
[0]);
622 mulp(s
[j
/2+1], s
[0]); polyrem(s
[0]);
623 subp(s
[0], s
[j
]); mulp(s
[j
/2], s
[j
]); polyrem(s
[j
]);
624 gtog(p
, aux
); iaddg(1, aux
); gshiftright(1, aux
);
625 scalarmul(aux
, s
[j
]);
627 ptop(s
[(j
-1)/2+2], s
[j
]);
628 mulp(s
[(j
-1)/2], s
[j
]);
630 mulp(s
[(j
-1)/2], s
[j
]);
632 mulp(s
[(j
-1)/2], s
[j
]);
634 ptop(s
[(j
-1)/2-1], s
[0]);
635 mulp(s
[(j
-1)/2 + 1], s
[0]); polyrem(s
[0]);
636 mulp(s
[(j
-1)/2 + 1], s
[0]); polyrem(s
[0]);
637 mulp(s
[(j
-1)/2 + 1], s
[0]); polyrem(s
[0]);
638 if(((j
-1)/2) % 2 == 1) {
639 mulp(cubic
, s
[0]); polyrem(s
[0]);
640 mulp(cubic
, s
[0]); polyrem(s
[0]);
642 mulp(cubic
, s
[j
]); polyrem(s
[j
]);
643 mulp(cubic
, s
[j
]); polyrem(s
[j
]);
645 // polyout(s[1]); polyout(s[3]); polyout(s[0]); polyout(s[j]);
656 mulp(cubic
, smonic
); polyrem(smonic
);
658 gtog(smonic
->coe
[smonic
->deg
], aux
); /* High coeff. */
660 scalarmul(aux
, smonic
); /* s is now monic. */
661 s
[0]->deg
= smonic
->deg
+ 1;
662 for(j
=0; j
<= s
[0]->deg
; j
++) itog(1, s
[0]->coe
[j
]);
664 remp(s
[0], pbuff
, 1); /* Initialize reciprocal of s as precip. */
667 /* void powerpoly(poly x, giant n)
670 x->deg = 0; itog(1, x->coe[0]);
674 if(bitval(n, pos++)) {
685 void powerpoly(poly x
, giant n
)
688 ptop(x
, pbuff
); /* x. */
690 mulmod(pbuff2
, pbuff2
); mulmod(pbuff
, pbuff2
); /* x^3. */
695 if(bitval(n
, pos
) != 0) {
700 code
= (bitval(n
, pos
) != 0) * 2 + (bitval(n
, pos
-1) != 0);
702 case 0: mulmod(x
,x
); break;
706 case 2: mulmod(pbuff
, x
);
708 case 3: mulmod(x
,x
); mulmod(pbuff2
, x
); break;
714 mulmod(poly x
, poly y
) {
715 mulp(x
, y
); fullmod(y
);
718 elldoublep(poly n1
, poly d1
, poly m1
, poly c1
, poly n0
, poly d0
,
721 ptop(n1
, mn
); mulmod(n1
, mn
);
722 ptop(mn
, pbuff
); addp(mn
, mn
); addp(pbuff
, mn
);
724 ptop(d1
, pbuff
); mulmod(d1
, pbuff
);
725 scalarmul(a
, pbuff
); addp(pbuff
, mn
);
728 ptop(m1
, md
); addp(md
, md
);
729 mulmod(d1
, md
); mulmod(d1
, md
); mulmod(cubic
, md
);
731 ptop(d1
, n0
); mulmod(mn
, n0
); mulmod(mn
, n0
);
733 ptop(n1
, pbuff
); addp(pbuff
, pbuff
); fullmod(pbuff
);
734 mulmod(md
, pbuff
); mulmod(md
, pbuff
);
735 subp(pbuff
, n0
); fullmod(n0
);
736 ptop(md
, d0
); mulmod(md
, d0
); mulmod(d1
, d0
);
738 ptop(mn
, m0
); mulmod(c1
, m0
);
739 ptop(d0
, pbuff
); mulmod(n1
, pbuff
);
740 ptop(n0
, c0
); mulmod(d1
, c0
); subp(c0
, pbuff
);
743 ptop(m1
, pbuff
); mulmod(md
, pbuff
);
744 mulmod(d1
, pbuff
); mulmod(d0
, pbuff
);
745 subp(pbuff
, m0
); fullmod(m0
);
747 ptop(c1
, c0
); mulmod(md
, c0
); mulmod(d1
, c0
); mulmod(d0
, c0
);
750 elladdp(poly n1
, poly d1
, poly m1
, poly c1
, poly n2
, poly d2
, poly m2
, poly c2
, poly n0
, poly d0
, poly m0
, poly c0
) {
751 ptop(m2
, mn
); mulmod(c1
, mn
);
752 ptop(m1
, pbuff
); mulmod(c2
, pbuff
);
753 subp(pbuff
, mn
); fullmod(mn
);
754 mulmod(d1
, mn
); mulmod(d2
, mn
);
756 ptop(n2
, md
); mulmod(d1
, md
);
757 ptop(n1
, pbuff
); mulmod(d2
, pbuff
);
758 subp(pbuff
, md
); fullmod(md
);
759 mulmod(c1
, md
); mulmod(c2
, md
);
761 ptop(cubic
, n0
); mulmod(mn
, n0
); mulmod(mn
, n0
);
762 mulmod(d1
, n0
); mulmod(d2
, n0
);
763 ptop(n1
, pbuff
); mulmod(d2
, pbuff
);
764 ptop(n2
, d0
); mulmod(d1
, d0
);
765 addp(d0
, pbuff
); mulmod(md
, pbuff
); mulmod(md
, pbuff
);
766 subp(pbuff
, n0
); fullmod(n0
);
768 ptop(md
, d0
); mulmod(md
, d0
); mulmod(d1
, d0
); mulmod(d2
, d0
);
770 ptop(mn
, m0
); mulmod(c1
, m0
);
771 ptop(d0
, pbuff
); mulmod(n1
, pbuff
);
772 ptop(d1
, c0
); mulmod(n0
, c0
);
773 subp(c0
, pbuff
); fullmod(pbuff
);
775 ptop(m1
, pbuff
); mulmod(md
, pbuff
);
776 mulmod(d0
, pbuff
); mulmod(d1
, pbuff
);
777 subp(pbuff
, m0
); fullmod(m0
);
779 ptop(md
, c0
); mulmod(c1
, c0
); mulmod(d0
, c0
); mulmod(d1
, c0
);
785 for(j
=0; j
<= x
->deg
; j
++) {printf("%d: ",j
); gout(x
->coe
[j
]);}
788 main(int argc
, char **argv
) {
789 int j
, ct
= 0, el
, xmatch
, ymatch
;
791 int T
[L_CEIL
], P
[L_CEIL
], LL
[L_CEIL
];
793 unsigned int ord
, ordminus
;
796 p
= newgiant(INFINITY
); /* Also sets up internal giants' stacks. */
803 printf("Give p > 3, a, b on separate lines:\n"); fflush(stdout
);
804 gin(p
); /* Field prime. */
805 if((Q
= bitlen(p
)) > Q_MAX
) {
806 fprintf(stderr
, "p too large, larger than %d bits.\n", Q
);
809 if(!prime_probable(p
)) {
810 fprintf(stderr
, "p is not but must be prime.\n", Q
);
813 gin(a
); gin(b
); /* Curve parameters. */
817 /* Next, discriminant test for legitimacy of curve. */
818 gtog(a
, t1
); squareg(t1
); modg(p
, t1
); mulg(a
, t1
); modg(p
, t1
);
819 gshiftleft(2, t1
); /* 4 a^3 mod p. */
820 gtog(b
, t2
); squareg(t2
); modg(p
, t2
); smulg(27, t2
);
821 addg(t2
, t1
); modg(p
, t1
);
823 fprintf(stderr
, "Discriminant FAILED\n");
826 printf("Discriminant PASSED\n"); fflush(stdout
);
828 /* Next, find an efficient prime power array such that
829 Prod[powers] >= 16 p. */
831 /* Create minimal prime power array such that Prod[powers]^2 > 16p. */
833 gtog(p
, t2
); gshiftleft(4, t2
); /* t2 := 16p. */
836 while(L_MAX
<= L_CEIL
-1) {
837 for(j
=0; j
<= L_MAX
; j
++) LL
[j
] = 0;
838 for(j
=2; j
<= L_MAX
; j
++) {
853 for(j
=2; j
<= L_MAX
; j
++) {
854 if(LL
[j
]) { smulg(j
, t1
); smulg(j
, t1
); } /* Building up t1^2. */
856 if(gcompg(t1
, t2
) > 0) break;
860 printf("Initializing for prime powers:\n");
861 for(j
=2; j
<= L_MAX
; j
++) {
862 if(LL
[j
]) printf("%d ", j
);
868 MAX_DIGS
= (2 + (Q
+15)/8); /* Size of (squared) coefficients. */
869 MAX_COEFFS
= ((L_MAX
+1)*(L_MAX
+2));
874 for(L
= 2; L
<= L_MAX
; L
++) {
876 printf("Resolving Schoof L = %d...\n", L
);
877 P
[ct
] = L
; /* Stuff another prime power. */
879 // printf("s: "); polyout(s[L]);
881 k
= idivg(L
, aux2
); /* p (mod L). */
883 printf("power...\n");
884 txd
->deg
= 0; itog(1, txd
->coe
[0]);
885 tyd
->deg
= 0; itog(1, tyd
->coe
[0]);
886 txn
->deg
= 1; itog(0, txn
->coe
[0]); itog(1, txn
->coe
[1]);
890 powerpoly(txn
, aux2
); /* x^p. */
891 printf("x^p done...\n");
893 powerpoly(powx
, aux2
);
894 printf("x^p^2 done...\n");
896 gtog(p
, aux2
); itog(1, aux
); subg(aux
, aux2
);
897 gshiftright(1, aux2
); /* aux2 := (p-1)/2. */
898 powerpoly(tyn
, aux2
); /* y^p. */
899 printf("y^p done...\n");
900 ptop(tyn
, powy
); mulp(tyn
, powy
); fullmod(powy
);
901 mulp(cubic
, powy
); fullmod(powy
);
902 powerpoly(powy
, aux2
);
903 mulp(tyn
, powy
); fullmod(powy
);
904 printf("Powers done...\n");
906 // printf("pow" ); polyout(powx); polyout(powy);
907 ptop(txn
, txn1
); ptop(txd
, txd1
); /* Save t = 1 case. */
908 ptop(tyn
, tyn1
); ptop(tyd
, tyd1
);
910 (powx, y powy) + k(kxn/kxd, y kyn/kyd) = t(txn/txd, y tyn/tyd)
913 if(k
==1) { ptop(txd
, kxd
); ptop(txd
, kyd
);
916 ptop(s
[k
], kxd
); mulp(s
[k
], kxd
); fullmod(kxd
);
917 if(k%2
==0) { mulp(cubic
, kxd
); fullmod(kxd
); }
918 mulp(kxd
, kxn
); fullmod(kxn
);
919 ptop(s
[k
-1], pbuff
); mulp(s
[k
+1], pbuff
); fullmod(pbuff
);
920 if(k%2
==1) {mulp(cubic
, pbuff
); fullmod(pbuff
); }
921 subp(pbuff
, kxn
); fullmod(kxn
);
923 ptop(s
[k
+2], kyn
); mulp(s
[k
-1], kyn
); fullmod(kyn
);
924 mulp(s
[k
-1], kyn
); fullmod(kyn
);
926 ptop(s
[k
-2], pbuff
); mulp(s
[k
+1], pbuff
); fullmod(pbuff
);
927 mulp(s
[k
+1], pbuff
); fullmod(pbuff
);
928 subp(pbuff
, kyn
); fullmod(kyn
);
930 ptop(s
[k
], kyd
); mulp(s
[k
], kyd
); fullmod(kyd
);
931 mulp(s
[k
], kyd
); fullmod(kyd
);
932 if(k%2
==0) { mulp(cubic
, kyd
); fullmod(kyd
);
933 mulp(cubic
, kyd
); fullmod(kyd
);}
934 itog(4, aux2
); scalarmul(aux2
, kyd
);
936 //printf("kP: "); polyout(kxn); polyout(kxd); polyout(kyn); polyout(kyd);
937 /* Commence t = 0 check. */
938 printf("Checking t = %d ...\n", 0);
941 ptop(powx
, pbuff
); mulp(kxd
, pbuff
);
948 /* Now check y coords. */
949 if(L
== 2) goto resolve
;
950 ptop(powy
, pbuff
); mulp(kyd
, pbuff
);
955 printf("%d %d\n", L
, 0);
960 /* Combine pt1 and pt2. */
961 if((xmatch
== 1) && (ymatch
== 1))
962 elldoublep(powx
, txd
, powy
, txd
, nx
, dx
, ny
, dy
);
964 elladdp(powx
, txd
, powy
, txd
, kxn
, kxd
, kyn
, kyd
, nx
, dx
, ny
, dy
);
965 /* Now {nx/dx, ny/dy} is (fixed) LHS. */
966 // printf("add12: "); polyout(nx); polyout(dx); polyout(ny); polyout(dy);
967 /* Commence t > 0 check. */
968 for(t
=1; t
<= L
/2; t
++) {
969 printf("Checking t = %d ...\n", t
);
970 if(t
> 1) { /* Add (tx1, ty1) to (txn, tyn). */
971 ptop(txn1
, pbuff
); mulmod(txd
, pbuff
);
972 ptop(txn
, powx
); mulmod(txd1
, powx
);
973 subp(powx
, pbuff
); fullmod(pbuff
);
975 elladdp(txn1
, txd1
, tyn1
, tyd1
, txn
, txd
, tyn
, tyd
,
976 tmp1
, tmp2
, tmp3
, tmp4
);
977 else elldoublep(txn
, txd
, tyn
, tyd
,
978 tmp1
, tmp2
, tmp3
, tmp4
);
979 ptop(tmp1
, txn
); ptop(tmp2
, txd
);
980 ptop(tmp3
, tyn
); ptop(tmp4
, tyd
);
982 // printf("tQ: "); polyout(txn); polyout(txd); polyout(tyn); polyout(tyd);
983 /* Next, check {nx/dx, ny/dy} =? {txn/txd, tyn/tyd}. */
984 ptop(nx
, pbuff
); mulmod(txd
, pbuff
);
985 ptop(dx
, powx
); mulmod(txn
, powx
);
986 subp(powx
, pbuff
); fullmod(pbuff
);
987 if(!iszerop(pbuff
)) continue;
989 // printf("y check!\n");
990 ptop(ny
, pbuff
); mulmod(tyd
, pbuff
);
991 ptop(dy
, powx
); mulmod(tyn
, powx
);
992 subp(powx
, pbuff
); fullmod(pbuff
);
994 printf("%d %d\n", L
, t
);
997 printf("%d %d\n", L
, L
-t
);
1005 /* Now, prime powers P[] and CRT residues T[] are intact. */
1006 printf("Prime powers L:\n");
1008 for(j
=0; j
< ct
-1; j
++) {
1009 printf("%d, ", P
[j
]);
1011 printf("%d }\n", P
[ct
-1]);
1013 printf("Residues t (mod L):\n");
1015 for(j
=0; j
< ct
-1; j
++) {
1016 printf("%d, ", T
[j
]);
1018 printf("%d }\n", T
[ct
-1]);
1020 /* Mathematica algorithm for order:
1021 plis = {2^5, 3^3, 5^2, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47};
1022 tlis = {1, 26, 4, 2, 4, 11, 6, 5, 19, 22, 10, 16, 7, 22, 11};
1023 prod = Apply[Times, plis];
1025 invlis = Table[PowerMod[prlis[[q]], -1, plis[[q]]],{q,1,Length[plis]}];
1027 t = Mod[tlis . (prlis * invlis), prod];
1028 ord = p + 1 - If[t^2 > 4p, t - prod, t]
1032 for(j
=0; j
< ct
; j
++) {
1033 free(s
[j
]); /* Just to clear memory. */
1037 for(j
=0; j
< 2*ct
; j
++) {
1038 ss
[j
] = newgiant(MAX_DIGS
);
1041 for(j
=0; j
< ct
; j
++) {
1047 for(j
=0; j
< ct
; j
++) {
1048 gtog(ss
[j
], ss
[j
+ct
]);
1054 for(j
=0; j
< ct
; j
++) {
1065 gtog(p
, t3
); gshiftleft(2, t3
);
1066 if(gcompg(t4
, t3
) > 0) subg(t1
, t2
);
1068 printf("Parameters:\n");
1069 printf("p = "); gout(p
);
1070 printf("a = "); gout(a
);
1071 printf("b = "); gout(b
);
1072 printf("Curve order:\n");
1073 printf("o = "); gout(t5
); gtog(t5
, t3
); /* Save order as t3. */
1074 printf("Twist order:\n");
1079 /* Next, verify the order. */
1080 printf("Verifying order o:...\n");
1081 init_ell_proj(MAX_DIGS
);
1082 pt
= new_point_proj(MAX_DIGS
);
1083 pt2
= new_point_proj(MAX_DIGS
);
1085 find_point_proj(pt
, t2
, a
, b
, p
);
1086 printf("A point on the curve y^2 = x^3 + a x + b (mod p) is:\n");
1087 printf("(x,y,z) = {\n"); gout(pt
->x
); printf(",");
1088 gout(pt
->y
); printf(","); gout(pt
->z
);
1090 ell_mul_proj(pt
, pt2
, t3
, a
, p
);
1091 printf("A multiple is:\n");
1092 printf("o * (x,y,z) = {\n");
1093 gout(pt2
->x
); printf(",");gout(pt2
->y
); printf(",");gout(pt2
->z
);
1095 if(!isZero(pt2
->z
)) {
1096 printf("TILT: multiple should be point-at-infinity.\n");
1099 printf("VERIFIED: multiple is indeed point-at-infinity.\n");