]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_cryptkit/lib/CurveParamDocs/schoofs.c
Security-57336.10.29.tar.gz
[apple/security.git] / OSX / libsecurity_cryptkit / lib / CurveParamDocs / schoofs.c
1 /* schoofs.c
2
3 Elliptic curve order calculator, for
4
5 y^2 = x^3 + a x + b (mod p)
6
7 (NOTE:
8 This version has order sieving, triggering on the
9 initial b parameter and incrementing same.
10 Parameter details are described in schoof.c)
11
12 Compile with:
13
14 % cc -O schoofs.c giants.c tools.c -lm -o schoofs
15
16 and run, entering the a,b parameters.
17
18 * Change history:
19
20 20 Mar 01 (REC) Added binarysegsquare() and base-4 ladder
21 20 Mar 01 (REC) Bumped MAX_DIGS as in schoof.c
22 4 Feb 99 (REC) Sieving invoked.
23 2 Feb 99 (REC) Added explicit CRT result
24 12 Jan 99 (REC) Removed (hopefully) last of memory crashes
25 20 Jan 98 (REC) Creation
26
27 * c. 1998 Perfectly Scientific, Inc.
28 * All Rights Reserved.
29 *
30 *
31 *************************************************************/
32
33 #include <stdio.h>
34 #include<assert.h>
35 #include <math.h>
36 #include"giants.h"
37 #include "tools.h"
38
39 #define P_BREAK 32
40
41
42 #define Q 256 /* See schoof.c for explanation. */
43 #define L_MAX 100
44 #define MAX_DIGS (2 + (Q+15)/8) /* Size of (squared) coefficients. */
45 #define MAX_COEFFS ((L_MAX+1)*(L_MAX+2))
46
47 typedef struct
48 {
49 int deg;
50 giant *coe;
51 } polystruct;
52 typedef polystruct *poly;
53
54
55 static giant *mcand, coe, tmp, err, aux, aux2, globx, globy, t1, t2,
56 t3, t4, t5;
57 static poly qscratch, rscratch, sscratch, tscratch, pbuff, pbuff2,
58 precip, cubic, powx, powy, kxn, kyn, kxd, kyd,
59 txn, txd, tyn, tyd, txn1, txd1, tyn1, tyd1,
60 nx, dx, ny, dy, mn, md, tmp1, tmp2, tmp3, tmp4;
61 static poly s[L_MAX+2], smonic;
62 static giant p, a, b, magcheck;
63 int L;
64
65 void quickmodg(giant g, giant x)
66 { int sgn = x->sign;
67
68 if(sgn == 0) return;
69 if(sgn > 0) {
70 if(gcompg(x, g) >= 0) subg(g, x);
71 return;
72 }
73 addg(g,x);
74 return;
75 }
76
77 int
78 log_2(int n) {
79 int c = 1, d = -1;
80 while(c <= n) {
81 c <<= 1;
82 ++d;
83 }
84 return(d);
85 }
86
87 void
88 justifyp(poly x) {
89 int j;
90 for(j = x->deg; j >= 0; j--) {
91 if(!is0(x->coe[j])) break;
92 }
93 x->deg = (j>0)? j : 0;
94 }
95
96 void
97 polyrem(poly x) {
98 int j;
99 for(j=0; j <= x->deg; j++) {
100 modg(p, x->coe[j]);
101 }
102 justifyp(x);
103 }
104
105
106 giant *
107 newa(int n) {
108 giant *p = (giant *)malloc(n*sizeof(giant));
109 int j;
110 for(j=0; j<n; j++) {
111 p[j] = newgiant(MAX_DIGS);
112 }
113 return(p);
114 }
115
116 poly
117 newpoly(int coeffs) {
118 poly pol;
119 pol = (poly) malloc(sizeof(polystruct));
120 pol->coe = (giant *)newa(coeffs);
121 return(pol);
122 }
123
124 void
125 init_all() {
126 int j;
127
128 j = (2*Q + log_2(MAX_COEFFS) + 32 + 15)/16;
129 globx = newgiant(MAX_COEFFS * j);
130 globy = newgiant(MAX_COEFFS * j);
131
132 init_tools(MAX_DIGS);
133 powx = newpoly(MAX_COEFFS);
134 powy = newpoly(MAX_COEFFS);
135 kxn = newpoly(MAX_COEFFS);
136 kxd = newpoly(MAX_COEFFS);
137 kyn = newpoly(MAX_COEFFS);
138 kyd = newpoly(MAX_COEFFS);
139 txn = newpoly(MAX_COEFFS);
140 txd = newpoly(MAX_COEFFS);
141 tyn = newpoly(MAX_COEFFS);
142 tyd = newpoly(MAX_COEFFS);
143 txn1 = newpoly(MAX_COEFFS);
144 txd1 = newpoly(MAX_COEFFS);
145 tyn1 = newpoly(MAX_COEFFS);
146 tyd1 = newpoly(MAX_COEFFS);
147 nx = newpoly(MAX_COEFFS);
148 ny = newpoly(MAX_COEFFS);
149 dx = newpoly(MAX_COEFFS);
150 dy = newpoly(MAX_COEFFS);
151 mn = newpoly(MAX_COEFFS);
152 md = newpoly(MAX_COEFFS);
153 tmp1 = newpoly(MAX_COEFFS);
154 tmp2 = newpoly(MAX_COEFFS);
155 tmp3 = newpoly(MAX_COEFFS);
156 tmp4 = newpoly(MAX_COEFFS);
157 mcand = (giant *)newa(MAX_COEFFS);
158
159 s[0] = newpoly(MAX_COEFFS);
160
161 for(j=1; j<=L_MAX+1; j++) {
162 s[j] = newpoly(j*(j+1));
163 }
164 smonic = newpoly(MAX_COEFFS);
165 /* The next three need extra space for remaindering routine. */
166 qscratch = newpoly(2*MAX_COEFFS);
167 rscratch = newpoly(2*MAX_COEFFS);
168 pbuff = newpoly(2*MAX_COEFFS);
169 pbuff2 = newpoly(MAX_COEFFS);
170 sscratch = newpoly(MAX_COEFFS);
171 tscratch = newpoly(MAX_COEFFS);
172 tmp = newgiant(MAX_DIGS);
173 err = newgiant(MAX_DIGS);
174 coe = newgiant(MAX_DIGS);
175 aux = newgiant(MAX_DIGS);
176 aux2 = newgiant(MAX_DIGS);
177 t1 = newgiant(MAX_DIGS);
178 t2 = newgiant(MAX_DIGS);
179 t3 = newgiant(MAX_DIGS);
180 t4 = newgiant(MAX_DIGS);
181 t5 = newgiant(MAX_DIGS);
182 cubic = newpoly(4);
183 p = newgiant(MAX_DIGS);
184 a = newgiant(MAX_DIGS);
185 b = newgiant(MAX_DIGS);
186 magcheck = newgiant(MAX_DIGS);
187 precip = newpoly(MAX_COEFFS);
188 }
189
190 void
191 atoa(giant *a, giant *b, int n) {
192 int j;
193 for(j=0; j<n; j++) gtog(a[j], b[j]);
194 }
195
196 void
197 ptop(poly x, poly y)
198 /* y := x. */
199 {
200 y->deg = x->deg;
201 atoa(x->coe, y->coe, y->deg+1);
202 }
203
204 void
205 negp(poly y)
206 /* y := -y. */
207 { int j;
208 for(j=0; j <= y->deg; j++) {
209 negg(y->coe[j]);
210 quickmodg(p, y->coe[j]);
211 }
212 }
213
214 int
215 iszer(giant a) {
216
217 if(a->sign == 0) return(1);
218 return(0);
219
220 }
221
222 int
223 iszerop(poly x) {
224 if(x->deg == 0 && iszer(x->coe[0])) return 1;
225 return 0;
226 }
227
228 int
229 is0(giant a) {
230 return(iszer(a));
231 }
232
233 int
234 is1(giant a) {
235 return(isone(a));
236 }
237
238
239 void
240 addp(poly x, poly y)
241 /* y += x. */
242 {
243 int d = x->deg, j;
244
245 if(y->deg > d) d = y->deg;
246 for(j = 0; j <= d; j++) {
247 if((j <= x->deg) && (j <= y->deg)) {
248 addg(x->coe[j], y->coe[j]);
249 quickmodg(p, y->coe[j]);
250 continue;
251 }
252 if((j <= x->deg) && (j > y->deg)) {
253 gtog(x->coe[j], y->coe[j]);
254 quickmodg(p, y->coe[j]);
255 continue;
256 }
257 }
258 y->deg = d;
259 justifyp(y);
260 }
261
262 void
263 subp(poly x, poly y)
264 /* y -= x. */
265 {
266 int d = x->deg, j;
267
268 if(y->deg > d) d = y->deg;
269 for(j = 0; j <= d; j++) {
270 if((j <= x->deg) && (j <= y->deg)) {
271 subg(x->coe[j], y->coe[j]);
272 quickmodg(p, y->coe[j]);
273 continue;
274 }
275 if((j <= x->deg) && (j > y->deg)) {
276 gtog(x->coe[j], y->coe[j]);
277 negg(y->coe[j]);
278 quickmodg(p, y->coe[j]);
279 continue;
280 }
281 }
282 y->deg = d;
283 justifyp(y);
284 }
285
286
287 void
288 grammarmulp(poly a, poly b)
289 /* b *= a. */
290 {
291 int dega = a->deg, degb = b->deg, deg = dega + degb;
292 register int d, kk, first, diffa;
293
294 for(d=deg; d>=0; d--) {
295 diffa = d-dega;
296 itog(0, coe);
297 for(kk=0; kk<=d; kk++) {
298 if((kk>degb)||(kk<diffa)) continue;
299 gtog(b->coe[kk], tmp);
300 mulg(a->coe[d-kk], tmp);
301 modg(p, tmp);
302 addg(tmp, coe);
303 quickmodg(p, coe);
304 }
305 gtog(coe, mcand[d]);
306 }
307 atoa(mcand, b->coe, deg+1);
308 b->deg = deg;
309 justifyp(b);
310 }
311
312 void
313 atop(giant *a, poly x, int deg)
314 /* Copy array to poly, with monic option. */
315 {
316 int adeg = abs(deg);
317 x->deg = adeg;
318 atoa(a, x->coe, adeg);
319 if(deg < 0) {
320 itog(1, x->coe[adeg]);
321 } else {
322 gtog(a[adeg], x->coe[adeg]);
323 }
324 }
325
326 void
327 just(giant g) {
328 while((g->n[g->sign-1] == 0) && (g->sign > 0)) --g->sign;
329 }
330
331 void
332 unstuff_partial(giant g, poly y, int words){
333 int j;
334 for(j=0; j < y->deg; j++) {
335 bcopy((g->n) + j*words, y->coe[j]->n, words*sizeof(short));
336 y->coe[j]->sign = words;
337 just(y->coe[j]);
338 }
339 }
340
341 void
342 stuff(poly x, giant g, int words) {
343 int deg = x->deg, j, coedigs;
344
345 g->sign = words*(1 + deg);
346 for(j=0; j <= deg; j++) {
347 coedigs = (x->coe[j])->sign;
348 bcopy(x->coe[j]->n, (g->n) + j*words, coedigs*sizeof(short));
349 bzero((g->n) + (j*words+coedigs),
350 sizeof(short)*(words-coedigs));
351 }
352 just(g);
353 }
354
355 int maxwords = 0;
356 void
357
358 binarysegmul(poly x, poly y) {
359 int bits = bitlen(p), xwords, ywords, words;
360
361 xwords = (2*bits + log_2(x->deg+1) + 32 + 15)/16;
362 ywords = (2*bits + log_2(y->deg+1) + 32 + 15)/16;
363 if(xwords > ywords) words = xwords; else words = ywords;
364 if(words > maxwords) {
365 maxwords = words;
366 // printf("m: %d\n", words);
367 fflush(stdout);
368 }
369 stuff(x, globx, words);
370 stuff(y, globy, words);
371 mulg(globx, globy);
372 gtog(y->coe[y->deg], globx); /* Save high coeff. */
373 y->deg += x->deg;
374 gtog(globx, y->coe[y->deg]); /* Move high coeff. */
375 unstuff_partial(globy, y, words);
376 mulg(x->coe[x->deg], y->coe[y->deg]); /* resolve high coeff. */
377 justifyp(y);
378 }
379
380 binarysegsquare(poly y) {
381 int bits = bitlen(p), words;
382 words = (2*bits + log_2(y->deg+1) + 32 + 15)/16;
383 stuff(y, globy, words);
384 squareg(globy);
385 gtog(y->coe[y->deg], globx); /* Save high coeff. */
386 y->deg += y->deg;
387 gtog(globx, y->coe[y->deg]); /* Move high coeff. */
388 unstuff_partial(globy, y, words);
389 mulg(y->coe[y->deg], y->coe[y->deg]); /* resolve high coeff. */
390 justifyp(y);
391 }
392
393
394 void
395 assess(poly x, poly y){
396 int max = 0, j;
397 for(j=0; j <= x->deg; j++) {
398 if(bitlen(x->coe[j]) > max) max = bitlen(x->coe[j]);
399 }
400 // printf("max: %d ", max);
401 max = 0;
402 for(j=0; j <= y->deg; j++) {
403 if(bitlen(y->coe[j]) > max) max = bitlen(y->coe[j]);
404 }
405 // printf("%d\n", max);
406
407
408 }
409
410 int
411 pcompp(poly x, poly y) {
412 int j;
413 if(x->deg != y->deg) return 1;
414 for(j=0; j <= x->deg; j++) {
415 if(gcompg(x->coe[j], y->coe[j])) return 1;
416 }
417 return 0;
418 }
419
420 int maxdeg = 0;
421
422 void
423 mulp(poly x, poly y)
424 /* y *= x. */
425 {
426 int n, degx = x->deg, degy = y->deg;
427
428 /*
429 if(degx > max_deg) {
430 max_deg = degx; printf("xdeg: %d\n", degx);
431 }
432
433 if(degy > max_deg) {
434 max_deg = degy; printf("ydeg: %d\n", degy);
435 }
436 */
437 if((degx < P_BREAK) || (degy < P_BREAK)) {
438 grammarmulp(x,y);
439 justifyp(y);
440 return;
441 }
442 if(x==y) binarysegsquare(y);
443 else binarysegmul(x, y);
444 }
445
446 void
447 revp(poly x)
448 /* Reverse the coefficients of x. */
449 { int j, deg = x->deg;
450
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]);
455 }
456 justifyp(x);
457 }
458
459 void
460 recipp(poly f, int deg)
461 /* f := 1/f, via newton method. */
462 {
463 int lim = deg + 1, prec = 1;
464
465 sscratch->deg = 0; itog(1, sscratch->coe[0]);
466 itog(1, aux);
467 while(prec < lim) {
468 prec <<= 1;
469 if(prec > lim) prec = lim;
470 f->deg = prec-1;
471 ptop(sscratch, tscratch);
472 mulp(f, tscratch);
473 tscratch->deg = prec-1;
474 polyrem(tscratch);
475 subg(aux, tscratch->coe[0]);
476 quickmodg(p, tscratch->coe[0]);
477 mulp(sscratch, tscratch);
478 tscratch->deg = prec-1;
479 polyrem(tscratch);
480 subp(tscratch, sscratch);
481 sscratch->deg = prec-1;
482 polyrem(sscratch);
483 }
484 justifyp(sscratch);
485 ptop(sscratch, f);
486 }
487
488 int
489 left_justifyp(poly x, int start)
490 /* Left-justify the polynomial, checking from position "start." */
491 {
492 int j, shift = 0;
493
494 for(j = start; j <= x->deg; j++) {
495 if(!is0(x->coe[j])) {
496 shift = start;
497 break;
498 }
499 }
500 x->deg -= shift;
501 for(j=0; j<= x->deg; j++) {
502 gtog(x->coe[j+shift], x->coe[j]);
503 }
504 return(shift);
505 }
506
507 void
508 remp(poly x, poly y, int mode)
509 /* y := x (mod y).
510 mode = 0 is normal operation,
511 = 1 jams a fixed reciprocal,
512 = 2 uses the fixed reciprocal.
513 */
514 {
515 int degx = x->deg, degy = y->deg, d, shift;
516
517 if(degy == 0) {
518 y->deg = 0;
519 itog(0, y->coe[0]);
520 return;
521 }
522 d = degx - degy;
523 if(d < 0) {
524 ptop(x, y);
525 return;
526 }
527 revp(x); revp(y);
528 ptop(y, rscratch);
529 switch(mode) {
530 case 0: recipp(rscratch, d);
531 break;
532 case 1: recipp(rscratch, degy); /* degy -1. */
533 ptop(rscratch, precip);
534 rscratch->deg = d; justifyp(rscratch);
535 break;
536 case 2: ptop(precip, rscratch);
537 rscratch->deg = d; justifyp(rscratch);
538 break;
539 }
540 /* Next, a limited-precision multiply. */
541 if(d < degx) { x->deg = d; justifyp(x);}
542 mulp(x, rscratch);
543 rscratch->deg = d;
544 polyrem(rscratch);
545 justifyp(rscratch);
546 x->deg = degx; justifyp(x);
547 mulp(rscratch, y);
548 subp(x, y);
549 negp(y); polyrem(y);
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;
553 revp(y);
554 revp(x);
555 }
556
557 fullmod(poly x) {
558 polyrem(x);
559 ptop(smonic, s[0]);
560 remp(x, s[0], 2);
561 ptop(s[0], x);
562 polyrem(x);
563 }
564
565 scalarmul(giant s, poly x) {
566 int j;
567 for(j=0; j <= x->deg; j++) {
568 mulg(s, x->coe[j]);
569 modg(p, x->coe[j]);
570 }
571 }
572
573
574 schain(int el) {
575 int j;
576
577 s[0]->deg = 0;
578 itog(0, s[0]->coe[0]);
579
580 s[1]->deg = 0;
581 itog(1, s[1]->coe[0]);
582 s[2]->deg = 0;
583 itog(2, s[2]->coe[0]);
584
585 s[3]->deg = 4;
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]);
594
595 s[4]->deg = 6;
596 gtog(a, aux); mulg(a, aux); mulg(a, aux);
597 gtog(b, tmp); mulg(b, tmp); smulg(8, tmp); addg(tmp, aux);
598 negg(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]);
610 itog(4, aux);
611 scalarmul(aux, s[4]);
612 cubic->deg = 3;
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++) {
618 if(j % 2 == 0) {
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]);
626 } else {
627 ptop(s[(j-1)/2+2], s[j]);
628 mulp(s[(j-1)/2], s[j]); polyrem(s[j]);
629 mulp(s[(j-1)/2], s[j]); polyrem(s[j]);
630 mulp(s[(j-1)/2], s[j]); polyrem(s[j]);
631 ptop(s[(j-1)/2-1], s[0]);
632 mulp(s[(j-1)/2 + 1], s[0]); polyrem(s[0]);
633 mulp(s[(j-1)/2 + 1], s[0]); polyrem(s[0]);
634 mulp(s[(j-1)/2 + 1], s[0]); polyrem(s[0]);
635 if(((j-1)/2) % 2 == 1) {
636 mulp(cubic, s[0]); polyrem(s[0]);
637 mulp(cubic, s[0]); polyrem(s[0]);
638 } else {
639 mulp(cubic, s[j]); polyrem(s[j]);
640 mulp(cubic, s[j]); polyrem(s[j]);
641 }
642 // polyout(s[1]); polyout(s[3]); polyout(s[0]); polyout(s[j]);
643 subp(s[0], s[j]);
644 polyrem(s[j]);
645 }
646 }
647 }
648
649 init_recip(int el) {
650 int j;
651 ptop(s[el], smonic);
652 if(el == 2) {
653 mulp(cubic, smonic); polyrem(smonic);
654 }
655 gtog(smonic->coe[smonic->deg], aux); /* High coeff. */
656 binvg(p, aux);
657 scalarmul(aux, smonic); /* s is now monic. */
658 s[0]->deg = smonic->deg + 1;
659 for(j=0; j <= s[0]->deg; j++) itog(1, s[0]->coe[j]);
660 ptop(smonic, pbuff);
661 remp(s[0], pbuff, 1); /* Initialize reciprocal of s as precip. */
662 }
663
664 void powerpoly(poly x, giant n)
665 /* Base-4 window. */
666 { int pos, code;
667 ptop(x, pbuff); /* x. */
668 ptop(pbuff, pbuff2);
669 mulmod(pbuff2, pbuff2); mulmod(pbuff, pbuff2); /* x^3. */
670 pos = bitlen(n)-2;
671 while(pos >= 0) {
672 mulmod(x, x);
673 if(pos==0) {
674 if(bitval(n, pos) != 0) {
675 mulmod(pbuff, x);
676 }
677 break;
678 }
679 code = (bitval(n, pos) != 0) * 2 + (bitval(n, pos-1) != 0);
680 switch(code) {
681 case 0: mulmod(x,x); break;
682 case 1: mulmod(x,x);
683 mulmod(pbuff, x);
684 break;
685 case 2: mulmod(pbuff, x);
686 mulmod(x,x); break;
687 case 3: mulmod(x,x); mulmod(pbuff2, x); break;
688 }
689 pos -= 2;
690 }
691 }
692
693 mulmod(poly x, poly y) {
694 mulp(x, y); fullmod(y);
695 }
696
697 elldoublep(poly n1, poly d1, poly m1, poly c1, poly n0, poly d0,
698 poly m0, poly c0) {
699
700 ptop(n1, mn); mulmod(n1, mn);
701 ptop(mn, pbuff); addp(mn, mn); addp(pbuff, mn);
702 fullmod(mn);
703 ptop(d1, pbuff); mulmod(d1, pbuff);
704 scalarmul(a, pbuff); addp(pbuff, mn);
705 fullmod(mn);
706 mulmod(c1, mn);
707 ptop(m1, md); addp(md, md);
708 mulmod(d1, md); mulmod(d1, md); mulmod(cubic, md);
709
710 ptop(d1, n0); mulmod(mn, n0); mulmod(mn, n0);
711 mulmod(cubic, n0);
712 ptop(n1, pbuff); addp(pbuff, pbuff); fullmod(pbuff);
713 mulmod(md, pbuff); mulmod(md, pbuff);
714 subp(pbuff, n0); fullmod(n0);
715 ptop(md, d0); mulmod(md, d0); mulmod(d1, d0);
716
717 ptop(mn, m0); mulmod(c1, m0);
718 ptop(d0, pbuff); mulmod(n1, pbuff);
719 ptop(n0, c0); mulmod(d1, c0); subp(c0, pbuff);
720 fullmod(pbuff);
721 mulmod(pbuff, m0);
722 ptop(m1, pbuff); mulmod(md, pbuff);
723 mulmod(d1, pbuff); mulmod(d0, pbuff);
724 subp(pbuff, m0); fullmod(m0);
725
726 ptop(c1, c0); mulmod(md, c0); mulmod(d1, c0); mulmod(d0, c0);
727 }
728
729 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) {
730 ptop(m2, mn); mulmod(c1, mn);
731 ptop(m1, pbuff); mulmod(c2, pbuff);
732 subp(pbuff, mn); fullmod(mn);
733 mulmod(d1, mn); mulmod(d2, mn);
734
735 ptop(n2, md); mulmod(d1, md);
736 ptop(n1, pbuff); mulmod(d2, pbuff);
737 subp(pbuff, md); fullmod(md);
738 mulmod(c1, md); mulmod(c2, md);
739
740 ptop(cubic, n0); mulmod(mn, n0); mulmod(mn, n0);
741 mulmod(d1, n0); mulmod(d2, n0);
742 ptop(n1, pbuff); mulmod(d2, pbuff);
743 ptop(n2, d0); mulmod(d1, d0);
744 addp(d0, pbuff); mulmod(md, pbuff); mulmod(md, pbuff);
745 subp(pbuff, n0); fullmod(n0);
746
747 ptop(md, d0); mulmod(md, d0); mulmod(d1, d0); mulmod(d2, d0);
748
749 ptop(mn, m0); mulmod(c1, m0);
750 ptop(d0, pbuff); mulmod(n1, pbuff);
751 ptop(d1, c0); mulmod(n0, c0);
752 subp(c0, pbuff); fullmod(pbuff);
753 mulmod(pbuff, m0);
754 ptop(m1, pbuff); mulmod(md, pbuff);
755 mulmod(d0, pbuff); mulmod(d1, pbuff);
756 subp(pbuff, m0); fullmod(m0);
757
758 ptop(md, c0); mulmod(c1, c0); mulmod(d0, c0); mulmod(d1, c0);
759
760 }
761
762 polyout(poly x) {
763 int j;
764 for(j=0; j <= x->deg; j++) {printf("%d: ",j); gout(x->coe[j]);}
765 }
766
767 #define SIEVE_CUT 7
768
769 main(int argc, char **argv) {
770 int j, ct, el, xmatch, ymatch;
771 int k, k2, t, linit;
772 int T[L_MAX], P[L_MAX];
773 giant ss[L_MAX];
774 unsigned int ord, ordminus;
775
776 printf("Initializing...\n"); fflush(stdout);
777 init_all();
778
779 for(j=0; j < L_MAX; j++) { /* Array to be used for CRT reconstruction. */
780 ss[j] = NULL;
781 }
782
783 printf("Give p, a, b on separate lines:\n"); fflush(stdout);
784 gin(p); /* Field prime. */
785 if(bitlen(p) > Q) {
786 fprintf(stderr, "p too large, larger than %d bits.\n", Q);
787 exit(0);
788 }
789
790 gin(a); gin(b); /* Curve parameters. */
791
792 newb:
793 printf("Checking discriminant for:\nb = ");
794 gout(b);
795 gtog(a, t1); squareg(t1); modg(p, t1); mulg(a, t1); modg(p, t1);
796 gshiftleft(2, t1); /* 4 a^3. */
797 gtog(b, t2); squareg(t2); modg(p, t2); smulg(27, t2);
798 addg(t2, t1); modg(p, t1);
799 if(isZero(t1)) {
800 printf("Discriminant FAILED\n");
801 iaddg(1, b);
802 goto newb;
803 }
804 printf("Discriminant PASSED\n");
805 printf("Starting sieve process:\n");
806
807
808 schain(SIEVE_CUT + 1); /* Do first piece of chain, for small-sieving. */
809 linit = 0;
810 ct = 0;
811 itog(1, magcheck);
812 for(el = 2; el <= L_MAX; el += 1 + (el%2)) {
813 if(!primeq(el)) continue;
814 L = el; while(L*el <= 4) L *= el;
815 printf("Resolving Schoof L = %d...\n", L);
816 P[ct] = L; /* Stuff another prime power. */
817 smulg(L, magcheck);
818 gtog(magcheck, tmp); squareg(tmp); gshiftright(2, tmp);
819 if(gcompg(tmp, p) > 0) break; /* Done...go to CRT phase. */
820 if((L > SIEVE_CUT) && (linit == 0)) {
821 schain(L_MAX+1);
822 linit = 1;
823 }
824 init_recip(L);
825 // printf("s: "); polyout(s[L]);
826 gtog(p, aux2);
827 k = idivg(L, aux2); /* p (mod L). */
828 gtog(p, aux2);
829 k2 = idivg(el, aux2);
830 // printf("power...\n");
831 txd->deg = 0; itog(1, txd->coe[0]);
832 tyd->deg = 0; itog(1, tyd->coe[0]);
833 txn->deg = 1; itog(0, txn->coe[0]); itog(1, txn->coe[1]);
834 ptop(txn, kxn);
835
836 gtog(p, aux2);
837 powerpoly(txn, aux2); /* x^p. */
838 // printf("x^p done...\n");
839 ptop(txn, powx);
840 powerpoly(powx, aux2);
841 // printf("x^p^2 done...\n");
842 ptop(cubic, tyn);
843 gtog(p, aux2); itog(1, aux); subg(aux, aux2);
844 gshiftright(1, aux2); /* aux2 := (p-1)/2. */
845 powerpoly(tyn, aux2); /* y^p. */
846 // printf("y^p done...\n");
847 ptop(tyn, powy); mulp(tyn, powy); fullmod(powy);
848 mulp(cubic, powy); fullmod(powy);
849 powerpoly(powy, aux2);
850 mulp(tyn, powy); fullmod(powy);
851 // printf("Powers done...\n");
852
853 // printf("pow" ); polyout(powx); polyout(powy);
854 ptop(txn, txn1); ptop(txd, txd1); /* Save t = 1 case. */
855 ptop(tyn, tyn1); ptop(tyd, tyd1);
856 /* We now shall test
857 (powx, y powy) + k(kxn/kxd, y kyn/kyd) = t(txn/txd, y tyn/tyd)
858 */
859
860 if(k==1) { ptop(txd, kxd); ptop(txd, kyd);
861 ptop(txd, kyn);
862 } else {
863 ptop(s[k], kxd); mulp(s[k], kxd); fullmod(kxd);
864 if(k%2==0) { mulp(cubic, kxd); fullmod(kxd); }
865 mulp(kxd, kxn); fullmod(kxn);
866 ptop(s[k-1], pbuff); mulp(s[k+1], pbuff); fullmod(pbuff);
867 if(k%2==1) {mulp(cubic, pbuff); fullmod(pbuff); }
868 subp(pbuff, kxn); fullmod(kxn);
869
870 ptop(s[k+2], kyn); mulp(s[k-1], kyn); fullmod(kyn);
871 mulp(s[k-1], kyn); fullmod(kyn);
872 if(k > 2) {
873 ptop(s[k-2], pbuff); mulp(s[k+1], pbuff); fullmod(pbuff);
874 mulp(s[k+1], pbuff); fullmod(pbuff);
875 subp(pbuff, kyn); fullmod(kyn);
876 }
877 ptop(s[k], kyd); mulp(s[k], kyd); fullmod(kyd);
878 mulp(s[k], kyd); fullmod(kyd);
879 if(k%2==0) { mulp(cubic, kyd); fullmod(kyd);
880 mulp(cubic, kyd); fullmod(kyd);}
881 itog(4, aux2); scalarmul(aux2, kyd);
882 }
883 //printf("kP: "); polyout(kxn); polyout(kxd); polyout(kyn); polyout(kyd);
884 /* Commence t = 0 check. */
885 // printf("Checking t = %d ...\n", 0);
886 fflush(stdout);
887
888 ptop(powx, pbuff); mulp(kxd, pbuff);
889 subp(kxn, pbuff);
890 fullmod(pbuff);
891
892 xmatch = ymatch = 0;
893 if(iszerop(pbuff)) {
894 xmatch = 1;
895 /* Now check y coords. */
896 if(L == 2) goto resolve;
897 ptop(powy, pbuff); mulp(kyd, pbuff);
898 addp(kyn, pbuff);
899 fullmod(pbuff);
900 if(iszerop(pbuff)) {
901 resolve:
902 printf("%d %d\n", L, 0);
903 T[ct++] = 0;
904 if((k2 + 1 - T[ct-1]) % el == 0) {
905 printf("TILT: %d\n", el);
906 el = 2;
907 iaddg(1, b);
908 goto newb;
909 }
910 continue;
911 } else ymatch = 1;
912 }
913 /* Combine pt1 and pt2. */
914 if((xmatch == 1) && (ymatch == 1))
915 elldoublep(powx, txd, powy, txd, nx, dx, ny, dy);
916 else
917 elladdp(powx, txd, powy, txd, kxn, kxd, kyn, kyd, nx, dx, ny, dy);
918
919 /* Now {nx/dx, ny/dy} is (fixed) LHS. */
920 // printf("add12: "); polyout(nx); polyout(dx); polyout(ny); polyout(dy);
921 /* Commence t > 0 check. */
922 for(t=1; t <= L/2; t++) {
923 // printf("Checking t = %d ...\n", t);
924 if(t > 1) { /* Add (tx1, ty1) to (txn, tyn). */
925 ptop(txn1, pbuff); mulmod(txd, pbuff);
926 ptop(txn, powx); mulmod(txd1, powx);
927 subp(powx, pbuff); fullmod(pbuff);
928 if(!iszerop(pbuff))
929 elladdp(txn1, txd1, tyn1, tyd1, txn, txd, tyn, tyd,
930 tmp1, tmp2, tmp3, tmp4);
931 else elldoublep(txn, txd, tyn, tyd,
932 tmp1, tmp2, tmp3, tmp4);
933 ptop(tmp1, txn); ptop(tmp2, txd);
934 ptop(tmp3, tyn); ptop(tmp4, tyd);
935 }
936 // printf("tQ: "); polyout(txn); polyout(txd); polyout(tyn); polyout(tyd);
937 /* Next, check {nx/dx, ny/dy} =? {txn/txd, tyn/tyd}. */
938 ptop(nx, pbuff); mulmod(txd, pbuff);
939 ptop(dx, powx); mulmod(txn, powx);
940 subp(powx, pbuff); fullmod(pbuff);
941 if(!iszerop(pbuff)) continue;
942 /* Next, check y. */
943 // printf("y check!\n");
944 ptop(ny, pbuff); mulmod(tyd, pbuff);
945 ptop(dy, powx); mulmod(tyn, powx);
946 subp(powx, pbuff); fullmod(pbuff);
947 if(iszerop(pbuff)) {
948 printf("%d %d\n", L, t);
949 T[ct++] = t;
950 } else {
951 printf("%d %d\n", L, L-t);
952 T[ct++] = L-t;
953 }
954 if((k2 + 1 - T[ct-1]) % el == 0) {
955 printf("TILT: %d\n", el);
956 el = 2;
957 iaddg(1, b);
958 goto newb;
959 }
960
961 fflush(stdout);
962 break;
963 }
964 }
965
966 /* Now, prime powers P[] and CRT residues T[] are intact. */
967 printf("Prime powers L:\n");
968 printf("{");
969 for(j=0; j < ct-1; j++) {
970 printf("%d, ", P[j]);
971 }
972 printf("%d }\n", P[ct-1]);
973
974 printf("Residues t (mod L):\n");
975 printf("{");
976 for(j=0; j < ct-1; j++) {
977 printf("%d, ", T[j]);
978 }
979 printf("%d }\n", T[ct-1]);
980
981 /* Mathematica algorithm for order:
982 plis = {2^5, 3^3, 5^2, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47};
983 tlis = {1, 26, 4, 2, 4, 11, 6, 5, 19, 22, 10, 16, 7, 22, 11};
984 prod = Apply[Times, plis];
985 prlis = prod/plis;
986 invlis = Table[PowerMod[prlis[[q]], -1, plis[[q]]],{q,1,Length[plis]}];
987 p = 2^127 - 1;
988 t = Mod[tlis . (prlis * invlis), prod];
989 ord = p + 1 - If[t^2 > 4p, t - prod, t]
990 */
991
992 itog(1, t1);
993 for(j=0; j < ct; j++) {
994 smulg(P[j], t1);
995 }
996
997 for(j=0; j < 2*ct; j++) {
998 if(!ss[j]) ss[j] = newgiant(MAX_DIGS);
999 }
1000
1001 for(j=0; j < ct; j++) {
1002 gtog(t1, ss[j]);
1003 itog(P[j], t2);
1004 divg(t2, ss[j]);
1005 }
1006
1007 for(j=0; j < ct; j++) {
1008 gtog(ss[j], ss[j+ct]);
1009 itog(P[j], t2);
1010 invg(t2, ss[j+ct]);
1011 }
1012
1013 itog(0, t4);
1014 for(j=0; j < ct; j++) {
1015 itog(T[j], t5);
1016 mulg(ss[j], t5);
1017 mulg(ss[j+ct], t5);
1018 addg(t5, t4);
1019 }
1020 modg(t1, t4);
1021 gtog(p, t5);
1022 iaddg(1, t5);
1023 gtog(t4, t2);
1024 squareg(t4);
1025 gtog(p, t3); gshiftleft(2, t3);
1026 if(gcompg(t4, t3) > 0) subg(t1, t2);
1027 subg(t2, t5);
1028 printf("Parameters:\n");
1029 printf("p = "); gout(p);
1030 printf("a = "); gout(a);
1031 printf("b = "); gout(b);
1032 printf("Curve order:\n");
1033 printf("o = "); gout(t5);
1034 printf("pprob: %d\n", prime_probable(t5));
1035 printf("Twist order:\n");
1036 printf("o' = ");
1037 addg(t2, t5);
1038 addg(t2, t5);
1039 gout(t5);
1040 printf("pprob: %d\n", prime_probable(t5));
1041
1042 iaddg(1,b);
1043 goto newb;
1044 }