Added SILC Thread Queue API
[silc.git] / lib / silcmath / tfm.c
1 /* Start: fp_2expt.c */
2 /* TomsFastMath, a fast ISO C bignum library.
3  *
4  * This project is meant to fill in where LibTomMath
5  * falls short.  That is speed ;-)
6  *
7  * This project is public domain and free for all purposes.
8  *
9  * Tom St Denis, tomstdenis@iahu.ca
10  */
11 #include <tfm.h>
12
13 /* computes a = 2**b */
14 void fp_2expt(fp_int *a, int b)
15 {
16    int     z;
17
18    /* zero a as per default */
19    fp_zero (a);
20
21    if (b < 0) {
22       return;
23    }
24
25    z = b / DIGIT_BIT;
26    if (z >= FP_SIZE) {
27       return;
28    }
29
30   /* set the used count of where the bit will go */
31   a->used = z + 1;
32
33   /* put the single bit in its place */
34   a->dp[z] = ((fp_digit)1) << (b % DIGIT_BIT);
35 }
36
37
38 /* End: fp_2expt.c */
39
40 /* Start: fp_add.c */
41 /* TomsFastMath, a fast ISO C bignum library.
42  *
43  * This project is meant to fill in where LibTomMath
44  * falls short.  That is speed ;-)
45  *
46  * This project is public domain and free for all purposes.
47  *
48  * Tom St Denis, tomstdenis@iahu.ca
49  */
50 #include <tfm.h>
51
52 void fp_add(fp_int *a, fp_int *b, fp_int *c)
53 {
54   int     sa, sb;
55
56   /* get sign of both inputs */
57   sa = a->sign;
58   sb = b->sign;
59
60   /* handle two cases, not four */
61   if (sa == sb) {
62     /* both positive or both negative */
63     /* add their magnitudes, copy the sign */
64     c->sign = sa;
65     s_fp_add (a, b, c);
66   } else {
67     /* one positive, the other negative */
68     /* subtract the one with the greater magnitude from */
69     /* the one of the lesser magnitude.  The result gets */
70     /* the sign of the one with the greater magnitude. */
71     if (fp_cmp_mag (a, b) == FP_LT) {
72       c->sign = sb;
73       s_fp_sub (b, a, c);
74     } else {
75       c->sign = sa;
76       s_fp_sub (a, b, c);
77     }
78   }
79 }
80
81 /* End: fp_add.c */
82
83 /* Start: fp_add_d.c */
84 /* TomsFastMath, a fast ISO C bignum library.
85  *
86  * This project is meant to fill in where LibTomMath
87  * falls short.  That is speed ;-)
88  *
89  * This project is public domain and free for all purposes.
90  *
91  * Tom St Denis, tomstdenis@iahu.ca
92  */
93 #include <tfm.h>
94
95 /* c = a + b */
96 void fp_add_d(fp_int *a, fp_digit b, fp_int *c)
97 {
98    fp_int tmp;
99    fp_set(&tmp, b);
100    fp_add(a,&tmp,c);
101 }
102
103 /* End: fp_add_d.c */
104
105 /* Start: fp_addmod.c */
106 /* TomsFastMath, a fast ISO C bignum library.
107  *
108  * This project is meant to fill in where LibTomMath
109  * falls short.  That is speed ;-)
110  *
111  * This project is public domain and free for all purposes.
112  *
113  * Tom St Denis, tomstdenis@iahu.ca
114  */
115 #include <tfm.h>
116
117 /* d = a + b (mod c) */
118 int fp_addmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
119 {
120   fp_int tmp;
121   fp_zero(&tmp);
122   fp_add(a, b, &tmp);
123   return fp_mod(&tmp, c, d);
124 }
125
126 /* End: fp_addmod.c */
127
128 /* Start: fp_cmp.c */
129 /* TomsFastMath, a fast ISO C bignum library.
130  *
131  * This project is meant to fill in where LibTomMath
132  * falls short.  That is speed ;-)
133  *
134  * This project is public domain and free for all purposes.
135  *
136  * Tom St Denis, tomstdenis@iahu.ca
137  */
138 #include <tfm.h>
139
140 int fp_cmp(fp_int *a, fp_int *b)
141 {
142    if (a->sign == FP_NEG && b->sign == FP_ZPOS) {
143       return FP_LT;
144    } else if (a->sign == FP_ZPOS && b->sign == FP_NEG) {
145       return FP_GT;
146    } else {
147       /* compare digits */
148       if (a->sign == FP_NEG) {
149          /* if negative compare opposite direction */
150          return fp_cmp_mag(b, a);
151       } else {
152          return fp_cmp_mag(a, b);
153       }
154    }
155 }
156
157 /* End: fp_cmp.c */
158
159 /* Start: fp_cmp_d.c */
160 /* TomsFastMath, a fast ISO C bignum library.
161  *
162  * This project is meant to fill in where LibTomMath
163  * falls short.  That is speed ;-)
164  *
165  * This project is public domain and free for all purposes.
166  *
167  * Tom St Denis, tomstdenis@iahu.ca
168  */
169 #include <tfm.h>
170
171 /* compare against a single digit */
172 int fp_cmp_d(fp_int *a, fp_digit b)
173 {
174   /* compare based on sign */
175   if ((b && a->used == 0) || a->sign == FP_NEG) {
176     return FP_LT;
177   }
178
179   /* compare based on magnitude */
180   if (a->used > 1) {
181     return FP_GT;
182   }
183
184   /* compare the only digit of a to b */
185   if (a->dp[0] > b) {
186     return FP_GT;
187   } else if (a->dp[0] < b) {
188     return FP_LT;
189   } else {
190     return FP_EQ;
191   }
192
193 }
194
195 /* End: fp_cmp_d.c */
196
197 /* Start: fp_cmp_mag.c */
198 /* TomsFastMath, a fast ISO C bignum library.
199  *
200  * This project is meant to fill in where LibTomMath
201  * falls short.  That is speed ;-)
202  *
203  * This project is public domain and free for all purposes.
204  *
205  * Tom St Denis, tomstdenis@iahu.ca
206  */
207 #include <tfm.h>
208
209 int fp_cmp_mag(fp_int *a, fp_int *b)
210 {
211    int x;
212
213    if (a->used > b->used) {
214       return FP_GT;
215    } else if (a->used < b->used) {
216       return FP_LT;
217    } else {
218       for (x = a->used - 1; x >= 0; x--) {
219           if (a->dp[x] > b->dp[x]) {
220              return FP_GT;
221           } else if (a->dp[x] < b->dp[x]) {
222              return FP_LT;
223           }
224       }
225    }
226    return FP_EQ;
227 }
228
229
230 /* End: fp_cmp_mag.c */
231
232 /* Start: fp_cnt_lsb.c */
233 /* TomsFastMath, a fast ISO C bignum library.
234  *
235  * This project is meant to fill in where LibTomMath
236  * falls short.  That is speed ;-)
237  *
238  * This project is public domain and free for all purposes.
239  *
240  * Tom St Denis, tomstdenis@iahu.ca
241  */
242 #include <tfm.h>
243
244 static const int lnz[16] = {
245    4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
246 };
247
248 /* Counts the number of lsbs which are zero before the first zero bit */
249 int fp_cnt_lsb(fp_int *a)
250 {
251    int x;
252    fp_digit q, qq;
253
254    /* easy out */
255    if (fp_iszero(a) == 1) {
256       return 0;
257    }
258
259    /* scan lower digits until non-zero */
260    for (x = 0; x < a->used && a->dp[x] == 0; x++);
261    q = a->dp[x];
262    x *= DIGIT_BIT;
263
264    /* now scan this digit until a 1 is found */
265    if ((q & 1) == 0) {
266       do {
267          qq  = q & 15;
268          x  += lnz[qq];
269          q >>= 4;
270       } while (qq == 0);
271    }
272    return x;
273 }
274
275
276 /* End: fp_cnt_lsb.c */
277
278 /* Start: fp_count_bits.c */
279 /* TomsFastMath, a fast ISO C bignum library.
280  *
281  * This project is meant to fill in where LibTomMath
282  * falls short.  That is speed ;-)
283  *
284  * This project is public domain and free for all purposes.
285  *
286  * Tom St Denis, tomstdenis@iahu.ca
287  */
288 #include <tfm.h>
289
290 int fp_count_bits (fp_int * a)
291 {
292   int     r;
293   fp_digit q;
294
295   /* shortcut */
296   if (a->used == 0) {
297     return 0;
298   }
299
300   /* get number of digits and add that */
301   r = (a->used - 1) * DIGIT_BIT;
302
303   /* take the last digit and count the bits in it */
304   q = a->dp[a->used - 1];
305   while (q > ((fp_digit) 0)) {
306     ++r;
307     q >>= ((fp_digit) 1);
308   }
309   return r;
310 }
311
312 /* End: fp_count_bits.c */
313
314 /* Start: fp_div.c */
315 /* TomsFastMath, a fast ISO C bignum library.
316  *
317  * This project is meant to fill in where LibTomMath
318  * falls short.  That is speed ;-)
319  *
320  * This project is public domain and free for all purposes.
321  *
322  * Tom St Denis, tomstdenis@iahu.ca
323  */
324 #include <tfm.h>
325
326 /* a/b => cb + d == a */
327 int fp_div(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
328 {
329   fp_int  q, x, y, t1, t2;
330   int     n, t, i, norm, neg;
331
332   /* is divisor zero ? */
333   if (fp_iszero (b) == 1) {
334     return FP_VAL;
335   }
336
337   /* if a < b then q=0, r = a */
338   if (fp_cmp_mag (a, b) == FP_LT) {
339     if (d != NULL) {
340       fp_copy (a, d);
341     }
342     if (c != NULL) {
343       fp_zero (c);
344     }
345     return FP_OKAY;
346   }
347
348   fp_init(&q);
349   q.used = a->used + 2;
350
351   fp_init(&t1);
352   fp_init(&t2);
353   fp_init_copy(&x, a);
354   fp_init_copy(&y, b);
355
356   /* fix the sign */
357   neg = (a->sign == b->sign) ? FP_ZPOS : FP_NEG;
358   x.sign = y.sign = FP_ZPOS;
359
360   /* normalize both x and y, ensure that y >= b/2, [b == 2**DIGIT_BIT] */
361   norm = fp_count_bits(&y) % DIGIT_BIT;
362   if (norm < (int)(DIGIT_BIT-1)) {
363      norm = (DIGIT_BIT-1) - norm;
364      fp_mul_2d (&x, norm, &x);
365      fp_mul_2d (&y, norm, &y);
366   } else {
367      norm = 0;
368   }
369
370   /* note hac does 0 based, so if used==5 then its 0,1,2,3,4, e.g. use 4 */
371   n = x.used - 1;
372   t = y.used - 1;
373
374   /* while (x >= y*b**n-t) do { q[n-t] += 1; x -= y*b**{n-t} } */
375   fp_lshd (&y, n - t);                                             /* y = y*b**{n-t} */
376
377   while (fp_cmp (&x, &y) != FP_LT) {
378     ++(q.dp[n - t]);
379     fp_sub (&x, &y, &x);
380   }
381
382   /* reset y by shifting it back down */
383   fp_rshd (&y, n - t);
384
385   /* step 3. for i from n down to (t + 1) */
386   for (i = n; i >= (t + 1); i--) {
387     if (i > x.used) {
388       continue;
389     }
390
391     /* step 3.1 if xi == yt then set q{i-t-1} to b-1,
392      * otherwise set q{i-t-1} to (xi*b + x{i-1})/yt */
393     if (x.dp[i] == y.dp[t]) {
394       q.dp[i - t - 1] = ((((fp_word)1) << DIGIT_BIT) - 1);
395     } else {
396       fp_word tmp;
397       tmp = ((fp_word) x.dp[i]) << ((fp_word) DIGIT_BIT);
398       tmp |= ((fp_word) x.dp[i - 1]);
399       tmp /= ((fp_word) y.dp[t]);
400       q.dp[i - t - 1] = (fp_digit) (tmp);
401     }
402
403     /* while (q{i-t-1} * (yt * b + y{t-1})) >
404              xi * b**2 + xi-1 * b + xi-2
405
406        do q{i-t-1} -= 1;
407     */
408     q.dp[i - t - 1] = (q.dp[i - t - 1] + 1);
409     do {
410       q.dp[i - t - 1] = (q.dp[i - t - 1] - 1);
411
412       /* find left hand */
413       fp_zero (&t1);
414       t1.dp[0] = (t - 1 < 0) ? 0 : y.dp[t - 1];
415       t1.dp[1] = y.dp[t];
416       t1.used = 2;
417       fp_mul_d (&t1, q.dp[i - t - 1], &t1);
418
419       /* find right hand */
420       t2.dp[0] = (i - 2 < 0) ? 0 : x.dp[i - 2];
421       t2.dp[1] = (i - 1 < 0) ? 0 : x.dp[i - 1];
422       t2.dp[2] = x.dp[i];
423       t2.used = 3;
424     } while (fp_cmp_mag(&t1, &t2) == FP_GT);
425
426     /* step 3.3 x = x - q{i-t-1} * y * b**{i-t-1} */
427     fp_mul_d (&y, q.dp[i - t - 1], &t1);
428     fp_lshd  (&t1, i - t - 1);
429     fp_sub   (&x, &t1, &x);
430
431     /* if x < 0 then { x = x + y*b**{i-t-1}; q{i-t-1} -= 1; } */
432     if (x.sign == FP_NEG) {
433       fp_copy (&y, &t1);
434       fp_lshd (&t1, i - t - 1);
435       fp_add (&x, &t1, &x);
436       q.dp[i - t - 1] = q.dp[i - t - 1] - 1;
437     }
438   }
439
440   /* now q is the quotient and x is the remainder
441    * [which we have to normalize]
442    */
443
444   /* get sign before writing to c */
445   x.sign = x.used == 0 ? FP_ZPOS : a->sign;
446
447   if (c != NULL) {
448     fp_clamp (&q);
449     fp_copy (&q, c);
450     c->sign = neg;
451   }
452
453   if (d != NULL) {
454     fp_div_2d (&x, norm, &x, NULL);
455
456 /* the following is a kludge, essentially we were seeing the right remainder but
457    with excess digits that should have been zero
458  */
459     for (i = b->used; i < x.used; i++) {
460         x.dp[i] = 0;
461     }
462     fp_clamp(&x);
463     fp_copy (&x, d);
464   }
465
466   return FP_OKAY;
467 }
468
469 /* End: fp_div.c */
470
471 /* Start: fp_div_2.c */
472 /* TomsFastMath, a fast ISO C bignum library.
473  *
474  * This project is meant to fill in where LibTomMath
475  * falls short.  That is speed ;-)
476  *
477  * This project is public domain and free for all purposes.
478  *
479  * Tom St Denis, tomstdenis@iahu.ca
480  */
481 #include <tfm.h>
482
483 /* b = a/2 */
484 void fp_div_2(fp_int * a, fp_int * b)
485 {
486   int     x, oldused;
487
488   oldused = b->used;
489   b->used = a->used;
490   {
491     register fp_digit r, rr, *tmpa, *tmpb;
492
493     /* source alias */
494     tmpa = a->dp + b->used - 1;
495
496     /* dest alias */
497     tmpb = b->dp + b->used - 1;
498
499     /* carry */
500     r = 0;
501     for (x = b->used - 1; x >= 0; x--) {
502       /* get the carry for the next iteration */
503       rr = *tmpa & 1;
504
505       /* shift the current digit, add in carry and store */
506       *tmpb-- = (*tmpa-- >> 1) | (r << (DIGIT_BIT - 1));
507
508       /* forward carry to next iteration */
509       r = rr;
510     }
511
512     /* zero excess digits */
513     tmpb = b->dp + b->used;
514     for (x = b->used; x < oldused; x++) {
515       *tmpb++ = 0;
516     }
517   }
518   b->sign = a->sign;
519   fp_clamp (b);
520 }
521
522 /* End: fp_div_2.c */
523
524 /* Start: fp_div_2d.c */
525 /* TomsFastMath, a fast ISO C bignum library.
526  *
527  * This project is meant to fill in where LibTomMath
528  * falls short.  That is speed ;-)
529  *
530  * This project is public domain and free for all purposes.
531  *
532  * Tom St Denis, tomstdenis@iahu.ca
533  */
534 #include <tfm.h>
535
536 /* c = a / 2**b */
537 void fp_div_2d(fp_int *a, int b, fp_int *c, fp_int *d)
538 {
539   fp_digit D, r, rr;
540   int      x;
541   fp_int   t;
542
543   /* if the shift count is <= 0 then we do no work */
544   if (b <= 0) {
545     fp_copy (a, c);
546     if (d != NULL) {
547       fp_zero (d);
548     }
549     return;
550   }
551
552   fp_init(&t);
553
554   /* get the remainder */
555   if (d != NULL) {
556     fp_mod_2d (a, b, &t);
557   }
558
559   /* copy */
560   fp_copy(a, c);
561
562   /* shift by as many digits in the bit count */
563   if (b >= (int)DIGIT_BIT) {
564     fp_rshd (c, b / DIGIT_BIT);
565   }
566
567   /* shift any bit count < DIGIT_BIT */
568   D = (fp_digit) (b % DIGIT_BIT);
569   if (D != 0) {
570     register fp_digit *tmpc, mask, shift;
571
572     /* mask */
573     mask = (((fp_digit)1) << D) - 1;
574
575     /* shift for lsb */
576     shift = DIGIT_BIT - D;
577
578     /* alias */
579     tmpc = c->dp + (c->used - 1);
580
581     /* carry */
582     r = 0;
583     for (x = c->used - 1; x >= 0; x--) {
584       /* get the lower  bits of this word in a temp */
585       rr = *tmpc & mask;
586
587       /* shift the current word and mix in the carry bits from the previous word */
588       *tmpc = (*tmpc >> D) | (r << shift);
589       --tmpc;
590
591       /* set the carry to the carry bits of the current word found above */
592       r = rr;
593     }
594   }
595   fp_clamp (c);
596   if (d != NULL) {
597     fp_copy (&t, d);
598   }
599 }
600
601 /* End: fp_div_2d.c */
602
603 /* Start: fp_div_d.c */
604 /* TomsFastMath, a fast ISO C bignum library.
605  *
606  * This project is meant to fill in where LibTomMath
607  * falls short.  That is speed ;-)
608  *
609  * This project is public domain and free for all purposes.
610  *
611  * Tom St Denis, tomstdenis@iahu.ca
612  */
613 #include <tfm.h>
614
615 static int s_is_power_of_two(fp_digit b, int *p)
616 {
617    int x;
618
619    for (x = 1; x < DIGIT_BIT; x++) {
620       if (b == (((fp_digit)1)<<x)) {
621          *p = x;
622          return 1;
623       }
624    }
625    return 0;
626 }
627
628 /* a/b => cb + d == a */
629 int fp_div_d(fp_int *a, fp_digit b, fp_int *c, fp_digit *d)
630 {
631   fp_int   q;
632   fp_word  w;
633   fp_digit t;
634   int      ix;
635
636   /* cannot divide by zero */
637   if (b == 0) {
638      return FP_VAL;
639   }
640
641   /* quick outs */
642   if (b == 1 || fp_iszero(a) == 1) {
643      if (d != NULL) {
644         *d = 0;
645      }
646      if (c != NULL) {
647         fp_copy(a, c);
648      }
649      return FP_OKAY;
650   }
651
652   /* power of two ? */
653   if (s_is_power_of_two(b, &ix) == 1) {
654      if (d != NULL) {
655         *d = a->dp[0] & ((((fp_digit)1)<<ix) - 1);
656      }
657      if (c != NULL) {
658         fp_div_2d(a, ix, c, NULL);
659      }
660      return FP_OKAY;
661   }
662
663   /* no easy answer [c'est la vie].  Just division */
664   fp_init(&q);
665
666   q.used = a->used;
667   q.sign = a->sign;
668   w = 0;
669   for (ix = a->used - 1; ix >= 0; ix--) {
670      w = (w << ((fp_word)DIGIT_BIT)) | ((fp_word)a->dp[ix]);
671
672      if (w >= b) {
673         t = (fp_digit)(w / b);
674         w -= ((fp_word)t) * ((fp_word)b);
675       } else {
676         t = 0;
677       }
678       q.dp[ix] = (fp_digit)t;
679   }
680
681   if (d != NULL) {
682      *d = (fp_digit)w;
683   }
684
685   if (c != NULL) {
686      fp_clamp(&q);
687      fp_copy(&q, c);
688   }
689
690   return FP_OKAY;
691 }
692
693
694 /* End: fp_div_d.c */
695
696 /* Start: fp_exptmod.c */
697 /* TomsFastMath, a fast ISO C bignum library.
698  *
699  * This project is meant to fill in where LibTomMath
700  * falls short.  That is speed ;-)
701  *
702  * This project is public domain and free for all purposes.
703  *
704  * Tom St Denis, tomstdenis@iahu.ca
705  */
706 #include <tfm.h>
707
708 /* y = g**x (mod b)
709  * Some restrictions... x must be positive and < b
710  */
711 static int _fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
712 {
713   fp_int   M[64], res;
714   fp_digit buf, mp;
715   int      err, bitbuf, bitcpy, bitcnt, mode, digidx, x, y, winsize;
716
717   /* find window size */
718   x = fp_count_bits (X);
719   if (x <= 7) {
720     winsize = 2;
721   } else if (x <= 36) {
722     winsize = 3;
723   } else if (x <= 140) {
724     winsize = 4;
725   } else if (x <= 450) {
726     winsize = 5;
727   } else {
728     winsize = 6;
729   }
730
731   /* init M array */
732   memset(M, 0, sizeof(M));
733
734   /* now setup montgomery  */
735   if ((err = fp_montgomery_setup (P, &mp)) != FP_OKAY) {
736      return err;
737   }
738
739   /* setup result */
740   fp_init(&res);
741
742   /* create M table
743    *
744    * The M table contains powers of the input base, e.g. M[x] = G^x mod P
745    *
746    * The first half of the table is not computed though accept for M[0] and M[1]
747    */
748
749    /* now we need R mod m */
750    fp_montgomery_calc_normalization (&res, P);
751
752    /* now set M[1] to G * R mod m */
753    if (fp_cmp_mag(P, G) != FP_GT) {
754       /* G > P so we reduce it first */
755       fp_mod(G, P, &M[1]);
756    } else {
757       fp_copy(G, &M[1]);
758    }
759    fp_mulmod (&M[1], &res, P, &M[1]);
760
761   /* compute the value at M[1<<(winsize-1)] by squaring M[1] (winsize-1) times */
762   fp_copy (&M[1], &M[1 << (winsize - 1)]);
763   for (x = 0; x < (winsize - 1); x++) {
764     fp_sqr (&M[1 << (winsize - 1)], &M[1 << (winsize - 1)]);
765     fp_montgomery_reduce (&M[1 << (winsize - 1)], P, mp);
766   }
767
768   /* create upper table */
769   for (x = (1 << (winsize - 1)) + 1; x < (1 << winsize); x++) {
770     fp_mul(&M[x - 1], &M[1], &M[x]);
771     fp_montgomery_reduce(&M[x], P, mp);
772   }
773
774   /* set initial mode and bit cnt */
775   mode   = 0;
776   bitcnt = 1;
777   buf    = 0;
778   digidx = X->used - 1;
779   bitcpy = 0;
780   bitbuf = 0;
781
782   for (;;) {
783     /* grab next digit as required */
784     if (--bitcnt == 0) {
785       /* if digidx == -1 we are out of digits so break */
786       if (digidx == -1) {
787         break;
788       }
789       /* read next digit and reset bitcnt */
790       buf    = X->dp[digidx--];
791       bitcnt = (int)DIGIT_BIT;
792     }
793
794     /* grab the next msb from the exponent */
795     y     = (fp_digit)(buf >> (DIGIT_BIT - 1)) & 1;
796     buf <<= (fp_digit)1;
797
798     /* if the bit is zero and mode == 0 then we ignore it
799      * These represent the leading zero bits before the first 1 bit
800      * in the exponent.  Technically this opt is not required but it
801      * does lower the # of trivial squaring/reductions used
802      */
803     if (mode == 0 && y == 0) {
804       continue;
805     }
806
807     /* if the bit is zero and mode == 1 then we square */
808     if (mode == 1 && y == 0) {
809       fp_sqr(&res, &res);
810       fp_montgomery_reduce(&res, P, mp);
811       continue;
812     }
813
814     /* else we add it to the window */
815     bitbuf |= (y << (winsize - ++bitcpy));
816     mode    = 2;
817
818     if (bitcpy == winsize) {
819       /* ok window is filled so square as required and multiply  */
820       /* square first */
821       for (x = 0; x < winsize; x++) {
822         fp_sqr(&res, &res);
823         fp_montgomery_reduce(&res, P, mp);
824       }
825
826       /* then multiply */
827       fp_mul(&res, &M[bitbuf], &res);
828       fp_montgomery_reduce(&res, P, mp);
829
830       /* empty window and reset */
831       bitcpy = 0;
832       bitbuf = 0;
833       mode   = 1;
834     }
835   }
836
837   /* if bits remain then square/multiply */
838   if (mode == 2 && bitcpy > 0) {
839     /* square then multiply if the bit is set */
840     for (x = 0; x < bitcpy; x++) {
841       fp_sqr(&res, &res);
842       fp_montgomery_reduce(&res, P, mp);
843
844       /* get next bit of the window */
845       bitbuf <<= 1;
846       if ((bitbuf & (1 << winsize)) != 0) {
847         /* then multiply */
848         fp_mul(&res, &M[1], &res);
849         fp_montgomery_reduce(&res, P, mp);
850       }
851     }
852   }
853
854   /* fixup result if Montgomery reduction is used
855    * recall that any value in a Montgomery system is
856    * actually multiplied by R mod n.  So we have
857    * to reduce one more time to cancel out the factor
858    * of R.
859    */
860   fp_montgomery_reduce(&res, P, mp);
861
862   /* swap res with Y */
863   fp_copy (&res, Y);
864   return FP_OKAY;
865 }
866
867
868 int fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y)
869 {
870    fp_int tmp;
871    int    err;
872
873    /* is X negative?  */
874    if (X->sign == FP_NEG) {
875       /* yes, copy G and invmod it */
876       fp_copy(G, &tmp);
877       if ((err = fp_invmod(&tmp, P, &tmp)) != FP_OKAY) {
878          return err;
879       }
880       X->sign = FP_ZPOS;
881       err =  _fp_exptmod(&tmp, X, P, Y);
882       X->sign = FP_NEG;
883       return err;
884    } else {
885       /* Positive exponent so just exptmod */
886       return _fp_exptmod(G, X, P, Y);
887    }
888 }
889
890 /* End: fp_exptmod.c */
891
892 /* Start: fp_gcd.c */
893 /* TomsFastMath, a fast ISO C bignum library.
894  *
895  * This project is meant to fill in where LibTomMath
896  * falls short.  That is speed ;-)
897  *
898  * This project is public domain and free for all purposes.
899  *
900  * Tom St Denis, tomstdenis@iahu.ca
901  */
902 #include <tfm.h>
903
904 /* c = (a, b) */
905 void fp_gcd(fp_int *a, fp_int *b, fp_int *c)
906 {
907    fp_int u, v, r;
908
909    /* either zero than gcd is the largest */
910    if (fp_iszero (a) == 1 && fp_iszero (b) == 0) {
911      fp_abs (b, c);
912      return;
913    }
914    if (fp_iszero (a) == 0 && fp_iszero (b) == 1) {
915      fp_abs (a, c);
916      return;
917    }
918
919    /* optimized.  At this point if a == 0 then
920     * b must equal zero too
921     */
922    if (fp_iszero (a) == 1) {
923      fp_zero(c);
924      return;
925    }
926
927    /* sort inputs */
928    if (fp_cmp_mag(a, b) != FP_LT) {
929       fp_init_copy(&u, a);
930       fp_init_copy(&v, b);
931    } else {
932       fp_init_copy(&u, b);
933       fp_init_copy(&v, a);
934    }
935
936    fp_zero(&r);
937    while (fp_iszero(&v) == FP_NO) {
938       fp_mod(&u, &v, &r);
939       fp_copy(&v, &u);
940       fp_copy(&r, &v);
941    }
942    fp_copy(&u, c);
943 }
944
945 /* End: fp_gcd.c */
946
947 /* Start: fp_ident.c */
948 #include "tfm.h"
949
950 const char *fp_ident(void)
951 {
952    static char buf[1024];
953
954    memset(buf, 0, sizeof(buf));
955    snprintf(buf, sizeof(buf)-1,
956 "TomsFastMath (%s)\n"
957 "\n"
958 "Sizeofs\n"
959 "\tfp_digit = %u\n"
960 "\tfp_word  = %u\n"
961 "\n"
962 "FP_MAX_SIZE = %u\n"
963 "\n"
964 "Defines: \n"
965 #ifdef __i386__
966 " __i386__ "
967 #endif
968 #ifdef __x86_64__
969 " __x86_64__ "
970 #endif
971 #ifdef TFM_X86
972 " TFM_X86 "
973 #endif
974 #ifdef TFM_X86_64
975 " TFM_X86_64 "
976 #endif
977 #ifdef TFM_SSE2
978 " TFM_SSE2 "
979 #endif
980 #ifdef TFM_ARM
981 " TFM_ARM "
982 #endif
983 #ifdef TFM_NO_ASM
984 " TFM_NO_ASM "
985 #endif
986 #ifdef FP_64BIT
987 " FP_64BIT "
988 #endif
989 #ifdef TFM_LARGE
990 " TFM_LARGE "
991 #endif
992 #ifdef TFM_HUGE
993 " TFM_HUGE "
994 #endif
995 "\n", __DATE__, sizeof(fp_digit), sizeof(fp_word), FP_MAX_SIZE);
996
997    if (sizeof(fp_digit) == sizeof(fp_word)) {
998       strncat(buf, "WARNING: sizeof(fp_digit) == sizeof(fp_word), this build is likely to not work properly.\n",
999               sizeof(buf)-1);
1000    }
1001    return buf;
1002 }
1003
1004 #ifdef STANDALONE
1005
1006 int main(void)
1007 {
1008    printf("%s\n", fp_ident());
1009    return 0;
1010 }
1011
1012 #endif
1013
1014
1015 /* End: fp_ident.c */
1016
1017 /* Start: fp_invmod.c */
1018 /* TomsFastMath, a fast ISO C bignum library.
1019  *
1020  * This project is meant to fill in where LibTomMath
1021  * falls short.  That is speed ;-)
1022  *
1023  * This project is public domain and free for all purposes.
1024  *
1025  * Tom St Denis, tomstdenis@iahu.ca
1026  */
1027 #include <tfm.h>
1028
1029 /* c = 1/a (mod b) for odd b only */
1030 int fp_invmod(fp_int *a, fp_int *b, fp_int *c)
1031 {
1032   fp_int  x, y, u, v, B, D;
1033   int     neg;
1034
1035   /* 2. [modified] b must be odd   */
1036   if (fp_iseven (b) == FP_YES) {
1037     return FP_VAL;
1038   }
1039
1040   /* init all our temps */
1041   fp_init(&x);  fp_init(&y);
1042   fp_init(&u);  fp_init(&v);
1043   fp_init(&B);  fp_init(&D);
1044
1045   /* x == modulus, y == value to invert */
1046   fp_copy(b, &x);
1047
1048   /* we need y = |a| */
1049   fp_abs(a, &y);
1050
1051   /* 3. u=x, v=y, A=1, B=0, C=0,D=1 */
1052   fp_copy(&x, &u);
1053   fp_copy(&y, &v);
1054   fp_set (&D, 1);
1055
1056 top:
1057   /* 4.  while u is even do */
1058   while (fp_iseven (&u) == FP_YES) {
1059     /* 4.1 u = u/2 */
1060     fp_div_2 (&u, &u);
1061
1062     /* 4.2 if B is odd then */
1063     if (fp_isodd (&B) == FP_YES) {
1064       fp_sub (&B, &x, &B);
1065     }
1066     /* B = B/2 */
1067     fp_div_2 (&B, &B);
1068   }
1069
1070   /* 5.  while v is even do */
1071   while (fp_iseven (&v) == FP_YES) {
1072     /* 5.1 v = v/2 */
1073     fp_div_2 (&v, &v);
1074
1075     /* 5.2 if D is odd then */
1076     if (fp_isodd (&D) == FP_YES) {
1077       /* D = (D-x)/2 */
1078       fp_sub (&D, &x, &D);
1079     }
1080     /* D = D/2 */
1081     fp_div_2 (&D, &D);
1082   }
1083
1084   /* 6.  if u >= v then */
1085   if (fp_cmp (&u, &v) != FP_LT) {
1086     /* u = u - v, B = B - D */
1087     fp_sub (&u, &v, &u);
1088     fp_sub (&B, &D, &B);
1089   } else {
1090     /* v - v - u, D = D - B */
1091     fp_sub (&v, &u, &v);
1092     fp_sub (&D, &B, &D);
1093   }
1094
1095   /* if not zero goto step 4 */
1096   if (fp_iszero (&u) == FP_NO) {
1097     goto top;
1098   }
1099
1100   /* now a = C, b = D, gcd == g*v */
1101
1102   /* if v != 1 then there is no inverse */
1103   if (fp_cmp_d (&v, 1) != FP_EQ) {
1104     return FP_VAL;
1105   }
1106
1107   /* b is now the inverse */
1108   neg = a->sign;
1109   while (D.sign == FP_NEG) {
1110     fp_add (&D, b, &D);
1111   }
1112   fp_copy (&D, c);
1113   c->sign = neg;
1114   return FP_OKAY;
1115 }
1116
1117 /* End: fp_invmod.c */
1118
1119 /* Start: fp_isprime.c */
1120 /* TomsFastMath, a fast ISO C bignum library.
1121  *
1122  * This project is meant to fill in where LibTomMath
1123  * falls short.  That is speed ;-)
1124  *
1125  * This project is public domain and free for all purposes.
1126  *
1127  * Tom St Denis, tomstdenis@iahu.ca
1128  */
1129 #include <tfm.h>
1130
1131 /* a few primes */
1132 static const fp_digit primes[256] = {
1133   0x0002, 0x0003, 0x0005, 0x0007, 0x000B, 0x000D, 0x0011, 0x0013,
1134   0x0017, 0x001D, 0x001F, 0x0025, 0x0029, 0x002B, 0x002F, 0x0035,
1135   0x003B, 0x003D, 0x0043, 0x0047, 0x0049, 0x004F, 0x0053, 0x0059,
1136   0x0061, 0x0065, 0x0067, 0x006B, 0x006D, 0x0071, 0x007F, 0x0083,
1137   0x0089, 0x008B, 0x0095, 0x0097, 0x009D, 0x00A3, 0x00A7, 0x00AD,
1138   0x00B3, 0x00B5, 0x00BF, 0x00C1, 0x00C5, 0x00C7, 0x00D3, 0x00DF,
1139   0x00E3, 0x00E5, 0x00E9, 0x00EF, 0x00F1, 0x00FB, 0x0101, 0x0107,
1140   0x010D, 0x010F, 0x0115, 0x0119, 0x011B, 0x0125, 0x0133, 0x0137,
1141
1142   0x0139, 0x013D, 0x014B, 0x0151, 0x015B, 0x015D, 0x0161, 0x0167,
1143   0x016F, 0x0175, 0x017B, 0x017F, 0x0185, 0x018D, 0x0191, 0x0199,
1144   0x01A3, 0x01A5, 0x01AF, 0x01B1, 0x01B7, 0x01BB, 0x01C1, 0x01C9,
1145   0x01CD, 0x01CF, 0x01D3, 0x01DF, 0x01E7, 0x01EB, 0x01F3, 0x01F7,
1146   0x01FD, 0x0209, 0x020B, 0x021D, 0x0223, 0x022D, 0x0233, 0x0239,
1147   0x023B, 0x0241, 0x024B, 0x0251, 0x0257, 0x0259, 0x025F, 0x0265,
1148   0x0269, 0x026B, 0x0277, 0x0281, 0x0283, 0x0287, 0x028D, 0x0293,
1149   0x0295, 0x02A1, 0x02A5, 0x02AB, 0x02B3, 0x02BD, 0x02C5, 0x02CF,
1150
1151   0x02D7, 0x02DD, 0x02E3, 0x02E7, 0x02EF, 0x02F5, 0x02F9, 0x0301,
1152   0x0305, 0x0313, 0x031D, 0x0329, 0x032B, 0x0335, 0x0337, 0x033B,
1153   0x033D, 0x0347, 0x0355, 0x0359, 0x035B, 0x035F, 0x036D, 0x0371,
1154   0x0373, 0x0377, 0x038B, 0x038F, 0x0397, 0x03A1, 0x03A9, 0x03AD,
1155   0x03B3, 0x03B9, 0x03C7, 0x03CB, 0x03D1, 0x03D7, 0x03DF, 0x03E5,
1156   0x03F1, 0x03F5, 0x03FB, 0x03FD, 0x0407, 0x0409, 0x040F, 0x0419,
1157   0x041B, 0x0425, 0x0427, 0x042D, 0x043F, 0x0443, 0x0445, 0x0449,
1158   0x044F, 0x0455, 0x045D, 0x0463, 0x0469, 0x047F, 0x0481, 0x048B,
1159
1160   0x0493, 0x049D, 0x04A3, 0x04A9, 0x04B1, 0x04BD, 0x04C1, 0x04C7,
1161   0x04CD, 0x04CF, 0x04D5, 0x04E1, 0x04EB, 0x04FD, 0x04FF, 0x0503,
1162   0x0509, 0x050B, 0x0511, 0x0515, 0x0517, 0x051B, 0x0527, 0x0529,
1163   0x052F, 0x0551, 0x0557, 0x055D, 0x0565, 0x0577, 0x0581, 0x058F,
1164   0x0593, 0x0595, 0x0599, 0x059F, 0x05A7, 0x05AB, 0x05AD, 0x05B3,
1165   0x05BF, 0x05C9, 0x05CB, 0x05CF, 0x05D1, 0x05D5, 0x05DB, 0x05E7,
1166   0x05F3, 0x05FB, 0x0607, 0x060D, 0x0611, 0x0617, 0x061F, 0x0623,
1167   0x062B, 0x062F, 0x063D, 0x0641, 0x0647, 0x0649, 0x064D, 0x0653
1168 };
1169
1170 int fp_isprime(fp_int *a)
1171 {
1172    fp_int   b;
1173    fp_digit d;
1174    int      r, res;
1175
1176    /* do trial division */
1177    for (r = 0; r < 256; r++) {
1178        fp_mod_d(a, primes[r], &d);
1179        if (d == 0) {
1180           return FP_NO;
1181        }
1182    }
1183
1184    /* now do 8 miller rabins */
1185    for (r = 0; r < 8; r++) {
1186        fp_set(&b, primes[r]);
1187        fp_prime_miller_rabin(a, &b, &res);
1188        if (res == FP_NO) {
1189           return FP_NO;
1190        }
1191    }
1192    return FP_YES;
1193 }
1194
1195 /* End: fp_isprime.c */
1196
1197 /* Start: fp_lcm.c */
1198 /* TomsFastMath, a fast ISO C bignum library.
1199  *
1200  * This project is meant to fill in where LibTomMath
1201  * falls short.  That is speed ;-)
1202  *
1203  * This project is public domain and free for all purposes.
1204  *
1205  * Tom St Denis, tomstdenis@iahu.ca
1206  */
1207 #include <tfm.h>
1208
1209 /* c = [a, b] */
1210 void fp_lcm(fp_int *a, fp_int *b, fp_int *c)
1211 {
1212    fp_int  t1, t2;
1213
1214    fp_init(&t1);
1215    fp_init(&t2);
1216    fp_gcd(a, b, &t1);
1217    if (fp_cmp_mag(a, b) == FP_GT) {
1218       fp_div(a, &t1, &t2, NULL);
1219       fp_mul(b, &t2, c);
1220    } else {
1221       fp_div(b, &t1, &t2, NULL);
1222       fp_mul(a, &t2, c);
1223    }
1224 }
1225
1226 /* End: fp_lcm.c */
1227
1228 /* Start: fp_lshd.c */
1229 /* TomsFastMath, a fast ISO C bignum library.
1230  *
1231  * This project is meant to fill in where LibTomMath
1232  * falls short.  That is speed ;-)
1233  *
1234  * This project is public domain and free for all purposes.
1235  *
1236  * Tom St Denis, tomstdenis@iahu.ca
1237  */
1238 #include <tfm.h>
1239
1240 void fp_lshd(fp_int *a, int x)
1241 {
1242    int y;
1243
1244    /* move up and truncate as required */
1245    y = MIN(a->used + x - 1, (int)(FP_SIZE-1));
1246
1247    /* store new size */
1248    a->used = y + 1;
1249
1250    /* move digits */
1251    for (; y >= x; y--) {
1252        a->dp[y] = a->dp[y-x];
1253    }
1254
1255    /* zero lower digits */
1256    for (; y >= 0; y--) {
1257        a->dp[y] = 0;
1258    }
1259
1260    /* clamp digits */
1261    fp_clamp(a);
1262 }
1263
1264 /* End: fp_lshd.c */
1265
1266 /* Start: fp_mod.c */
1267 /* TomsFastMath, a fast ISO C bignum library.
1268  *
1269  * This project is meant to fill in where LibTomMath
1270  * falls short.  That is speed ;-)
1271  *
1272  * This project is public domain and free for all purposes.
1273  *
1274  * Tom St Denis, tomstdenis@iahu.ca
1275  */
1276 #include <tfm.h>
1277
1278 /* c = a mod b, 0 <= c < b  */
1279 int fp_mod(fp_int *a, fp_int *b, fp_int *c)
1280 {
1281    fp_int t;
1282    int    err;
1283
1284    fp_zero(&t);
1285    if ((err = fp_div(a, b, NULL, &t)) != FP_OKAY) {
1286       return err;
1287    }
1288    if (t.sign != b->sign) {
1289       fp_add(&t, b, c);
1290    } else {
1291       fp_copy(&t, c);
1292   }
1293   return FP_OKAY;
1294 }
1295
1296
1297
1298 /* End: fp_mod.c */
1299
1300 /* Start: fp_mod_2d.c */
1301 /* TomsFastMath, a fast ISO C bignum library.
1302  *
1303  * This project is meant to fill in where LibTomMath
1304  * falls short.  That is speed ;-)
1305  *
1306  * This project is public domain and free for all purposes.
1307  *
1308  * Tom St Denis, tomstdenis@iahu.ca
1309  */
1310 #include <tfm.h>
1311
1312 /* c = a mod 2**d */
1313 void fp_mod_2d(fp_int *a, int b, fp_int *c)
1314 {
1315    int x;
1316
1317    /* zero if count less than or equal to zero */
1318    if (b <= 0) {
1319       fp_zero(c);
1320       return;
1321    }
1322
1323    /* get copy of input */
1324    fp_copy(a, c);
1325
1326    /* if 2**d is larger than we just return */
1327    if (b >= (DIGIT_BIT * a->used)) {
1328       return;
1329    }
1330
1331   /* zero digits above the last digit of the modulus */
1332   for (x = (b / DIGIT_BIT) + ((b % DIGIT_BIT) == 0 ? 0 : 1); x < c->used; x++) {
1333     c->dp[x] = 0;
1334   }
1335   /* clear the digit that is not completely outside/inside the modulus */
1336   c->dp[b / DIGIT_BIT] &= ~((fp_digit)0) >> (DIGIT_BIT - b);
1337   fp_clamp (c);
1338 }
1339
1340 /* End: fp_mod_2d.c */
1341
1342 /* Start: fp_mod_d.c */
1343 /* TomsFastMath, a fast ISO C bignum library.
1344  *
1345  * This project is meant to fill in where LibTomMath
1346  * falls short.  That is speed ;-)
1347  *
1348  * This project is public domain and free for all purposes.
1349  *
1350  * Tom St Denis, tomstdenis@iahu.ca
1351  */
1352 #include <tfm.h>
1353
1354 /* c = a mod b, 0 <= c < b  */
1355 int fp_mod_d(fp_int *a, fp_digit b, fp_digit *c)
1356 {
1357    return fp_div_d(a, b, NULL, c);
1358 }
1359
1360 /* End: fp_mod_d.c */
1361
1362 /* Start: fp_montgomery_calc_normalization.c */
1363 /* TomsFastMath, a fast ISO C bignum library.
1364  *
1365  * This project is meant to fill in where LibTomMath
1366  * falls short.  That is speed ;-)
1367  *
1368  * This project is public domain and free for all purposes.
1369  *
1370  * Tom St Denis, tomstdenis@iahu.ca
1371  */
1372 #include <tfm.h>
1373
1374 /* computes a = B**n mod b without division or multiplication useful for
1375  * normalizing numbers in a Montgomery system.
1376  */
1377 void fp_montgomery_calc_normalization(fp_int *a, fp_int *b)
1378 {
1379   int     x, bits;
1380
1381   /* how many bits of last digit does b use */
1382   bits = fp_count_bits (b) % DIGIT_BIT;
1383
1384   /* compute A = B^(n-1) * 2^(bits-1) */
1385   if (b->used > 1) {
1386      fp_2expt (a, (b->used - 1) * DIGIT_BIT + bits - 1);
1387   } else {
1388      fp_set(a, 1);
1389      bits = 1;
1390   }
1391
1392   /* now compute C = A * B mod b */
1393   for (x = bits - 1; x < (int)DIGIT_BIT; x++) {
1394     fp_mul_2 (a, a);
1395     if (fp_cmp_mag (a, b) != FP_LT) {
1396       s_fp_sub (a, b, a);
1397     }
1398   }
1399 }
1400
1401
1402 /* End: fp_montgomery_calc_normalization.c */
1403
1404 /* Start: fp_montgomery_reduce.c */
1405 /* TomsFastMath, a fast ISO C bignum library.
1406  *
1407  * This project is meant to fill in where LibTomMath
1408  * falls short.  That is speed ;-)
1409  *
1410  * This project is public domain and free for all purposes.
1411  *
1412  * Tom St Denis, tomstdenis@iahu.ca
1413  */
1414 #include <tfm.h>
1415
1416 #if defined(TFM_X86)
1417
1418 /* x86-32 code */
1419
1420 #define MONT_START
1421
1422 #define MONT_FINI
1423
1424 #define LOOP_START \
1425    mu = c[x] * mp;
1426
1427 #define INNERMUL \
1428 asm(                                                                                          \
1429 "movl %7,%%eax                \n\t"                                                           \
1430 "mull %6                      \n\t"                                                           \
1431 "addl %%eax,%0                \n\t"                                                           \
1432 "adcl %%edx,%1                \n\t"                                                           \
1433 "adcl $0,%2                   \n\t"                                                           \
1434 :"=g"(_c[OFF0]), "=g"(_c[OFF1]), "=g"(_c[OFF2]):"0"(_c[OFF0]), "1"(_c[OFF1]), "2"(_c[OFF2]),  \
1435                                                 "g"(mu), "g"(*tmpm++)                          \
1436                                                : "%eax", "%edx", "%cc");
1437
1438 #define PROPCARRY \
1439 asm(                                                                                               \
1440 "movl %1,%%eax                \n\t"                                                                \
1441 "addl  %%eax,%6               \n\t"                                                                \
1442 "movl %2,%%eax                \n\t"                                                                \
1443 "adcl  %%eax,%7               \n\t"                                                                \
1444 "adcl $0,%8                   \n\t"                                                                \
1445 :"=g"(_c[OFF0]), "=g"(_c[OFF1]), "=g"(_c[OFF2]):"0"(_c[OFF0]), "1"(_c[OFF1]), "2"(_c[OFF2]),       \
1446                                                 "m"(_c[OFF0+1]), "m"(_c[OFF1+1]), "m"(_c[OFF2+1])  \
1447 : "%eax", "%cc");
1448
1449 #elif defined(TFM_X86_64)
1450 /* x86-64 code */
1451
1452 #define MONT_START
1453
1454 #define MONT_FINI
1455
1456 #define LOOP_START \
1457    mu = c[x] * mp;
1458
1459 #define INNERMUL \
1460 asm(                                                                                          \
1461 "movq %7,%%rax                \n\t"                                                           \
1462 "mulq %6                      \n\t"                                                           \
1463 "addq %%rax,%0                \n\t"                                                           \
1464 "adcq %%rdx,%1                \n\t"                                                           \
1465 "adcq $0,%2                   \n\t"                                                           \
1466 :"=g"(_c[OFF0]), "=g"(_c[OFF1]), "=g"(_c[OFF2]):"0"(_c[OFF0]), "1"(_c[OFF1]), "2"(_c[OFF2]),  \
1467                                                 "g"(mu), "g"(*tmpm++)                          \
1468                                                : "%rax", "%rdx", "%cc");
1469
1470 #define PROPCARRY \
1471 asm(                                                                                               \
1472 "movq %1,%%rax                \n\t"                                                                \
1473 "movq %2,%%rbx                \n\t"                                                                \
1474 "addq  %%rax,%6               \n\t"                                                                \
1475 "adcq  %%rbx,%7               \n\t"                                                                \
1476 "adcq $0,%8                   \n\t"                                                                \
1477 :"=g"(_c[OFF0]), "=g"(_c[OFF1]), "=g"(_c[OFF2]):"0"(_c[OFF0]), "1"(_c[OFF1]), "2"(_c[OFF2]),       \
1478                                                 "m"(_c[OFF0+1]), "m"(_c[OFF1+1]), "m"(_c[OFF2+1])  \
1479 : "%rax", "%rbx", "%cc");
1480
1481 #elif defined(TFM_SSE2)
1482
1483 /* SSE2 code */
1484
1485 #define MONT_START \
1486 asm("movd %0,%%mm2"::"g"(mp));
1487
1488 #define MONT_FINI \
1489 asm("emms");
1490
1491 #define LOOP_START \
1492 asm(\
1493 "movd %0,%%mm1                \n\t" \
1494 "pmuludq %%mm2,%%mm1          \n\t" \
1495 :: "g"(c[x]));
1496
1497 #define INNERMUL \
1498 asm(                                                                                          \
1499 "movd %6,%%mm0                \n\t"                                                           \
1500 "pmuludq %%mm1,%%mm0          \n\t"                                                           \
1501 "movd %%mm0,%%eax             \n\t"                                                           \
1502 "psrlq $32, %%mm0             \n\t"                                                           \
1503 "addl %%eax,%0                \n\t"                                                           \
1504 "movd %%mm0,%%eax             \n\t"                                                           \
1505 "adcl %%eax,%1                \n\t"                                                           \
1506 "adcl $0,%2                   \n\t"                                                           \
1507 :"=g"(_c[OFF0]), "=g"(_c[OFF1]), "=g"(_c[OFF2]):"0"(_c[OFF0]), "1"(_c[OFF1]), "2"(_c[OFF2]),  \
1508                                                 "g"(*tmpm++)                                  \
1509                                                : "%eax", "%cc");
1510
1511 #define PROPCARRY \
1512 asm(                                                                                               \
1513 "movl %1,%%eax                \n\t"                                                                \
1514 "addl  %%eax,%6               \n\t"                                                                \
1515 "movl %2,%%eax                \n\t"                                                                \
1516 "adcl  %%eax,%7               \n\t"                                                                \
1517 "adcl $0,%8                   \n\t"                                                                \
1518 :"=g"(_c[OFF0]), "=g"(_c[OFF1]), "=g"(_c[OFF2]):"0"(_c[OFF0]), "1"(_c[OFF1]), "2"(_c[OFF2]),       \
1519                                                 "g"(_c[OFF0+1]), "g"(_c[OFF1+1]), "g"(_c[OFF2+1])  \
1520 : "%eax", "%cc");
1521
1522 #elif defined(TFM_ARM)
1523
1524 /* ISO C code */
1525 #define MONT_START
1526
1527 #define MONT_FINI
1528
1529 #define LOOP_START \
1530    mu = c[x] * mp;
1531
1532 /* NOTE: later write it using two regs instead of three for _c + ... */
1533 #define INNERMUL \
1534 asm(                                             \
1535 "UMULL r0,r1,%0,%1                \n\t"          \
1536 "LDR   r2,[%2]                    \n\t"          \
1537 "ADDS  r2,r2,r0                   \n\t"          \
1538 "STR   r2,[%2]                    \n\t"          \
1539 "LDR   r2,[%3]                    \n\t"          \
1540 "ADCS  r2,r2,r1                   \n\t"          \
1541 "STR   r2,[%3]                    \n\t"          \
1542 "LDR   r2,[%4]                    \n\t"          \
1543 "ADC   r2,r2,#0                   \n\t"          \
1544 "STR   r2,[%4]                    \n\t"          \
1545 ::"r"(mu),"r"(*tmpm++),"r"(_c + OFF0),"r"(_c + OFF1),"r"(_c + OFF2):"r0", "r1", "r2", "%cc");
1546
1547 #define PROPCARRY \
1548 asm(                                             \
1549 "LDR   r0,[%1]                    \n\t"          \
1550 "LDR   r1,[%0,#4]                 \n\t"          \
1551 "ADDS  r0,r0,r1                   \n\t"          \
1552 "STR   r0,[%0,#4]                 \n\t"          \
1553 "LDR   r0,[%2]                    \n\t"          \
1554 "LDR   r1,[%1,#4]                 \n\t"          \
1555 "ADCS  r0,r0,r1                   \n\t"          \
1556 "STR   r0,[%1,#4]                 \n\t"          \
1557 "LDR   r0,[%2,#4]                 \n\t"          \
1558 "ADC   r0,r0,#0                   \n\t"          \
1559 "STR   r0,[%2,#4]                 \n\t"          \
1560 ::"r"(_c + OFF0),"r"(_c + OFF1),"r"(_c + OFF2):"r0", "r1", "%cc");
1561
1562 #else
1563
1564 /* ISO C code */
1565 #define MONT_START
1566
1567 #define MONT_FINI
1568
1569 #define LOOP_START \
1570    mu = c[x] * mp;
1571
1572 #define INNERMUL \
1573    do { fp_word t;                                                           \
1574    t = (fp_word)_c[OFF0] + ((fp_word)mu) * ((fp_word)*tmpm++); _c[OFF0] = t; \
1575    t = (fp_word)_c[OFF1] + (t >> DIGIT_BIT);                   _c[OFF1] = t; \
1576    _c[OFF2] += (t >> DIGIT_BIT);                                             \
1577    } while (0);
1578
1579 #define PROPCARRY \
1580    do { fp_word t;                                                           \
1581    t = (fp_word)_c[OFF0+1] + (fp_word)_c[OFF1];                    _c[OFF0+1] = t; \
1582    t = (fp_word)_c[OFF1+1] + (t >> DIGIT_BIT) + (fp_word)_c[OFF2]; _c[OFF1+1] = t; \
1583    _c[OFF2+1] += (t >> DIGIT_BIT);                                           \
1584    } while (0);
1585
1586 #endif
1587
1588
1589 #define OFF0  (0)
1590 #define OFF1  (FP_SIZE)
1591 #define OFF2  (FP_SIZE+FP_SIZE)
1592
1593 /* computes x/R == x (mod N) via Montgomery Reduction */
1594 void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp)
1595 {
1596    fp_digit c[3*FP_SIZE], *_c, *tmpm, mu;
1597    int      oldused, x, y, pa;
1598
1599    /* now zero the buff */
1600    pa = m->used;
1601    memset(c, 0, sizeof(c));
1602
1603    /* copy the input */
1604    oldused = a->used;
1605    for (x = 0; x < oldused; x++) {
1606        c[x] = a->dp[x];
1607    }
1608
1609    MONT_START;
1610
1611    /* now let's get bizz-sy! */
1612    for (x = 0; x < pa; x++) {
1613        /* get Mu for this round */
1614        LOOP_START;
1615
1616        /* our friendly neighbourhood alias */
1617        _c   = c + x;
1618        tmpm = m->dp;
1619
1620        for (y = 0; y < pa; y++) {
1621           INNERMUL;
1622           ++_c;
1623        }
1624        /* send carry up man... */
1625        _c = c + x;
1626        PROPCARRY;
1627   }
1628
1629   /* fix the rest of the carries */
1630   _c = c + pa;
1631   for (x = pa; x < pa * 2 + 2; x++) {
1632      PROPCARRY;
1633      ++_c;
1634   }
1635
1636   /* now copy out */
1637   _c   = c + pa;
1638   tmpm = a->dp;
1639   for (x = 0; x < pa+1; x++) {
1640      *tmpm++ = *_c++;
1641   }
1642
1643   for (; x < oldused; x++)   {
1644      *tmpm++ = 0;
1645   }
1646
1647   MONT_FINI;
1648
1649   a->used = pa+1;
1650   fp_clamp(a);
1651
1652   /* if A >= m then A = A - m */
1653   if (fp_cmp_mag (a, m) != FP_LT) {
1654     s_fp_sub (a, m, a);
1655   }
1656 }
1657
1658 /* End: fp_montgomery_reduce.c */
1659
1660 /* Start: fp_montgomery_setup.c */
1661 /* TomsFastMath, a fast ISO C bignum library.
1662  *
1663  * This project is meant to fill in where LibTomMath
1664  * falls short.  That is speed ;-)
1665  *
1666  * This project is public domain and free for all purposes.
1667  *
1668  * Tom St Denis, tomstdenis@iahu.ca
1669  */
1670 #include <tfm.h>
1671
1672 /* setups the montgomery reduction */
1673 int fp_montgomery_setup(fp_int *a, fp_digit *rho)
1674 {
1675   fp_digit x, b;
1676
1677 /* fast inversion mod 2**k
1678  *
1679  * Based on the fact that
1680  *
1681  * XA = 1 (mod 2**n)  =>  (X(2-XA)) A = 1 (mod 2**2n)
1682  *                    =>  2*X*A - X*X*A*A = 1
1683  *                    =>  2*(1) - (1)     = 1
1684  */
1685   b = a->dp[0];
1686
1687   if ((b & 1) == 0) {
1688     return FP_VAL;
1689   }
1690
1691   x = (((b + 2) & 4) << 1) + b; /* here x*a==1 mod 2**4 */
1692   x *= 2 - b * x;               /* here x*a==1 mod 2**8 */
1693   x *= 2 - b * x;               /* here x*a==1 mod 2**16 */
1694   x *= 2 - b * x;               /* here x*a==1 mod 2**32 */
1695 #ifdef FP_64BIT
1696   x *= 2 - b * x;               /* here x*a==1 mod 2**64 */
1697 #endif
1698
1699   /* rho = -1/m mod b */
1700   *rho = (((fp_word) 1 << ((fp_word) DIGIT_BIT)) - ((fp_word)x));
1701
1702   return FP_OKAY;
1703 }
1704
1705
1706 /* End: fp_montgomery_setup.c */
1707
1708 /* Start: fp_mul.c */
1709 /* TomsFastMath, a fast ISO C bignum library.
1710  *
1711  * This project is meant to fill in where LibTomMath
1712  * falls short.  That is speed ;-)
1713  *
1714  * This project is public domain and free for all purposes.
1715  *
1716  * Tom St Denis, tomstdenis@iahu.ca
1717  */
1718 #include <tfm.h>
1719
1720 /* c = a * b */
1721 void fp_mul(fp_int *A, fp_int *B, fp_int *C)
1722 {
1723     int    r, y, yy, s;
1724     fp_int ac, bd, comp, amb, cmd, t1, t2;
1725
1726      y  = MAX(A->used, B->used);
1727      yy = MIN(A->used, B->used);
1728      if (yy <= 8 || y <= 64) {
1729
1730     /* pick a comba (unrolled 4/8/16/32 x or rolled) based on the size
1731        of the largest input.  We also want to avoid doing excess mults if the
1732        inputs are not close to the next power of two.  That is, for example,
1733        if say y=17 then we would do (32-17)^2 = 225 unneeded multiplications
1734     */
1735         if (y <= 4) {
1736            fp_mul_comba4(A,B,C);
1737         } else if (y <= 8) {
1738            fp_mul_comba8(A,B,C);
1739 #if defined(TFM_LARGE)
1740         } else if (y <= 16 && y >= 10) {
1741            fp_mul_comba16(A,B,C);
1742 #endif
1743 #if defined(TFM_HUGE)
1744         } else if (y <= 32 && y >= 24) {
1745            fp_mul_comba32(A,B,C);
1746 #endif
1747         } else {
1748            fp_mul_comba(A,B,C);
1749         }
1750     } else {
1751         /* do the karatsuba action
1752
1753            if A = ab and B = cd for ||a|| = r we need to solve
1754
1755            ac*r^2 + (-(a-b)(c-d) + ac + bd)*r + bd
1756
1757            So we solve for the three products then we form the final result with careful shifting
1758            and addition.
1759
1760 Obvious points of optimization
1761
1762 - "ac" parts can be memcpy'ed with an offset [all you have to do is zero upto the next 8 digits]
1763 - Similarly the "bd" parts can be memcpy'ed and zeroed to 8
1764 -
1765
1766         */
1767         /* get our value of r */
1768         r = yy >> 1;
1769
1770         /* now solve for ac */
1771 //        fp_copy(A, &t1); fp_rshd(&t1, r);
1772         for (s = 0; s < A->used - r; s++) {
1773             t1.dp[s] = A->dp[s+r];
1774         }
1775         for (; s < FP_SIZE; s++) {
1776             t1.dp[s] = 0;
1777         }
1778         if (A->used >= r) {
1779            t1.used = A->used - r;
1780         } else {
1781            t1.used = 0;
1782         }
1783         t1.sign = A->sign;
1784
1785 //        fp_copy(B, &t2); fp_rshd(&t2, r);
1786         for (s = 0; s < B->used - r; s++) {
1787             t2.dp[s] = B->dp[s+r];
1788         }
1789         for (; s < FP_SIZE; s++) {
1790             t2.dp[s] = 0;
1791         }
1792         if (B->used >= r) {
1793            t2.used = B->used - r;
1794         } else {
1795            t2.used = 0;
1796         }
1797         t2.sign = B->sign;
1798
1799         fp_copy(&t1, &amb); fp_copy(&t2, &cmd);
1800         fp_zero(&ac);
1801         fp_mul(&t1, &t2, &ac);
1802
1803         /* now solve for bd */
1804 //        fp_mod_2d(A, r * DIGIT_BIT, &t1);
1805 //        fp_mod_2d(B, r * DIGIT_BIT, &t2);
1806         for (s = 0; s < r; s++) {
1807             t1.dp[s] = A->dp[s];
1808             t2.dp[s] = B->dp[s];
1809         }
1810         for (; s < FP_SIZE; s++) {
1811             t1.dp[s]   = 0;
1812             t2.dp[s] = 0;
1813         }
1814         t1.used = r;
1815         t2.used = r;
1816         fp_clamp(&t1);
1817         fp_clamp(&t2);
1818
1819         fp_sub(&amb, &t1, &amb); fp_sub(&cmd, &t2, &cmd);
1820         fp_zero(&bd);
1821         fp_mul(&t1, &t2, &bd);
1822
1823         /* now get the (a-b)(c-d) term */
1824         fp_zero(&comp);
1825         fp_mul(&amb, &cmd, &comp);
1826
1827         /* now solve the system, do the middle term first */
1828         comp.sign ^= 1;
1829         fp_add(&comp, &ac, &comp);
1830         fp_add(&comp, &bd, &comp);
1831         fp_lshd(&comp, r);
1832
1833         /* leading term */
1834         fp_lshd(&ac, r+r);
1835
1836         /* now sum them together */
1837         s = A->sign ^ B->sign;
1838         fp_zero(C);
1839         fp_add(&ac, &comp, C);
1840         fp_add(&bd, C, C);
1841         C->sign = C->used ? s : FP_ZPOS;
1842     }
1843 }
1844
1845
1846 /* End: fp_mul.c */
1847
1848 /* Start: fp_mul_2.c */
1849 /* TomsFastMath, a fast ISO C bignum library.
1850  *
1851  * This project is meant to fill in where LibTomMath
1852  * falls short.  That is speed ;-)
1853  *
1854  * This project is public domain and free for all purposes.
1855  *
1856  * Tom St Denis, tomstdenis@iahu.ca
1857  */
1858 #include <tfm.h>
1859
1860 void fp_mul_2(fp_int * a, fp_int * b)
1861 {
1862   int     x, oldused;
1863
1864   oldused = b->used;
1865   b->used = a->used;
1866
1867   {
1868     register fp_digit r, rr, *tmpa, *tmpb;
1869
1870     /* alias for source */
1871     tmpa = a->dp;
1872
1873     /* alias for dest */
1874     tmpb = b->dp;
1875
1876     /* carry */
1877     r = 0;
1878     for (x = 0; x < a->used; x++) {
1879
1880       /* get what will be the *next* carry bit from the
1881        * MSB of the current digit
1882        */
1883       rr = *tmpa >> ((fp_digit)(DIGIT_BIT - 1));
1884
1885       /* now shift up this digit, add in the carry [from the previous] */
1886       *tmpb++ = ((*tmpa++ << ((fp_digit)1)) | r);
1887
1888       /* copy the carry that would be from the source
1889        * digit into the next iteration
1890        */
1891       r = rr;
1892     }
1893
1894     /* new leading digit? */
1895     if (r != 0 && b->used != (FP_SIZE-1)) {
1896       /* add a MSB which is always 1 at this point */
1897       *tmpb = 1;
1898       ++(b->used);
1899     }
1900
1901     /* now zero any excess digits on the destination
1902      * that we didn't write to
1903      */
1904     tmpb = b->dp + b->used;
1905     for (x = b->used; x < oldused; x++) {
1906       *tmpb++ = 0;
1907     }
1908   }
1909   b->sign = a->sign;
1910 }
1911
1912
1913 /* End: fp_mul_2.c */
1914
1915 /* Start: fp_mul_2d.c */
1916 /* TomsFastMath, a fast ISO C bignum library.
1917  *
1918  * This project is meant to fill in where LibTomMath
1919  * falls short.  That is speed ;-)
1920  *
1921  * This project is public domain and free for all purposes.
1922  *
1923  * Tom St Denis, tomstdenis@iahu.ca
1924  */
1925 #include <tfm.h>
1926
1927 /* c = a * 2**d */
1928 void fp_mul_2d(fp_int *a, int b, fp_int *c)
1929 {
1930    fp_digit carry, carrytmp, shift;
1931    int x;
1932
1933    /* copy it */
1934    fp_copy(a, c);
1935
1936    /* handle whole digits */
1937    if (b >= DIGIT_BIT) {
1938       fp_lshd(c, b/DIGIT_BIT);
1939    }
1940    b %= DIGIT_BIT;
1941
1942    /* shift the digits */
1943    if (b != 0) {
1944       carry = 0;
1945       shift = DIGIT_BIT - b;
1946       for (x = 0; x < c->used; x++) {
1947           carrytmp = c->dp[x] >> shift;
1948           c->dp[x] = (c->dp[x] << b) + carry;
1949           carry = carrytmp;
1950       }
1951       /* store last carry if room */
1952       if (carry && x < FP_SIZE) {
1953          c->dp[c->used++] = carry;
1954       }
1955    }
1956    fp_clamp(c);
1957 }
1958
1959
1960 /* End: fp_mul_2d.c */
1961
1962 /* Start: fp_mul_comba.c */
1963 /* TomsFastMath, a fast ISO C bignum library.
1964  *
1965  * This project is meant to fill in where LibTomMath
1966  * falls short.  That is speed ;-)
1967  *
1968  * This project is public domain and free for all purposes.
1969  *
1970  * Tom St Denis, tomstdenis@iahu.ca
1971  */
1972
1973 /* About this file...
1974
1975 */
1976
1977 #include <tfm.h>
1978
1979 /* these are the combas.  Worship them. */
1980 #if defined(TFM_X86)
1981 /* Generic x86 optimized code */
1982
1983 /* anything you need at the start */
1984 #define COMBA_START
1985
1986 /* clear the chaining variables */
1987 #define COMBA_CLEAR \
1988    c0 = c1 = c2 = 0;
1989
1990 /* forward the carry to the next digit */
1991 #define COMBA_FORWARD \
1992    do { c0 = c1; c1 = c2; c2 = 0; } while (0);
1993
1994 /* store the first sum */
1995 #define COMBA_STORE(x) \
1996    x = c0;
1997
1998 /* store the second sum [carry] */
1999 #define COMBA_STORE2(x) \
2000    x = c1;
2001
2002 /* anything you need at the end */
2003 #define COMBA_FINI
2004
2005 /* this should multiply i and j  */
2006 #define MULADD(i, j)                                      \
2007 asm (                                                     \
2008      "movl  %6,%%eax     \n\t"                            \
2009      "mull  %7           \n\t"                            \
2010      "addl  %%eax,%0     \n\t"                            \
2011      "adcl  %%edx,%1     \n\t"                            \
2012      "adcl  $0,%2        \n\t"                            \
2013      :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","%cc");
2014
2015 #elif defined(TFM_X86_64)
2016 /* x86-64 optimized */
2017
2018 /* anything you need at the start */
2019 #define COMBA_START
2020
2021 /* clear the chaining variables */
2022 #define COMBA_CLEAR \
2023    c0 = c1 = c2 = 0;
2024
2025 /* forward the carry to the next digit */
2026 #define COMBA_FORWARD \
2027    do { c0 = c1; c1 = c2; c2 = 0; } while (0);
2028
2029 /* store the first sum */
2030 #define COMBA_STORE(x) \
2031    x = c0;
2032
2033 /* store the second sum [carry] */
2034 #define COMBA_STORE2(x) \
2035    x = c1;
2036
2037 /* anything you need at the end */
2038 #define COMBA_FINI
2039
2040 /* this should multiply i and j  */
2041 #define MULADD(i, j)                                      \
2042 asm  (                                                    \
2043      "movq  %6,%%rax     \n\t"                            \
2044      "mulq  %7           \n\t"                            \
2045      "addq  %%rax,%0     \n\t"                            \
2046      "adcq  %%rdx,%1     \n\t"                            \
2047      "adcq  $0,%2        \n\t"                            \
2048      :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i), "g"(j)  :"%rax","%rdx","%cc");
2049
2050 #elif defined(TFM_SSE2)
2051 /* use SSE2 optimizations */
2052
2053 /* anything you need at the start */
2054 #define COMBA_START
2055
2056 /* clear the chaining variables */
2057 #define COMBA_CLEAR \
2058    c0 = c1 = c2 = 0;
2059
2060 /* forward the carry to the next digit */
2061 #define COMBA_FORWARD \
2062    do { c0 = c1; c1 = c2; c2 = 0; } while (0);
2063
2064 /* store the first sum */
2065 #define COMBA_STORE(x) \
2066    x = c0;
2067
2068 /* store the second sum [carry] */
2069 #define COMBA_STORE2(x) \
2070    x = c1;
2071
2072 /* anything you need at the end */
2073 #define COMBA_FINI \
2074    asm("emms");
2075
2076 /* this should multiply i and j  */
2077    #define MULADD(i, j)                                      \
2078    asm volatile (                                            \
2079         "movd  %6,%%mm0     \n\t"                            \
2080         "movd  %7,%%mm1     \n\t"                            \
2081         "pmuludq %%mm1,%%mm0\n\t"                            \
2082         "movd  %%mm0,%%eax  \n\t"                            \
2083         "psrlq $32,%%mm0    \n\t"                            \
2084         "addl  %%eax,%0     \n\t"                            \
2085         "movd  %%mm0,%%eax  \n\t"                            \
2086         "adcl  %%eax,%1     \n\t"                            \
2087         "adcl  $0,%2        \n\t"                            \
2088         :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%cc");
2089
2090 #elif defined(TFM_ARM)
2091 /* ARM code */
2092
2093 #define COMBA_START
2094
2095 #define COMBA_CLEAR \
2096    c0 = c1 = c2 = 0;
2097
2098 #define COMBA_FORWARD \
2099    do { c0 = c1; c1 = c2; c2 = 0; } while (0);
2100
2101 #define COMBA_STORE(x) \
2102    x = c0;
2103
2104 #define COMBA_STORE2(x) \
2105    x = c1;
2106
2107 #define COMBA_FINI
2108
2109 #define MULADD(i, j)                                          \
2110 asm(                                                          \
2111 "  UMULL  r0,r1,%6,%7           \n\t"                         \
2112 "  ADDS   %0,%0,r0              \n\t"                         \
2113 "  ADCS   %1,%1,r1              \n\t"                         \
2114 "  ADC    %2, %2, #0            \n\t"                         \
2115 :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "%cc");
2116
2117 #else
2118 /* ISO C code */
2119
2120 #define COMBA_START
2121
2122 #define COMBA_CLEAR \
2123    c0 = c1 = c2 = 0;
2124
2125 #define COMBA_FORWARD \
2126    do { c0 = c1; c1 = c2; c2 = 0; } while (0);
2127
2128 #define COMBA_STORE(x) \
2129    x = c0;
2130
2131 #define COMBA_STORE2(x) \
2132    x = c1;
2133
2134 #define COMBA_FINI
2135
2136 #define MULADD(i, j)                                                              \
2137    do { fp_word t;                                                                \
2138    t = (fp_word)c0 + ((fp_word)i) * ((fp_word)j); c0 = t;                         \
2139    t = (fp_word)c1 + (t >> DIGIT_BIT);            c1 = t; c2 += t >> DIGIT_BIT;   \
2140    } while (0);
2141
2142 #endif
2143
2144
2145 /* generic PxQ multiplier */
2146 void fp_mul_comba(fp_int *A, fp_int *B, fp_int *C)
2147 {
2148    int       ix, iy, iz, tx, ty, pa;
2149    fp_digit  c0, c1, c2, *tmpx, *tmpy;
2150    fp_int    tmp, *dst;
2151
2152    COMBA_START;
2153    COMBA_CLEAR;
2154
2155    /* get size of output and trim */
2156    pa = A->used + B->used;
2157    if (pa >= FP_SIZE) {
2158       pa = FP_SIZE-1;
2159    }
2160
2161    if (A == C || B == C) {
2162       fp_zero(&tmp);
2163       dst = &tmp;
2164    } else {
2165       fp_zero(C);
2166       dst = C;
2167    }
2168
2169    for (ix = 0; ix < pa; ix++) {
2170       /* get offsets into the two bignums */
2171       ty = MIN(ix, B->used-1);
2172       tx = ix - ty;
2173
2174       /* setup temp aliases */
2175       tmpx = A->dp + tx;
2176       tmpy = B->dp + ty;
2177
2178       /* this is the number of times the loop will iterrate, essentially its
2179          while (tx++ < a->used && ty-- >= 0) { ... }
2180        */
2181       iy = MIN(A->used-tx, ty+1);
2182
2183       /* execute loop */
2184       COMBA_FORWARD;
2185       for (iz = 0; iz < iy; ++iz) {
2186           MULADD(*tmpx++, *tmpy--);
2187       }
2188
2189       /* store term */
2190       COMBA_STORE(dst->dp[ix]);
2191   }
2192   /* store final carry */
2193   COMBA_STORE2(dst->dp[ix]);
2194   COMBA_FINI;
2195
2196   dst->used = pa;
2197   fp_clamp(dst);
2198   dst->sign = dst->used ? A->sign ^ B->sign : FP_ZPOS;
2199   fp_copy(dst, C);
2200 }
2201
2202 void fp_mul_comba4(fp_int *A, fp_int *B, fp_int *C)
2203 {
2204    fp_digit c0, c1, c2, at[8];
2205
2206    memcpy(at, A->dp, 4 * sizeof(fp_digit));
2207    memcpy(at+4, B->dp, 4 * sizeof(fp_digit));
2208    COMBA_START;
2209
2210    COMBA_CLEAR;
2211    /* 0 */
2212    MULADD(at[0], at[4]);
2213    COMBA_STORE(C->dp[0]);
2214    /* 1 */
2215    COMBA_FORWARD;
2216    MULADD(at[0], at[5]);    MULADD(at[1], at[4]);
2217    COMBA_STORE(C->dp[1]);
2218    /* 2 */
2219    COMBA_FORWARD;
2220    MULADD(at[0], at[6]);    MULADD(at[1], at[5]);    MULADD(at[2], at[4]);
2221    COMBA_STORE(C->dp[2]);
2222    /* 3 */
2223    COMBA_FORWARD;
2224    MULADD(at[0], at[7]);    MULADD(at[1], at[6]);    MULADD(at[2], at[5]);    MULADD(at[3], at[4]);
2225    COMBA_STORE(C->dp[3]);
2226    /* 4 */
2227    COMBA_FORWARD;
2228    MULADD(at[1], at[7]);    MULADD(at[2], at[6]);    MULADD(at[3], at[5]);
2229    COMBA_STORE(C->dp[4]);
2230    /* 5 */
2231    COMBA_FORWARD;
2232    MULADD(at[2], at[7]);    MULADD(at[3], at[6]);
2233    COMBA_STORE(C->dp[5]);
2234    /* 6 */
2235    COMBA_FORWARD;
2236    MULADD(at[3], at[7]);
2237    COMBA_STORE(C->dp[6]);
2238    COMBA_STORE2(C->dp[7]);
2239    C->used = 8;
2240    C->sign = A->sign ^ B->sign;
2241    fp_clamp(C);
2242    COMBA_FINI;
2243 }
2244
2245
2246 void fp_mul_comba8(fp_int *A, fp_int *B, fp_int *C)
2247 {
2248    fp_digit c0, c1, c2, at[16];
2249
2250    memcpy(at, A->dp, 8 * sizeof(fp_digit));
2251    memcpy(at+8, B->dp, 8 * sizeof(fp_digit));
2252    COMBA_START;
2253
2254    COMBA_CLEAR;
2255    /* 0 */
2256    MULADD(at[0], at[8]);
2257    COMBA_STORE(C->dp[0]);
2258    /* 1 */
2259    COMBA_FORWARD;
2260    MULADD(at[0], at[9]);    MULADD(at[1], at[8]);
2261    COMBA_STORE(C->dp[1]);
2262    /* 2 */
2263    COMBA_FORWARD;
2264    MULADD(at[0], at[10]);    MULADD(at[1], at[9]);    MULADD(at[2], at[8]);
2265    COMBA_STORE(C->dp[2]);
2266    /* 3 */
2267    COMBA_FORWARD;
2268    MULADD(at[0], at[11]);    MULADD(at[1], at[10]);    MULADD(at[2], at[9]);    MULADD(at[3], at[8]);
2269    COMBA_STORE(C->dp[3]);
2270    /* 4 */
2271    COMBA_FORWARD;
2272    MULADD(at[0], at[12]);    MULADD(at[1], at[11]);    MULADD(at[2], at[10]);    MULADD(at[3], at[9]);    MULADD(at[4], at[8]);
2273    COMBA_STORE(C->dp[4]);
2274    /* 5 */
2275    COMBA_FORWARD;
2276    MULADD(at[0], at[13]);    MULADD(at[1], at[12]);    MULADD(at[2], at[11]);    MULADD(at[3], at[10]);    MULADD(at[4], at[9]);    MULADD(at[5], at[8]);
2277    COMBA_STORE(C->dp[5]);
2278    /* 6 */
2279    COMBA_FORWARD;
2280    MULADD(at[0], at[14]);    MULADD(at[1], at[13]);    MULADD(at[2], at[12]);    MULADD(at[3], at[11]);    MULADD(at[4], at[10]);    MULADD(at[5], at[9]);    MULADD(at[6], at[8]);
2281    COMBA_STORE(C->dp[6]);
2282    /* 7 */
2283    COMBA_FORWARD;
2284    MULADD(at[0], at[15]);    MULADD(at[1], at[14]);    MULADD(at[2], at[13]);    MULADD(at[3], at[12]);    MULADD(at[4], at[11]);    MULADD(at[5], at[10]);    MULADD(at[6], at[9]);    MULADD(at[7], at[8]);
2285    COMBA_STORE(C->dp[7]);
2286    /* 8 */
2287    COMBA_FORWARD;
2288    MULADD(at[1], at[15]);    MULADD(at[2], at[14]);    MULADD(at[3], at[13]);    MULADD(at[4], at[12]);    MULADD(at[5], at[11]);    MULADD(at[6], at[10]);    MULADD(at[7], at[9]);
2289    COMBA_STORE(C->dp[8]);
2290    /* 9 */
2291    COMBA_FORWARD;
2292    MULADD(at[2], at[15]);    MULADD(at[3], at[14]);    MULADD(at[4], at[13]);    MULADD(at[5], at[12]);    MULADD(at[6], at[11]);    MULADD(at[7], at[10]);
2293    COMBA_STORE(C->dp[9]);
2294    /* 10 */
2295    COMBA_FORWARD;
2296    MULADD(at[3], at[15]);    MULADD(at[4], at[14]);    MULADD(at[5], at[13]);    MULADD(at[6], at[12]);    MULADD(at[7], at[11]);
2297    COMBA_STORE(C->dp[10]);
2298    /* 11 */
2299    COMBA_FORWARD;
2300    MULADD(at[4], at[15]);    MULADD(at[5], at[14]);    MULADD(at[6], at[13]);    MULADD(at[7], at[12]);
2301    COMBA_STORE(C->dp[11]);
2302    /* 12 */
2303    COMBA_FORWARD;
2304    MULADD(at[5], at[15]);    MULADD(at[6], at[14]);    MULADD(at[7], at[13]);
2305    COMBA_STORE(C->dp[12]);
2306    /* 13 */
2307    COMBA_FORWARD;
2308    MULADD(at[6], at[15]);    MULADD(at[7], at[14]);
2309    COMBA_STORE(C->dp[13]);
2310    /* 14 */
2311    COMBA_FORWARD;
2312    MULADD(at[7], at[15]);
2313    COMBA_STORE(C->dp[14]);
2314    COMBA_STORE2(C->dp[15]);
2315    C->used = 16;
2316    C->sign = A->sign ^ B->sign;
2317    fp_clamp(C);
2318    COMBA_FINI;
2319 }
2320
2321 #if defined(TFM_LARGE)
2322
2323 void fp_mul_comba16(fp_int *A, fp_int *B, fp_int *C)
2324 {
2325    fp_digit c0, c1, c2, at[32];
2326
2327    memcpy(at, A->dp, 16 * sizeof(fp_digit));
2328    memcpy(at+16, B->dp, 16 * sizeof(fp_digit));
2329    COMBA_START;
2330
2331    COMBA_CLEAR;
2332    /* 0 */
2333    MULADD(at[0], at[16]);
2334    COMBA_STORE(C->dp[0]);
2335    /* 1 */
2336    COMBA_FORWARD;
2337    MULADD(at[0], at[17]);    MULADD(at[1], at[16]);
2338    COMBA_STORE(C->dp[1]);
2339    /* 2 */
2340    COMBA_FORWARD;
2341    MULADD(at[0], at[18]);    MULADD(at[1], at[17]);    MULADD(at[2], at[16]);
2342    COMBA_STORE(C->dp[2]);
2343    /* 3 */
2344    COMBA_FORWARD;
2345    MULADD(at[0], at[19]);    MULADD(at[1], at[18]);    MULADD(at[2], at[17]);    MULADD(at[3], at[16]);
2346    COMBA_STORE(C->dp[3]);
2347    /* 4 */
2348    COMBA_FORWARD;
2349    MULADD(at[0], at[20]);    MULADD(at[1], at[19]);    MULADD(at[2], at[18]);    MULADD(at[3], at[17]);    MULADD(at[4], at[16]);
2350    COMBA_STORE(C->dp[4]);
2351    /* 5 */
2352    COMBA_FORWARD;
2353    MULADD(at[0], at[21]);    MULADD(at[1], at[20]);    MULADD(at[2], at[19]);    MULADD(at[3], at[18]);    MULADD(at[4], at[17]);    MULADD(at[5], at[16]);
2354    COMBA_STORE(C->dp[5]);
2355    /* 6 */
2356    COMBA_FORWARD;
2357    MULADD(at[0], at[22]);    MULADD(at[1], at[21]);    MULADD(at[2], at[20]);    MULADD(at[3], at[19]);    MULADD(at[4], at[18]);    MULADD(at[5], at[17]);    MULADD(at[6], at[16]);
2358    COMBA_STORE(C->dp[6]);
2359    /* 7 */
2360    COMBA_FORWARD;
2361    MULADD(at[0], at[23]);    MULADD(at[1], at[22]);    MULADD(at[2], at[21]);    MULADD(at[3], at[20]);    MULADD(at[4], at[19]);    MULADD(at[5], at[18]);    MULADD(at[6], at[17]);    MULADD(at[7], at[16]);
2362    COMBA_STORE(C->dp[7]);
2363    /* 8 */
2364    COMBA_FORWARD;
2365    MULADD(at[0], at[24]);    MULADD(at[1], at[23]);    MULADD(at[2], at[22]);    MULADD(at[3], at[21]);    MULADD(at[4], at[20]);    MULADD(at[5], at[19]);    MULADD(at[6], at[18]);    MULADD(at[7], at[17]);    MULADD(at[8], at[16]);
2366    COMBA_STORE(C->dp[8]);
2367    /* 9 */
2368    COMBA_FORWARD;
2369    MULADD(at[0], at[25]);    MULADD(at[1], at[24]);    MULADD(at[2], at[23]);    MULADD(at[3], at[22]);    MULADD(at[4], at[21]);    MULADD(at[5], at[20]);    MULADD(at[6], at[19]);    MULADD(at[7], at[18]);    MULADD(at[8], at[17]);    MULADD(at[9], at[16]);
2370    COMBA_STORE(C->dp[9]);
2371    /* 10 */
2372    COMBA_FORWARD;
2373    MULADD(at[0], at[26]);    MULADD(at[1], at[25]);    MULADD(at[2], at[24]);    MULADD(at[3], at[23]);    MULADD(at[4], at[22]);    MULADD(at[5], at[21]);    MULADD(at[6], at[20]);    MULADD(at[7], at[19]);    MULADD(at[8], at[18]);    MULADD(at[9], at[17]);    MULADD(at[10], at[16]);
2374    COMBA_STORE(C->dp[10]);
2375    /* 11 */
2376    COMBA_FORWARD;
2377    MULADD(at[0], at[27]);    MULADD(at[1], at[26]);    MULADD(at[2], at[25]);    MULADD(at[3], at[24]);    MULADD(at[4], at[23]);    MULADD(at[5], at[22]);    MULADD(at[6], at[21]);    MULADD(at[7], at[20]);    MULADD(at[8], at[19]);    MULADD(at[9], at[18]);    MULADD(at[10], at[17]);    MULADD(at[11], at[16]);
2378    COMBA_STORE(C->dp[11]);
2379    /* 12 */
2380    COMBA_FORWARD;
2381    MULADD(at[0], at[28]);    MULADD(at[1], at[27]);    MULADD(at[2], at[26]);    MULADD(at[3], at[25]);    MULADD(at[4], at[24]);    MULADD(at[5], at[23]);    MULADD(at[6], at[22]);    MULADD(at[7], at[21]);    MULADD(at[8], at[20]);    MULADD(at[9], at[19]);    MULADD(at[10], at[18]);    MULADD(at[11], at[17]);    MULADD(at[12], at[16]);
2382    COMBA_STORE(C->dp[12]);
2383    /* 13 */
2384    COMBA_FORWARD;
2385    MULADD(at[0], at[29]);    MULADD(at[1], at[28]);    MULADD(at[2], at[27]);    MULADD(at[3], at[26]);    MULADD(at[4], at[25]);    MULADD(at[5], at[24]);    MULADD(at[6], at[23]);    MULADD(at[7], at[22]);    MULADD(at[8], at[21]);    MULADD(at[9], at[20]);    MULADD(at[10], at[19]);    MULADD(at[11], at[18]);    MULADD(at[12], at[17]);    MULADD(at[13], at[16]);
2386    COMBA_STORE(C->dp[13]);
2387    /* 14 */
2388    COMBA_FORWARD;
2389    MULADD(at[0], at[30]);    MULADD(at[1], at[29]);    MULADD(at[2], at[28]);    MULADD(at[3], at[27]);    MULADD(at[4], at[26]);    MULADD(at[5], at[25]);    MULADD(at[6], at[24]);    MULADD(at[7], at[23]);    MULADD(at[8], at[22]);    MULADD(at[9], at[21]);    MULADD(at[10], at[20]);    MULADD(at[11], at[19]);    MULADD(at[12], at[18]);    MULADD(at[13], at[17]);    MULADD(at[14], at[16]);
2390    COMBA_STORE(C->dp[14]);
2391    /* 15 */
2392    COMBA_FORWARD;
2393    MULADD(at[0], at[31]);    MULADD(at[1], at[30]);    MULADD(at[2], at[29]);    MULADD(at[3], at[28]);    MULADD(at[4], at[27]);    MULADD(at[5], at[26]);    MULADD(at[6], at[25]);    MULADD(at[7], at[24]);    MULADD(at[8], at[23]);    MULADD(at[9], at[22]);    MULADD(at[10], at[21]);    MULADD(at[11], at[20]);    MULADD(at[12], at[19]);    MULADD(at[13], at[18]);    MULADD(at[14], at[17]);    MULADD(at[15], at[16]);
2394    COMBA_STORE(C->dp[15]);
2395    /* 16 */
2396    COMBA_FORWARD;
2397    MULADD(at[1], at[31]);    MULADD(at[2], at[30]);    MULADD(at[3], at[29]);    MULADD(at[4], at[28]);    MULADD(at[5], at[27]);    MULADD(at[6], at[26]);    MULADD(at[7], at[25]);    MULADD(at[8], at[24]);    MULADD(at[9], at[23]);    MULADD(at[10], at[22]);    MULADD(at[11], at[21]);    MULADD(at[12], at[20]);    MULADD(at[13], at[19]);    MULADD(at[14], at[18]);    MULADD(at[15], at[17]);
2398    COMBA_STORE(C->dp[16]);
2399    /* 17 */
2400    COMBA_FORWARD;
2401    MULADD(at[2], at[31]);    MULADD(at[3], at[30]);    MULADD(at[4], at[29]);    MULADD(at[5], at[28]);    MULADD(at[6], at[27]);    MULADD(at[7], at[26]);    MULADD(at[8], at[25]);    MULADD(at[9], at[24]);    MULADD(at[10], at[23]);    MULADD(at[11], at[22]);    MULADD(at[12], at[21]);    MULADD(at[13], at[20]);    MULADD(at[14], at[19]);    MULADD(at[15], at[18]);
2402    COMBA_STORE(C->dp[17]);
2403    /* 18 */
2404    COMBA_FORWARD;
2405    MULADD(at[3], at[31]);    MULADD(at[4], at[30]);    MULADD(at[5], at[29]);    MULADD(at[6], at[28]);    MULADD(at[7], at[27]);    MULADD(at[8], at[26]);    MULADD(at[9], at[25]);    MULADD(at[10], at[24]);    MULADD(at[11], at[23]);    MULADD(at[12], at[22]);    MULADD(at[13], at[21]);    MULADD(at[14], at[20]);    MULADD(at[15], at[19]);
2406    COMBA_STORE(C->dp[18]);
2407    /* 19 */
2408    COMBA_FORWARD;
2409    MULADD(at[4], at[31]);    MULADD(at[5], at[30]);    MULADD(at[6], at[29]);    MULADD(at[7], at[28]);    MULADD(at[8], at[27]);    MULADD(at[9], at[26]);    MULADD(at[10], at[25]);    MULADD(at[11], at[24]);    MULADD(at[12], at[23]);    MULADD(at[13], at[22]);    MULADD(at[14], at[21]);    MULADD(at[15], at[20]);
2410    COMBA_STORE(C->dp[19]);
2411    /* 20 */
2412    COMBA_FORWARD;
2413    MULADD(at[5], at[31]);    MULADD(at[6], at[30]);    MULADD(at[7], at[29]);    MULADD(at[8], at[28]);    MULADD(at[9], at[27]);    MULADD(at[10], at[26]);    MULADD(at[11], at[25]);    MULADD(at[12], at[24]);    MULADD(at[13], at[23]);    MULADD(at[14], at[22]);    MULADD(at[15], at[21]);
2414    COMBA_STORE(C->dp[20]);
2415    /* 21 */
2416    COMBA_FORWARD;
2417    MULADD(at[6], at[31]);    MULADD(at[7], at[30]);    MULADD(at[8], at[29]);    MULADD(at[9], at[28]);    MULADD(at[10], at[27]);    MULADD(at[11], at[26]);    MULADD(at[12], at[25]);    MULADD(at[13], at[24]);    MULADD(at[14], at[23]);    MULADD(at[15], at[22]);
2418    COMBA_STORE(C->dp[21]);
2419    /* 22 */
2420    COMBA_FORWARD;
2421    MULADD(at[7], at[31]);    MULADD(at[8], at[30]);    MULADD(at[9], at[29]);    MULADD(at[10], at[28]);    MULADD(at[11], at[27]);    MULADD(at[12], at[26]);    MULADD(at[13], at[25]);    MULADD(at[14], at[24]);    MULADD(at[15], at[23]);
2422    COMBA_STORE(C->dp[22]);
2423    /* 23 */
2424    COMBA_FORWARD;
2425    MULADD(at[8], at[31]);    MULADD(at[9], at[30]);    MULADD(at[10], at[29]);    MULADD(at[11], at[28]);    MULADD(at[12], at[27]);    MULADD(at[13], at[26]);    MULADD(at[14], at[25]);    MULADD(at[15], at[24]);
2426    COMBA_STORE(C->dp[23]);
2427    /* 24 */
2428    COMBA_FORWARD;
2429    MULADD(at[9], at[31]);    MULADD(at[10], at[30]);    MULADD(at[11], at[29]);    MULADD(at[12], at[28]);    MULADD(at[13], at[27]);    MULADD(at[14], at[26]);    MULADD(at[15], at[25]);
2430    COMBA_STORE(C->dp[24]);
2431    /* 25 */
2432    COMBA_FORWARD;
2433    MULADD(at[10], at[31]);    MULADD(at[11], at[30]);    MULADD(at[12], at[29]);    MULADD(at[13], at[28]);    MULADD(at[14], at[27]);    MULADD(at[15], at[26]);
2434    COMBA_STORE(C->dp[25]);
2435    /* 26 */
2436    COMBA_FORWARD;
2437    MULADD(at[11], at[31]);    MULADD(at[12], at[30]);    MULADD(at[13], at[29]);    MULADD(at[14], at[28]);    MULADD(at[15], at[27]);
2438    COMBA_STORE(C->dp[26]);
2439    /* 27 */
2440    COMBA_FORWARD;
2441    MULADD(at[12], at[31]);    MULADD(at[13], at[30]);    MULADD(at[14], at[29]);    MULADD(at[15], at[28]);
2442    COMBA_STORE(C->dp[27]);
2443    /* 28 */
2444    COMBA_FORWARD;
2445    MULADD(at[13], at[31]);    MULADD(at[14], at[30]);    MULADD(at[15], at[29]);
2446    COMBA_STORE(C->dp[28]);
2447    /* 29 */
2448    COMBA_FORWARD;
2449    MULADD(at[14], at[31]);    MULADD(at[15], at[30]);
2450    COMBA_STORE(C->dp[29]);
2451    /* 30 */
2452    COMBA_FORWARD;
2453    MULADD(at[15], at[31]);
2454    COMBA_STORE(C->dp[30]);
2455    COMBA_STORE2(C->dp[31]);
2456    C->used = 32;
2457    C->sign = A->sign ^ B->sign;
2458    fp_clamp(C);
2459    COMBA_FINI;
2460 }
2461
2462 #endif /* TFM_LARGE */
2463
2464 #ifdef TFM_HUGE
2465
2466 void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C)
2467 {
2468    fp_digit c0, c1, c2, at[64];
2469
2470    memcpy(at, A->dp, 32 * sizeof(fp_digit));
2471    memcpy(at+32, B->dp, 32 * sizeof(fp_digit));
2472    COMBA_START;
2473
2474    COMBA_CLEAR;
2475    /* 0 */
2476    MULADD(at[0], at[32]);
2477    COMBA_STORE(C->dp[0]);
2478    /* 1 */
2479    COMBA_FORWARD;
2480    MULADD(at[0], at[33]);    MULADD(at[1], at[32]);
2481    COMBA_STORE(C->dp[1]);
2482    /* 2 */
2483    COMBA_FORWARD;
2484    MULADD(at[0], at[34]);    MULADD(at[1], at[33]);    MULADD(at[2], at[32]);
2485    COMBA_STORE(C->dp[2]);
2486    /* 3 */
2487    COMBA_FORWARD;
2488    MULADD(at[0], at[35]);    MULADD(at[1], at[34]);    MULADD(at[2], at[33]);    MULADD(at[3], at[32]);
2489    COMBA_STORE(C->dp[3]);
2490    /* 4 */
2491    COMBA_FORWARD;
2492    MULADD(at[0], at[36]);    MULADD(at[1], at[35]);    MULADD(at[2], at[34]);    MULADD(at[3], at[33]);    MULADD(at[4], at[32]);
2493    COMBA_STORE(C->dp[4]);
2494    /* 5 */
2495    COMBA_FORWARD;
2496    MULADD(at[0], at[37]);    MULADD(at[1], at[36]);    MULADD(at[2], at[35]);    MULADD(at[3], at[34]);    MULADD(at[4], at[33]);    MULADD(at[5], at[32]);
2497    COMBA_STORE(C->dp[5]);
2498    /* 6 */
2499    COMBA_FORWARD;
2500    MULADD(at[0], at[38]);    MULADD(at[1], at[37]);    MULADD(at[2], at[36]);    MULADD(at[3], at[35]);    MULADD(at[4], at[34]);    MULADD(at[5], at[33]);    MULADD(at[6], at[32]);
2501    COMBA_STORE(C->dp[6]);
2502    /* 7 */
2503    COMBA_FORWARD;
2504    MULADD(at[0], at[39]);    MULADD(at[1], at[38]);    MULADD(at[2], at[37]);    MULADD(at[3], at[36]);    MULADD(at[4], at[35]);    MULADD(at[5], at[34]);    MULADD(at[6], at[33]);    MULADD(at[7], at[32]);
2505    COMBA_STORE(C->dp[7]);
2506    /* 8 */
2507    COMBA_FORWARD;
2508    MULADD(at[0], at[40]);    MULADD(at[1], at[39]);    MULADD(at[2], at[38]);    MULADD(at[3], at[37]);    MULADD(at[4], at[36]);    MULADD(at[5], at[35]);    MULADD(at[6], at[34]);    MULADD(at[7], at[33]);    MULADD(at[8], at[32]);
2509    COMBA_STORE(C->dp[8]);
2510    /* 9 */
2511    COMBA_FORWARD;
2512    MULADD(at[0], at[41]);    MULADD(at[1], at[40]);    MULADD(at[2], at[39]);    MULADD(at[3], at[38]);    MULADD(at[4], at[37]);    MULADD(at[5], at[36]);    MULADD(at[6], at[35]);    MULADD(at[7], at[34]);    MULADD(at[8], at[33]);    MULADD(at[9], at[32]);
2513    COMBA_STORE(C->dp[9]);
2514    /* 10 */
2515    COMBA_FORWARD;
2516    MULADD(at[0], at[42]);    MULADD(at[1], at[41]);    MULADD(at[2], at[40]);    MULADD(at[3], at[39]);    MULADD(at[4], at[38]);    MULADD(at[5], at[37]);    MULADD(at[6], at[36]);    MULADD(at[7], at[35]);    MULADD(at[8], at[34]);    MULADD(at[9], at[33]);    MULADD(at[10], at[32]);
2517    COMBA_STORE(C->dp[10]);
2518    /* 11 */
2519    COMBA_FORWARD;
2520    MULADD(at[0], at[43]);    MULADD(at[1], at[42]);    MULADD(at[2], at[41]);    MULADD(at[3], at[40]);    MULADD(at[4], at[39]);    MULADD(at[5], at[38]);    MULADD(at[6], at[37]);    MULADD(at[7], at[36]);    MULADD(at[8], at[35]);    MULADD(at[9], at[34]);    MULADD(at[10], at[33]);    MULADD(at[11], at[32]);
2521    COMBA_STORE(C->dp[11]);
2522    /* 12 */
2523    COMBA_FORWARD;
2524    MULADD(at[0], at[44]);    MULADD(at[1], at[43]);    MULADD(at[2], at[42]);    MULADD(at[3], at[41]);    MULADD(at[4], at[40]);    MULADD(at[5], at[39]);    MULADD(at[6], at[38]);    MULADD(at[7], at[37]);    MULADD(at[8], at[36]);    MULADD(at[9], at[35]);    MULADD(at[10], at[34]);    MULADD(at[11], at[33]);    MULADD(at[12], at[32]);
2525    COMBA_STORE(C->dp[12]);
2526    /* 13 */
2527    COMBA_FORWARD;
2528    MULADD(at[0], at[45]);    MULADD(at[1], at[44]);    MULADD(at[2], at[43]);    MULADD(at[3], at[42]);    MULADD(at[4], at[41]);    MULADD(at[5], at[40]);    MULADD(at[6], at[39]);    MULADD(at[7], at[38]);    MULADD(at[8], at[37]);    MULADD(at[9], at[36]);    MULADD(at[10], at[35]);    MULADD(at[11], at[34]);    MULADD(at[12], at[33]);    MULADD(at[13], at[32]);
2529    COMBA_STORE(C->dp[13]);
2530    /* 14 */
2531    COMBA_FORWARD;
2532    MULADD(at[0], at[46]);    MULADD(at[1], at[45]);    MULADD(at[2], at[44]);    MULADD(at[3], at[43]);    MULADD(at[4], at[42]);    MULADD(at[5], at[41]);    MULADD(at[6], at[40]);    MULADD(at[7], at[39]);    MULADD(at[8], at[38]);    MULADD(at[9], at[37]);    MULADD(at[10], at[36]);    MULADD(at[11], at[35]);    MULADD(at[12], at[34]);    MULADD(at[13], at[33]);    MULADD(at[14], at[32]);
2533    COMBA_STORE(C->dp[14]);
2534    /* 15 */
2535    COMBA_FORWARD;
2536    MULADD(at[0], at[47]);    MULADD(at[1], at[46]);    MULADD(at[2], at[45]);    MULADD(at[3], at[44]);    MULADD(at[4], at[43]);    MULADD(at[5], at[42]);    MULADD(at[6], at[41]);    MULADD(at[7], at[40]);    MULADD(at[8], at[39]);    MULADD(at[9], at[38]);    MULADD(at[10], at[37]);    MULADD(at[11], at[36]);    MULADD(at[12], at[35]);    MULADD(at[13], at[34]);    MULADD(at[14], at[33]);    MULADD(at[15], at[32]);
2537    COMBA_STORE(C->dp[15]);
2538    /* 16 */
2539    COMBA_FORWARD;
2540    MULADD(at[0], at[48]);    MULADD(at[1], at[47]);    MULADD(at[2], at[46]);    MULADD(at[3], at[45]);    MULADD(at[4], at[44]);    MULADD(at[5], at[43]);    MULADD(at[6], at[42]);    MULADD(at[7], at[41]);    MULADD(at[8], at[40]);    MULADD(at[9], at[39]);    MULADD(at[10], at[38]);    MULADD(at[11], at[37]);    MULADD(at[12], at[36]);    MULADD(at[13], at[35]);    MULADD(at[14], at[34]);    MULADD(at[15], at[33]);    MULADD(at[16], at[32]);
2541    COMBA_STORE(C->dp[16]);
2542    /* 17 */
2543    COMBA_FORWARD;
2544    MULADD(at[0], at[49]);    MULADD(at[1], at[48]);    MULADD(at[2], at[47]);    MULADD(at[3], at[46]);    MULADD(at[4], at[45]);    MULADD(at[5], at[44]);    MULADD(at[6], at[43]);    MULADD(at[7], at[42]);    MULADD(at[8], at[41]);    MULADD(at[9], at[40]);    MULADD(at[10], at[39]);    MULADD(at[11], at[38]);    MULADD(at[12], at[37]);    MULADD(at[13], at[36]);    MULADD(at[14], at[35]);    MULADD(at[15], at[34]);    MULADD(at[16], at[33]);    MULADD(at[17], at[32]);
2545    COMBA_STORE(C->dp[17]);
2546    /* 18 */
2547    COMBA_FORWARD;
2548    MULADD(at[0], at[50]);    MULADD(at[1], at[49]);    MULADD(at[2], at[48]);    MULADD(at[3], at[47]);    MULADD(at[4], at[46]);    MULADD(at[5], at[45]);    MULADD(at[6], at[44]);    MULADD(at[7], at[43]);    MULADD(at[8], at[42]);    MULADD(at[9], at[41]);    MULADD(at[10], at[40]);    MULADD(at[11], at[39]);    MULADD(at[12], at[38]);    MULADD(at[13], at[37]);    MULADD(at[14], at[36]);    MULADD(at[15], at[35]);    MULADD(at[16], at[34]);    MULADD(at[17], at[33]);    MULADD(at[18], at[32]);
2549    COMBA_STORE(C->dp[18]);
2550    /* 19 */
2551    COMBA_FORWARD;
2552    MULADD(at[0], at[51]);    MULADD(at[1], at[50]);    MULADD(at[2], at[49]);    MULADD(at[3], at[48]);    MULADD(at[4], at[47]);    MULADD(at[5], at[46]);    MULADD(at[6], at[45]);    MULADD(at[7], at[44]);    MULADD(at[8], at[43]);    MULADD(at[9], at[42]);    MULADD(at[10], at[41]);    MULADD(at[11], at[40]);    MULADD(at[12], at[39]);    MULADD(at[13], at[38]);    MULADD(at[14], at[37]);    MULADD(at[15], at[36]);    MULADD(at[16], at[35]);    MULADD(at[17], at[34]);    MULADD(at[18], at[33]);    MULADD(at[19], at[32]);
2553    COMBA_STORE(C->dp[19]);
2554    /* 20 */
2555    COMBA_FORWARD;
2556    MULADD(at[0], at[52]);    MULADD(at[1], at[51]);    MULADD(at[2], at[50]);    MULADD(at[3], at[49]);    MULADD(at[4], at[48]);    MULADD(at[5], at[47]);    MULADD(at[6], at[46]);    MULADD(at[7], at[45]);    MULADD(at[8], at[44]);    MULADD(at[9], at[43]);    MULADD(at[10], at[42]);    MULADD(at[11], at[41]);    MULADD(at[12], at[40]);    MULADD(at[13], at[39]);    MULADD(at[14], at[38]);    MULADD(at[15], at[37]);    MULADD(at[16], at[36]);    MULADD(at[17], at[35]);    MULADD(at[18], at[34]);    MULADD(at[19], at[33]);    MULADD(at[20], at[32]);
2557    COMBA_STORE(C->dp[20]);
2558    /* 21 */
2559    COMBA_FORWARD;
2560    MULADD(at[0], at[53]);    MULADD(at[1], at[52]);    MULADD(at[2], at[51]);    MULADD(at[3], at[50]);    MULADD(at[4], at[49]);    MULADD(at[5], at[48]);    MULADD(at[6], at[47]);    MULADD(at[7], at[46]);    MULADD(at[8], at[45]);    MULADD(at[9], at[44]);    MULADD(at[10], at[43]);    MULADD(at[11], at[42]);    MULADD(at[12], at[41]);    MULADD(at[13], at[40]);    MULADD(at[14], at[39]);    MULADD(at[15], at[38]);    MULADD(at[16], at[37]);    MULADD(at[17], at[36]);    MULADD(at[18], at[35]);    MULADD(at[19], at[34]);    MULADD(at[20], at[33]);    MULADD(at[21], at[32]);
2561    COMBA_STORE(C->dp[21]);
2562    /* 22 */
2563    COMBA_FORWARD;
2564    MULADD(at[0], at[54]);    MULADD(at[1], at[53]);    MULADD(at[2], at[52]);    MULADD(at[3], at[51]);    MULADD(at[4], at[50]);    MULADD(at[5], at[49]);    MULADD(at[6], at[48]);    MULADD(at[7], at[47]);    MULADD(at[8], at[46]);    MULADD(at[9], at[45]);    MULADD(at[10], at[44]);    MULADD(at[11], at[43]);    MULADD(at[12], at[42]);    MULADD(at[13], at[41]);    MULADD(at[14], at[40]);    MULADD(at[15], at[39]);    MULADD(at[16], at[38]);    MULADD(at[17], at[37]);    MULADD(at[18], at[36]);    MULADD(at[19], at[35]);    MULADD(at[20], at[34]);    MULADD(at[21], at[33]);    MULADD(at[22], at[32]);
2565    COMBA_STORE(C->dp[22]);
2566    /* 23 */
2567    COMBA_FORWARD;
2568    MULADD(at[0], at[55]);    MULADD(at[1], at[54]);    MULADD(at[2], at[53]);    MULADD(at[3], at[52]);    MULADD(at[4], at[51]);    MULADD(at[5], at[50]);    MULADD(at[6], at[49]);    MULADD(at[7], at[48]);    MULADD(at[8], at[47]);    MULADD(at[9], at[46]);    MULADD(at[10], at[45]);    MULADD(at[11], at[44]);    MULADD(at[12], at[43]);    MULADD(at[13], at[42]);    MULADD(at[14], at[41]);    MULADD(at[15], at[40]);    MULADD(at[16], at[39]);    MULADD(at[17], at[38]);    MULADD(at[18], at[37]);    MULADD(at[19], at[36]);    MULADD(at[20], at[35]);    MULADD(at[21], at[34]);    MULADD(at[22], at[33]);    MULADD(at[23], at[32]);
2569    COMBA_STORE(C->dp[23]);
2570    /* 24 */
2571    COMBA_FORWARD;
2572    MULADD(at[0], at[56]);    MULADD(at[1], at[55]);    MULADD(at[2], at[54]);    MULADD(at[3], at[53]);    MULADD(at[4], at[52]);    MULADD(at[5], at[51]);    MULADD(at[6], at[50]);    MULADD(at[7], at[49]);    MULADD(at[8], at[48]);    MULADD(at[9], at[47]);    MULADD(at[10], at[46]);    MULADD(at[11], at[45]);    MULADD(at[12], at[44]);    MULADD(at[13], at[43]);    MULADD(at[14], at[42]);    MULADD(at[15], at[41]);    MULADD(at[16], at[40]);    MULADD(at[17], at[39]);    MULADD(at[18], at[38]);    MULADD(at[19], at[37]);    MULADD(at[20], at[36]);    MULADD(at[21], at[35]);    MULADD(at[22], at[34]);    MULADD(at[23], at[33]);    MULADD(at[24], at[32]);
2573    COMBA_STORE(C->dp[24]);
2574    /* 25 */
2575    COMBA_FORWARD;
2576    MULADD(at[0], at[57]);    MULADD(at[1], at[56]);    MULADD(at[2], at[55]);    MULADD(at[3], at[54]);    MULADD(at[4], at[53]);    MULADD(at[5], at[52]);    MULADD(at[6], at[51]);    MULADD(at[7], at[50]);    MULADD(at[8], at[49]);    MULADD(at[9], at[48]);    MULADD(at[10], at[47]);    MULADD(at[11], at[46]);    MULADD(at[12], at[45]);    MULADD(at[13], at[44]);    MULADD(at[14], at[43]);    MULADD(at[15], at[42]);    MULADD(at[16], at[41]);    MULADD(at[17], at[40]);    MULADD(at[18], at[39]);    MULADD(at[19], at[38]);    MULADD(at[20], at[37]);    MULADD(at[21], at[36]);    MULADD(at[22], at[35]);    MULADD(at[23], at[34]);    MULADD(at[24], at[33]);    MULADD(at[25], at[32]);
2577    COMBA_STORE(C->dp[25]);
2578    /* 26 */
2579    COMBA_FORWARD;
2580    MULADD(at[0], at[58]);    MULADD(at[1], at[57]);    MULADD(at[2], at[56]);    MULADD(at[3], at[55]);    MULADD(at[4], at[54]);    MULADD(at[5], at[53]);    MULADD(at[6], at[52]);    MULADD(at[7], at[51]);    MULADD(at[8], at[50]);    MULADD(at[9], at[49]);    MULADD(at[10], at[48]);    MULADD(at[11], at[47]);    MULADD(at[12], at[46]);    MULADD(at[13], at[45]);    MULADD(at[14], at[44]);    MULADD(at[15], at[43]);    MULADD(at[16], at[42]);    MULADD(at[17], at[41]);    MULADD(at[18], at[40]);    MULADD(at[19], at[39]);    MULADD(at[20], at[38]);    MULADD(at[21], at[37]);    MULADD(at[22], at[36]);    MULADD(at[23], at[35]);    MULADD(at[24], at[34]);    MULADD(at[25], at[33]);    MULADD(at[26], at[32]);
2581    COMBA_STORE(C->dp[26]);
2582    /* 27 */
2583    COMBA_FORWARD;
2584    MULADD(at[0], at[59]);    MULADD(at[1], at[58]);    MULADD(at[2], at[57]);    MULADD(at[3], at[56]);    MULADD(at[4], at[55]);    MULADD(at[5], at[54]);    MULADD(at[6], at[53]);    MULADD(at[7], at[52]);    MULADD(at[8], at[51]);    MULADD(at[9], at[50]);    MULADD(at[10], at[49]);    MULADD(at[11], at[48]);    MULADD(at[12], at[47]);    MULADD(at[13], at[46]);    MULADD(at[14], at[45]);    MULADD(at[15], at[44]);    MULADD(at[16], at[43]);    MULADD(at[17], at[42]);    MULADD(at[18], at[41]);    MULADD(at[19], at[40]);    MULADD(at[20], at[39]);    MULADD(at[21], at[38]);    MULADD(at[22], at[37]);    MULADD(at[23], at[36]);    MULADD(at[24], at[35]);    MULADD(at[25], at[34]);    MULADD(at[26], at[33]);    MULADD(at[27], at[32]);
2585    COMBA_STORE(C->dp[27]);
2586    /* 28 */
2587    COMBA_FORWARD;
2588    MULADD(at[0], at[60]);    MULADD(at[1], at[59]);    MULADD(at[2], at[58]);    MULADD(at[3], at[57]);    MULADD(at[4], at[56]);    MULADD(at[5], at[55]);    MULADD(at[6], at[54]);    MULADD(at[7], at[53]);    MULADD(at[8], at[52]);    MULADD(at[9], at[51]);    MULADD(at[10], at[50]);    MULADD(at[11], at[49]);    MULADD(at[12], at[48]);    MULADD(at[13], at[47]);    MULADD(at[14], at[46]);    MULADD(at[15], at[45]);    MULADD(at[16], at[44]);    MULADD(at[17], at[43]);    MULADD(at[18], at[42]);    MULADD(at[19], at[41]);    MULADD(at[20], at[40]);    MULADD(at[21], at[39]);    MULADD(at[22], at[38]);    MULADD(at[23], at[37]);    MULADD(at[24], at[36]);    MULADD(at[25], at[35]);    MULADD(at[26], at[34]);    MULADD(at[27], at[33]);    MULADD(at[28], at[32]);
2589    COMBA_STORE(C->dp[28]);
2590    /* 29 */
2591    COMBA_FORWARD;
2592    MULADD(at[0], at[61]);    MULADD(at[1], at[60]);    MULADD(at[2], at[59]);    MULADD(at[3], at[58]);    MULADD(at[4], at[57]);    MULADD(at[5], at[56]);    MULADD(at[6], at[55]);    MULADD(at[7], at[54]);    MULADD(at[8], at[53]);    MULADD(at[9], at[52]);    MULADD(at[10], at[51]);    MULADD(at[11], at[50]);    MULADD(at[12], at[49]);    MULADD(at[13], at[48]);    MULADD(at[14], at[47]);    MULADD(at[15], at[46]);    MULADD(at[16], at[45]);    MULADD(at[17], at[44]);    MULADD(at[18], at[43]);    MULADD(at[19], at[42]);    MULADD(at[20], at[41]);    MULADD(at[21], at[40]);    MULADD(at[22], at[39]);    MULADD(at[23], at[38]);    MULADD(at[24], at[37]);    MULADD(at[25], at[36]);    MULADD(at[26], at[35]);    MULADD(at[27], at[34]);    MULADD(at[28], at[33]);    MULADD(at[29], at[32]);
2593    COMBA_STORE(C->dp[29]);
2594    /* 30 */
2595    COMBA_FORWARD;
2596    MULADD(at[0], at[62]);    MULADD(at[1], at[61]);    MULADD(at[2], at[60]);    MULADD(at[3], at[59]);    MULADD(at[4], at[58]);    MULADD(at[5], at[57]);    MULADD(at[6], at[56]);    MULADD(at[7], at[55]);    MULADD(at[8], at[54]);    MULADD(at[9], at[53]);    MULADD(at[10], at[52]);    MULADD(at[11], at[51]);    MULADD(at[12], at[50]);    MULADD(at[13], at[49]);    MULADD(at[14], at[48]);    MULADD(at[15], at[47]);    MULADD(at[16], at[46]);    MULADD(at[17], at[45]);    MULADD(at[18], at[44]);    MULADD(at[19], at[43]);    MULADD(at[20], at[42]);    MULADD(at[21], at[41]);    MULADD(at[22], at[40]);    MULADD(at[23], at[39]);    MULADD(at[24], at[38]);    MULADD(at[25], at[37]);    MULADD(at[26], at[36]);    MULADD(at[27], at[35]);    MULADD(at[28], at[34]);    MULADD(at[29], at[33]);    MULADD(at[30], at[32]);
2597    COMBA_STORE(C->dp[30]);
2598    /* 31 */
2599    COMBA_FORWARD;
2600    MULADD(at[0], at[63]);    MULADD(at[1], at[62]);    MULADD(at[2], at[61]);    MULADD(at[3], at[60]);    MULADD(at[4], at[59]);    MULADD(at[5], at[58]);    MULADD(at[6], at[57]);    MULADD(at[7], at[56]);    MULADD(at[8], at[55]);    MULADD(at[9], at[54]);    MULADD(at[10], at[53]);    MULADD(at[11], at[52]);    MULADD(at[12], at[51]);    MULADD(at[13], at[50]);    MULADD(at[14], at[49]);    MULADD(at[15], at[48]);    MULADD(at[16], at[47]);    MULADD(at[17], at[46]);    MULADD(at[18], at[45]);    MULADD(at[19], at[44]);    MULADD(at[20], at[43]);    MULADD(at[21], at[42]);    MULADD(at[22], at[41]);    MULADD(at[23], at[40]);    MULADD(at[24], at[39]);    MULADD(at[25], at[38]);    MULADD(at[26], at[37]);    MULADD(at[27], at[36]);    MULADD(at[28], at[35]);    MULADD(at[29], at[34]);    MULADD(at[30], at[33]);    MULADD(at[31], at[32]);
2601    COMBA_STORE(C->dp[31]);
2602    /* 32 */
2603    COMBA_FORWARD;
2604    MULADD(at[1], at[63]);    MULADD(at[2], at[62]);    MULADD(at[3], at[61]);    MULADD(at[4], at[60]);    MULADD(at[5], at[59]);    MULADD(at[6], at[58]);    MULADD(at[7], at[57]);    MULADD(at[8], at[56]);    MULADD(at[9], at[55]);    MULADD(at[10], at[54]);    MULADD(at[11], at[53]);    MULADD(at[12], at[52]);    MULADD(at[13], at[51]);    MULADD(at[14], at[50]);    MULADD(at[15], at[49]);    MULADD(at[16], at[48]);    MULADD(at[17], at[47]);    MULADD(at[18], at[46]);    MULADD(at[19], at[45]);    MULADD(at[20], at[44]);    MULADD(at[21], at[43]);    MULADD(at[22], at[42]);    MULADD(at[23], at[41]);    MULADD(at[24], at[40]);    MULADD(at[25], at[39]);    MULADD(at[26], at[38]);    MULADD(at[27], at[37]);    MULADD(at[28], at[36]);    MULADD(at[29], at[35]);    MULADD(at[30], at[34]);    MULADD(at[31], at[33]);
2605    COMBA_STORE(C->dp[32]);
2606    /* 33 */
2607    COMBA_FORWARD;
2608    MULADD(at[2], at[63]);    MULADD(at[3], at[62]);    MULADD(at[4], at[61]);    MULADD(at[5], at[60]);    MULADD(at[6], at[59]);    MULADD(at[7], at[58]);    MULADD(at[8], at[57]);    MULADD(at[9], at[56]);    MULADD(at[10], at[55]);    MULADD(at[11], at[54]);    MULADD(at[12], at[53]);    MULADD(at[13], at[52]);    MULADD(at[14], at[51]);    MULADD(at[15], at[50]);    MULADD(at[16], at[49]);    MULADD(at[17], at[48]);    MULADD(at[18], at[47]);    MULADD(at[19], at[46]);    MULADD(at[20], at[45]);    MULADD(at[21], at[44]);    MULADD(at[22], at[43]);    MULADD(at[23], at[42]);    MULADD(at[24], at[41]);    MULADD(at[25], at[40]);    MULADD(at[26], at[39]);    MULADD(at[27], at[38]);    MULADD(at[28], at[37]);    MULADD(at[29], at[36]);    MULADD(at[30], at[35]);    MULADD(at[31], at[34]);
2609    COMBA_STORE(C->dp[33]);
2610    /* 34 */
2611    COMBA_FORWARD;
2612    MULADD(at[3], at[63]);    MULADD(at[4], at[62]);    MULADD(at[5], at[61]);    MULADD(at[6], at[60]);    MULADD(at[7], at[59]);    MULADD(at[8], at[58]);    MULADD(at[9], at[57]);    MULADD(at[10], at[56]);    MULADD(at[11], at[55]);    MULADD(at[12], at[54]);    MULADD(at[13], at[53]);    MULADD(at[14], at[52]);    MULADD(at[15], at[51]);    MULADD(at[16], at[50]);    MULADD(at[17], at[49]);    MULADD(at[18], at[48]);    MULADD(at[19], at[47]);    MULADD(at[20], at[46]);    MULADD(at[21], at[45]);    MULADD(at[22], at[44]);    MULADD(at[23], at[43]);    MULADD(at[24], at[42]);    MULADD(at[25], at[41]);    MULADD(at[26], at[40]);    MULADD(at[27], at[39]);    MULADD(at[28], at[38]);    MULADD(at[29], at[37]);    MULADD(at[30], at[36]);    MULADD(at[31], at[35]);
2613    COMBA_STORE(C->dp[34]);
2614    /* 35 */
2615    COMBA_FORWARD;
2616    MULADD(at[4], at[63]);    MULADD(at[5], at[62]);    MULADD(at[6], at[61]);    MULADD(at[7], at[60]);    MULADD(at[8], at[59]);    MULADD(at[9], at[58]);    MULADD(at[10], at[57]);    MULADD(at[11], at[56]);    MULADD(at[12], at[55]);    MULADD(at[13], at[54]);    MULADD(at[14], at[53]);    MULADD(at[15], at[52]);    MULADD(at[16], at[51]);    MULADD(at[17], at[50]);    MULADD(at[18], at[49]);    MULADD(at[19], at[48]);    MULADD(at[20], at[47]);    MULADD(at[21], at[46]);    MULADD(at[22], at[45]);    MULADD(at[23], at[44]);    MULADD(at[24], at[43]);    MULADD(at[25], at[42]);    MULADD(at[26], at[41]);    MULADD(at[27], at[40]);    MULADD(at[28], at[39]);    MULADD(at[29], at[38]);    MULADD(at[30], at[37]);    MULADD(at[31], at[36]);
2617    COMBA_STORE(C->dp[35]);
2618    /* 36 */
2619    COMBA_FORWARD;
2620    MULADD(at[5], at[63]);    MULADD(at[6], at[62]);    MULADD(at[7], at[61]);    MULADD(at[8], at[60]);    MULADD(at[9], at[59]);    MULADD(at[10], at[58]);    MULADD(at[11], at[57]);    MULADD(at[12], at[56]);    MULADD(at[13], at[55]);    MULADD(at[14], at[54]);    MULADD(at[15], at[53]);    MULADD(at[16], at[52]);    MULADD(at[17], at[51]);    MULADD(at[18], at[50]);    MULADD(at[19], at[49]);    MULADD(at[20], at[48]);    MULADD(at[21], at[47]);    MULADD(at[22], at[46]);    MULADD(at[23], at[45]);    MULADD(at[24], at[44]);    MULADD(at[25], at[43]);    MULADD(at[26], at[42]);    MULADD(at[27], at[41]);    MULADD(at[28], at[40]);    MULADD(at[29], at[39]);    MULADD(at[30], at[38]);    MULADD(at[31], at[37]);
2621    COMBA_STORE(C->dp[36]);
2622    /* 37 */
2623    COMBA_FORWARD;
2624    MULADD(at[6], at[63]);    MULADD(at[7], at[62]);    MULADD(at[8], at[61]);    MULADD(at[9], at[60]);    MULADD(at[10], at[59]);    MULADD(at[11], at[58]);    MULADD(at[12], at[57]);    MULADD(at[13], at[56]);    MULADD(at[14], at[55]);    MULADD(at[15], at[54]);    MULADD(at[16], at[53]);    MULADD(at[17], at[52]);    MULADD(at[18], at[51]);    MULADD(at[19], at[50]);    MULADD(at[20], at[49]);    MULADD(at[21], at[48]);    MULADD(at[22], at[47]);    MULADD(at[23], at[46]);    MULADD(at[24], at[45]);    MULADD(at[25], at[44]);    MULADD(at[26], at[43]);    MULADD(at[27], at[42]);    MULADD(at[28], at[41]);    MULADD(at[29], at[40]);    MULADD(at[30], at[39]);    MULADD(at[31], at[38]);
2625    COMBA_STORE(C->dp[37]);
2626    /* 38 */
2627    COMBA_FORWARD;
2628    MULADD(at[7], at[63]);    MULADD(at[8], at[62]);    MULADD(at[9], at[61]);    MULADD(at[10], at[60]);    MULADD(at[11], at[59]);    MULADD(at[12], at[58]);    MULADD(at[13], at[57]);    MULADD(at[14], at[56]);    MULADD(at[15], at[55]);    MULADD(at[16], at[54]);    MULADD(at[17], at[53]);    MULADD(at[18], at[52]);    MULADD(at[19], at[51]);    MULADD(at[20], at[50]);    MULADD(at[21], at[49]);    MULADD(at[22], at[48]);    MULADD(at[23], at[47]);    MULADD(at[24], at[46]);    MULADD(at[25], at[45]);    MULADD(at[26], at[44]);    MULADD(at[27], at[43]);    MULADD(at[28], at[42]);    MULADD(at[29], at[41]);    MULADD(at[30], at[40]);    MULADD(at[31], at[39]);
2629    COMBA_STORE(C->dp[38]);
2630    /* 39 */
2631    COMBA_FORWARD;
2632    MULADD(at[8], at[63]);    MULADD(at[9], at[62]);    MULADD(at[10], at[61]);    MULADD(at[11], at[60]);    MULADD(at[12], at[59]);    MULADD(at[13], at[58]);    MULADD(at[14], at[57]);    MULADD(at[15], at[56]);    MULADD(at[16], at[55]);    MULADD(at[17], at[54]);    MULADD(at[18], at[53]);    MULADD(at[19], at[52]);    MULADD(at[20], at[51]);    MULADD(at[21], at[50]);    MULADD(at[22], at[49]);    MULADD(at[23], at[48]);    MULADD(at[24], at[47]);    MULADD(at[25], at[46]);    MULADD(at[26], at[45]);    MULADD(at[27], at[44]);    MULADD(at[28], at[43]);    MULADD(at[29], at[42]);    MULADD(at[30], at[41]);    MULADD(at[31], at[40]);
2633    COMBA_STORE(C->dp[39]);
2634    /* 40 */
2635    COMBA_FORWARD;
2636    MULADD(at[9], at[63]);    MULADD(at[10], at[62]);    MULADD(at[11], at[61]);    MULADD(at[12], at[60]);    MULADD(at[13], at[59]);    MULADD(at[14], at[58]);    MULADD(at[15], at[57]);    MULADD(at[16], at[56]);    MULADD(at[17], at[55]);    MULADD(at[18], at[54]);    MULADD(at[19], at[53]);    MULADD(at[20], at[52]);    MULADD(at[21], at[51]);    MULADD(at[22], at[50]);    MULADD(at[23], at[49]);    MULADD(at[24], at[48]);    MULADD(at[25], at[47]);    MULADD(at[26], at[46]);    MULADD(at[27], at[45]);    MULADD(at[28], at[44]);    MULADD(at[29], at[43]);    MULADD(at[30], at[42]);    MULADD(at[31], at[41]);
2637    COMBA_STORE(C->dp[40]);
2638    /* 41 */
2639    COMBA_FORWARD;
2640    MULADD(at[10], at[63]);    MULADD(at[11], at[62]);    MULADD(at[12], at[61]);    MULADD(at[13], at[60]);    MULADD(at[14], at[59]);    MULADD(at[15], at[58]);    MULADD(at[16], at[57]);    MULADD(at[17], at[56]);    MULADD(at[18], at[55]);    MULADD(at[19], at[54]);    MULADD(at[20], at[53]);    MULADD(at[21], at[52]);    MULADD(at[22], at[51]);    MULADD(at[23], at[50]);    MULADD(at[24], at[49]);    MULADD(at[25], at[48]);    MULADD(at[26], at[47]);    MULADD(at[27], at[46]);    MULADD(at[28], at[45]);    MULADD(at[29], at[44]);    MULADD(at[30], at[43]);    MULADD(at[31], at[42]);
2641    COMBA_STORE(C->dp[41]);
2642    /* 42 */
2643    COMBA_FORWARD;
2644    MULADD(at[11], at[63]);    MULADD(at[12], at[62]);    MULADD(at[13], at[61]);    MULADD(at[14], at[60]);    MULADD(at[15], at[59]);    MULADD(at[16], at[58]);    MULADD(at[17], at[57]);    MULADD(at[18], at[56]);    MULADD(at[19], at[55]);    MULADD(at[20], at[54]);    MULADD(at[21], at[53]);    MULADD(at[22], at[52]);    MULADD(at[23], at[51]);    MULADD(at[24], at[50]);    MULADD(at[25], at[49]);    MULADD(at[26], at[48]);    MULADD(at[27], at[47]);    MULADD(at[28], at[46]);    MULADD(at[29], at[45]);    MULADD(at[30], at[44]);    MULADD(at[31], at[43]);
2645    COMBA_STORE(C->dp[42]);
2646    /* 43 */
2647    COMBA_FORWARD;
2648    MULADD(at[12], at[63]);    MULADD(at[13], at[62]);    MULADD(at[14], at[61]);    MULADD(at[15], at[60]);    MULADD(at[16], at[59]);    MULADD(at[17], at[58]);    MULADD(at[18], at[57]);    MULADD(at[19], at[56]);    MULADD(at[20], at[55]);    MULADD(at[21], at[54]);    MULADD(at[22], at[53]);    MULADD(at[23], at[52]);    MULADD(at[24], at[51]);    MULADD(at[25], at[50]);    MULADD(at[26], at[49]);    MULADD(at[27], at[48]);    MULADD(at[28], at[47]);    MULADD(at[29], at[46]);    MULADD(at[30], at[45]);    MULADD(at[31], at[44]);
2649    COMBA_STORE(C->dp[43]);
2650    /* 44 */
2651    COMBA_FORWARD;
2652    MULADD(at[13], at[63]);    MULADD(at[14], at[62]);    MULADD(at[15], at[61]);    MULADD(at[16], at[60]);    MULADD(at[17], at[59]);    MULADD(at[18], at[58]);    MULADD(at[19], at[57]);    MULADD(at[20], at[56]);    MULADD(at[21], at[55]);    MULADD(at[22], at[54]);    MULADD(at[23], at[53]);    MULADD(at[24], at[52]);    MULADD(at[25], at[51]);    MULADD(at[26], at[50]);    MULADD(at[27], at[49]);    MULADD(at[28], at[48]);    MULADD(at[29], at[47]);    MULADD(at[30], at[46]);    MULADD(at[31], at[45]);
2653    COMBA_STORE(C->dp[44]);
2654    /* 45 */
2655    COMBA_FORWARD;
2656    MULADD(at[14], at[63]);    MULADD(at[15], at[62]);    MULADD(at[16], at[61]);    MULADD(at[17], at[60]);    MULADD(at[18], at[59]);    MULADD(at[19], at[58]);    MULADD(at[20], at[57]);    MULADD(at[21], at[56]);    MULADD(at[22], at[55]);    MULADD(at[23], at[54]);    MULADD(at[24], at[53]);    MULADD(at[25], at[52]);    MULADD(at[26], at[51]);    MULADD(at[27], at[50]);    MULADD(at[28], at[49]);    MULADD(at[29], at[48]);    MULADD(at[30], at[47]);    MULADD(at[31], at[46]);
2657    COMBA_STORE(C->dp[45]);
2658    /* 46 */
2659    COMBA_FORWARD;
2660    MULADD(at[15], at[63]);    MULADD(at[16], at[62]);    MULADD(at[17], at[61]);    MULADD(at[18], at[60]);    MULADD(at[19], at[59]);    MULADD(at[20], at[58]);    MULADD(at[21], at[57]);    MULADD(at[22], at[56]);    MULADD(at[23], at[55]);    MULADD(at[24], at[54]);    MULADD(at[25], at[53]);    MULADD(at[26], at[52]);    MULADD(at[27], at[51]);    MULADD(at[28], at[50]);    MULADD(at[29], at[49]);    MULADD(at[30], at[48]);    MULADD(at[31], at[47]);
2661    COMBA_STORE(C->dp[46]);
2662    /* 47 */
2663    COMBA_FORWARD;
2664    MULADD(at[16], at[63]);    MULADD(at[17], at[62]);    MULADD(at[18], at[61]);    MULADD(at[19], at[60]);    MULADD(at[20], at[59]);    MULADD(at[21], at[58]);    MULADD(at[22], at[57]);    MULADD(at[23], at[56]);    MULADD(at[24], at[55]);    MULADD(at[25], at[54]);    MULADD(at[26], at[53]);    MULADD(at[27], at[52]);    MULADD(at[28], at[51]);    MULADD(at[29], at[50]);    MULADD(at[30], at[49]);    MULADD(at[31], at[48]);
2665    COMBA_STORE(C->dp[47]);
2666    /* 48 */
2667    COMBA_FORWARD;
2668    MULADD(at[17], at[63]);    MULADD(at[18], at[62]);    MULADD(at[19], at[61]);    MULADD(at[20], at[60]);    MULADD(at[21], at[59]);    MULADD(at[22], at[58]);    MULADD(at[23], at[57]);    MULADD(at[24], at[56]);    MULADD(at[25], at[55]);    MULADD(at[26], at[54]);    MULADD(at[27], at[53]);    MULADD(at[28], at[52]);    MULADD(at[29], at[51]);    MULADD(at[30], at[50]);    MULADD(at[31], at[49]);
2669    COMBA_STORE(C->dp[48]);
2670    /* 49 */
2671    COMBA_FORWARD;
2672    MULADD(at[18], at[63]);    MULADD(at[19], at[62]);    MULADD(at[20], at[61]);    MULADD(at[21], at[60]);    MULADD(at[22], at[59]);    MULADD(at[23], at[58]);    MULADD(at[24], at[57]);    MULADD(at[25], at[56]);    MULADD(at[26], at[55]);    MULADD(at[27], at[54]);    MULADD(at[28], at[53]);    MULADD(at[29], at[52]);    MULADD(at[30], at[51]);    MULADD(at[31], at[50]);
2673    COMBA_STORE(C->dp[49]);
2674    /* 50 */
2675    COMBA_FORWARD;
2676    MULADD(at[19], at[63]);    MULADD(at[20], at[62]);    MULADD(at[21], at[61]);    MULADD(at[22], at[60]);    MULADD(at[23], at[59]);    MULADD(at[24], at[58]);    MULADD(at[25], at[57]);    MULADD(at[26], at[56]);    MULADD(at[27], at[55]);    MULADD(at[28], at[54]);    MULADD(at[29], at[53]);    MULADD(at[30], at[52]);    MULADD(at[31], at[51]);
2677    COMBA_STORE(C->dp[50]);
2678    /* 51 */
2679    COMBA_FORWARD;
2680    MULADD(at[20], at[63]);    MULADD(at[21], at[62]);    MULADD(at[22], at[61]);    MULADD(at[23], at[60]);    MULADD(at[24], at[59]);    MULADD(at[25], at[58]);    MULADD(at[26], at[57]);    MULADD(at[27], at[56]);    MULADD(at[28], at[55]);    MULADD(at[29], at[54]);    MULADD(at[30], at[53]);    MULADD(at[31], at[52]);
2681    COMBA_STORE(C->dp[51]);
2682    /* 52 */
2683    COMBA_FORWARD;
2684    MULADD(at[21], at[63]);    MULADD(at[22], at[62]);    MULADD(at[23], at[61]);    MULADD(at[24], at[60]);    MULADD(at[25], at[59]);    MULADD(at[26], at[58]);    MULADD(at[27], at[57]);    MULADD(at[28], at[56]);    MULADD(at[29], at[55]);    MULADD(at[30], at[54]);    MULADD(at[31], at[53]);
2685    COMBA_STORE(C->dp[52]);
2686    /* 53 */
2687    COMBA_FORWARD;
2688    MULADD(at[22], at[63]);    MULADD(at[23], at[62]);    MULADD(at[24], at[61]);    MULADD(at[25], at[60]);    MULADD(at[26], at[59]);    MULADD(at[27], at[58]);    MULADD(at[28], at[57]);    MULADD(at[29], at[56]);    MULADD(at[30], at[55]);    MULADD(at[31], at[54]);
2689    COMBA_STORE(C->dp[53]);
2690    /* 54 */
2691    COMBA_FORWARD;
2692    MULADD(at[23], at[63]);    MULADD(at[24], at[62]);    MULADD(at[25], at[61]);    MULADD(at[26], at[60]);    MULADD(at[27], at[59]);    MULADD(at[28], at[58]);    MULADD(at[29], at[57]);    MULADD(at[30], at[56]);    MULADD(at[31], at[55]);
2693    COMBA_STORE(C->dp[54]);
2694    /* 55 */
2695    COMBA_FORWARD;
2696    MULADD(at[24], at[63]);    MULADD(at[25], at[62]);    MULADD(at[26], at[61]);    MULADD(at[27], at[60]);    MULADD(at[28], at[59]);    MULADD(at[29], at[58]);    MULADD(at[30], at[57]);    MULADD(at[31], at[56]);
2697    COMBA_STORE(C->dp[55]);
2698    /* 56 */
2699    COMBA_FORWARD;
2700    MULADD(at[25], at[63]);    MULADD(at[26], at[62]);    MULADD(at[27], at[61]);    MULADD(at[28], at[60]);    MULADD(at[29], at[59]);    MULADD(at[30], at[58]);    MULADD(at[31], at[57]);
2701    COMBA_STORE(C->dp[56]);
2702    /* 57 */
2703    COMBA_FORWARD;
2704    MULADD(at[26], at[63]);    MULADD(at[27], at[62]);    MULADD(at[28], at[61]);    MULADD(at[29], at[60]);    MULADD(at[30], at[59]);    MULADD(at[31], at[58]);
2705    COMBA_STORE(C->dp[57]);
2706    /* 58 */
2707    COMBA_FORWARD;
2708    MULADD(at[27], at[63]);    MULADD(at[28], at[62]);    MULADD(at[29], at[61]);    MULADD(at[30], at[60]);    MULADD(at[31], at[59]);
2709    COMBA_STORE(C->dp[58]);
2710    /* 59 */
2711    COMBA_FORWARD;
2712    MULADD(at[28], at[63]);    MULADD(at[29], at[62]);    MULADD(at[30], at[61]);    MULADD(at[31], at[60]);
2713    COMBA_STORE(C->dp[59]);
2714    /* 60 */
2715    COMBA_FORWARD;
2716    MULADD(at[29], at[63]);    MULADD(at[30], at[62]);    MULADD(at[31], at[61]);
2717    COMBA_STORE(C->dp[60]);
2718    /* 61 */
2719    COMBA_FORWARD;
2720    MULADD(at[30], at[63]);    MULADD(at[31], at[62]);
2721    COMBA_STORE(C->dp[61]);
2722    /* 62 */
2723    COMBA_FORWARD;
2724    MULADD(at[31], at[63]);
2725    COMBA_STORE(C->dp[62]);
2726    COMBA_STORE2(C->dp[63]);
2727    C->used = 64;
2728    C->sign = A->sign ^ B->sign;
2729    fp_clamp(C);
2730    COMBA_FINI;
2731 }
2732
2733 #endif
2734
2735 /* End: fp_mul_comba.c */
2736
2737 /* Start: fp_mul_d.c */
2738 /* TomsFastMath, a fast ISO C bignum library.
2739  *
2740  * This project is meant to fill in where LibTomMath
2741  * falls short.  That is speed ;-)
2742  *
2743  * This project is public domain and free for all purposes.
2744  *
2745  * Tom St Denis, tomstdenis@iahu.ca
2746  */
2747 #include <tfm.h>
2748
2749 /* c = a * b */
2750 void fp_mul_d(fp_int *a, fp_digit b, fp_int *c)
2751 {
2752    fp_word  w;
2753    int      x, oldused;
2754
2755    oldused = c->used;
2756    c->used = a->used;
2757    c->sign = a->sign;
2758    w       = 0;
2759    for (x = 0; x < a->used; x++) {
2760        w         = ((fp_word)a->dp[x]) * ((fp_word)b) + w;
2761        c->dp[x]  = (fp_digit)w;
2762        w         = w >> DIGIT_BIT;
2763    }
2764    if (w != 0 && (a->used != FP_SIZE)) {
2765       c->dp[c->used++] = w;
2766       ++x;
2767    }
2768    for (; x < oldused; x++) {
2769       c->dp[x] = 0;
2770    }
2771    fp_clamp(c);
2772 }
2773
2774
2775 /* End: fp_mul_d.c */
2776
2777 /* Start: fp_mulmod.c */
2778 /* TomsFastMath, a fast ISO C bignum library.
2779  *
2780  * This project is meant to fill in where LibTomMath
2781  * falls short.  That is speed ;-)
2782  *
2783  * This project is public domain and free for all purposes.
2784  *
2785  * Tom St Denis, tomstdenis@iahu.ca
2786  */
2787 #include <tfm.h>
2788 /* d = a * b (mod c) */
2789 int fp_mulmod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
2790 {
2791   fp_int tmp;
2792   fp_zero(&tmp);
2793   fp_mul(a, b, &tmp);
2794   return fp_mod(&tmp, c, d);
2795 }
2796
2797 /* End: fp_mulmod.c */
2798
2799 /* Start: fp_prime_miller_rabin.c */
2800 /* TomsFastMath, a fast ISO C bignum library.
2801  *
2802  * This project is meant to fill in where LibTomMath
2803  * falls short.  That is speed ;-)
2804  *
2805  * This project is public domain and free for all purposes.
2806  *
2807  * Tom St Denis, tomstdenis@iahu.ca
2808  */
2809 #include <tfm.h>
2810
2811 /* Miller-Rabin test of "a" to the base of "b" as described in
2812  * HAC pp. 139 Algorithm 4.24
2813  *
2814  * Sets result to 0 if definitely composite or 1 if probably prime.
2815  * Randomly the chance of error is no more than 1/4 and often
2816  * very much lower.
2817  */
2818 void fp_prime_miller_rabin (fp_int * a, fp_int * b, int *result)
2819 {
2820   fp_int  n1, y, r;
2821   int     s, j;
2822
2823   /* default */
2824   *result = FP_NO;
2825
2826   /* ensure b > 1 */
2827   if (fp_cmp_d(b, 1) != FP_GT) {
2828      return;
2829   }
2830
2831   /* get n1 = a - 1 */
2832   fp_init_copy(&n1, a);
2833   fp_sub_d(&n1, 1, &n1);
2834
2835   /* set 2**s * r = n1 */
2836   fp_init_copy(&r, &n1);
2837
2838   /* count the number of least significant bits
2839    * which are zero
2840    */
2841   s = fp_cnt_lsb(&r);
2842
2843   /* now divide n - 1 by 2**s */
2844   fp_div_2d (&r, s, &r, NULL);
2845
2846   /* compute y = b**r mod a */
2847   fp_init(&y);
2848   fp_exptmod(b, &r, a, &y);
2849
2850   /* if y != 1 and y != n1 do */
2851   if (fp_cmp_d (&y, 1) != FP_EQ && fp_cmp (&y, &n1) != FP_EQ) {
2852     j = 1;
2853     /* while j <= s-1 and y != n1 */
2854     while ((j <= (s - 1)) && fp_cmp (&y, &n1) != FP_EQ) {
2855       fp_sqrmod (&y, a, &y);
2856
2857       /* if y == 1 then composite */
2858       if (fp_cmp_d (&y, 1) == FP_EQ) {
2859          return;
2860       }
2861       ++j;
2862     }
2863
2864     /* if y != n1 then composite */
2865     if (fp_cmp (&y, &n1) != FP_EQ) {
2866        return;
2867     }
2868   }
2869
2870   /* probably prime now */
2871   *result = FP_YES;
2872 }
2873
2874 /* End: fp_prime_miller_rabin.c */
2875
2876 /* Start: fp_prime_random_ex.c */
2877 /* TomsFastMath, a fast ISO C bignum library.
2878  *
2879  * This project is meant to fill in where LibTomMath
2880  * falls short.  That is speed ;-)
2881  *
2882  * This project is public domain and free for all purposes.
2883  *
2884  * Tom St Denis, tomstdenis@iahu.ca
2885  */
2886 #include <tfm.h>
2887
2888 /* This is possibly the mother of all prime generation functions, muahahahahaha! */
2889 int fp_prime_random_ex(fp_int *a, int t, int size, int flags, tfm_prime_callback cb, void *dat)
2890 {
2891    unsigned char *tmp, maskAND, maskOR_msb, maskOR_lsb;
2892    int res, err, bsize, maskOR_msb_offset;
2893
2894    /* sanity check the input */
2895    if (size <= 1 || t <= 0) {
2896       return FP_VAL;
2897    }
2898
2899    /* TFM_PRIME_SAFE implies TFM_PRIME_BBS */
2900    if (flags & TFM_PRIME_SAFE) {
2901       flags |= TFM_PRIME_BBS;
2902    }
2903
2904    /* calc the byte size */
2905    bsize = (size>>3)+(size&7?1:0);
2906
2907    /* we need a buffer of bsize bytes */
2908    tmp = malloc(bsize);
2909    if (tmp == NULL) {
2910       return FP_MEM;
2911    }
2912
2913    /* calc the maskAND value for the MSbyte*/
2914    maskAND = 0xFF >> (8 - (size & 7));
2915
2916    /* calc the maskOR_msb */
2917    maskOR_msb        = 0;
2918    maskOR_msb_offset = (size - 2) >> 3;
2919    if (flags & TFM_PRIME_2MSB_ON) {
2920       maskOR_msb     |= 1 << ((size - 2) & 7);
2921    } else if (flags & TFM_PRIME_2MSB_OFF) {
2922       maskAND        &= ~(1 << ((size - 2) & 7));
2923    }
2924
2925    /* get the maskOR_lsb */
2926    maskOR_lsb         = 1;
2927    if (flags & TFM_PRIME_BBS) {
2928       maskOR_lsb     |= 3;
2929    }
2930
2931    do {
2932       /* read the bytes */
2933       if (cb(tmp, bsize, dat) != bsize) {
2934          err = FP_VAL;
2935          goto error;
2936       }
2937
2938       /* work over the MSbyte */
2939       tmp[0]    &= maskAND;
2940       tmp[0]    |= 1 << ((size - 1) & 7);
2941
2942       /* mix in the maskORs */
2943       tmp[maskOR_msb_offset]   |= maskOR_msb;
2944       tmp[bsize-1]             |= maskOR_lsb;
2945
2946       /* read it in */
2947       fp_read_unsigned_bin(a, tmp, bsize);
2948
2949       /* is it prime? */
2950       res = fp_isprime(a);
2951       if (res == FP_NO) continue;
2952
2953       if (flags & TFM_PRIME_SAFE) {
2954          /* see if (a-1)/2 is prime */
2955          fp_sub_d(a, 1, a);
2956          fp_div_2(a, a);
2957
2958          /* is it prime? */
2959          res = fp_isprime(a);
2960       }
2961    } while (res == FP_NO);
2962
2963    if (flags & TFM_PRIME_SAFE) {
2964       /* restore a to the original value */
2965       fp_mul_2(a, a);
2966       fp_add_d(a, 1, a);
2967    }
2968
2969    err = FP_OKAY;
2970 error:
2971    free(tmp);
2972    return err;
2973 }
2974
2975 /* End: fp_prime_random_ex.c */
2976
2977 /* Start: fp_radix_size.c */
2978 /* TomsFastMath, a fast ISO C bignum library.
2979  *
2980  * This project is meant to fill in where LibTomMath
2981  * falls short.  That is speed ;-)
2982  *
2983  * This project is public domain and free for all purposes.
2984  *
2985  * Tom St Denis, tomstdenis@iahu.ca
2986  */
2987 #include <tfm.h>
2988
2989 int fp_radix_size(fp_int *a, int radix, int *size)
2990 {
2991   int     digs;
2992   fp_int  t;
2993   fp_digit d;
2994
2995   *size = 0;
2996
2997   /* check range of the radix */
2998   if (radix < 2 || radix > 64) {
2999     return FP_VAL;
3000   }
3001
3002   /* quick out if its zero */
3003   if (fp_iszero(a) == 1) {
3004      *size = 2;
3005      return FP_OKAY;
3006   }
3007
3008   fp_init_copy(&t, a);
3009
3010   /* if it is negative output a - */
3011   if (t.sign == FP_NEG) {
3012     *size++;
3013     t.sign = FP_ZPOS;
3014   }
3015
3016   digs = 0;
3017   while (fp_iszero (&t) == FP_NO) {
3018     fp_div_d (&t, (fp_digit) radix, &t, &d);
3019     *size++;
3020   }
3021
3022   /* append a NULL so the string is properly terminated */
3023   *size++;
3024   return FP_OKAY;
3025
3026 }
3027
3028 /* End: fp_radix_size.c */
3029
3030 /* Start: fp_read_radix.c */
3031 /* TomsFastMath, a fast ISO C bignum library.
3032  *
3033  * This project is meant to fill in where LibTomMath
3034  * falls short.  That is speed ;-)
3035  *
3036  * This project is public domain and free for all purposes.
3037  *
3038  * Tom St Denis, tomstdenis@iahu.ca
3039  */
3040 #include <tfm.h>
3041
3042 int fp_read_radix(fp_int *a, char *str, int radix)
3043 {
3044   int     y, neg;
3045   char    ch;
3046
3047   /* make sure the radix is ok */
3048   if (radix < 2 || radix > 64) {
3049     return FP_VAL;
3050   }
3051
3052   /* if the leading digit is a
3053    * minus set the sign to negative.
3054    */
3055   if (*str == '-') {
3056     ++str;
3057     neg = FP_NEG;
3058   } else {
3059     neg = FP_ZPOS;
3060   }
3061
3062   /* set the integer to the default of zero */
3063   fp_zero (a);
3064
3065   /* process each digit of the string */
3066   while (*str) {
3067     /* if the radix < 36 the conversion is case insensitive
3068      * this allows numbers like 1AB and 1ab to represent the same  value
3069      * [e.g. in hex]
3070      */
3071     ch = (char) ((radix < 36) ? toupper (*str) : *str);
3072     for (y = 0; y < 64; y++) {
3073       if (ch == fp_s_rmap[y]) {
3074          break;
3075       }
3076     }
3077
3078     /* if the char was found in the map
3079      * and is less than the given radix add it
3080      * to the number, otherwise exit the loop.
3081      */
3082     if (y < radix) {
3083       fp_mul_d (a, (fp_digit) radix, a);
3084       fp_add_d (a, (fp_digit) y, a);
3085     } else {
3086       break;
3087     }
3088     ++str;
3089   }
3090
3091   /* set the sign only if a != 0 */
3092   if (fp_iszero(a) != FP_YES) {
3093      a->sign = neg;
3094   }
3095   return FP_OKAY;
3096 }
3097
3098 /* End: fp_read_radix.c */
3099
3100 /* Start: fp_read_signed_bin.c */
3101 /* TomsFastMath, a fast ISO C bignum library.
3102  *
3103  * This project is meant to fill in where LibTomMath
3104  * falls short.  That is speed ;-)
3105  *
3106  * This project is public domain and free for all purposes.
3107  *
3108  * Tom St Denis, tomstdenis@iahu.ca
3109  */
3110 #include <tfm.h>
3111
3112 void fp_read_signed_bin(fp_int *a, unsigned char *b, int c)
3113 {
3114   /* read magnitude */
3115   fp_read_unsigned_bin (a, b + 1, c - 1);
3116
3117   /* first byte is 0 for positive, non-zero for negative */
3118   if (b[0] == 0) {
3119      a->sign = FP_ZPOS;
3120   } else {
3121      a->sign = FP_NEG;
3122   }
3123 }
3124
3125 /* End: fp_read_signed_bin.c */
3126
3127 /* Start: fp_read_unsigned_bin.c */
3128 /* TomsFastMath, a fast ISO C bignum library.
3129  *
3130  * This project is meant to fill in where LibTomMath
3131  * falls short.  That is speed ;-)
3132  *
3133  * This project is public domain and free for all purposes.
3134  *
3135  * Tom St Denis, tomstdenis@iahu.ca
3136  */
3137 #include <tfm.h>
3138
3139 void fp_read_unsigned_bin(fp_int *a, unsigned char *b, int c)
3140 {
3141   /* zero the int */
3142   fp_zero (a);
3143
3144   /* read the bytes in */
3145   for (; c > 0; c--) {
3146     fp_mul_2d (a, 8, a);
3147     a->dp[0] |= *b++;
3148     a->used += 1;
3149   }
3150   fp_clamp (a);
3151 }
3152
3153 /* End: fp_read_unsigned_bin.c */
3154
3155 /* Start: fp_reverse.c */
3156 /* TomsFastMath, a fast ISO C bignum library.
3157  *
3158  * This project is meant to fill in where LibTomMath
3159  * falls short.  That is speed ;-)
3160  *
3161  * This project is public domain and free for all purposes.
3162  *
3163  * Tom St Denis, tomstdenis@iahu.ca
3164  */
3165 #include <tfm.h>
3166
3167 /* reverse an array, used for radix code */
3168 void bn_reverse (unsigned char *s, int len)
3169 {
3170   int     ix, iy;
3171   unsigned char t;
3172
3173   ix = 0;
3174   iy = len - 1;
3175   while (ix < iy) {
3176     t     = s[ix];
3177     s[ix] = s[iy];
3178     s[iy] = t;
3179     ++ix;
3180     --iy;
3181   }
3182 }
3183
3184 /* End: fp_reverse.c */
3185
3186 /* Start: fp_rshd.c */
3187 /* TomsFastMath, a fast ISO C bignum library.
3188  *
3189  * This project is meant to fill in where LibTomMath
3190  * falls short.  That is speed ;-)
3191  *
3192  * This project is public domain and free for all purposes.
3193  *
3194  * Tom St Denis, tomstdenis@iahu.ca
3195  */
3196 #include <tfm.h>
3197
3198 void fp_rshd(fp_int *a, int x)
3199 {
3200   int y;
3201
3202   /* too many digits just zero and return */
3203   if (x >= a->used) {
3204      fp_zero(a);
3205      return;
3206   }
3207
3208    /* shift */
3209    for (y = 0; y < a->used - x; y++) {
3210       a->dp[y] = a->dp[y+x];
3211    }
3212
3213    /* zero rest */
3214    for (; y < a->used; y++) {
3215       a->dp[y] = 0;
3216    }
3217
3218    /* decrement count */
3219    a->used -= x;
3220    fp_clamp(a);
3221 }
3222
3223
3224 /* End: fp_rshd.c */
3225
3226 /* Start: fp_s_rmap.c */
3227 /* TomsFastMath, a fast ISO C bignum library.
3228  *
3229  * This project is meant to fill in where LibTomMath
3230  * falls short.  That is speed ;-)
3231  *
3232  * This project is public domain and free for all purposes.
3233  *
3234  * Tom St Denis, tomstdenis@iahu.ca
3235  */
3236 #include <tfm.h>
3237
3238 /* chars used in radix conversions */
3239 const char *fp_s_rmap = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/";
3240
3241 /* End: fp_s_rmap.c */
3242
3243 /* Start: fp_set.c */
3244 /* TomsFastMath, a fast ISO C bignum library.
3245  *
3246  * This project is meant to fill in where LibTomMath
3247  * falls short.  That is speed ;-)
3248  *
3249  * This project is public domain and free for all purposes.
3250  *
3251  * Tom St Denis, tomstdenis@iahu.ca
3252  */
3253 #include <tfm.h>
3254
3255 void fp_set(fp_int *a, fp_digit b)
3256 {
3257    fp_zero(a);
3258    a->dp[0] = b;
3259    a->used  = b ? 1 : 0;
3260 }
3261
3262 /* End: fp_set.c */
3263
3264 /* Start: fp_signed_bin_size.c */
3265 /* TomsFastMath, a fast ISO C bignum library.
3266  *
3267  * This project is meant to fill in where LibTomMath
3268  * falls short.  That is speed ;-)
3269  *
3270  * This project is public domain and free for all purposes.
3271  *
3272  * Tom St Denis, tomstdenis@iahu.ca
3273  */
3274 #include <tfm.h>
3275
3276 int fp_signed_bin_size(fp_int *a)
3277 {
3278   return 1 + fp_unsigned_bin_size (a);
3279 }
3280
3281 /* End: fp_signed_bin_size.c */
3282
3283 /* Start: fp_sqr.c */
3284 /* TomsFastMath, a fast ISO C bignum library.
3285  *
3286  * This project is meant to fill in where LibTomMath
3287  * falls short.  That is speed ;-)
3288  *
3289  * This project is public domain and free for all purposes.
3290  *
3291  * Tom St Denis, tomstdenis@iahu.ca
3292  */
3293 #include <tfm.h>
3294
3295 /* b = a*a  */
3296 void fp_sqr(fp_int *A, fp_int *B)
3297 {
3298     int    r, y, s;
3299     fp_int aa, bb, comp, amb, t1;
3300
3301     y = A->used;
3302     if (y <= 64) {
3303         if (y <= 4) {
3304            fp_sqr_comba4(A,B);
3305         } else if (y <= 8) {
3306            fp_sqr_comba8(A,B);
3307 #if defined(TFM_LARGE)
3308         } else if (y <= 16 && y >= 12) {
3309            fp_sqr_comba16(A,B);
3310 #endif
3311 #if defined(TFM_HUGE)
3312         } else if (y <= 32 && y >= 20) {
3313            fp_sqr_comba32(A,B);
3314         } else if (y <= 64 && y >= 48) {
3315            fp_sqr_comba64(A,B);
3316 #endif
3317         } else {
3318            fp_sqr_comba(A, B);
3319         }
3320
3321     } else {
3322         /* do the karatsuba action
3323
3324            if A = ab ||a|| = r we need to solve
3325
3326            a^2*r^2 + (-(a-b)^2 + a^2 + b^2)*r + b^2
3327
3328            So we solve for the three products then we form the final result with careful shifting
3329            and addition.
3330
3331 Obvious points of optimization
3332
3333 - "ac" parts can be memcpy'ed with an offset [all you have to do is zero upto the next 8 digits]
3334 - Similarly the "bd" parts can be memcpy'ed and zeroed to 8
3335 -
3336
3337         */
3338         /* get our value of r */
3339         r = y >> 1;
3340
3341         /* now solve for ac */
3342 //        fp_copy(A, &t1); fp_rshd(&t1, r);
3343         for (s = 0; s < A->used - r; s++) {
3344             t1.dp[s] = A->dp[s+r];
3345         }
3346         for (; s < FP_SIZE; s++) {
3347             t1.dp[s] = 0;
3348         }
3349         if (A->used >= r) {
3350            t1.used = A->used - r;
3351         } else {
3352            t1.used = 0;
3353         }
3354         t1.sign = A->sign;
3355         fp_copy(&t1, &amb);
3356         fp_zero(&aa);
3357         fp_sqr(&t1, &aa);
3358
3359         /* now solve for bd */
3360 //        fp_mod_2d(A, r * DIGIT_BIT, &t1);
3361         for (s = 0; s < r; s++) {
3362             t1.dp[s] = A->dp[s];
3363         }
3364         for (; s < FP_SIZE; s++) {
3365             t1.dp[s]   = 0;
3366         }
3367         t1.used = r;
3368         fp_clamp(&t1);
3369
3370         fp_sub(&amb, &t1, &amb);
3371         fp_zero(&bb);
3372         fp_sqr(&t1, &bb);
3373
3374         /* now get the (a-b) term */
3375         fp_zero(&comp);
3376         fp_sqr(&amb, &comp);
3377
3378         /* now solve the system, do the middle term first */
3379         comp.sign ^= 1;
3380         fp_add(&comp, &aa, &comp);
3381         fp_add(&comp, &bb, &comp);
3382         fp_lshd(&comp, r);
3383
3384         /* leading term */
3385         fp_lshd(&aa, r+r);
3386
3387         /* now sum them together */
3388         fp_zero(B);
3389         fp_add(&aa, &comp, B);
3390         fp_add(&bb, B, B);
3391         B->sign = FP_ZPOS;
3392     }
3393 }
3394
3395
3396 /* End: fp_sqr.c */
3397
3398 /* Start: fp_sqr_comba.c */
3399 /* TomsFastMath, a fast ISO C bignum library.
3400  *
3401  * This project is meant to fill in where LibTomMath
3402  * falls short.  That is speed ;-)
3403  *
3404  * This project is public domain and free for all purposes.
3405  *
3406  * Tom St Denis, tomstdenis@iahu.ca
3407  */
3408 #include <tfm.h>
3409
3410 /* About this file...
3411 */
3412
3413 #if defined(TFM_X86)
3414
3415 /* x86-32 optimized */
3416
3417 #define COMBA_START
3418
3419 #define CLEAR_CARRY \
3420    c0 = c1 = c2 = 0;
3421
3422 #define COMBA_STORE(x) \
3423    x = c0;
3424
3425 #define COMBA_STORE2(x) \
3426    x = c1;
3427
3428 #define CARRY_FORWARD \
3429    do { c0 = c1; c1 = c2; c2 = 0; } while (0);
3430
3431 #define COMBA_FINI
3432
3433 #define SQRADD(i, j)                                      \
3434 asm volatile (                                            \
3435      "movl  %6,%%eax     \n\t"                            \
3436      "mull  %%eax        \n\t"                            \
3437      "addl  %%eax,%0     \n\t"                            \
3438      "adcl  %%edx,%1     \n\t"                            \
3439      "adcl  $0,%2        \n\t"                            \
3440      :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","%edx","%cc");
3441
3442 #define SQRADD2(i, j)                                     \
3443 asm volatile (                                            \
3444      "movl  %6,%%eax     \n\t"                            \
3445      "mull  %7           \n\t"                            \
3446      "addl  %%eax,%0     \n\t"                            \
3447      "adcl  %%edx,%1     \n\t"                            \
3448      "adcl  $0,%2        \n\t"                            \
3449      "addl  %%eax,%0     \n\t"                            \
3450      "adcl  %%edx,%1     \n\t"                            \
3451      "adcl  $0,%2        \n\t"                            \
3452      :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","%cc");
3453
3454 #define SQRADDSC(i, j)                                    \
3455 asm (                                                     \
3456      "movl  %6,%%eax     \n\t"                            \
3457      "mull  %7           \n\t"                            \
3458      "movl  %%eax,%0     \n\t"                            \
3459      "movl  %%edx,%1     \n\t"                            \
3460      "xorl  %2,%2        \n\t"                            \
3461      :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","%cc");
3462
3463 #define SQRADDAC(i, j)                                    \
3464 asm (                                                     \
3465      "movl  %6,%%eax     \n\t"                            \
3466      "mull  %7           \n\t"                            \
3467      "addl  %%eax,%0     \n\t"                            \
3468      "adcl  %%edx,%1     \n\t"                            \
3469      "adcl  $0,%2        \n\t"                            \
3470      :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%eax","%edx","%cc");
3471
3472 #define SQRADDDB                                          \
3473 asm (                                                     \
3474      "addl %3,%0         \n\t"                            \
3475      "adcl %4,%1         \n\t"                            \
3476      "adcl %5,%2         \n\t"                            \
3477      "addl %3,%0         \n\t"                            \
3478      "adcl %4,%1         \n\t"                            \
3479      "adcl %5,%2         \n\t"                            \
3480      :"=r"(c0), "=r"(c1), "=r"(c2), "=g"(sc0), "=g"(sc1), "=g"(sc2) : "0"(c0), "1"(c1), "2"(c2), "3"(sc0), "4"(sc1), "5"(sc2) : "%cc");
3481
3482 #elif defined(TFM_X86_64)
3483 /* x86-64 optimized */
3484
3485 #define COMBA_START
3486
3487 #define CLEAR_CARRY \
3488    c0 = c1 = c2 = 0;
3489
3490 #define COMBA_STORE(x) \
3491    x = c0;
3492
3493 #define COMBA_STORE2(x) \
3494    x = c1;
3495
3496 #define CARRY_FORWARD \
3497    do { c0 = c1; c1 = c2; c2 = 0; } while (0);
3498
3499 #define COMBA_FINI
3500
3501 #define SQRADD(i, j)                                      \
3502 asm (                                                     \
3503      "movq  %6,%%rax     \n\t"                            \
3504      "mulq  %%rax        \n\t"                            \
3505      "addq  %%rax,%0     \n\t"                            \
3506      "adcq  %%rdx,%1     \n\t"                            \
3507      "adcq  $0,%2        \n\t"                            \
3508      :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i) :"%rax","%rdx","%cc");
3509
3510 #define SQRADD2(i, j)                                     \
3511 asm (                                                     \
3512      "movq  %6,%%rax     \n\t"                            \
3513      "mulq  %7           \n\t"                            \
3514      "addq  %%rax,%0     \n\t"                            \
3515      "adcq  %%rdx,%1     \n\t"                            \
3516      "adcq  $0,%2        \n\t"                            \
3517      "addq  %%rax,%0     \n\t"                            \
3518      "adcq  %%rdx,%1     \n\t"                            \
3519      "adcq  $0,%2        \n\t"                            \
3520      :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "g"(i), "g"(j)  :"%rax","%rdx","%cc");
3521
3522 #define SQRADDSC(i, j)                                    \
3523 asm (                                                     \
3524      "movq  %6,%%rax     \n\t"                            \
3525      "mulq  %7           \n\t"                            \
3526      "movq  %%rax,%0     \n\t"                            \
3527      "movq  %%rdx,%1     \n\t"                            \
3528      "xorq  %2,%2        \n\t"                            \
3529      :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%rax","%rdx","%cc");
3530
3531 #define SQRADDAC(i, j)                                                         \
3532 asm (                                                     \
3533      "movq  %6,%%rax     \n\t"                            \
3534      "mulq  %7           \n\t"                            \
3535      "addq  %%rax,%0     \n\t"                            \
3536      "adcq  %%rdx,%1     \n\t"                            \
3537      "adcq  $0,%2        \n\t"                            \
3538      :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "g"(i), "g"(j) :"%rax","%rdx","%cc");
3539
3540 #define SQRADDDB                                                               \
3541 asm (                                                     \
3542      "addq %3,%0         \n\t"                            \
3543      "adcq %4,%1         \n\t"                            \
3544      "adcq %5,%2         \n\t"                            \
3545      "addq %3,%0         \n\t"                            \
3546      "adcq %4,%1         \n\t"                            \
3547      "adcq %5,%2         \n\t"                            \
3548      :"=r"(c0), "=r"(c1), "=r"(c2), "=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(c0), "1"(c1), "2"(c2), "3"(sc0), "4"(sc1), "5"(sc2) : "%cc");
3549
3550 #elif defined(TFM_SSE2)
3551
3552 /* SSE2 Optimized */
3553 #define COMBA_START
3554
3555 #define CLEAR_CARRY \
3556    c0 = c1 = c2 = 0;
3557
3558 #define COMBA_STORE(x) \
3559    x = c0;
3560
3561 #define COMBA_STORE2(x) \
3562    x = c1;
3563
3564 #define CARRY_FORWARD \
3565    do { c0 = c1; c1 = c2; c2 = 0; } while (0);
3566
3567 #define COMBA_FINI \
3568    asm("emms");
3569
3570 #define SQRADD(i, j)                                      \
3571 asm volatile (                                            \
3572      "movd  %6,%%mm0     \n\t"                            \
3573      "pmuludq %%mm0,%%mm0\n\t"                            \
3574      "movd  %%mm0,%%eax  \n\t"                            \
3575      "psrlq $32,%%mm0    \n\t"                            \
3576      "addl  %%eax,%0     \n\t"                            \
3577      "movd  %%mm0,%%eax  \n\t"                            \
3578      "adcl  %%eax,%1     \n\t"                            \
3579      "adcl  $0,%2        \n\t"                            \
3580      :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i) :"%eax","%cc");
3581
3582 #define SQRADD2(i, j)                                     \
3583 asm volatile (                                            \
3584      "movd  %6,%%mm0     \n\t"                            \
3585      "movd  %7,%%mm1     \n\t"                            \
3586      "pmuludq %%mm1,%%mm0\n\t"                            \
3587      "movd  %%mm0,%%eax  \n\t"                            \
3588      "psrlq $32,%%mm0    \n\t"                            \
3589      "movd  %%mm0,%%edx  \n\t"                            \
3590      "addl  %%eax,%0     \n\t"                            \
3591      "adcl  %%edx,%1     \n\t"                            \
3592      "adcl  $0,%2        \n\t"                            \
3593      "addl  %%eax,%0     \n\t"                            \
3594      "adcl  %%edx,%1     \n\t"                            \
3595      "adcl  $0,%2        \n\t"                            \
3596      :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j)  :"%eax","%edx","%cc");
3597
3598 #define SQRADDSC(i, j)                                                         \
3599 asm volatile (                                            \
3600      "movd  %6,%%mm0     \n\t"                            \
3601      "pmuludq %%mm0,%%mm0\n\t"                            \
3602      "movd  %%mm0,%%eax  \n\t"                            \
3603      "psrlq $32,%%mm0    \n\t"                            \
3604      "movl  %%eax,%0     \n\t"                            \
3605      "movd  %%mm0,%%eax  \n\t"                            \
3606      "movl  %%eax,%1     \n\t"                            \
3607      "xorl  %2,%2        \n\t"                            \
3608      :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "m"(i) :"%eax","%cc");
3609
3610 #define SQRADDAC(i, j)                                                         \
3611 asm volatile (                                            \
3612      "movd  %6,%%mm0     \n\t"                            \
3613      "movd  %7,%%mm1     \n\t"                            \
3614      "pmuludq %%mm1,%%mm0\n\t"                            \
3615      "movd  %%mm0,%%eax  \n\t"                            \
3616      "psrlq $32,%%mm0    \n\t"                            \
3617      "movd  %%mm0,%%edx  \n\t"                            \
3618      "addl  %%eax,%0     \n\t"                            \
3619      "adcl  %%edx,%1     \n\t"                            \
3620      "adcl  $0,%2        \n\t"                            \
3621      "addl  %%eax,%0     \n\t"                            \
3622      "adcl  %%edx,%1     \n\t"                            \
3623      "adcl  $0,%2        \n\t"                            \
3624      :"=r"(sc0), "=r"(sc1), "=r"(sc2): "0"(sc0), "1"(sc1), "2"(sc2), "m"(i), "m"(j)  :"%eax","%edx","%cc");
3625
3626 #define SQRADDDB                                                               \
3627 asm (                                                     \
3628      "addl %3,%0         \n\t"                            \
3629      "adcl %4,%1         \n\t"                            \
3630      "adcl %5,%2         \n\t"                            \
3631      "addl %3,%0         \n\t"                            \
3632      "adcl %4,%1         \n\t"                            \
3633      "adcl %5,%2         \n\t"                            \
3634      :"=r"(c0), "=r"(c1), "=r"(c2), "=g"(sc0), "=g"(sc1), "=g"(sc2) : "0"(c0), "1"(c1), "2"(c2), "3"(sc0), "4"(sc1), "5"(sc2) : "%cc");
3635
3636 #elif defined(TFM_ARM)
3637
3638 /* ARM code */
3639
3640 #define COMBA_START
3641
3642 #define CLEAR_CARRY \
3643    c0 = c1 = c2 = 0;
3644
3645 #define COMBA_STORE(x) \
3646    x = c0;
3647
3648 #define COMBA_STORE2(x) \
3649    x = c1;
3650
3651 #define CARRY_FORWARD \
3652    do { c0 = c1; c1 = c2; c2 = 0; } while (0);
3653
3654 #define COMBA_FINI
3655
3656 /* multiplies point i and j, updates carry "c1" and digit c2 */
3657 #define SQRADD(i, j)                                             \
3658 asm(                                                             \
3659 "  UMULL  r0,r1,%6,%6              \n\t"                         \
3660 "  ADDS   %0,%0,r0                 \n\t"                         \
3661 "  ADCS   %1,%1,r1                 \n\t"                         \
3662 "  ADC    %2,%2,#0                 \n\t"                         \
3663 :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i) : "r0", "r1", "%cc");
3664
3665 /* for squaring some of the terms are doubled... */
3666 #define SQRADD2(i, j)                                            \
3667 asm(                                                             \
3668 "  UMULL  r0,r1,%6,%7              \n\t"                         \
3669 "  ADDS   %0,%0,r0                 \n\t"                         \
3670 "  ADCS   %1,%1,r1                 \n\t"                         \
3671 "  ADC    %2,%2,#0                 \n\t"                         \
3672 "  ADDS   %0,%0,r0                 \n\t"                         \
3673 "  ADCS   %1,%1,r1                 \n\t"                         \
3674 "  ADC    %2,%2,#0                 \n\t"                         \
3675 :"=r"(c0), "=r"(c1), "=r"(c2) : "0"(c0), "1"(c1), "2"(c2), "r"(i), "r"(j) : "r0", "r1", "%cc");
3676
3677 #define SQRADDSC(i, j)                                           \
3678 asm(                                                             \
3679 "  UMULL  %0,%1,%6,%7              \n\t"                         \
3680 "  SUB    %2,%2,%2                 \n\t"                         \
3681 :"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "%cc");
3682
3683 #define SQRADDAC(i, j)                                           \
3684 asm(                                                             \
3685 "  UMULL  r0,r1,%6,%7              \n\t"                         \
3686 "  ADDS   %0,%0,r0                 \n\t"                         \
3687 "  ADCS   %1,%1,r1                 \n\t"                         \
3688 "  ADC    %2,%2,#0                 \n\t"                         \
3689 :"=r"(sc0), "=r"(sc1), "=r"(sc2) : "0"(sc0), "1"(sc1), "2"(sc2), "r"(i), "r"(j) : "r0", "r1", "%cc");
3690
3691 #define SQRADDDB                                                 \
3692 asm(                                                             \
3693 "  ADDS  %3,%0                     \n\t"                         \
3694 "  ADCS  %4,%1                     \n\t"                         \
3695 "  ADC   %5,%2                     \n\t"                         \
3696 "  ADDS  %3,%0                     \n\t"                         \
3697 "  ADCS  %4,%1                     \n\t"                         \
3698 "  ADC   %5,%2                     \n\t"                         \
3699 :"=r"(sc0), "=r"(sc1), "=r"(sc2), "=r"(c0), "=r"(c1), "=r"(c2) : "0"(sc0), "1"(sc1), "2"(sc2), "3"(c0), "4"(c1), "5"(c2) : "%cc");
3700
3701 #else
3702
3703 /* ISO C portable code */
3704
3705 #define COMBA_START \
3706    { fp_word tt;
3707
3708 #define CLEAR_CARRY \
3709    c0 = c1 = c2 = 0;
3710
3711 #define COMBA_STORE(x) \
3712    x = c0;
3713
3714 #define COMBA_STORE2(x) \
3715    x = c1;
3716
3717 #define CARRY_FORWARD \
3718    do { c0 = c1; c1 = c2; c2 = 0; } while (0);
3719
3720 #define COMBA_FINI \
3721    }
3722
3723 /* multiplies point i and j, updates carry "c1" and digit c2 */
3724 #define SQRADD(i, j)                                 \
3725    do { fp_word t;                                   \
3726    t = c0 + ((fp_word)i) * ((fp_word)j);  c0 = t;    \
3727    t = c1 + (t >> DIGIT_BIT);             c1 = t; c2 += t >> DIGIT_BIT; \
3728    } while (0);
3729
3730
3731 /* for squaring some of the terms are doubled... */
3732 #define SQRADD2(i, j)                                                 \
3733    do { fp_word t;                                                    \
3734    t  = ((fp_word)i) * ((fp_word)j);                                  \
3735    tt = (fp_word)c0 + t;                 c0 = tt;                              \
3736    tt = (fp_word)c1 + (tt >> DIGIT_BIT); c1 = tt; c2 += tt >> DIGIT_BIT;       \
3737    tt = (fp_word)c0 + t;                 c0 = tt;                              \
3738    tt = (fp_word)c1 + (tt >> DIGIT_BIT); c1 = tt; c2 += tt >> DIGIT_BIT;       \
3739    } while (0);
3740
3741 #define SQRADDSC(i, j)                                                         \
3742    do { fp_word t;                                                             \
3743       t =  ((fp_word)i) * ((fp_word)j);                                        \
3744       sc0 = (fp_digit)t; sc1 = (t >> DIGIT_BIT); sc2 = 0;                      \
3745    } while (0);
3746
3747 #define SQRADDAC(i, j)                                                         \
3748    do { fp_word t;                                                             \
3749    t = sc0 + ((fp_word)i) * ((fp_word)j);  sc0 = t;                            \
3750    t = sc1 + (t >> DIGIT_BIT);             sc1 = t; sc2 += t >> DIGIT_BIT;     \
3751    } while (0);
3752
3753 #define SQRADDDB                                                               \
3754    do { fp_word t;                                                             \
3755    t = ((fp_word)sc0) + ((fp_word)sc0) + c0; c0 = t;                                                 \
3756    t = ((fp_word)sc1) + ((fp_word)sc1) + c1 + (t >> DIGIT_BIT); c1 = t;                              \
3757    c2 = c2 + ((fp_word)sc2) + ((fp_word)sc2) + (t >> DIGIT_BIT);                                     \
3758    } while (0);
3759
3760 #endif
3761
3762 #include "fp_sqr_comba_generic.c"
3763 void fp_sqr_comba4(fp_int *A, fp_int *B)
3764 {
3765    fp_digit *a, b[8], c0, c1, c2, sc0, sc1, sc2;
3766
3767    a = A->dp;
3768    COMBA_START;
3769
3770    /* clear carries */
3771    CLEAR_CARRY;
3772
3773    /* output 0 */
3774    SQRADD(a[0],a[0]);
3775    COMBA_STORE(b[0]);
3776
3777    /* output 1 */
3778    CARRY_FORWARD;
3779    SQRADD2(a[0], a[1]);
3780    COMBA_STORE(b[1]);
3781
3782    /* output 2 */
3783    CARRY_FORWARD;
3784    SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
3785    COMBA_STORE(b[2]);
3786
3787    /* output 3 */
3788    CARRY_FORWARD;
3789    SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
3790    COMBA_STORE(b[3]);
3791
3792    /* output 4 */
3793    CARRY_FORWARD;
3794    SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
3795    COMBA_STORE(b[4]);
3796
3797    /* output 5 */
3798    CARRY_FORWARD;
3799    SQRADD2(a[2], a[3]);
3800    COMBA_STORE(b[5]);
3801
3802    /* output 6 */
3803    CARRY_FORWARD;
3804    SQRADD(a[3], a[3]);
3805    COMBA_STORE(b[6]);
3806    COMBA_STORE2(b[7]);
3807    COMBA_FINI;
3808
3809    B->used = 8;
3810    B->sign = FP_ZPOS;
3811    memcpy(B->dp, b, 8 * sizeof(fp_digit));
3812    fp_clamp(B);
3813 }
3814
3815
3816 void fp_sqr_comba8(fp_int *A, fp_int *B)
3817 {
3818    fp_digit *a, b[16], c0, c1, c2, sc0, sc1, sc2;
3819
3820    a = A->dp;
3821    COMBA_START;
3822
3823    /* clear carries */
3824    CLEAR_CARRY;
3825
3826    /* output 0 */
3827    SQRADD(a[0],a[0]);
3828    COMBA_STORE(b[0]);
3829
3830    /* output 1 */
3831    CARRY_FORWARD;
3832    SQRADD2(a[0], a[1]);
3833    COMBA_STORE(b[1]);
3834
3835    /* output 2 */
3836    CARRY_FORWARD;
3837    SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
3838    COMBA_STORE(b[2]);
3839
3840    /* output 3 */
3841    CARRY_FORWARD;
3842    SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
3843    COMBA_STORE(b[3]);
3844
3845    /* output 4 */
3846    CARRY_FORWARD;
3847    SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
3848    COMBA_STORE(b[4]);
3849
3850    /* output 5 */
3851    CARRY_FORWARD;
3852    SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
3853    COMBA_STORE(b[5]);
3854
3855    /* output 6 */
3856    CARRY_FORWARD;
3857    SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
3858    COMBA_STORE(b[6]);
3859
3860    /* output 7 */
3861    CARRY_FORWARD;
3862    SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
3863    COMBA_STORE(b[7]);
3864
3865    /* output 8 */
3866    CARRY_FORWARD;
3867    SQRADDSC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
3868    COMBA_STORE(b[8]);
3869
3870    /* output 9 */
3871    CARRY_FORWARD;
3872    SQRADDSC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
3873    COMBA_STORE(b[9]);
3874
3875    /* output 10 */
3876    CARRY_FORWARD;
3877    SQRADD2(a[3], a[7]); SQRADD2(a[4], a[6]); SQRADD(a[5], a[5]);
3878    COMBA_STORE(b[10]);
3879
3880    /* output 11 */
3881    CARRY_FORWARD;
3882    SQRADD2(a[4], a[7]); SQRADD2(a[5], a[6]);
3883    COMBA_STORE(b[11]);
3884
3885    /* output 12 */
3886    CARRY_FORWARD;
3887    SQRADD2(a[5], a[7]); SQRADD(a[6], a[6]);
3888    COMBA_STORE(b[12]);
3889
3890    /* output 13 */
3891    CARRY_FORWARD;
3892    SQRADD2(a[6], a[7]);
3893    COMBA_STORE(b[13]);
3894
3895    /* output 14 */
3896    CARRY_FORWARD;
3897    SQRADD(a[7], a[7]);
3898    COMBA_STORE(b[14]);
3899    COMBA_STORE2(b[15]);
3900    COMBA_FINI;
3901
3902    B->used = 16;
3903    B->sign = FP_ZPOS;
3904    memcpy(B->dp, b, 16 * sizeof(fp_digit));
3905    fp_clamp(B);
3906 }
3907
3908
3909 #ifdef TFM_LARGE
3910 void fp_sqr_comba16(fp_int *A, fp_int *B)
3911 {
3912    fp_digit *a, b[32], c0, c1, c2, sc0, sc1, sc2;
3913
3914    a = A->dp;
3915    COMBA_START;
3916
3917    /* clear carries */
3918    CLEAR_CARRY;
3919
3920    /* output 0 */
3921    SQRADD(a[0],a[0]);
3922    COMBA_STORE(b[0]);
3923
3924    /* output 1 */
3925    CARRY_FORWARD;
3926    SQRADD2(a[0], a[1]);
3927    COMBA_STORE(b[1]);
3928
3929    /* output 2 */
3930    CARRY_FORWARD;
3931    SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
3932    COMBA_STORE(b[2]);
3933
3934    /* output 3 */
3935    CARRY_FORWARD;
3936    SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
3937    COMBA_STORE(b[3]);
3938
3939    /* output 4 */
3940    CARRY_FORWARD;
3941    SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
3942    COMBA_STORE(b[4]);
3943
3944    /* output 5 */
3945    CARRY_FORWARD;
3946    SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
3947    COMBA_STORE(b[5]);
3948
3949    /* output 6 */
3950    CARRY_FORWARD;
3951    SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
3952    COMBA_STORE(b[6]);
3953
3954    /* output 7 */
3955    CARRY_FORWARD;
3956    SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
3957    COMBA_STORE(b[7]);
3958
3959    /* output 8 */
3960    CARRY_FORWARD;
3961    SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
3962    COMBA_STORE(b[8]);
3963
3964    /* output 9 */
3965    CARRY_FORWARD;
3966    SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
3967    COMBA_STORE(b[9]);
3968
3969    /* output 10 */
3970    CARRY_FORWARD;
3971    SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
3972    COMBA_STORE(b[10]);
3973
3974    /* output 11 */
3975    CARRY_FORWARD;
3976    SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
3977    COMBA_STORE(b[11]);
3978
3979    /* output 12 */
3980    CARRY_FORWARD;
3981    SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
3982    COMBA_STORE(b[12]);
3983
3984    /* output 13 */
3985    CARRY_FORWARD;
3986    SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
3987    COMBA_STORE(b[13]);
3988
3989    /* output 14 */
3990    CARRY_FORWARD;
3991    SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
3992    COMBA_STORE(b[14]);
3993
3994    /* output 15 */
3995    CARRY_FORWARD;
3996    SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
3997    COMBA_STORE(b[15]);
3998
3999    /* output 16 */
4000    CARRY_FORWARD;
4001    SQRADDSC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
4002    COMBA_STORE(b[16]);
4003
4004    /* output 17 */
4005    CARRY_FORWARD;
4006    SQRADDSC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
4007    COMBA_STORE(b[17]);
4008
4009    /* output 18 */
4010    CARRY_FORWARD;
4011    SQRADDSC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]);
4012    COMBA_STORE(b[18]);
4013
4014    /* output 19 */
4015    CARRY_FORWARD;
4016    SQRADDSC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB;
4017    COMBA_STORE(b[19]);
4018
4019    /* output 20 */
4020    CARRY_FORWARD;
4021    SQRADDSC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]);
4022    COMBA_STORE(b[20]);
4023
4024    /* output 21 */
4025    CARRY_FORWARD;
4026    SQRADDSC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB;
4027    COMBA_STORE(b[21]);
4028
4029    /* output 22 */
4030    CARRY_FORWARD;
4031    SQRADDSC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]);
4032    COMBA_STORE(b[22]);
4033
4034    /* output 23 */
4035    CARRY_FORWARD;
4036    SQRADDSC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB;
4037    COMBA_STORE(b[23]);
4038
4039    /* output 24 */
4040    CARRY_FORWARD;
4041    SQRADDSC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]);
4042    COMBA_STORE(b[24]);
4043
4044    /* output 25 */
4045    CARRY_FORWARD;
4046    SQRADDSC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB;
4047    COMBA_STORE(b[25]);
4048
4049    /* output 26 */
4050    CARRY_FORWARD;
4051    SQRADD2(a[11], a[15]); SQRADD2(a[12], a[14]); SQRADD(a[13], a[13]);
4052    COMBA_STORE(b[26]);
4053
4054    /* output 27 */
4055    CARRY_FORWARD;
4056    SQRADD2(a[12], a[15]); SQRADD2(a[13], a[14]);
4057    COMBA_STORE(b[27]);
4058
4059    /* output 28 */
4060    CARRY_FORWARD;
4061    SQRADD2(a[13], a[15]); SQRADD(a[14], a[14]);
4062    COMBA_STORE(b[28]);
4063
4064    /* output 29 */
4065    CARRY_FORWARD;
4066    SQRADD2(a[14], a[15]);
4067    COMBA_STORE(b[29]);
4068
4069    /* output 30 */
4070    CARRY_FORWARD;
4071    SQRADD(a[15], a[15]);
4072    COMBA_STORE(b[30]);
4073    COMBA_STORE2(b[31]);
4074    COMBA_FINI;
4075
4076    B->used = 32;
4077    B->sign = FP_ZPOS;
4078    memcpy(B->dp, b, 32 * sizeof(fp_digit));
4079    fp_clamp(B);
4080 }
4081
4082
4083 #endif
4084 #ifdef TFM_HUGE
4085 void fp_sqr_comba32(fp_int *A, fp_int *B)
4086 {
4087    fp_digit *a, b[64], c0, c1, c2, sc0, sc1, sc2;
4088
4089    a = A->dp;
4090    COMBA_START;
4091
4092    /* clear carries */
4093    CLEAR_CARRY;
4094
4095    /* output 0 */
4096    SQRADD(a[0],a[0]);
4097    COMBA_STORE(b[0]);
4098
4099    /* output 1 */
4100    CARRY_FORWARD;
4101    SQRADD2(a[0], a[1]);
4102    COMBA_STORE(b[1]);
4103
4104    /* output 2 */
4105    CARRY_FORWARD;
4106    SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
4107    COMBA_STORE(b[2]);
4108
4109    /* output 3 */
4110    CARRY_FORWARD;
4111    SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
4112    COMBA_STORE(b[3]);
4113
4114    /* output 4 */
4115    CARRY_FORWARD;
4116    SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
4117    COMBA_STORE(b[4]);
4118
4119    /* output 5 */
4120    CARRY_FORWARD;
4121    SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
4122    COMBA_STORE(b[5]);
4123
4124    /* output 6 */
4125    CARRY_FORWARD;
4126    SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
4127    COMBA_STORE(b[6]);
4128
4129    /* output 7 */
4130    CARRY_FORWARD;
4131    SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
4132    COMBA_STORE(b[7]);
4133
4134    /* output 8 */
4135    CARRY_FORWARD;
4136    SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
4137    COMBA_STORE(b[8]);
4138
4139    /* output 9 */
4140    CARRY_FORWARD;
4141    SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
4142    COMBA_STORE(b[9]);
4143
4144    /* output 10 */
4145    CARRY_FORWARD;
4146    SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
4147    COMBA_STORE(b[10]);
4148
4149    /* output 11 */
4150    CARRY_FORWARD;
4151    SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
4152    COMBA_STORE(b[11]);
4153
4154    /* output 12 */
4155    CARRY_FORWARD;
4156    SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
4157    COMBA_STORE(b[12]);
4158
4159    /* output 13 */
4160    CARRY_FORWARD;
4161    SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
4162    COMBA_STORE(b[13]);
4163
4164    /* output 14 */
4165    CARRY_FORWARD;
4166    SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
4167    COMBA_STORE(b[14]);
4168
4169    /* output 15 */
4170    CARRY_FORWARD;
4171    SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
4172    COMBA_STORE(b[15]);
4173
4174    /* output 16 */
4175    CARRY_FORWARD;
4176    SQRADDSC(a[0], a[16]); SQRADDAC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
4177    COMBA_STORE(b[16]);
4178
4179    /* output 17 */
4180    CARRY_FORWARD;
4181    SQRADDSC(a[0], a[17]); SQRADDAC(a[1], a[16]); SQRADDAC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
4182    COMBA_STORE(b[17]);
4183
4184    /* output 18 */
4185    CARRY_FORWARD;
4186    SQRADDSC(a[0], a[18]); SQRADDAC(a[1], a[17]); SQRADDAC(a[2], a[16]); SQRADDAC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]);
4187    COMBA_STORE(b[18]);
4188
4189    /* output 19 */
4190    CARRY_FORWARD;
4191    SQRADDSC(a[0], a[19]); SQRADDAC(a[1], a[18]); SQRADDAC(a[2], a[17]); SQRADDAC(a[3], a[16]); SQRADDAC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB;
4192    COMBA_STORE(b[19]);
4193
4194    /* output 20 */
4195    CARRY_FORWARD;
4196    SQRADDSC(a[0], a[20]); SQRADDAC(a[1], a[19]); SQRADDAC(a[2], a[18]); SQRADDAC(a[3], a[17]); SQRADDAC(a[4], a[16]); SQRADDAC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]);
4197    COMBA_STORE(b[20]);
4198
4199    /* output 21 */
4200    CARRY_FORWARD;
4201    SQRADDSC(a[0], a[21]); SQRADDAC(a[1], a[20]); SQRADDAC(a[2], a[19]); SQRADDAC(a[3], a[18]); SQRADDAC(a[4], a[17]); SQRADDAC(a[5], a[16]); SQRADDAC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB;
4202    COMBA_STORE(b[21]);
4203
4204    /* output 22 */
4205    CARRY_FORWARD;
4206    SQRADDSC(a[0], a[22]); SQRADDAC(a[1], a[21]); SQRADDAC(a[2], a[20]); SQRADDAC(a[3], a[19]); SQRADDAC(a[4], a[18]); SQRADDAC(a[5], a[17]); SQRADDAC(a[6], a[16]); SQRADDAC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]);
4207    COMBA_STORE(b[22]);
4208
4209    /* output 23 */
4210    CARRY_FORWARD;
4211    SQRADDSC(a[0], a[23]); SQRADDAC(a[1], a[22]); SQRADDAC(a[2], a[21]); SQRADDAC(a[3], a[20]); SQRADDAC(a[4], a[19]); SQRADDAC(a[5], a[18]); SQRADDAC(a[6], a[17]); SQRADDAC(a[7], a[16]); SQRADDAC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB;
4212    COMBA_STORE(b[23]);
4213
4214    /* output 24 */
4215    CARRY_FORWARD;
4216    SQRADDSC(a[0], a[24]); SQRADDAC(a[1], a[23]); SQRADDAC(a[2], a[22]); SQRADDAC(a[3], a[21]); SQRADDAC(a[4], a[20]); SQRADDAC(a[5], a[19]); SQRADDAC(a[6], a[18]); SQRADDAC(a[7], a[17]); SQRADDAC(a[8], a[16]); SQRADDAC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]);
4217    COMBA_STORE(b[24]);
4218
4219    /* output 25 */
4220    CARRY_FORWARD;
4221    SQRADDSC(a[0], a[25]); SQRADDAC(a[1], a[24]); SQRADDAC(a[2], a[23]); SQRADDAC(a[3], a[22]); SQRADDAC(a[4], a[21]); SQRADDAC(a[5], a[20]); SQRADDAC(a[6], a[19]); SQRADDAC(a[7], a[18]); SQRADDAC(a[8], a[17]); SQRADDAC(a[9], a[16]); SQRADDAC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB;
4222    COMBA_STORE(b[25]);
4223
4224    /* output 26 */
4225    CARRY_FORWARD;
4226    SQRADDSC(a[0], a[26]); SQRADDAC(a[1], a[25]); SQRADDAC(a[2], a[24]); SQRADDAC(a[3], a[23]); SQRADDAC(a[4], a[22]); SQRADDAC(a[5], a[21]); SQRADDAC(a[6], a[20]); SQRADDAC(a[7], a[19]); SQRADDAC(a[8], a[18]); SQRADDAC(a[9], a[17]); SQRADDAC(a[10], a[16]); SQRADDAC(a[11], a[15]); SQRADDAC(a[12], a[14]); SQRADDDB; SQRADD(a[13], a[13]);
4227    COMBA_STORE(b[26]);
4228
4229    /* output 27 */
4230    CARRY_FORWARD;
4231    SQRADDSC(a[0], a[27]); SQRADDAC(a[1], a[26]); SQRADDAC(a[2], a[25]); SQRADDAC(a[3], a[24]); SQRADDAC(a[4], a[23]); SQRADDAC(a[5], a[22]); SQRADDAC(a[6], a[21]); SQRADDAC(a[7], a[20]); SQRADDAC(a[8], a[19]); SQRADDAC(a[9], a[18]); SQRADDAC(a[10], a[17]); SQRADDAC(a[11], a[16]); SQRADDAC(a[12], a[15]); SQRADDAC(a[13], a[14]); SQRADDDB;
4232    COMBA_STORE(b[27]);
4233
4234    /* output 28 */
4235    CARRY_FORWARD;
4236    SQRADDSC(a[0], a[28]); SQRADDAC(a[1], a[27]); SQRADDAC(a[2], a[26]); SQRADDAC(a[3], a[25]); SQRADDAC(a[4], a[24]); SQRADDAC(a[5], a[23]); SQRADDAC(a[6], a[22]); SQRADDAC(a[7], a[21]); SQRADDAC(a[8], a[20]); SQRADDAC(a[9], a[19]); SQRADDAC(a[10], a[18]); SQRADDAC(a[11], a[17]); SQRADDAC(a[12], a[16]); SQRADDAC(a[13], a[15]); SQRADDDB; SQRADD(a[14], a[14]);
4237    COMBA_STORE(b[28]);
4238
4239    /* output 29 */
4240    CARRY_FORWARD;
4241    SQRADDSC(a[0], a[29]); SQRADDAC(a[1], a[28]); SQRADDAC(a[2], a[27]); SQRADDAC(a[3], a[26]); SQRADDAC(a[4], a[25]); SQRADDAC(a[5], a[24]); SQRADDAC(a[6], a[23]); SQRADDAC(a[7], a[22]); SQRADDAC(a[8], a[21]); SQRADDAC(a[9], a[20]); SQRADDAC(a[10], a[19]); SQRADDAC(a[11], a[18]); SQRADDAC(a[12], a[17]); SQRADDAC(a[13], a[16]); SQRADDAC(a[14], a[15]); SQRADDDB;
4242    COMBA_STORE(b[29]);
4243
4244    /* output 30 */
4245    CARRY_FORWARD;
4246    SQRADDSC(a[0], a[30]); SQRADDAC(a[1], a[29]); SQRADDAC(a[2], a[28]); SQRADDAC(a[3], a[27]); SQRADDAC(a[4], a[26]); SQRADDAC(a[5], a[25]); SQRADDAC(a[6], a[24]); SQRADDAC(a[7], a[23]); SQRADDAC(a[8], a[22]); SQRADDAC(a[9], a[21]); SQRADDAC(a[10], a[20]); SQRADDAC(a[11], a[19]); SQRADDAC(a[12], a[18]); SQRADDAC(a[13], a[17]); SQRADDAC(a[14], a[16]); SQRADDDB; SQRADD(a[15], a[15]);
4247    COMBA_STORE(b[30]);
4248
4249    /* output 31 */
4250    CARRY_FORWARD;
4251    SQRADDSC(a[0], a[31]); SQRADDAC(a[1], a[30]); SQRADDAC(a[2], a[29]); SQRADDAC(a[3], a[28]); SQRADDAC(a[4], a[27]); SQRADDAC(a[5], a[26]); SQRADDAC(a[6], a[25]); SQRADDAC(a[7], a[24]); SQRADDAC(a[8], a[23]); SQRADDAC(a[9], a[22]); SQRADDAC(a[10], a[21]); SQRADDAC(a[11], a[20]); SQRADDAC(a[12], a[19]); SQRADDAC(a[13], a[18]); SQRADDAC(a[14], a[17]); SQRADDAC(a[15], a[16]); SQRADDDB;
4252    COMBA_STORE(b[31]);
4253
4254    /* output 32 */
4255    CARRY_FORWARD;
4256    SQRADDSC(a[1], a[31]); SQRADDAC(a[2], a[30]); SQRADDAC(a[3], a[29]); SQRADDAC(a[4], a[28]); SQRADDAC(a[5], a[27]); SQRADDAC(a[6], a[26]); SQRADDAC(a[7], a[25]); SQRADDAC(a[8], a[24]); SQRADDAC(a[9], a[23]); SQRADDAC(a[10], a[22]); SQRADDAC(a[11], a[21]); SQRADDAC(a[12], a[20]); SQRADDAC(a[13], a[19]); SQRADDAC(a[14], a[18]); SQRADDAC(a[15], a[17]); SQRADDDB; SQRADD(a[16], a[16]);
4257    COMBA_STORE(b[32]);
4258
4259    /* output 33 */
4260    CARRY_FORWARD;
4261    SQRADDSC(a[2], a[31]); SQRADDAC(a[3], a[30]); SQRADDAC(a[4], a[29]); SQRADDAC(a[5], a[28]); SQRADDAC(a[6], a[27]); SQRADDAC(a[7], a[26]); SQRADDAC(a[8], a[25]); SQRADDAC(a[9], a[24]); SQRADDAC(a[10], a[23]); SQRADDAC(a[11], a[22]); SQRADDAC(a[12], a[21]); SQRADDAC(a[13], a[20]); SQRADDAC(a[14], a[19]); SQRADDAC(a[15], a[18]); SQRADDAC(a[16], a[17]); SQRADDDB;
4262    COMBA_STORE(b[33]);
4263
4264    /* output 34 */
4265    CARRY_FORWARD;
4266    SQRADDSC(a[3], a[31]); SQRADDAC(a[4], a[30]); SQRADDAC(a[5], a[29]); SQRADDAC(a[6], a[28]); SQRADDAC(a[7], a[27]); SQRADDAC(a[8], a[26]); SQRADDAC(a[9], a[25]); SQRADDAC(a[10], a[24]); SQRADDAC(a[11], a[23]); SQRADDAC(a[12], a[22]); SQRADDAC(a[13], a[21]); SQRADDAC(a[14], a[20]); SQRADDAC(a[15], a[19]); SQRADDAC(a[16], a[18]); SQRADDDB; SQRADD(a[17], a[17]);
4267    COMBA_STORE(b[34]);
4268
4269    /* output 35 */
4270    CARRY_FORWARD;
4271    SQRADDSC(a[4], a[31]); SQRADDAC(a[5], a[30]); SQRADDAC(a[6], a[29]); SQRADDAC(a[7], a[28]); SQRADDAC(a[8], a[27]); SQRADDAC(a[9], a[26]); SQRADDAC(a[10], a[25]); SQRADDAC(a[11], a[24]); SQRADDAC(a[12], a[23]); SQRADDAC(a[13], a[22]); SQRADDAC(a[14], a[21]); SQRADDAC(a[15], a[20]); SQRADDAC(a[16], a[19]); SQRADDAC(a[17], a[18]); SQRADDDB;
4272    COMBA_STORE(b[35]);
4273
4274    /* output 36 */
4275    CARRY_FORWARD;
4276    SQRADDSC(a[5], a[31]); SQRADDAC(a[6], a[30]); SQRADDAC(a[7], a[29]); SQRADDAC(a[8], a[28]); SQRADDAC(a[9], a[27]); SQRADDAC(a[10], a[26]); SQRADDAC(a[11], a[25]); SQRADDAC(a[12], a[24]); SQRADDAC(a[13], a[23]); SQRADDAC(a[14], a[22]); SQRADDAC(a[15], a[21]); SQRADDAC(a[16], a[20]); SQRADDAC(a[17], a[19]); SQRADDDB; SQRADD(a[18], a[18]);
4277    COMBA_STORE(b[36]);
4278
4279    /* output 37 */
4280    CARRY_FORWARD;
4281    SQRADDSC(a[6], a[31]); SQRADDAC(a[7], a[30]); SQRADDAC(a[8], a[29]); SQRADDAC(a[9], a[28]); SQRADDAC(a[10], a[27]); SQRADDAC(a[11], a[26]); SQRADDAC(a[12], a[25]); SQRADDAC(a[13], a[24]); SQRADDAC(a[14], a[23]); SQRADDAC(a[15], a[22]); SQRADDAC(a[16], a[21]); SQRADDAC(a[17], a[20]); SQRADDAC(a[18], a[19]); SQRADDDB;
4282    COMBA_STORE(b[37]);
4283
4284    /* output 38 */
4285    CARRY_FORWARD;
4286    SQRADDSC(a[7], a[31]); SQRADDAC(a[8], a[30]); SQRADDAC(a[9], a[29]); SQRADDAC(a[10], a[28]); SQRADDAC(a[11], a[27]); SQRADDAC(a[12], a[26]); SQRADDAC(a[13], a[25]); SQRADDAC(a[14], a[24]); SQRADDAC(a[15], a[23]); SQRADDAC(a[16], a[22]); SQRADDAC(a[17], a[21]); SQRADDAC(a[18], a[20]); SQRADDDB; SQRADD(a[19], a[19]);
4287    COMBA_STORE(b[38]);
4288
4289    /* output 39 */
4290    CARRY_FORWARD;
4291    SQRADDSC(a[8], a[31]); SQRADDAC(a[9], a[30]); SQRADDAC(a[10], a[29]); SQRADDAC(a[11], a[28]); SQRADDAC(a[12], a[27]); SQRADDAC(a[13], a[26]); SQRADDAC(a[14], a[25]); SQRADDAC(a[15], a[24]); SQRADDAC(a[16], a[23]); SQRADDAC(a[17], a[22]); SQRADDAC(a[18], a[21]); SQRADDAC(a[19], a[20]); SQRADDDB;
4292    COMBA_STORE(b[39]);
4293
4294    /* output 40 */
4295    CARRY_FORWARD;
4296    SQRADDSC(a[9], a[31]); SQRADDAC(a[10], a[30]); SQRADDAC(a[11], a[29]); SQRADDAC(a[12], a[28]); SQRADDAC(a[13], a[27]); SQRADDAC(a[14], a[26]); SQRADDAC(a[15], a[25]); SQRADDAC(a[16], a[24]); SQRADDAC(a[17], a[23]); SQRADDAC(a[18], a[22]); SQRADDAC(a[19], a[21]); SQRADDDB; SQRADD(a[20], a[20]);
4297    COMBA_STORE(b[40]);
4298
4299    /* output 41 */
4300    CARRY_FORWARD;
4301    SQRADDSC(a[10], a[31]); SQRADDAC(a[11], a[30]); SQRADDAC(a[12], a[29]); SQRADDAC(a[13], a[28]); SQRADDAC(a[14], a[27]); SQRADDAC(a[15], a[26]); SQRADDAC(a[16], a[25]); SQRADDAC(a[17], a[24]); SQRADDAC(a[18], a[23]); SQRADDAC(a[19], a[22]); SQRADDAC(a[20], a[21]); SQRADDDB;
4302    COMBA_STORE(b[41]);
4303
4304    /* output 42 */
4305    CARRY_FORWARD;
4306    SQRADDSC(a[11], a[31]); SQRADDAC(a[12], a[30]); SQRADDAC(a[13], a[29]); SQRADDAC(a[14], a[28]); SQRADDAC(a[15], a[27]); SQRADDAC(a[16], a[26]); SQRADDAC(a[17], a[25]); SQRADDAC(a[18], a[24]); SQRADDAC(a[19], a[23]); SQRADDAC(a[20], a[22]); SQRADDDB; SQRADD(a[21], a[21]);
4307    COMBA_STORE(b[42]);
4308
4309    /* output 43 */
4310    CARRY_FORWARD;
4311    SQRADDSC(a[12], a[31]); SQRADDAC(a[13], a[30]); SQRADDAC(a[14], a[29]); SQRADDAC(a[15], a[28]); SQRADDAC(a[16], a[27]); SQRADDAC(a[17], a[26]); SQRADDAC(a[18], a[25]); SQRADDAC(a[19], a[24]); SQRADDAC(a[20], a[23]); SQRADDAC(a[21], a[22]); SQRADDDB;
4312    COMBA_STORE(b[43]);
4313
4314    /* output 44 */
4315    CARRY_FORWARD;
4316    SQRADDSC(a[13], a[31]); SQRADDAC(a[14], a[30]); SQRADDAC(a[15], a[29]); SQRADDAC(a[16], a[28]); SQRADDAC(a[17], a[27]); SQRADDAC(a[18], a[26]); SQRADDAC(a[19], a[25]); SQRADDAC(a[20], a[24]); SQRADDAC(a[21], a[23]); SQRADDDB; SQRADD(a[22], a[22]);
4317    COMBA_STORE(b[44]);
4318
4319    /* output 45 */
4320    CARRY_FORWARD;
4321    SQRADDSC(a[14], a[31]); SQRADDAC(a[15], a[30]); SQRADDAC(a[16], a[29]); SQRADDAC(a[17], a[28]); SQRADDAC(a[18], a[27]); SQRADDAC(a[19], a[26]); SQRADDAC(a[20], a[25]); SQRADDAC(a[21], a[24]); SQRADDAC(a[22], a[23]); SQRADDDB;
4322    COMBA_STORE(b[45]);
4323
4324    /* output 46 */
4325    CARRY_FORWARD;
4326    SQRADDSC(a[15], a[31]); SQRADDAC(a[16], a[30]); SQRADDAC(a[17], a[29]); SQRADDAC(a[18], a[28]); SQRADDAC(a[19], a[27]); SQRADDAC(a[20], a[26]); SQRADDAC(a[21], a[25]); SQRADDAC(a[22], a[24]); SQRADDDB; SQRADD(a[23], a[23]);
4327    COMBA_STORE(b[46]);
4328
4329    /* output 47 */
4330    CARRY_FORWARD;
4331    SQRADDSC(a[16], a[31]); SQRADDAC(a[17], a[30]); SQRADDAC(a[18], a[29]); SQRADDAC(a[19], a[28]); SQRADDAC(a[20], a[27]); SQRADDAC(a[21], a[26]); SQRADDAC(a[22], a[25]); SQRADDAC(a[23], a[24]); SQRADDDB;
4332    COMBA_STORE(b[47]);
4333
4334    /* output 48 */
4335    CARRY_FORWARD;
4336    SQRADDSC(a[17], a[31]); SQRADDAC(a[18], a[30]); SQRADDAC(a[19], a[29]); SQRADDAC(a[20], a[28]); SQRADDAC(a[21], a[27]); SQRADDAC(a[22], a[26]); SQRADDAC(a[23], a[25]); SQRADDDB; SQRADD(a[24], a[24]);
4337    COMBA_STORE(b[48]);
4338
4339    /* output 49 */
4340    CARRY_FORWARD;
4341    SQRADDSC(a[18], a[31]); SQRADDAC(a[19], a[30]); SQRADDAC(a[20], a[29]); SQRADDAC(a[21], a[28]); SQRADDAC(a[22], a[27]); SQRADDAC(a[23], a[26]); SQRADDAC(a[24], a[25]); SQRADDDB;
4342    COMBA_STORE(b[49]);
4343
4344    /* output 50 */
4345    CARRY_FORWARD;
4346    SQRADDSC(a[19], a[31]); SQRADDAC(a[20], a[30]); SQRADDAC(a[21], a[29]); SQRADDAC(a[22], a[28]); SQRADDAC(a[23], a[27]); SQRADDAC(a[24], a[26]); SQRADDDB; SQRADD(a[25], a[25]);
4347    COMBA_STORE(b[50]);
4348
4349    /* output 51 */
4350    CARRY_FORWARD;
4351    SQRADDSC(a[20], a[31]); SQRADDAC(a[21], a[30]); SQRADDAC(a[22], a[29]); SQRADDAC(a[23], a[28]); SQRADDAC(a[24], a[27]); SQRADDAC(a[25], a[26]); SQRADDDB;
4352    COMBA_STORE(b[51]);
4353
4354    /* output 52 */
4355    CARRY_FORWARD;
4356    SQRADDSC(a[21], a[31]); SQRADDAC(a[22], a[30]); SQRADDAC(a[23], a[29]); SQRADDAC(a[24], a[28]); SQRADDAC(a[25], a[27]); SQRADDDB; SQRADD(a[26], a[26]);
4357    COMBA_STORE(b[52]);
4358
4359    /* output 53 */
4360    CARRY_FORWARD;
4361    SQRADDSC(a[22], a[31]); SQRADDAC(a[23], a[30]); SQRADDAC(a[24], a[29]); SQRADDAC(a[25], a[28]); SQRADDAC(a[26], a[27]); SQRADDDB;
4362    COMBA_STORE(b[53]);
4363
4364    /* output 54 */
4365    CARRY_FORWARD;
4366    SQRADDSC(a[23], a[31]); SQRADDAC(a[24], a[30]); SQRADDAC(a[25], a[29]); SQRADDAC(a[26], a[28]); SQRADDDB; SQRADD(a[27], a[27]);
4367    COMBA_STORE(b[54]);
4368
4369    /* output 55 */
4370    CARRY_FORWARD;
4371    SQRADDSC(a[24], a[31]); SQRADDAC(a[25], a[30]); SQRADDAC(a[26], a[29]); SQRADDAC(a[27], a[28]); SQRADDDB;
4372    COMBA_STORE(b[55]);
4373
4374    /* output 56 */
4375    CARRY_FORWARD;
4376    SQRADDSC(a[25], a[31]); SQRADDAC(a[26], a[30]); SQRADDAC(a[27], a[29]); SQRADDDB; SQRADD(a[28], a[28]);
4377    COMBA_STORE(b[56]);
4378
4379    /* output 57 */
4380    CARRY_FORWARD;
4381    SQRADDSC(a[26], a[31]); SQRADDAC(a[27], a[30]); SQRADDAC(a[28], a[29]); SQRADDDB;
4382    COMBA_STORE(b[57]);
4383
4384    /* output 58 */
4385    CARRY_FORWARD;
4386    SQRADD2(a[27], a[31]); SQRADD2(a[28], a[30]); SQRADD(a[29], a[29]);
4387    COMBA_STORE(b[58]);
4388
4389    /* output 59 */
4390    CARRY_FORWARD;
4391    SQRADD2(a[28], a[31]); SQRADD2(a[29], a[30]);
4392    COMBA_STORE(b[59]);
4393
4394    /* output 60 */
4395    CARRY_FORWARD;
4396    SQRADD2(a[29], a[31]); SQRADD(a[30], a[30]);
4397    COMBA_STORE(b[60]);
4398
4399    /* output 61 */
4400    CARRY_FORWARD;
4401    SQRADD2(a[30], a[31]);
4402    COMBA_STORE(b[61]);
4403
4404    /* output 62 */
4405    CARRY_FORWARD;
4406    SQRADD(a[31], a[31]);
4407    COMBA_STORE(b[62]);
4408    COMBA_STORE2(b[63]);
4409    COMBA_FINI;
4410
4411    B->used = 64;
4412    B->sign = FP_ZPOS;
4413    memcpy(B->dp, b, 64 * sizeof(fp_digit));
4414    fp_clamp(B);
4415 }
4416
4417
4418 #endif
4419
4420 #ifdef TFM_HUGE
4421 void fp_sqr_comba64(fp_int *A, fp_int *B)
4422 {
4423    fp_digit *a, b[128], c0, c1, c2, sc0, sc1, sc2;
4424
4425    a = A->dp;
4426    COMBA_START;
4427
4428    /* clear carries */
4429    CLEAR_CARRY;
4430
4431    /* output 0 */
4432    SQRADD(a[0],a[0]);
4433    COMBA_STORE(b[0]);
4434
4435    /* output 1 */
4436    CARRY_FORWARD;
4437    SQRADD2(a[0], a[1]);
4438    COMBA_STORE(b[1]);
4439
4440    /* output 2 */
4441    CARRY_FORWARD;
4442    SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]);
4443    COMBA_STORE(b[2]);
4444
4445    /* output 3 */
4446    CARRY_FORWARD;
4447    SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]);
4448    COMBA_STORE(b[3]);
4449
4450    /* output 4 */
4451    CARRY_FORWARD;
4452    SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]);
4453    COMBA_STORE(b[4]);
4454
4455    /* output 5 */
4456    CARRY_FORWARD;
4457    SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB;
4458    COMBA_STORE(b[5]);
4459
4460    /* output 6 */
4461    CARRY_FORWARD;
4462    SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]);
4463    COMBA_STORE(b[6]);
4464
4465    /* output 7 */
4466    CARRY_FORWARD;
4467    SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB;
4468    COMBA_STORE(b[7]);
4469
4470    /* output 8 */
4471    CARRY_FORWARD;
4472    SQRADDSC(a[0], a[8]); SQRADDAC(a[1], a[7]); SQRADDAC(a[2], a[6]); SQRADDAC(a[3], a[5]); SQRADDDB; SQRADD(a[4], a[4]);
4473    COMBA_STORE(b[8]);
4474
4475    /* output 9 */
4476    CARRY_FORWARD;
4477    SQRADDSC(a[0], a[9]); SQRADDAC(a[1], a[8]); SQRADDAC(a[2], a[7]); SQRADDAC(a[3], a[6]); SQRADDAC(a[4], a[5]); SQRADDDB;
4478    COMBA_STORE(b[9]);
4479
4480    /* output 10 */
4481    CARRY_FORWARD;
4482    SQRADDSC(a[0], a[10]); SQRADDAC(a[1], a[9]); SQRADDAC(a[2], a[8]); SQRADDAC(a[3], a[7]); SQRADDAC(a[4], a[6]); SQRADDDB; SQRADD(a[5], a[5]);
4483    COMBA_STORE(b[10]);
4484
4485    /* output 11 */
4486    CARRY_FORWARD;
4487    SQRADDSC(a[0], a[11]); SQRADDAC(a[1], a[10]); SQRADDAC(a[2], a[9]); SQRADDAC(a[3], a[8]); SQRADDAC(a[4], a[7]); SQRADDAC(a[5], a[6]); SQRADDDB;
4488    COMBA_STORE(b[11]);
4489
4490    /* output 12 */
4491    CARRY_FORWARD;
4492    SQRADDSC(a[0], a[12]); SQRADDAC(a[1], a[11]); SQRADDAC(a[2], a[10]); SQRADDAC(a[3], a[9]); SQRADDAC(a[4], a[8]); SQRADDAC(a[5], a[7]); SQRADDDB; SQRADD(a[6], a[6]);
4493    COMBA_STORE(b[12]);
4494
4495    /* output 13 */
4496    CARRY_FORWARD;
4497    SQRADDSC(a[0], a[13]); SQRADDAC(a[1], a[12]); SQRADDAC(a[2], a[11]); SQRADDAC(a[3], a[10]); SQRADDAC(a[4], a[9]); SQRADDAC(a[5], a[8]); SQRADDAC(a[6], a[7]); SQRADDDB;
4498    COMBA_STORE(b[13]);
4499
4500    /* output 14 */
4501    CARRY_FORWARD;
4502    SQRADDSC(a[0], a[14]); SQRADDAC(a[1], a[13]); SQRADDAC(a[2], a[12]); SQRADDAC(a[3], a[11]); SQRADDAC(a[4], a[10]); SQRADDAC(a[5], a[9]); SQRADDAC(a[6], a[8]); SQRADDDB; SQRADD(a[7], a[7]);
4503    COMBA_STORE(b[14]);
4504
4505    /* output 15 */
4506    CARRY_FORWARD;
4507    SQRADDSC(a[0], a[15]); SQRADDAC(a[1], a[14]); SQRADDAC(a[2], a[13]); SQRADDAC(a[3], a[12]); SQRADDAC(a[4], a[11]); SQRADDAC(a[5], a[10]); SQRADDAC(a[6], a[9]); SQRADDAC(a[7], a[8]); SQRADDDB;
4508    COMBA_STORE(b[15]);
4509
4510    /* output 16 */
4511    CARRY_FORWARD;
4512    SQRADDSC(a[0], a[16]); SQRADDAC(a[1], a[15]); SQRADDAC(a[2], a[14]); SQRADDAC(a[3], a[13]); SQRADDAC(a[4], a[12]); SQRADDAC(a[5], a[11]); SQRADDAC(a[6], a[10]); SQRADDAC(a[7], a[9]); SQRADDDB; SQRADD(a[8], a[8]);
4513    COMBA_STORE(b[16]);
4514
4515    /* output 17 */
4516    CARRY_FORWARD;
4517    SQRADDSC(a[0], a[17]); SQRADDAC(a[1], a[16]); SQRADDAC(a[2], a[15]); SQRADDAC(a[3], a[14]); SQRADDAC(a[4], a[13]); SQRADDAC(a[5], a[12]); SQRADDAC(a[6], a[11]); SQRADDAC(a[7], a[10]); SQRADDAC(a[8], a[9]); SQRADDDB;
4518    COMBA_STORE(b[17]);
4519
4520    /* output 18 */
4521    CARRY_FORWARD;
4522    SQRADDSC(a[0], a[18]); SQRADDAC(a[1], a[17]); SQRADDAC(a[2], a[16]); SQRADDAC(a[3], a[15]); SQRADDAC(a[4], a[14]); SQRADDAC(a[5], a[13]); SQRADDAC(a[6], a[12]); SQRADDAC(a[7], a[11]); SQRADDAC(a[8], a[10]); SQRADDDB; SQRADD(a[9], a[9]);
4523    COMBA_STORE(b[18]);
4524
4525    /* output 19 */
4526    CARRY_FORWARD;
4527    SQRADDSC(a[0], a[19]); SQRADDAC(a[1], a[18]); SQRADDAC(a[2], a[17]); SQRADDAC(a[3], a[16]); SQRADDAC(a[4], a[15]); SQRADDAC(a[5], a[14]); SQRADDAC(a[6], a[13]); SQRADDAC(a[7], a[12]); SQRADDAC(a[8], a[11]); SQRADDAC(a[9], a[10]); SQRADDDB;
4528    COMBA_STORE(b[19]);
4529
4530    /* output 20 */
4531    CARRY_FORWARD;
4532    SQRADDSC(a[0], a[20]); SQRADDAC(a[1], a[19]); SQRADDAC(a[2], a[18]); SQRADDAC(a[3], a[17]); SQRADDAC(a[4], a[16]); SQRADDAC(a[5], a[15]); SQRADDAC(a[6], a[14]); SQRADDAC(a[7], a[13]); SQRADDAC(a[8], a[12]); SQRADDAC(a[9], a[11]); SQRADDDB; SQRADD(a[10], a[10]);
4533    COMBA_STORE(b[20]);
4534
4535    /* output 21 */
4536    CARRY_FORWARD;
4537    SQRADDSC(a[0], a[21]); SQRADDAC(a[1], a[20]); SQRADDAC(a[2], a[19]); SQRADDAC(a[3], a[18]); SQRADDAC(a[4], a[17]); SQRADDAC(a[5], a[16]); SQRADDAC(a[6], a[15]); SQRADDAC(a[7], a[14]); SQRADDAC(a[8], a[13]); SQRADDAC(a[9], a[12]); SQRADDAC(a[10], a[11]); SQRADDDB;
4538    COMBA_STORE(b[21]);
4539
4540    /* output 22 */
4541    CARRY_FORWARD;
4542    SQRADDSC(a[0], a[22]); SQRADDAC(a[1], a[21]); SQRADDAC(a[2], a[20]); SQRADDAC(a[3], a[19]); SQRADDAC(a[4], a[18]); SQRADDAC(a[5], a[17]); SQRADDAC(a[6], a[16]); SQRADDAC(a[7], a[15]); SQRADDAC(a[8], a[14]); SQRADDAC(a[9], a[13]); SQRADDAC(a[10], a[12]); SQRADDDB; SQRADD(a[11], a[11]);
4543    COMBA_STORE(b[22]);
4544
4545    /* output 23 */
4546    CARRY_FORWARD;
4547    SQRADDSC(a[0], a[23]); SQRADDAC(a[1], a[22]); SQRADDAC(a[2], a[21]); SQRADDAC(a[3], a[20]); SQRADDAC(a[4], a[19]); SQRADDAC(a[5], a[18]); SQRADDAC(a[6], a[17]); SQRADDAC(a[7], a[16]); SQRADDAC(a[8], a[15]); SQRADDAC(a[9], a[14]); SQRADDAC(a[10], a[13]); SQRADDAC(a[11], a[12]); SQRADDDB;
4548    COMBA_STORE(b[23]);
4549
4550    /* output 24 */
4551    CARRY_FORWARD;
4552    SQRADDSC(a[0], a[24]); SQRADDAC(a[1], a[23]); SQRADDAC(a[2], a[22]); SQRADDAC(a[3], a[21]); SQRADDAC(a[4], a[20]); SQRADDAC(a[5], a[19]); SQRADDAC(a[6], a[18]); SQRADDAC(a[7], a[17]); SQRADDAC(a[8], a[16]); SQRADDAC(a[9], a[15]); SQRADDAC(a[10], a[14]); SQRADDAC(a[11], a[13]); SQRADDDB; SQRADD(a[12], a[12]);
4553    COMBA_STORE(b[24]);
4554
4555    /* output 25 */
4556    CARRY_FORWARD;
4557    SQRADDSC(a[0], a[25]); SQRADDAC(a[1], a[24]); SQRADDAC(a[2], a[23]); SQRADDAC(a[3], a[22]); SQRADDAC(a[4], a[21]); SQRADDAC(a[5], a[20]); SQRADDAC(a[6], a[19]); SQRADDAC(a[7], a[18]); SQRADDAC(a[8], a[17]); SQRADDAC(a[9], a[16]); SQRADDAC(a[10], a[15]); SQRADDAC(a[11], a[14]); SQRADDAC(a[12], a[13]); SQRADDDB;
4558    COMBA_STORE(b[25]);
4559
4560    /* output 26 */
4561    CARRY_FORWARD;
4562    SQRADDSC(a[0], a[26]); SQRADDAC(a[1], a[25]); SQRADDAC(a[2], a[24]); SQRADDAC(a[3], a[23]); SQRADDAC(a[4], a[22]); SQRADDAC(a[5], a[21]); SQRADDAC(a[6], a[20]); SQRADDAC(a[7], a[19]); SQRADDAC(a[8], a[18]); SQRADDAC(a[9], a[17]); SQRADDAC(a[10], a[16]); SQRADDAC(a[11], a[15]); SQRADDAC(a[12], a[14]); SQRADDDB; SQRADD(a[13], a[13]);
4563    COMBA_STORE(b[26]);
4564
4565    /* output 27 */
4566    CARRY_FORWARD;
4567    SQRADDSC(a[0], a[27]); SQRADDAC(a[1], a[26]); SQRADDAC(a[2], a[25]); SQRADDAC(a[3], a[24]); SQRADDAC(a[4], a[23]); SQRADDAC(a[5], a[22]); SQRADDAC(a[6], a[21]); SQRADDAC(a[7], a[20]); SQRADDAC(a[8], a[19]); SQRADDAC(a[9], a[18]); SQRADDAC(a[10], a[17]); SQRADDAC(a[11], a[16]); SQRADDAC(a[12], a[15]); SQRADDAC(a[13], a[14]); SQRADDDB;
4568    COMBA_STORE(b[27]);
4569
4570    /* output 28 */
4571    CARRY_FORWARD;
4572    SQRADDSC(a[0], a[28]); SQRADDAC(a[1], a[27]); SQRADDAC(a[2], a[26]); SQRADDAC(a[3], a[25]); SQRADDAC(a[4], a[24]); SQRADDAC(a[5], a[23]); SQRADDAC(a[6], a[22]); SQRADDAC(a[7], a[21]); SQRADDAC(a[8], a[20]); SQRADDAC(a[9], a[19]); SQRADDAC(a[10], a[18]); SQRADDAC(a[11], a[17]); SQRADDAC(a[12], a[16]); SQRADDAC(a[13], a[15]); SQRADDDB; SQRADD(a[14], a[14]);
4573    COMBA_STORE(b[28]);
4574
4575    /* output 29 */
4576    CARRY_FORWARD;
4577    SQRADDSC(a[0], a[29]); SQRADDAC(a[1], a[28]); SQRADDAC(a[2], a[27]); SQRADDAC(a[3], a[26]); SQRADDAC(a[4], a[25]); SQRADDAC(a[5], a[24]); SQRADDAC(a[6], a[23]); SQRADDAC(a[7], a[22]); SQRADDAC(a[8], a[21]); SQRADDAC(a[9], a[20]); SQRADDAC(a[10], a[19]); SQRADDAC(a[11], a[18]); SQRADDAC(a[12], a[17]); SQRADDAC(a[13], a[16]); SQRADDAC(a[14], a[15]); SQRADDDB;
4578    COMBA_STORE(b[29]);
4579
4580    /* output 30 */
4581    CARRY_FORWARD;
4582    SQRADDSC(a[0], a[30]); SQRADDAC(a[1], a[29]); SQRADDAC(a[2], a[28]); SQRADDAC(a[3], a[27]); SQRADDAC(a[4], a[26]); SQRADDAC(a[5], a[25]); SQRADDAC(a[6], a[24]); SQRADDAC(a[7], a[23]); SQRADDAC(a[8], a[22]); SQRADDAC(a[9], a[21]); SQRADDAC(a[10], a[20]); SQRADDAC(a[11], a[19]); SQRADDAC(a[12], a[18]); SQRADDAC(a[13], a[17]); SQRADDAC(a[14], a[16]); SQRADDDB; SQRADD(a[15], a[15]);
4583    COMBA_STORE(b[30]);
4584
4585    /* output 31 */
4586    CARRY_FORWARD;
4587    SQRADDSC(a[0], a[31]); SQRADDAC(a[1], a[30]); SQRADDAC(a[2], a[29]); SQRADDAC(a[3], a[28]); SQRADDAC(a[4], a[27]); SQRADDAC(a[5], a[26]); SQRADDAC(a[6], a[25]); SQRADDAC(a[7], a[24]); SQRADDAC(a[8], a[23]); SQRADDAC(a[9], a[22]); SQRADDAC(a[10], a[21]); SQRADDAC(a[11], a[20]); SQRADDAC(a[12], a[19]); SQRADDAC(a[13], a[18]); SQRADDAC(a[14], a[17]); SQRADDAC(a[15], a[16]); SQRADDDB;
4588    COMBA_STORE(b[31]);
4589
4590    /* output 32 */
4591    CARRY_FORWARD;
4592    SQRADDSC(a[0], a[32]); SQRADDAC(a[1], a[31]); SQRADDAC(a[2], a[30]); SQRADDAC(a[3], a[29]); SQRADDAC(a[4], a[28]); SQRADDAC(a[5], a[27]); SQRADDAC(a[6], a[26]); SQRADDAC(a[7], a[25]); SQRADDAC(a[8], a[24]); SQRADDAC(a[9], a[23]); SQRADDAC(a[10], a[22]); SQRADDAC(a[11], a[21]); SQRADDAC(a[12], a[20]); SQRADDAC(a[13], a[19]); SQRADDAC(a[14], a[18]); SQRADDAC(a[15], a[17]); SQRADDDB; SQRADD(a[16], a[16]);
4593    COMBA_STORE(b[32]);
4594
4595    /* output 33 */
4596    CARRY_FORWARD;
4597    SQRADDSC(a[0], a[33]); SQRADDAC(a[1], a[32]); SQRADDAC(a[2], a[31]); SQRADDAC(a[3], a[30]); SQRADDAC(a[4], a[29]); SQRADDAC(a[5], a[28]); SQRADDAC(a[6], a[27]); SQRADDAC(a[7], a[26]); SQRADDAC(a[8], a[25]); SQRADDAC(a[9], a[24]); SQRADDAC(a[10], a[23]); SQRADDAC(a[11], a[22]); SQRADDAC(a[12], a[21]); SQRADDAC(a[13], a[20]); SQRADDAC(a[14], a[19]); SQRADDAC(a[15], a[18]); SQRADDAC(a[16], a[17]); SQRADDDB;
4598    COMBA_STORE(b[33]);
4599
4600    /* output 34 */
4601    CARRY_FORWARD;
4602    SQRADDSC(a[0], a[34]); SQRADDAC(a[1], a[33]); SQRADDAC(a[2], a[32]); SQRADDAC(a[3], a[31]); SQRADDAC(a[4], a[30]); SQRADDAC(a[5], a[29]); SQRADDAC(a[6], a[28]); SQRADDAC(a[7], a[27]); SQRADDAC(a[8], a[26]); SQRADDAC(a[9], a[25]); SQRADDAC(a[10], a[24]); SQRADDAC(a[11], a[23]); SQRADDAC(a[12], a[22]); SQRADDAC(a[13], a[21]); SQRADDAC(a[14], a[20]); SQRADDAC(a[15], a[19]); SQRADDAC(a[16], a[18]); SQRADDDB; SQRADD(a[17], a[17]);
4603    COMBA_STORE(b[34]);
4604
4605    /* output 35 */
4606    CARRY_FORWARD;
4607    SQRADDSC(a[0], a[35]); SQRADDAC(a[1], a[34]); SQRADDAC(a[2], a[33]); SQRADDAC(a[3], a[32]); SQRADDAC(a[4], a[31]); SQRADDAC(a[5], a[30]); SQRADDAC(a[6], a[29]); SQRADDAC(a[7], a[28]); SQRADDAC(a[8], a[27]); SQRADDAC(a[9], a[26]); SQRADDAC(a[10], a[25]); SQRADDAC(a[11], a[24]); SQRADDAC(a[12], a[23]); SQRADDAC(a[13], a[22]); SQRADDAC(a[14], a[21]); SQRADDAC(a[15], a[20]); SQRADDAC(a[16], a[19]); SQRADDAC(a[17], a[18]); SQRADDDB;
4608    COMBA_STORE(b[35]);
4609
4610    /* output 36 */
4611    CARRY_FORWARD;
4612    SQRADDSC(a[0], a[36]); SQRADDAC(a[1], a[35]); SQRADDAC(a[2], a[34]); SQRADDAC(a[3], a[33]); SQRADDAC(a[4], a[32]); SQRADDAC(a[5], a[31]); SQRADDAC(a[6], a[30]); SQRADDAC(a[7], a[29]); SQRADDAC(a[8], a[28]); SQRADDAC(a[9], a[27]); SQRADDAC(a[10], a[26]); SQRADDAC(a[11], a[25]); SQRADDAC(a[12], a[24]); SQRADDAC(a[13], a[23]); SQRADDAC(a[14], a[22]); SQRADDAC(a[15], a[21]); SQRADDAC(a[16], a[20]); SQRADDAC(a[17], a[19]); SQRADDDB; SQRADD(a[18], a[18]);
4613    COMBA_STORE(b[36]);
4614
4615    /* output 37 */
4616    CARRY_FORWARD;
4617    SQRADDSC(a[0], a[37]); SQRADDAC(a[1], a[36]); SQRADDAC(a[2], a[35]); SQRADDAC(a[3], a[34]); SQRADDAC(a[4], a[33]); SQRADDAC(a[5], a[32]); SQRADDAC(a[6], a[31]); SQRADDAC(a[7], a[30]); SQRADDAC(a[8], a[29]); SQRADDAC(a[9], a[28]); SQRADDAC(a[10], a[27]); SQRADDAC(a[11], a[26]); SQRADDAC(a[12], a[25]); SQRADDAC(a[13], a[24]); SQRADDAC(a[14], a[23]); SQRADDAC(a[15], a[22]); SQRADDAC(a[16], a[21]); SQRADDAC(a[17], a[20]); SQRADDAC(a[18], a[19]); SQRADDDB;
4618    COMBA_STORE(b[37]);
4619
4620    /* output 38 */
4621    CARRY_FORWARD;
4622    SQRADDSC(a[0], a[38]); SQRADDAC(a[1], a[37]); SQRADDAC(a[2], a[36]); SQRADDAC(a[3], a[35]); SQRADDAC(a[4], a[34]); SQRADDAC(a[5], a[33]); SQRADDAC(a[6], a[32]); SQRADDAC(a[7], a[31]); SQRADDAC(a[8], a[30]); SQRADDAC(a[9], a[29]); SQRADDAC(a[10], a[28]); SQRADDAC(a[11], a[27]); SQRADDAC(a[12], a[26]); SQRADDAC(a[13], a[25]); SQRADDAC(a[14], a[24]); SQRADDAC(a[15], a[23]); SQRADDAC(a[16], a[22]); SQRADDAC(a[17], a[21]); SQRADDAC(a[18], a[20]); SQRADDDB; SQRADD(a[19], a[19]);
4623    COMBA_STORE(b[38]);
4624
4625    /* output 39 */
4626    CARRY_FORWARD;
4627    SQRADDSC(a[0], a[39]); SQRADDAC(a[1], a[38]); SQRADDAC(a[2], a[37]); SQRADDAC(a[3], a[36]); SQRADDAC(a[4], a[35]); SQRADDAC(a[5], a[34]); SQRADDAC(a[6], a[33]); SQRADDAC(a[7], a[32]); SQRADDAC(a[8], a[31]); SQRADDAC(a[9], a[30]); SQRADDAC(a[10], a[29]); SQRADDAC(a[11], a[28]); SQRADDAC(a[12], a[27]); SQRADDAC(a[13], a[26]); SQRADDAC(a[14], a[25]); SQRADDAC(a[15], a[24]); SQRADDAC(a[16], a[23]); SQRADDAC(a[17], a[22]); SQRADDAC(a[18], a[21]); SQRADDAC(a[19], a[20]); SQRADDDB;
4628    COMBA_STORE(b[39]);
4629
4630    /* output 40 */
4631    CARRY_FORWARD;
4632    SQRADDSC(a[0], a[40]); SQRADDAC(a[1], a[39]); SQRADDAC(a[2], a[38]); SQRADDAC(a[3], a[37]); SQRADDAC(a[4], a[36]); SQRADDAC(a[5], a[35]); SQRADDAC(a[6], a[34]); SQRADDAC(a[7], a[33]); SQRADDAC(a[8], a[32]); SQRADDAC(a[9], a[31]); SQRADDAC(a[10], a[30]); SQRADDAC(a[11], a[29]); SQRADDAC(a[12], a[28]); SQRADDAC(a[13], a[27]); SQRADDAC(a[14], a[26]); SQRADDAC(a[15], a[25]); SQRADDAC(a[16], a[24]); SQRADDAC(a[17], a[23]); SQRADDAC(a[18], a[22]); SQRADDAC(a[19], a[21]); SQRADDDB; SQRADD(a[20], a[20]);
4633    COMBA_STORE(b[40]);
4634
4635    /* output 41 */
4636    CARRY_FORWARD;
4637    SQRADDSC(a[0], a[41]); SQRADDAC(a[1], a[40]); SQRADDAC(a[2], a[39]); SQRADDAC(a[3], a[38]); SQRADDAC(a[4], a[37]); SQRADDAC(a[5], a[36]); SQRADDAC(a[6], a[35]); SQRADDAC(a[7], a[34]); SQRADDAC(a[8], a[33]); SQRADDAC(a[9], a[32]); SQRADDAC(a[10], a[31]); SQRADDAC(a[11], a[30]); SQRADDAC(a[12], a[29]); SQRADDAC(a[13], a[28]); SQRADDAC(a[14], a[27]); SQRADDAC(a[15], a[26]); SQRADDAC(a[16], a[25]); SQRADDAC(a[17], a[24]); SQRADDAC(a[18], a[23]); SQRADDAC(a[19], a[22]); SQRADDAC(a[20], a[21]); SQRADDDB;
4638    COMBA_STORE(b[41]);
4639
4640    /* output 42 */
4641    CARRY_FORWARD;
4642    SQRADDSC(a[0], a[42]); SQRADDAC(a[1], a[41]); SQRADDAC(a[2], a[40]); SQRADDAC(a[3], a[39]); SQRADDAC(a[4], a[38]); SQRADDAC(a[5], a[37]); SQRADDAC(a[6], a[36]); SQRADDAC(a[7], a[35]); SQRADDAC(a[8], a[34]); SQRADDAC(a[9], a[33]); SQRADDAC(a[10], a[32]); SQRADDAC(a[11], a[31]); SQRADDAC(a[12], a[30]); SQRADDAC(a[13], a[29]); SQRADDAC(a[14], a[28]); SQRADDAC(a[15], a[27]); SQRADDAC(a[16], a[26]); SQRADDAC(a[17], a[25]); SQRADDAC(a[18], a[24]); SQRADDAC(a[19], a[23]); SQRADDAC(a[20], a[22]); SQRADDDB; SQRADD(a[21], a[21]);
4643    COMBA_STORE(b[42]);
4644
4645    /* output 43 */
4646    CARRY_FORWARD;
4647    SQRADDSC(a[0], a[43]); SQRADDAC(a[1], a[42]); SQRADDAC(a[2], a[41]); SQRADDAC(a[3], a[40]); SQRADDAC(a[4], a[39]); SQRADDAC(a[5], a[38]); SQRADDAC(a[6], a[37]); SQRADDAC(a[7], a[36]); SQRADDAC(a[8], a[35]); SQRADDAC(a[9], a[34]); SQRADDAC(a[10], a[33]); SQRADDAC(a[11], a[32]); SQRADDAC(a[12], a[31]); SQRADDAC(a[13], a[30]); SQRADDAC(a[14], a[29]); SQRADDAC(a[15], a[28]); SQRADDAC(a[16], a[27]); SQRADDAC(a[17], a[26]); SQRADDAC(a[18], a[25]); SQRADDAC(a[19], a[24]); SQRADDAC(a[20], a[23]); SQRADDAC(a[21], a[22]); SQRADDDB;
4648    COMBA_STORE(b[43]);
4649
4650    /* output 44 */
4651    CARRY_FORWARD;
4652    SQRADDSC(a[0], a[44]); SQRADDAC(a[1], a[43]); SQRADDAC(a[2], a[42]); SQRADDAC(a[3], a[41]); SQRADDAC(a[4], a[40]); SQRADDAC(a[5], a[39]); SQRADDAC(a[6], a[38]); SQRADDAC(a[7], a[37]); SQRADDAC(a[8], a[36]); SQRADDAC(a[9], a[35]); SQRADDAC(a[10], a[34]); SQRADDAC(a[11], a[33]); SQRADDAC(a[12], a[32]); SQRADDAC(a[13], a[31]); SQRADDAC(a[14], a[30]); SQRADDAC(a[15], a[29]); SQRADDAC(a[16], a[28]); SQRADDAC(a[17], a[27]); SQRADDAC(a[18], a[26]); SQRADDAC(a[19], a[25]); SQRADDAC(a[20], a[24]); SQRADDAC(a[21], a[23]); SQRADDDB; SQRADD(a[22], a[22]);
4653    COMBA_STORE(b[44]);
4654
4655    /* output 45 */
4656    CARRY_FORWARD;
4657    SQRADDSC(a[0], a[45]); SQRADDAC(a[1], a[44]); SQRADDAC(a[2], a[43]); SQRADDAC(a[3], a[42]); SQRADDAC(a[4], a[41]); SQRADDAC(a[5], a[40]); SQRADDAC(a[6], a[39]); SQRADDAC(a[7], a[38]); SQRADDAC(a[8], a[37]); SQRADDAC(a[9], a[36]); SQRADDAC(a[10], a[35]); SQRADDAC(a[11], a[34]); SQRADDAC(a[12], a[33]); SQRADDAC(a[13], a[32]); SQRADDAC(a[14], a[31]); SQRADDAC(a[15], a[30]); SQRADDAC(a[16], a[29]); SQRADDAC(a[17], a[28]); SQRADDAC(a[18], a[27]); SQRADDAC(a[19], a[26]); SQRADDAC(a[20], a[25]); SQRADDAC(a[21], a[24]); SQRADDAC(a[22], a[23]); SQRADDDB;
4658    COMBA_STORE(b[45]);
4659
4660    /* output 46 */
4661    CARRY_FORWARD;
4662    SQRADDSC(a[0], a[46]); SQRADDAC(a[1], a[45]); SQRADDAC(a[2], a[44]); SQRADDAC(a[3], a[43]); SQRADDAC(a[4], a[42]); SQRADDAC(a[5], a[41]); SQRADDAC(a[6], a[40]); SQRADDAC(a[7], a[39]); SQRADDAC(a[8], a[38]); SQRADDAC(a[9], a[37]); SQRADDAC(a[10], a[36]); SQRADDAC(a[11], a[35]); SQRADDAC(a[12], a[34]); SQRADDAC(a[13], a[33]); SQRADDAC(a[14], a[32]); SQRADDAC(a[15], a[31]); SQRADDAC(a[16], a[30]); SQRADDAC(a[17], a[29]); SQRADDAC(a[18], a[28]); SQRADDAC(a[19], a[27]); SQRADDAC(a[20], a[26]); SQRADDAC(a[21], a[25]); SQRADDAC(a[22], a[24]); SQRADDDB; SQRADD(a[23], a[23]);
4663    COMBA_STORE(b[46]);
4664
4665    /* output 47 */
4666    CARRY_FORWARD;
4667    SQRADDSC(a[0], a[47]); SQRADDAC(a[1], a[46]); SQRADDAC(a[2], a[45]); SQRADDAC(a[3], a[44]); SQRADDAC(a[4], a[43]); SQRADDAC(a[5], a[42]); SQRADDAC(a[6], a[41]); SQRADDAC(a[7], a[40]); SQRADDAC(a[8], a[39]); SQRADDAC(a[9], a[38]); SQRADDAC(a[10], a[37]); SQRADDAC(a[11], a[36]); SQRADDAC(a[12], a[35]); SQRADDAC(a[13], a[34]); SQRADDAC(a[14], a[33]); SQRADDAC(a[15], a[32]); SQRADDAC(a[16], a[31]); SQRADDAC(a[17], a[30]); SQRADDAC(a[18], a[29]); SQRADDAC(a[19], a[28]); SQRADDAC(a[20], a[27]); SQRADDAC(a[21], a[26]); SQRADDAC(a[22], a[25]); SQRADDAC(a[23], a[24]); SQRADDDB;
4668    COMBA_STORE(b[47]);
4669
4670    /* output 48 */
4671    CARRY_FORWARD;
4672    SQRADDSC(a[0], a[48]); SQRADDAC(a[1], a[47]); SQRADDAC(a[2], a[46]); SQRADDAC(a[3], a[45]); SQRADDAC(a[4], a[44]); SQRADDAC(a[5], a[43]); SQRADDAC(a[6], a[42]); SQRADDAC(a[7], a[41]); SQRADDAC(a[8], a[40]); SQRADDAC(a[9], a[39]); SQRADDAC(a[10], a[38]); SQRADDAC(a[11], a[37]); SQRADDAC(a[12], a[36]); SQRADDAC(a[13], a[35]); SQRADDAC(a[14], a[34]); SQRADDAC(a[15], a[33]); SQRADDAC(a[16], a[32]); SQRADDAC(a[17], a[31]); SQRADDAC(a[18], a[30]); SQRADDAC(a[19], a[29]); SQRADDAC(a[20], a[28]); SQRADDAC(a[21], a[27]); SQRADDAC(a[22], a[26]); SQRADDAC(a[23], a[25]); SQRADDDB; SQRADD(a[24], a[24]);
4673    COMBA_STORE(b[48]);
4674
4675    /* output 49 */
4676    CARRY_FORWARD;
4677    SQRADDSC(a[0], a[49]); SQRADDAC(a[1], a[48]); SQRADDAC(a[2], a[47]); SQRADDAC(a[3], a[46]); SQRADDAC(a[4], a[45]); SQRADDAC(a[5], a[44]); SQRADDAC(a[6], a[43]); SQRADDAC(a[7], a[42]); SQRADDAC(a[8], a[41]); SQRADDAC(a[9], a[40]); SQRADDAC(a[10], a[39]); SQRADDAC(a[11], a[38]); SQRADDAC(a[12], a[37]); SQRADDAC(a[13], a[36]); SQRADDAC(a[14], a[35]); SQRADDAC(a[15], a[34]); SQRADDAC(a[16], a[33]); SQRADDAC(a[17], a[32]); SQRADDAC(a[18], a[31]); SQRADDAC(a[19], a[30]); SQRADDAC(a[20], a[29]); SQRADDAC(a[21], a[28]); SQRADDAC(a[22], a[27]); SQRADDAC(a[23], a[26]); SQRADDAC(a[24], a[25]); SQRADDDB;
4678    COMBA_STORE(b[49]);
4679
4680    /* output 50 */
4681    CARRY_FORWARD;
4682    SQRADDSC(a[0], a[50]); SQRADDAC(a[1], a[49]); SQRADDAC(a[2], a[48]); SQRADDAC(a[3], a[47]); SQRADDAC(a[4], a[46]); SQRADDAC(a[5], a[45]); SQRADDAC(a[6], a[44]); SQRADDAC(a[7], a[43]); SQRADDAC(a[8], a[42]); SQRADDAC(a[9], a[41]); SQRADDAC(a[10], a[40]); SQRADDAC(a[11], a[39]); SQRADDAC(a[12], a[38]); SQRADDAC(a[13], a[37]); SQRADDAC(a[14], a[36]); SQRADDAC(a[15], a[35]); SQRADDAC(a[16], a[34]); SQRADDAC(a[17], a[33]); SQRADDAC(a[18], a[32]); SQRADDAC(a[19], a[31]); SQRADDAC(a[20], a[30]); SQRADDAC(a[21], a[29]); SQRADDAC(a[22], a[28]); SQRADDAC(a[23], a[27]); SQRADDAC(a[24], a[26]); SQRADDDB; SQRADD(a[25], a[25]);
4683    COMBA_STORE(b[50]);
4684
4685    /* output 51 */
4686    CARRY_FORWARD;
4687    SQRADDSC(a[0], a[51]); SQRADDAC(a[1], a[50]); SQRADDAC(a[2], a[49]); SQRADDAC(a[3], a[48]); SQRADDAC(a[4], a[47]); SQRADDAC(a[5], a[46]); SQRADDAC(a[6], a[45]); SQRADDAC(a[7], a[44]); SQRADDAC(a[8], a[43]); SQRADDAC(a[9], a[42]); SQRADDAC(a[10], a[41]); SQRADDAC(a[11], a[40]); SQRADDAC(a[12], a[39]); SQRADDAC(a[13], a[38]); SQRADDAC(a[14], a[37]); SQRADDAC(a[15], a[36]); SQRADDAC(a[16], a[35]); SQRADDAC(a[17], a[34]); SQRADDAC(a[18], a[33]); SQRADDAC(a[19], a[32]); SQRADDAC(a[20], a[31]); SQRADDAC(a[21], a[30]); SQRADDAC(a[22], a[29]); SQRADDAC(a[23], a[28]); SQRADDAC(a[24], a[27]); SQRADDAC(a[25], a[26]); SQRADDDB;
4688    COMBA_STORE(b[51]);
4689
4690    /* output 52 */
4691    CARRY_FORWARD;
4692    SQRADDSC(a[0], a[52]); SQRADDAC(a[1], a[51]); SQRADDAC(a[2], a[50]); SQRADDAC(a[3], a[49]); SQRADDAC(a[4], a[48]); SQRADDAC(a[5], a[47]); SQRADDAC(a[6], a[46]); SQRADDAC(a[7], a[45]); SQRADDAC(a[8], a[44]); SQRADDAC(a[9], a[43]); SQRADDAC(a[10], a[42]); SQRADDAC(a[11], a[41]); SQRADDAC(a[12], a[40]); SQRADDAC(a[13], a[39]); SQRADDAC(a[14], a[38]); SQRADDAC(a[15], a[37]); SQRADDAC(a[16], a[36]); SQRADDAC(a[17], a[35]); SQRADDAC(a[18], a[34]); SQRADDAC(a[19], a[33]); SQRADDAC(a[20], a[32]); SQRADDAC(a[21], a[31]); SQRADDAC(a[22], a[30]); SQRADDAC(a[23], a[29]); SQRADDAC(a[24], a[28]); SQRADDAC(a[25], a[27]); SQRADDDB; SQRADD(a[26], a[26]);
4693    COMBA_STORE(b[52]);
4694
4695    /* output 53 */
4696    CARRY_FORWARD;
4697    SQRADDSC(a[0], a[53]); SQRADDAC(a[1], a[52]); SQRADDAC(a[2], a[51]); SQRADDAC(a[3], a[50]); SQRADDAC(a[4], a[49]); SQRADDAC(a[5], a[48]); SQRADDAC(a[6], a[47]); SQRADDAC(a[7], a[46]); SQRADDAC(a[8], a[45]); SQRADDAC(a[9], a[44]); SQRADDAC(a[10], a[43]); SQRADDAC(a[11], a[42]); SQRADDAC(a[12], a[41]); SQRADDAC(a[13], a[40]); SQRADDAC(a[14], a[39]); SQRADDAC(a[15], a[38]); SQRADDAC(a[16], a[37]); SQRADDAC(a[17], a[36]); SQRADDAC(a[18], a[35]); SQRADDAC(a[19], a[34]); SQRADDAC(a[20], a[33]); SQRADDAC(a[21], a[32]); SQRADDAC(a[22], a[31]); SQRADDAC(a[23], a[30]); SQRADDAC(a[24], a[29]); SQRADDAC(a[25], a[28]); SQRADDAC(a[26], a[27]); SQRADDDB;
4698    COMBA_STORE(b[53]);
4699
4700    /* output 54 */
4701    CARRY_FORWARD;
4702    SQRADDSC(a[0], a[54]); SQRADDAC(a[1], a[53]); SQRADDAC(a[2], a[52]); SQRADDAC(a[3], a[51]); SQRADDAC(a[4], a[50]); SQRADDAC(a[5], a[49]); SQRADDAC(a[6], a[48]); SQRADDAC(a[7], a[47]); SQRADDAC(a[8], a[46]); SQRADDAC(a[9], a[45]); SQRADDAC(a[10], a[44]); SQRADDAC(a[11], a[43]); SQRADDAC(a[12], a[42]); SQRADDAC(a[13], a[41]); SQRADDAC(a[14], a[40]); SQRADDAC(a[15], a[39]); SQRADDAC(a[16], a[38]); SQRADDAC(a[17], a[37]); SQRADDAC(a[18], a[36]); SQRADDAC(a[19], a[35]); SQRADDAC(a[20], a[34]); SQRADDAC(a[21], a[33]); SQRADDAC(a[22], a[32]); SQRADDAC(a[23], a[31]); SQRADDAC(a[24], a[30]); SQRADDAC(a[25], a[29]); SQRADDAC(a[26], a[28]); SQRADDDB; SQRADD(a[27], a[27]);
4703    COMBA_STORE(b[54]);
4704
4705    /* output 55 */
4706    CARRY_FORWARD;
4707    SQRADDSC(a[0], a[55]); SQRADDAC(a[1], a[54]); SQRADDAC(a[2], a[53]); SQRADDAC(a[3], a[52]); SQRADDAC(a[4], a[51]); SQRADDAC(a[5], a[50]); SQRADDAC(a[6], a[49]); SQRADDAC(a[7], a[48]); SQRADDAC(a[8], a[47]); SQRADDAC(a[9], a[46]); SQRADDAC(a[10], a[45]); SQRADDAC(a[11], a[44]); SQRADDAC(a[12], a[43]); SQRADDAC(a[13], a[42]); SQRADDAC(a[14], a[41]); SQRADDAC(a[15], a[40]); SQRADDAC(a[16], a[39]); SQRADDAC(a[17], a[38]); SQRADDAC(a[18], a[37]); SQRADDAC(a[19], a[36]); SQRADDAC(a[20], a[35]); SQRADDAC(a[21], a[34]); SQRADDAC(a[22], a[33]); SQRADDAC(a[23], a[32]); SQRADDAC(a[24], a[31]); SQRADDAC(a[25], a[30]); SQRADDAC(a[26], a[29]); SQRADDAC(a[27], a[28]); SQRADDDB;
4708    COMBA_STORE(b[55]);
4709
4710    /* output 56 */
4711    CARRY_FORWARD;
4712    SQRADDSC(a[0], a[56]); SQRADDAC(a[1], a[55]); SQRADDAC(a[2], a[54]); SQRADDAC(a[3], a[53]); SQRADDAC(a[4], a[52]); SQRADDAC(a[5], a[51]); SQRADDAC(a[6], a[50]); SQRADDAC(a[7], a[49]); SQRADDAC(a[8], a[48]); SQRADDAC(a[9], a[47]); SQRADDAC(a[10], a[46]); SQRADDAC(a[11], a[45]); SQRADDAC(a[12], a[44]); SQRADDAC(a[13], a[43]); SQRADDAC(a[14], a[42]); SQRADDAC(a[15], a[41]); SQRADDAC(a[16], a[40]); SQRADDAC(a[17], a[39]); SQRADDAC(a[18], a[38]); SQRADDAC(a[19], a[37]); SQRADDAC(a[20], a[36]); SQRADDAC(a[21], a[35]); SQRADDAC(a[22], a[34]); SQRADDAC(a[23], a[33]); SQRADDAC(a[24], a[32]); SQRADDAC(a[25], a[31]); SQRADDAC(a[26], a[30]); SQRADDAC(a[27], a[29]); SQRADDDB; SQRADD(a[28], a[28]);
4713    COMBA_STORE(b[56]);
4714
4715    /* output 57 */
4716    CARRY_FORWARD;
4717    SQRADDSC(a[0], a[57]); SQRADDAC(a[1], a[56]); SQRADDAC(a[2], a[55]); SQRADDAC(a[3], a[54]); SQRADDAC(a[4], a[53]); SQRADDAC(a[5], a[52]); SQRADDAC(a[6], a[51]); SQRADDAC(a[7], a[50]); SQRADDAC(a[8], a[49]); SQRADDAC(a[9], a[48]); SQRADDAC(a[10], a[47]); SQRADDAC(a[11], a[46]); SQRADDAC(a[12], a[45]); SQRADDAC(a[13], a[44]); SQRADDAC(a[14], a[43]); SQRADDAC(a[15], a[42]); SQRADDAC(a[16], a[41]); SQRADDAC(a[17], a[40]); SQRADDAC(a[18], a[39]); SQRADDAC(a[19], a[38]); SQRADDAC(a[20], a[37]); SQRADDAC(a[21], a[36]); SQRADDAC(a[22], a[35]); SQRADDAC(a[23], a[34]); SQRADDAC(a[24], a[33]); SQRADDAC(a[25], a[32]); SQRADDAC(a[26], a[31]); SQRADDAC(a[27], a[30]); SQRADDAC(a[28], a[29]); SQRADDDB;
4718    COMBA_STORE(b[57]);
4719
4720    /* output 58 */
4721    CARRY_FORWARD;
4722    SQRADDSC(a[0], a[58]); SQRADDAC(a[1], a[57]); SQRADDAC(a[2], a[56]); SQRADDAC(a[3], a[55]); SQRADDAC(a[4], a[54]); SQRADDAC(a[5], a[53]); SQRADDAC(a[6], a[52]); SQRADDAC(a[7], a[51]); SQRADDAC(a[8], a[50]); SQRADDAC(a[9], a[49]); SQRADDAC(a[10], a[48]); SQRADDAC(a[11], a[47]); SQRADDAC(a[12], a[46]); SQRADDAC(a[13], a[45]); SQRADDAC(a[14], a[44]); SQRADDAC(a[15], a[43]); SQRADDAC(a[16], a[42]); SQRADDAC(a[17], a[41]); SQRADDAC(a[18], a[40]); SQRADDAC(a[19], a[39]); SQRADDAC(a[20], a[38]); SQRADDAC(a[21], a[37]); SQRADDAC(a[22], a[36]); SQRADDAC(a[23], a[35]); SQRADDAC(a[24], a[34]); SQRADDAC(a[25], a[33]); SQRADDAC(a[26], a[32]); SQRADDAC(a[27], a[31]); SQRADDAC(a[28], a[30]); SQRADDDB; SQRADD(a[29], a[29]);
4723    COMBA_STORE(b[58]);
4724
4725    /* output 59 */
4726    CARRY_FORWARD;
4727    SQRADDSC(a[0], a[59]); SQRADDAC(a[1], a[58]); SQRADDAC(a[2], a[57]); SQRADDAC(a[3], a[56]); SQRADDAC(a[4], a[55]); SQRADDAC(a[5], a[54]); SQRADDAC(a[6], a[53]); SQRADDAC(a[7], a[52]); SQRADDAC(a[8], a[51]); SQRADDAC(a[9], a[50]); SQRADDAC(a[10], a[49]); SQRADDAC(a[11], a[48]); SQRADDAC(a[12], a[47]); SQRADDAC(a[13], a[46]); SQRADDAC(a[14], a[45]); SQRADDAC(a[15], a[44]); SQRADDAC(a[16], a[43]); SQRADDAC(a[17], a[42]); SQRADDAC(a[18], a[41]); SQRADDAC(a[19], a[40]); SQRADDAC(a[20], a[39]); SQRADDAC(a[21], a[38]); SQRADDAC(a[22], a[37]); SQRADDAC(a[23], a[36]); SQRADDAC(a[24], a[35]); SQRADDAC(a[25], a[34]); SQRADDAC(a[26], a[33]); SQRADDAC(a[27], a[32]); SQRADDAC(a[28], a[31]); SQRADDAC(a[29], a[30]); SQRADDDB;
4728    COMBA_STORE(b[59]);
4729
4730    /* output 60 */
4731    CARRY_FORWARD;
4732    SQRADDSC(a[0], a[60]); SQRADDAC(a[1], a[59]); SQRADDAC(a[2], a[58]); SQRADDAC(a[3], a[57]); SQRADDAC(a[4], a[56]); SQRADDAC(a[5], a[55]); SQRADDAC(a[6], a[54]); SQRADDAC(a[7], a[53]); SQRADDAC(a[8], a[52]); SQRADDAC(a[9], a[51]); SQRADDAC(a[10], a[50]); SQRADDAC(a[11], a[49]); SQRADDAC(a[12], a[48]); SQRADDAC(a[13], a[47]); SQRADDAC(a[14], a[46]); SQRADDAC(a[15], a[45]); SQRADDAC(a[16], a[44]); SQRADDAC(a[17], a[43]); SQRADDAC(a[18], a[42]); SQRADDAC(a[19], a[41]); SQRADDAC(a[20], a[40]); SQRADDAC(a[21], a[39]); SQRADDAC(a[22], a[38]); SQRADDAC(a[23], a[37]); SQRADDAC(a[24], a[36]); SQRADDAC(a[25], a[35]); SQRADDAC(a[26], a[34]); SQRADDAC(a[27], a[33]); SQRADDAC(a[28], a[32]); SQRADDAC(a[29], a[31]); SQRADDDB; SQRADD(a[30], a[30]);
4733    COMBA_STORE(b[60]);
4734
4735    /* output 61 */
4736    CARRY_FORWARD;
4737    SQRADDSC(a[0], a[61]); SQRADDAC(a[1], a[60]); SQRADDAC(a[2], a[59]); SQRADDAC(a[3], a[58]); SQRADDAC(a[4], a[57]); SQRADDAC(a[5], a[56]); SQRADDAC(a[6], a[55]); SQRADDAC(a[7], a[54]); SQRADDAC(a[8], a[53]); SQRADDAC(a[9], a[52]); SQRADDAC(a[10], a[51]); SQRADDAC(a[11], a[50]); SQRADDAC(a[12], a[49]); SQRADDAC(a[13], a[48]); SQRADDAC(a[14], a[47]); SQRADDAC(a[15], a[46]); SQRADDAC(a[16], a[45]); SQRADDAC(a[17], a[44]); SQRADDAC(a[18], a[43]); SQRADDAC(a[19], a[42]); SQRADDAC(a[20], a[41]); SQRADDAC(a[21], a[40]); SQRADDAC(a[22], a[39]); SQRADDAC(a[23], a[38]); SQRADDAC(a[24], a[37]); SQRADDAC(a[25], a[36]); SQRADDAC(a[26], a[35]); SQRADDAC(a[27], a[34]); SQRADDAC(a[28], a[33]); SQRADDAC(a[29], a[32]); SQRADDAC(a[30], a[31]); SQRADDDB;
4738    COMBA_STORE(b[61]);
4739
4740    /* output 62 */
4741    CARRY_FORWARD;
4742    SQRADDSC(a[0], a[62]); SQRADDAC(a[1], a[61]); SQRADDAC(a[2], a[60]); SQRADDAC(a[3], a[59]); SQRADDAC(a[4], a[58]); SQRADDAC(a[5], a[57]); SQRADDAC(a[6], a[56]); SQRADDAC(a[7], a[55]); SQRADDAC(a[8], a[54]); SQRADDAC(a[9], a[53]); SQRADDAC(a[10], a[52]); SQRADDAC(a[11], a[51]); SQRADDAC(a[12], a[50]); SQRADDAC(a[13], a[49]); SQRADDAC(a[14], a[48]); SQRADDAC(a[15], a[47]); SQRADDAC(a[16], a[46]); SQRADDAC(a[17], a[45]); SQRADDAC(a[18], a[44]); SQRADDAC(a[19], a[43]); SQRADDAC(a[20], a[42]); SQRADDAC(a[21], a[41]); SQRADDAC(a[22], a[40]); SQRADDAC(a[23], a[39]); SQRADDAC(a[24], a[38]); SQRADDAC(a[25], a[37]); SQRADDAC(a[26], a[36]); SQRADDAC(a[27], a[35]); SQRADDAC(a[28], a[34]); SQRADDAC(a[29], a[33]); SQRADDAC(a[30], a[32]); SQRADDDB; SQRADD(a[31], a[31]);
4743    COMBA_STORE(b[62]);
4744
4745    /* output 63 */
4746    CARRY_FORWARD;
4747    SQRADDSC(a[0], a[63]); SQRADDAC(a[1], a[62]); SQRADDAC(a[2], a[61]); SQRADDAC(a[3], a[60]); SQRADDAC(a[4], a[59]); SQRADDAC(a[5], a[58]); SQRADDAC(a[6], a[57]); SQRADDAC(a[7], a[56]); SQRADDAC(a[8], a[55]); SQRADDAC(a[9], a[54]); SQRADDAC(a[10], a[53]); SQRADDAC(a[11], a[52]); SQRADDAC(a[12], a[51]); SQRADDAC(a[13], a[50]); SQRADDAC(a[14], a[49]); SQRADDAC(a[15], a[48]); SQRADDAC(a[16], a[47]); SQRADDAC(a[17], a[46]); SQRADDAC(a[18], a[45]); SQRADDAC(a[19], a[44]); SQRADDAC(a[20], a[43]); SQRADDAC(a[21], a[42]); SQRADDAC(a[22], a[41]); SQRADDAC(a[23], a[40]); SQRADDAC(a[24], a[39]); SQRADDAC(a[25], a[38]); SQRADDAC(a[26], a[37]); SQRADDAC(a[27], a[36]); SQRADDAC(a[28], a[35]); SQRADDAC(a[29], a[34]); SQRADDAC(a[30], a[33]); SQRADDAC(a[31], a[32]); SQRADDDB;
4748    COMBA_STORE(b[63]);
4749
4750    /* output 64 */
4751    CARRY_FORWARD;
4752    SQRADDSC(a[1], a[63]); SQRADDAC(a[2], a[62]); SQRADDAC(a[3], a[61]); SQRADDAC(a[4], a[60]); SQRADDAC(a[5], a[59]); SQRADDAC(a[6], a[58]); SQRADDAC(a[7], a[57]); SQRADDAC(a[8], a[56]); SQRADDAC(a[9], a[55]); SQRADDAC(a[10], a[54]); SQRADDAC(a[11], a[53]); SQRADDAC(a[12], a[52]); SQRADDAC(a[13], a[51]); SQRADDAC(a[14], a[50]); SQRADDAC(a[15], a[49]); SQRADDAC(a[16], a[48]); SQRADDAC(a[17], a[47]); SQRADDAC(a[18], a[46]); SQRADDAC(a[19], a[45]); SQRADDAC(a[20], a[44]); SQRADDAC(a[21], a[43]); SQRADDAC(a[22], a[42]); SQRADDAC(a[23], a[41]); SQRADDAC(a[24], a[40]); SQRADDAC(a[25], a[39]); SQRADDAC(a[26], a[38]); SQRADDAC(a[27], a[37]); SQRADDAC(a[28], a[36]); SQRADDAC(a[29], a[35]); SQRADDAC(a[30], a[34]); SQRADDAC(a[31], a[33]); SQRADDDB; SQRADD(a[32], a[32]);
4753    COMBA_STORE(b[64]);
4754
4755    /* output 65 */
4756    CARRY_FORWARD;
4757    SQRADDSC(a[2], a[63]); SQRADDAC(a[3], a[62]); SQRADDAC(a[4], a[61]); SQRADDAC(a[5], a[60]); SQRADDAC(a[6], a[59]); SQRADDAC(a[7], a[58]); SQRADDAC(a[8], a[57]); SQRADDAC(a[9], a[56]); SQRADDAC(a[10], a[55]); SQRADDAC(a[11], a[54]); SQRADDAC(a[12], a[53]); SQRADDAC(a[13], a[52]); SQRADDAC(a[14], a[51]); SQRADDAC(a[15], a[50]); SQRADDAC(a[16], a[49]); SQRADDAC(a[17], a[48]); SQRADDAC(a[18], a[47]); SQRADDAC(a[19], a[46]); SQRADDAC(a[20], a[45]); SQRADDAC(a[21], a[44]); SQRADDAC(a[22], a[43]); SQRADDAC(a[23], a[42]); SQRADDAC(a[24], a[41]); SQRADDAC(a[25], a[40]); SQRADDAC(a[26], a[39]); SQRADDAC(a[27], a[38]); SQRADDAC(a[28], a[37]); SQRADDAC(a[29], a[36]); SQRADDAC(a[30], a[35]); SQRADDAC(a[31], a[34]); SQRADDAC(a[32], a[33]); SQRADDDB;
4758    COMBA_STORE(b[65]);
4759
4760    /* output 66 */
4761    CARRY_FORWARD;
4762    SQRADDSC(a[3], a[63]); SQRADDAC(a[4], a[62]); SQRADDAC(a[5], a[61]); SQRADDAC(a[6], a[60]); SQRADDAC(a[7], a[59]); SQRADDAC(a[8], a[58]); SQRADDAC(a[9], a[57]); SQRADDAC(a[10], a[56]); SQRADDAC(a[11], a[55]); SQRADDAC(a[12], a[54]); SQRADDAC(a[13], a[53]); SQRADDAC(a[14], a[52]); SQRADDAC(a[15], a[51]); SQRADDAC(a[16], a[50]); SQRADDAC(a[17], a[49]); SQRADDAC(a[18], a[48]); SQRADDAC(a[19], a[47]); SQRADDAC(a[20], a[46]); SQRADDAC(a[21], a[45]); SQRADDAC(a[22], a[44]); SQRADDAC(a[23], a[43]); SQRADDAC(a[24], a[42]); SQRADDAC(a[25], a[41]); SQRADDAC(a[26], a[40]); SQRADDAC(a[27], a[39]); SQRADDAC(a[28], a[38]); SQRADDAC(a[29], a[37]); SQRADDAC(a[30], a[36]); SQRADDAC(a[31], a[35]); SQRADDAC(a[32], a[34]); SQRADDDB; SQRADD(a[33], a[33]);
4763    COMBA_STORE(b[66]);
4764
4765    /* output 67 */
4766    CARRY_FORWARD;
4767    SQRADDSC(a[4], a[63]); SQRADDAC(a[5], a[62]); SQRADDAC(a[6], a[61]); SQRADDAC(a[7], a[60]); SQRADDAC(a[8], a[59]); SQRADDAC(a[9], a[58]); SQRADDAC(a[10], a[57]); SQRADDAC(a[11], a[56]); SQRADDAC(a[12], a[55]); SQRADDAC(a[13], a[54]); SQRADDAC(a[14], a[53]); SQRADDAC(a[15], a[52]); SQRADDAC(a[16], a[51]); SQRADDAC(a[17], a[50]); SQRADDAC(a[18], a[49]); SQRADDAC(a[19], a[48]); SQRADDAC(a[20], a[47]); SQRADDAC(a[21], a[46]); SQRADDAC(a[22], a[45]); SQRADDAC(a[23], a[44]); SQRADDAC(a[24], a[43]); SQRADDAC(a[25], a[42]); SQRADDAC(a[26], a[41]); SQRADDAC(a[27], a[40]); SQRADDAC(a[28], a[39]); SQRADDAC(a[29], a[38]); SQRADDAC(a[30], a[37]); SQRADDAC(a[31], a[36]); SQRADDAC(a[32], a[35]); SQRADDAC(a[33], a[34]); SQRADDDB;
4768    COMBA_STORE(b[67]);
4769
4770    /* output 68 */
4771    CARRY_FORWARD;
4772    SQRADDSC(a[5], a[63]); SQRADDAC(a[6], a[62]); SQRADDAC(a[7], a[61]); SQRADDAC(a[8], a[60]); SQRADDAC(a[9], a[59]); SQRADDAC(a[10], a[58]); SQRADDAC(a[11], a[57]); SQRADDAC(a[12], a[56]); SQRADDAC(a[13], a[55]); SQRADDAC(a[14], a[54]); SQRADDAC(a[15], a[53]); SQRADDAC(a[16], a[52]); SQRADDAC(a[17], a[51]); SQRADDAC(a[18], a[50]); SQRADDAC(a[19], a[49]); SQRADDAC(a[20], a[48]); SQRADDAC(a[21], a[47]); SQRADDAC(a[22], a[46]); SQRADDAC(a[23], a[45]); SQRADDAC(a[24], a[44]); SQRADDAC(a[25], a[43]); SQRADDAC(a[26], a[42]); SQRADDAC(a[27], a[41]); SQRADDAC(a[28], a[40]); SQRADDAC(a[29], a[39]); SQRADDAC(a[30], a[38]); SQRADDAC(a[31], a[37]); SQRADDAC(a[32], a[36]); SQRADDAC(a[33], a[35]); SQRADDDB; SQRADD(a[34], a[34]);
4773    COMBA_STORE(b[68]);
4774
4775    /* output 69 */
4776    CARRY_FORWARD;
4777    SQRADDSC(a[6], a[63]); SQRADDAC(a[7], a[62]); SQRADDAC(a[8], a[61]); SQRADDAC(a[9], a[60]); SQRADDAC(a[10], a[59]); SQRADDAC(a[11], a[58]); SQRADDAC(a[12], a[57]); SQRADDAC(a[13], a[56]); SQRADDAC(a[14], a[55]); SQRADDAC(a[15], a[54]); SQRADDAC(a[16], a[53]); SQRADDAC(a[17], a[52]); SQRADDAC(a[18], a[51]); SQRADDAC(a[19], a[50]); SQRADDAC(a[20], a[49]); SQRADDAC(a[21], a[48]); SQRADDAC(a[22], a[47]); SQRADDAC(a[23], a[46]); SQRADDAC(a[24], a[45]); SQRADDAC(a[25], a[44]); SQRADDAC(a[26], a[43]); SQRADDAC(a[27], a[42]); SQRADDAC(a[28], a[41]); SQRADDAC(a[29], a[40]); SQRADDAC(a[30], a[39]); SQRADDAC(a[31], a[38]); SQRADDAC(a[32], a[37]); SQRADDAC(a[33], a[36]); SQRADDAC(a[34], a[35]); SQRADDDB;
4778    COMBA_STORE(b[69]);
4779
4780    /* output 70 */
4781    CARRY_FORWARD;
4782    SQRADDSC(a[7], a[63]); SQRADDAC(a[8], a[62]); SQRADDAC(a[9], a[61]); SQRADDAC(a[10], a[60]); SQRADDAC(a[11], a[59]); SQRADDAC(a[12], a[58]); SQRADDAC(a[13], a[57]); SQRADDAC(a[14], a[56]); SQRADDAC(a[15], a[55]); SQRADDAC(a[16], a[54]); SQRADDAC(a[17], a[53]); SQRADDAC(a[18], a[52]); SQRADDAC(a[19], a[51]); SQRADDAC(a[20], a[50]); SQRADDAC(a[21], a[49]); SQRADDAC(a[22], a[48]); SQRADDAC(a[23], a[47]); SQRADDAC(a[24], a[46]); SQRADDAC(a[25], a[45]); SQRADDAC(a[26], a[44]); SQRADDAC(a[27], a[43]); SQRADDAC(a[28], a[42]); SQRADDAC(a[29], a[41]); SQRADDAC(a[30], a[40]); SQRADDAC(a[31], a[39]); SQRADDAC(a[32], a[38]); SQRADDAC(a[33], a[37]); SQRADDAC(a[34], a[36]); SQRADDDB; SQRADD(a[35], a[35]);
4783    COMBA_STORE(b[70]);
4784
4785    /* output 71 */
4786    CARRY_FORWARD;
4787    SQRADDSC(a[8], a[63]); SQRADDAC(a[9], a[62]); SQRADDAC(a[10], a[61]); SQRADDAC(a[11], a[60]); SQRADDAC(a[12], a[59]); SQRADDAC(a[13], a[58]); SQRADDAC(a[14], a[57]); SQRADDAC(a[15], a[56]); SQRADDAC(a[16], a[55]); SQRADDAC(a[17], a[54]); SQRADDAC(a[18], a[53]); SQRADDAC(a[19], a[52]); SQRADDAC(a[20], a[51]); SQRADDAC(a[21], a[50]); SQRADDAC(a[22], a[49]); SQRADDAC(a[23], a[48]); SQRADDAC(a[24], a[47]); SQRADDAC(a[25], a[46]); SQRADDAC(a[26], a[45]); SQRADDAC(a[27], a[44]); SQRADDAC(a[28], a[43]); SQRADDAC(a[29], a[42]); SQRADDAC(a[30], a[41]); SQRADDAC(a[31], a[40]); SQRADDAC(a[32], a[39]); SQRADDAC(a[33], a[38]); SQRADDAC(a[34], a[37]); SQRADDAC(a[35], a[36]); SQRADDDB;
4788    COMBA_STORE(b[71]);
4789
4790    /* output 72 */
4791    CARRY_FORWARD;
4792    SQRADDSC(a[9], a[63]); SQRADDAC(a[10], a[62]); SQRADDAC(a[11], a[61]); SQRADDAC(a[12], a[60]); SQRADDAC(a[13], a[59]); SQRADDAC(a[14], a[58]); SQRADDAC(a[15], a[57]); SQRADDAC(a[16], a[56]); SQRADDAC(a[17], a[55]); SQRADDAC(a[18], a[54]); SQRADDAC(a[19], a[53]); SQRADDAC(a[20], a[52]); SQRADDAC(a[21], a[51]); SQRADDAC(a[22], a[50]); SQRADDAC(a[23], a[49]); SQRADDAC(a[24], a[48]); SQRADDAC(a[25], a[47]); SQRADDAC(a[26], a[46]); SQRADDAC(a[27], a[45]); SQRADDAC(a[28], a[44]); SQRADDAC(a[29], a[43]); SQRADDAC(a[30], a[42]); SQRADDAC(a[31], a[41]); SQRADDAC(a[32], a[40]); SQRADDAC(a[33], a[39]); SQRADDAC(a[34], a[38]); SQRADDAC(a[35], a[37]); SQRADDDB; SQRADD(a[36], a[36]);
4793    COMBA_STORE(b[72]);
4794
4795    /* output 73 */
4796    CARRY_FORWARD;
4797    SQRADDSC(a[10], a[63]); SQRADDAC(a[11], a[62]); SQRADDAC(a[12], a[61]); SQRADDAC(a[13], a[60]); SQRADDAC(a[14], a[59]); SQRADDAC(a[15], a[58]); SQRADDAC(a[16], a[57]); SQRADDAC(a[17], a[56]); SQRADDAC(a[18], a[55]); SQRADDAC(a[19], a[54]); SQRADDAC(a[20], a[53]); SQRADDAC(a[21], a[52]); SQRADDAC(a[22], a[51]); SQRADDAC(a[23], a[50]); SQRADDAC(a[24], a[49]); SQRADDAC(a[25], a[48]); SQRADDAC(a[26], a[47]); SQRADDAC(a[27], a[46]); SQRADDAC(a[28], a[45]); SQRADDAC(a[29], a[44]); SQRADDAC(a[30], a[43]); SQRADDAC(a[31], a[42]); SQRADDAC(a[32], a[41]); SQRADDAC(a[33], a[40]); SQRADDAC(a[34], a[39]); SQRADDAC(a[35], a[38]); SQRADDAC(a[36], a[37]); SQRADDDB;
4798    COMBA_STORE(b[73]);
4799
4800    /* output 74 */
4801    CARRY_FORWARD;
4802    SQRADDSC(a[11], a[63]); SQRADDAC(a[12], a[62]); SQRADDAC(a[13], a[61]); SQRADDAC(a[14], a[60]); SQRADDAC(a[15], a[59]); SQRADDAC(a[16], a[58]); SQRADDAC(a[17], a[57]); SQRADDAC(a[18], a[56]); SQRADDAC(a[19], a[55]); SQRADDAC(a[20], a[54]); SQRADDAC(a[21], a[53]); SQRADDAC(a[22], a[52]); SQRADDAC(a[23], a[51]); SQRADDAC(a[24], a[50]); SQRADDAC(a[25], a[49]); SQRADDAC(a[26], a[48]); SQRADDAC(a[27], a[47]); SQRADDAC(a[28], a[46]); SQRADDAC(a[29], a[45]); SQRADDAC(a[30], a[44]); SQRADDAC(a[31], a[43]); SQRADDAC(a[32], a[42]); SQRADDAC(a[33], a[41]); SQRADDAC(a[34], a[40]); SQRADDAC(a[35], a[39]); SQRADDAC(a[36], a[38]); SQRADDDB; SQRADD(a[37], a[37]);
4803    COMBA_STORE(b[74]);
4804
4805    /* output 75 */
4806    CARRY_FORWARD;
4807    SQRADDSC(a[12], a[63]); SQRADDAC(a[13], a[62]); SQRADDAC(a[14], a[61]); SQRADDAC(a[15], a[60]); SQRADDAC(a[16], a[59]); SQRADDAC(a[17], a[58]); SQRADDAC(a[18], a[57]); SQRADDAC(a[19], a[56]); SQRADDAC(a[20], a[55]); SQRADDAC(a[21], a[54]); SQRADDAC(a[22], a[53]); SQRADDAC(a[23], a[52]); SQRADDAC(a[24], a[51]); SQRADDAC(a[25], a[50]); SQRADDAC(a[26], a[49]); SQRADDAC(a[27], a[48]); SQRADDAC(a[28], a[47]); SQRADDAC(a[29], a[46]); SQRADDAC(a[30], a[45]); SQRADDAC(a[31], a[44]); SQRADDAC(a[32], a[43]); SQRADDAC(a[33], a[42]); SQRADDAC(a[34], a[41]); SQRADDAC(a[35], a[40]); SQRADDAC(a[36], a[39]); SQRADDAC(a[37], a[38]); SQRADDDB;
4808    COMBA_STORE(b[75]);
4809
4810    /* output 76 */
4811    CARRY_FORWARD;
4812    SQRADDSC(a[13], a[63]); SQRADDAC(a[14], a[62]); SQRADDAC(a[15], a[61]); SQRADDAC(a[16], a[60]); SQRADDAC(a[17], a[59]); SQRADDAC(a[18], a[58]); SQRADDAC(a[19], a[57]); SQRADDAC(a[20], a[56]); SQRADDAC(a[21], a[55]); SQRADDAC(a[22], a[54]); SQRADDAC(a[23], a[53]); SQRADDAC(a[24], a[52]); SQRADDAC(a[25], a[51]); SQRADDAC(a[26], a[50]); SQRADDAC(a[27], a[49]); SQRADDAC(a[28], a[48]); SQRADDAC(a[29], a[47]); SQRADDAC(a[30], a[46]); SQRADDAC(a[31], a[45]); SQRADDAC(a[32], a[44]); SQRADDAC(a[33], a[43]); SQRADDAC(a[34], a[42]); SQRADDAC(a[35], a[41]); SQRADDAC(a[36], a[40]); SQRADDAC(a[37], a[39]); SQRADDDB; SQRADD(a[38], a[38]);
4813    COMBA_STORE(b[76]);
4814
4815    /* output 77 */
4816    CARRY_FORWARD;
4817    SQRADDSC(a[14], a[63]); SQRADDAC(a[15], a[62]); SQRADDAC(a[16], a[61]); SQRADDAC(a[17], a[60]); SQRADDAC(a[18], a[59]); SQRADDAC(a[19], a[58]); SQRADDAC(a[20], a[57]); SQRADDAC(a[21], a[56]); SQRADDAC(a[22], a[55]); SQRADDAC(a[23], a[54]); SQRADDAC(a[24], a[53]); SQRADDAC(a[25], a[52]); SQRADDAC(a[26], a[51]); SQRADDAC(a[27], a[50]); SQRADDAC(a[28], a[49]); SQRADDAC(a[29], a[48]); SQRADDAC(a[30], a[47]); SQRADDAC(a[31], a[46]); SQRADDAC(a[32], a[45]); SQRADDAC(a[33], a[44]); SQRADDAC(a[34], a[43]); SQRADDAC(a[35], a[42]); SQRADDAC(a[36], a[41]); SQRADDAC(a[37], a[40]); SQRADDAC(a[38], a[39]); SQRADDDB;
4818    COMBA_STORE(b[77]);
4819
4820    /* output 78 */
4821    CARRY_FORWARD;
4822    SQRADDSC(a[15], a[63]); SQRADDAC(a[16], a[62]); SQRADDAC(a[17], a[61]); SQRADDAC(a[18], a[60]); SQRADDAC(a[19], a[59]); SQRADDAC(a[20], a[58]); SQRADDAC(a[21], a[57]); SQRADDAC(a[22], a[56]); SQRADDAC(a[23], a[55]); SQRADDAC(a[24], a[54]); SQRADDAC(a[25], a[53]); SQRADDAC(a[26], a[52]); SQRADDAC(a[27], a[51]); SQRADDAC(a[28], a[50]); SQRADDAC(a[29], a[49]); SQRADDAC(a[30], a[48]); SQRADDAC(a[31], a[47]); SQRADDAC(a[32], a[46]); SQRADDAC(a[33], a[45]); SQRADDAC(a[34], a[44]); SQRADDAC(a[35], a[43]); SQRADDAC(a[36], a[42]); SQRADDAC(a[37], a[41]); SQRADDAC(a[38], a[40]); SQRADDDB; SQRADD(a[39], a[39]);
4823    COMBA_STORE(b[78]);
4824
4825    /* output 79 */
4826    CARRY_FORWARD;
4827    SQRADDSC(a[16], a[63]); SQRADDAC(a[17], a[62]); SQRADDAC(a[18], a[61]); SQRADDAC(a[19], a[60]); SQRADDAC(a[20], a[59]); SQRADDAC(a[21], a[58]); SQRADDAC(a[22], a[57]); SQRADDAC(a[23], a[56]); SQRADDAC(a[24], a[55]); SQRADDAC(a[25], a[54]); SQRADDAC(a[26], a[53]); SQRADDAC(a[27], a[52]); SQRADDAC(a[28], a[51]); SQRADDAC(a[29], a[50]); SQRADDAC(a[30], a[49]); SQRADDAC(a[31], a[48]); SQRADDAC(a[32], a[47]); SQRADDAC(a[33], a[46]); SQRADDAC(a[34], a[45]); SQRADDAC(a[35], a[44]); SQRADDAC(a[36], a[43]); SQRADDAC(a[37], a[42]); SQRADDAC(a[38], a[41]); SQRADDAC(a[39], a[40]); SQRADDDB;
4828    COMBA_STORE(b[79]);
4829
4830    /* output 80 */
4831    CARRY_FORWARD;
4832    SQRADDSC(a[17], a[63]); SQRADDAC(a[18], a[62]); SQRADDAC(a[19], a[61]); SQRADDAC(a[20], a[60]); SQRADDAC(a[21], a[59]); SQRADDAC(a[22], a[58]); SQRADDAC(a[23], a[57]); SQRADDAC(a[24], a[56]); SQRADDAC(a[25], a[55]); SQRADDAC(a[26], a[54]); SQRADDAC(a[27], a[53]); SQRADDAC(a[28], a[52]); SQRADDAC(a[29], a[51]); SQRADDAC(a[30], a[50]); SQRADDAC(a[31], a[49]); SQRADDAC(a[32], a[48]); SQRADDAC(a[33], a[47]); SQRADDAC(a[34], a[46]); SQRADDAC(a[35], a[45]); SQRADDAC(a[36], a[44]); SQRADDAC(a[37], a[43]); SQRADDAC(a[38], a[42]); SQRADDAC(a[39], a[41]); SQRADDDB; SQRADD(a[40], a[40]);
4833    COMBA_STORE(b[80]);
4834
4835    /* output 81 */
4836    CARRY_FORWARD;
4837    SQRADDSC(a[18], a[63]); SQRADDAC(a[19], a[62]); SQRADDAC(a[20], a[61]); SQRADDAC(a[21], a[60]); SQRADDAC(a[22], a[59]); SQRADDAC(a[23], a[58]); SQRADDAC(a[24], a[57]); SQRADDAC(a[25], a[56]); SQRADDAC(a[26], a[55]); SQRADDAC(a[27], a[54]); SQRADDAC(a[28], a[53]); SQRADDAC(a[29], a[52]); SQRADDAC(a[30], a[51]); SQRADDAC(a[31], a[50]); SQRADDAC(a[32], a[49]); SQRADDAC(a[33], a[48]); SQRADDAC(a[34], a[47]); SQRADDAC(a[35], a[46]); SQRADDAC(a[36], a[45]); SQRADDAC(a[37], a[44]); SQRADDAC(a[38], a[43]); SQRADDAC(a[39], a[42]); SQRADDAC(a[40], a[41]); SQRADDDB;
4838    COMBA_STORE(b[81]);
4839
4840    /* output 82 */
4841    CARRY_FORWARD;
4842    SQRADDSC(a[19], a[63]); SQRADDAC(a[20], a[62]); SQRADDAC(a[21], a[61]); SQRADDAC(a[22], a[60]); SQRADDAC(a[23], a[59]); SQRADDAC(a[24], a[58]); SQRADDAC(a[25], a[57]); SQRADDAC(a[26], a[56]); SQRADDAC(a[27], a[55]); SQRADDAC(a[28], a[54]); SQRADDAC(a[29], a[53]); SQRADDAC(a[30], a[52]); SQRADDAC(a[31], a[51]); SQRADDAC(a[32], a[50]); SQRADDAC(a[33], a[49]); SQRADDAC(a[34], a[48]); SQRADDAC(a[35], a[47]); SQRADDAC(a[36], a[46]); SQRADDAC(a[37], a[45]); SQRADDAC(a[38], a[44]); SQRADDAC(a[39], a[43]); SQRADDAC(a[40], a[42]); SQRADDDB; SQRADD(a[41], a[41]);
4843    COMBA_STORE(b[82]);
4844
4845    /* output 83 */
4846    CARRY_FORWARD;
4847    SQRADDSC(a[20], a[63]); SQRADDAC(a[21], a[62]); SQRADDAC(a[22], a[61]); SQRADDAC(a[23], a[60]); SQRADDAC(a[24], a[59]); SQRADDAC(a[25], a[58]); SQRADDAC(a[26], a[57]); SQRADDAC(a[27], a[56]); SQRADDAC(a[28], a[55]); SQRADDAC(a[29], a[54]); SQRADDAC(a[30], a[53]); SQRADDAC(a[31], a[52]); SQRADDAC(a[32], a[51]); SQRADDAC(a[33], a[50]); SQRADDAC(a[34], a[49]); SQRADDAC(a[35], a[48]); SQRADDAC(a[36], a[47]); SQRADDAC(a[37], a[46]); SQRADDAC(a[38], a[45]); SQRADDAC(a[39], a[44]); SQRADDAC(a[40], a[43]); SQRADDAC(a[41], a[42]); SQRADDDB;
4848    COMBA_STORE(b[83]);
4849
4850    /* output 84 */
4851    CARRY_FORWARD;
4852    SQRADDSC(a[21], a[63]); SQRADDAC(a[22], a[62]); SQRADDAC(a[23], a[61]); SQRADDAC(a[24], a[60]); SQRADDAC(a[25], a[59]); SQRADDAC(a[26], a[58]); SQRADDAC(a[27], a[57]); SQRADDAC(a[28], a[56]); SQRADDAC(a[29], a[55]); SQRADDAC(a[30], a[54]); SQRADDAC(a[31], a[53]); SQRADDAC(a[32], a[52]); SQRADDAC(a[33], a[51]); SQRADDAC(a[34], a[50]); SQRADDAC(a[35], a[49]); SQRADDAC(a[36], a[48]); SQRADDAC(a[37], a[47]); SQRADDAC(a[38], a[46]); SQRADDAC(a[39], a[45]); SQRADDAC(a[40], a[44]); SQRADDAC(a[41], a[43]); SQRADDDB; SQRADD(a[42], a[42]);
4853    COMBA_STORE(b[84]);
4854
4855    /* output 85 */
4856    CARRY_FORWARD;
4857    SQRADDSC(a[22], a[63]); SQRADDAC(a[23], a[62]); SQRADDAC(a[24], a[61]); SQRADDAC(a[25], a[60]); SQRADDAC(a[26], a[59]); SQRADDAC(a[27], a[58]); SQRADDAC(a[28], a[57]); SQRADDAC(a[29], a[56]); SQRADDAC(a[30], a[55]); SQRADDAC(a[31], a[54]); SQRADDAC(a[32], a[53]); SQRADDAC(a[33], a[52]); SQRADDAC(a[34], a[51]); SQRADDAC(a[35], a[50]); SQRADDAC(a[36], a[49]); SQRADDAC(a[37], a[48]); SQRADDAC(a[38], a[47]); SQRADDAC(a[39], a[46]); SQRADDAC(a[40], a[45]); SQRADDAC(a[41], a[44]); SQRADDAC(a[42], a[43]); SQRADDDB;
4858    COMBA_STORE(b[85]);
4859
4860    /* output 86 */
4861    CARRY_FORWARD;
4862    SQRADDSC(a[23], a[63]); SQRADDAC(a[24], a[62]); SQRADDAC(a[25], a[61]); SQRADDAC(a[26], a[60]); SQRADDAC(a[27], a[59]); SQRADDAC(a[28], a[58]); SQRADDAC(a[29], a[57]); SQRADDAC(a[30], a[56]); SQRADDAC(a[31], a[55]); SQRADDAC(a[32], a[54]); SQRADDAC(a[33], a[53]); SQRADDAC(a[34], a[52]); SQRADDAC(a[35], a[51]); SQRADDAC(a[36], a[50]); SQRADDAC(a[37], a[49]); SQRADDAC(a[38], a[48]); SQRADDAC(a[39], a[47]); SQRADDAC(a[40], a[46]); SQRADDAC(a[41], a[45]); SQRADDAC(a[42], a[44]); SQRADDDB; SQRADD(a[43], a[43]);
4863    COMBA_STORE(b[86]);
4864
4865    /* output 87 */
4866    CARRY_FORWARD;
4867    SQRADDSC(a[24], a[63]); SQRADDAC(a[25], a[62]); SQRADDAC(a[26], a[61]); SQRADDAC(a[27], a[60]); SQRADDAC(a[28], a[59]); SQRADDAC(a[29], a[58]); SQRADDAC(a[30], a[57]); SQRADDAC(a[31], a[56]); SQRADDAC(a[32], a[55]); SQRADDAC(a[33], a[54]); SQRADDAC(a[34], a[53]); SQRADDAC(a[35], a[52]); SQRADDAC(a[36], a[51]); SQRADDAC(a[37], a[50]); SQRADDAC(a[38], a[49]); SQRADDAC(a[39], a[48]); SQRADDAC(a[40], a[47]); SQRADDAC(a[41], a[46]); SQRADDAC(a[42], a[45]); SQRADDAC(a[43], a[44]); SQRADDDB;
4868    COMBA_STORE(b[87]);
4869
4870    /* output 88 */
4871    CARRY_FORWARD;
4872    SQRADDSC(a[25], a[63]); SQRADDAC(a[26], a[62]); SQRADDAC(a[27], a[61]); SQRADDAC(a[28], a[60]); SQRADDAC(a[29], a[59]); SQRADDAC(a[30], a[58]); SQRADDAC(a[31], a[57]); SQRADDAC(a[32], a[56]); SQRADDAC(a[33], a[55]); SQRADDAC(a[34], a[54]); SQRADDAC(a[35], a[53]); SQRADDAC(a[36], a[52]); SQRADDAC(a[37], a[51]); SQRADDAC(a[38], a[50]); SQRADDAC(a[39], a[49]); SQRADDAC(a[40], a[48]); SQRADDAC(a[41], a[47]); SQRADDAC(a[42], a[46]); SQRADDAC(a[43], a[45]); SQRADDDB; SQRADD(a[44], a[44]);
4873    COMBA_STORE(b[88]);
4874
4875    /* output 89 */
4876    CARRY_FORWARD;
4877    SQRADDSC(a[26], a[63]); SQRADDAC(a[27], a[62]); SQRADDAC(a[28], a[61]); SQRADDAC(a[29], a[60]); SQRADDAC(a[30], a[59]); SQRADDAC(a[31], a[58]); SQRADDAC(a[32], a[57]); SQRADDAC(a[33], a[56]); SQRADDAC(a[34], a[55]); SQRADDAC(a[35], a[54]); SQRADDAC(a[36], a[53]); SQRADDAC(a[37], a[52]); SQRADDAC(a[38], a[51]); SQRADDAC(a[39], a[50]); SQRADDAC(a[40], a[49]); SQRADDAC(a[41], a[48]); SQRADDAC(a[42], a[47]); SQRADDAC(a[43], a[46]); SQRADDAC(a[44], a[45]); SQRADDDB;
4878    COMBA_STORE(b[89]);
4879
4880    /* output 90 */
4881    CARRY_FORWARD;
4882    SQRADDSC(a[27], a[63]); SQRADDAC(a[28], a[62]); SQRADDAC(a[29], a[61]); SQRADDAC(a[30], a[60]); SQRADDAC(a[31], a[59]); SQRADDAC(a[32], a[58]); SQRADDAC(a[33], a[57]); SQRADDAC(a[34], a[56]); SQRADDAC(a[35], a[55]); SQRADDAC(a[36], a[54]); SQRADDAC(a[37], a[53]); SQRADDAC(a[38], a[52]); SQRADDAC(a[39], a[51]); SQRADDAC(a[40], a[50]); SQRADDAC(a[41], a[49]); SQRADDAC(a[42], a[48]); SQRADDAC(a[43], a[47]); SQRADDAC(a[44], a[46]); SQRADDDB; SQRADD(a[45], a[45]);
4883    COMBA_STORE(b[90]);
4884
4885    /* output 91 */
4886    CARRY_FORWARD;
4887    SQRADDSC(a[28], a[63]); SQRADDAC(a[29], a[62]); SQRADDAC(a[30], a[61]); SQRADDAC(a[31], a[60]); SQRADDAC(a[32], a[59]); SQRADDAC(a[33], a[58]); SQRADDAC(a[34], a[57]); SQRADDAC(a[35], a[56]); SQRADDAC(a[36], a[55]); SQRADDAC(a[37], a[54]); SQRADDAC(a[38], a[53]); SQRADDAC(a[39], a[52]); SQRADDAC(a[40], a[51]); SQRADDAC(a[41], a[50]); SQRADDAC(a[42], a[49]); SQRADDAC(a[43], a[48]); SQRADDAC(a[44], a[47]); SQRADDAC(a[45], a[46]); SQRADDDB;
4888    COMBA_STORE(b[91]);
4889
4890    /* output 92 */
4891    CARRY_FORWARD;
4892    SQRADDSC(a[29], a[63]); SQRADDAC(a[30], a[62]); SQRADDAC(a[31], a[61]); SQRADDAC(a[32], a[60]); SQRADDAC(a[33], a[59]); SQRADDAC(a[34], a[58]); SQRADDAC(a[35], a[57]); SQRADDAC(a[36], a[56]); SQRADDAC(a[37], a[55]); SQRADDAC(a[38], a[54]); SQRADDAC(a[39], a[53]); SQRADDAC(a[40], a[52]); SQRADDAC(a[41], a[51]); SQRADDAC(a[42], a[50]); SQRADDAC(a[43], a[49]); SQRADDAC(a[44], a[48]); SQRADDAC(a[45], a[47]); SQRADDDB; SQRADD(a[46], a[46]);
4893    COMBA_STORE(b[92]);
4894
4895    /* output 93 */
4896    CARRY_FORWARD;
4897    SQRADDSC(a[30], a[63]); SQRADDAC(a[31], a[62]); SQRADDAC(a[32], a[61]); SQRADDAC(a[33], a[60]); SQRADDAC(a[34], a[59]); SQRADDAC(a[35], a[58]); SQRADDAC(a[36], a[57]); SQRADDAC(a[37], a[56]); SQRADDAC(a[38], a[55]); SQRADDAC(a[39], a[54]); SQRADDAC(a[40], a[53]); SQRADDAC(a[41], a[52]); SQRADDAC(a[42], a[51]); SQRADDAC(a[43], a[50]); SQRADDAC(a[44], a[49]); SQRADDAC(a[45], a[48]); SQRADDAC(a[46], a[47]); SQRADDDB;
4898    COMBA_STORE(b[93]);
4899
4900    /* output 94 */
4901    CARRY_FORWARD;
4902    SQRADDSC(a[31], a[63]); SQRADDAC(a[32], a[62]); SQRADDAC(a[33], a[61]); SQRADDAC(a[34], a[60]); SQRADDAC(a[35], a[59]); SQRADDAC(a[36], a[58]); SQRADDAC(a[37], a[57]); SQRADDAC(a[38], a[56]); SQRADDAC(a[39], a[55]); SQRADDAC(a[40], a[54]); SQRADDAC(a[41], a[53]); SQRADDAC(a[42], a[52]); SQRADDAC(a[43], a[51]); SQRADDAC(a[44], a[50]); SQRADDAC(a[45], a[49]); SQRADDAC(a[46], a[48]); SQRADDDB; SQRADD(a[47], a[47]);
4903    COMBA_STORE(b[94]);
4904
4905    /* output 95 */
4906    CARRY_FORWARD;
4907    SQRADDSC(a[32], a[63]); SQRADDAC(a[33], a[62]); SQRADDAC(a[34], a[61]); SQRADDAC(a[35], a[60]); SQRADDAC(a[36], a[59]); SQRADDAC(a[37], a[58]); SQRADDAC(a[38], a[57]); SQRADDAC(a[39], a[56]); SQRADDAC(a[40], a[55]); SQRADDAC(a[41], a[54]); SQRADDAC(a[42], a[53]); SQRADDAC(a[43], a[52]); SQRADDAC(a[44], a[51]); SQRADDAC(a[45], a[50]); SQRADDAC(a[46], a[49]); SQRADDAC(a[47], a[48]); SQRADDDB;
4908    COMBA_STORE(b[95]);
4909
4910    /* output 96 */
4911    CARRY_FORWARD;
4912    SQRADDSC(a[33], a[63]); SQRADDAC(a[34], a[62]); SQRADDAC(a[35], a[61]); SQRADDAC(a[36], a[60]); SQRADDAC(a[37], a[59]); SQRADDAC(a[38], a[58]); SQRADDAC(a[39], a[57]); SQRADDAC(a[40], a[56]); SQRADDAC(a[41], a[55]); SQRADDAC(a[42], a[54]); SQRADDAC(a[43], a[53]); SQRADDAC(a[44], a[52]); SQRADDAC(a[45], a[51]); SQRADDAC(a[46], a[50]); SQRADDAC(a[47], a[49]); SQRADDDB; SQRADD(a[48], a[48]);
4913    COMBA_STORE(b[96]);
4914
4915    /* output 97 */
4916    CARRY_FORWARD;
4917    SQRADDSC(a[34], a[63]); SQRADDAC(a[35], a[62]); SQRADDAC(a[36], a[61]); SQRADDAC(a[37], a[60]); SQRADDAC(a[38], a[59]); SQRADDAC(a[39], a[58]); SQRADDAC(a[40], a[57]); SQRADDAC(a[41], a[56]); SQRADDAC(a[42], a[55]); SQRADDAC(a[43], a[54]); SQRADDAC(a[44], a[53]); SQRADDAC(a[45], a[52]); SQRADDAC(a[46], a[51]); SQRADDAC(a[47], a[50]); SQRADDAC(a[48], a[49]); SQRADDDB;
4918    COMBA_STORE(b[97]);
4919
4920    /* output 98 */
4921    CARRY_FORWARD;
4922    SQRADDSC(a[35], a[63]); SQRADDAC(a[36], a[62]); SQRADDAC(a[37], a[61]); SQRADDAC(a[38], a[60]); SQRADDAC(a[39], a[59]); SQRADDAC(a[40], a[58]); SQRADDAC(a[41], a[57]); SQRADDAC(a[42], a[56]); SQRADDAC(a[43], a[55]); SQRADDAC(a[44], a[54]); SQRADDAC(a[45], a[53]); SQRADDAC(a[46], a[52]); SQRADDAC(a[47], a[51]); SQRADDAC(a[48], a[50]); SQRADDDB; SQRADD(a[49], a[49]);
4923    COMBA_STORE(b[98]);
4924
4925    /* output 99 */
4926    CARRY_FORWARD;
4927    SQRADDSC(a[36], a[63]); SQRADDAC(a[37], a[62]); SQRADDAC(a[38], a[61]); SQRADDAC(a[39], a[60]); SQRADDAC(a[40], a[59]); SQRADDAC(a[41], a[58]); SQRADDAC(a[42], a[57]); SQRADDAC(a[43], a[56]); SQRADDAC(a[44], a[55]); SQRADDAC(a[45], a[54]); SQRADDAC(a[46], a[53]); SQRADDAC(a[47], a[52]); SQRADDAC(a[48], a[51]); SQRADDAC(a[49], a[50]); SQRADDDB;
4928    COMBA_STORE(b[99]);
4929
4930    /* output 100 */
4931    CARRY_FORWARD;
4932    SQRADDSC(a[37], a[63]); SQRADDAC(a[38], a[62]); SQRADDAC(a[39], a[61]); SQRADDAC(a[40], a[60]); SQRADDAC(a[41], a[59]); SQRADDAC(a[42], a[58]); SQRADDAC(a[43], a[57]); SQRADDAC(a[44], a[56]); SQRADDAC(a[45], a[55]); SQRADDAC(a[46], a[54]); SQRADDAC(a[47], a[53]); SQRADDAC(a[48], a[52]); SQRADDAC(a[49], a[51]); SQRADDDB; SQRADD(a[50], a[50]);
4933    COMBA_STORE(b[100]);
4934
4935    /* output 101 */
4936    CARRY_FORWARD;
4937    SQRADDSC(a[38], a[63]); SQRADDAC(a[39], a[62]); SQRADDAC(a[40], a[61]); SQRADDAC(a[41], a[60]); SQRADDAC(a[42], a[59]); SQRADDAC(a[43], a[58]); SQRADDAC(a[44], a[57]); SQRADDAC(a[45], a[56]); SQRADDAC(a[46], a[55]); SQRADDAC(a[47], a[54]); SQRADDAC(a[48], a[53]); SQRADDAC(a[49], a[52]); SQRADDAC(a[50], a[51]); SQRADDDB;
4938    COMBA_STORE(b[101]);
4939
4940    /* output 102 */
4941    CARRY_FORWARD;
4942    SQRADDSC(a[39], a[63]); SQRADDAC(a[40], a[62]); SQRADDAC(a[41], a[61]); SQRADDAC(a[42], a[60]); SQRADDAC(a[43], a[59]); SQRADDAC(a[44], a[58]); SQRADDAC(a[45], a[57]); SQRADDAC(a[46], a[56]); SQRADDAC(a[47], a[55]); SQRADDAC(a[48], a[54]); SQRADDAC(a[49], a[53]); SQRADDAC(a[50], a[52]); SQRADDDB; SQRADD(a[51], a[51]);
4943    COMBA_STORE(b[102]);
4944
4945    /* output 103 */
4946    CARRY_FORWARD;
4947    SQRADDSC(a[40], a[63]); SQRADDAC(a[41], a[62]); SQRADDAC(a[42], a[61]); SQRADDAC(a[43], a[60]); SQRADDAC(a[44], a[59]); SQRADDAC(a[45], a[58]); SQRADDAC(a[46], a[57]); SQRADDAC(a[47], a[56]); SQRADDAC(a[48], a[55]); SQRADDAC(a[49], a[54]); SQRADDAC(a[50], a[53]); SQRADDAC(a[51], a[52]); SQRADDDB;
4948    COMBA_STORE(b[103]);
4949
4950    /* output 104 */
4951    CARRY_FORWARD;
4952    SQRADDSC(a[41], a[63]); SQRADDAC(a[42], a[62]); SQRADDAC(a[43], a[61]); SQRADDAC(a[44], a[60]); SQRADDAC(a[45], a[59]); SQRADDAC(a[46], a[58]); SQRADDAC(a[47], a[57]); SQRADDAC(a[48], a[56]); SQRADDAC(a[49], a[55]); SQRADDAC(a[50], a[54]); SQRADDAC(a[51], a[53]); SQRADDDB; SQRADD(a[52], a[52]);
4953    COMBA_STORE(b[104]);
4954
4955    /* output 105 */
4956    CARRY_FORWARD;
4957    SQRADDSC(a[42], a[63]); SQRADDAC(a[43], a[62]); SQRADDAC(a[44], a[61]); SQRADDAC(a[45], a[60]); SQRADDAC(a[46], a[59]); SQRADDAC(a[47], a[58]); SQRADDAC(a[48], a[57]); SQRADDAC(a[49], a[56]); SQRADDAC(a[50], a[55]); SQRADDAC(a[51], a[54]); SQRADDAC(a[52], a[53]); SQRADDDB;
4958    COMBA_STORE(b[105]);
4959
4960    /* output 106 */
4961    CARRY_FORWARD;
4962    SQRADDSC(a[43], a[63]); SQRADDAC(a[44], a[62]); SQRADDAC(a[45], a[61]); SQRADDAC(a[46], a[60]); SQRADDAC(a[47], a[59]); SQRADDAC(a[48], a[58]); SQRADDAC(a[49], a[57]); SQRADDAC(a[50], a[56]); SQRADDAC(a[51], a[55]); SQRADDAC(a[52], a[54]); SQRADDDB; SQRADD(a[53], a[53]);
4963    COMBA_STORE(b[106]);
4964
4965    /* output 107 */
4966    CARRY_FORWARD;
4967    SQRADDSC(a[44], a[63]); SQRADDAC(a[45], a[62]); SQRADDAC(a[46], a[61]); SQRADDAC(a[47], a[60]); SQRADDAC(a[48], a[59]); SQRADDAC(a[49], a[58]); SQRADDAC(a[50], a[57]); SQRADDAC(a[51], a[56]); SQRADDAC(a[52], a[55]); SQRADDAC(a[53], a[54]); SQRADDDB;
4968    COMBA_STORE(b[107]);
4969
4970    /* output 108 */
4971    CARRY_FORWARD;
4972    SQRADDSC(a[45], a[63]); SQRADDAC(a[46], a[62]); SQRADDAC(a[47], a[61]); SQRADDAC(a[48], a[60]); SQRADDAC(a[49], a[59]); SQRADDAC(a[50], a[58]); SQRADDAC(a[51], a[57]); SQRADDAC(a[52], a[56]); SQRADDAC(a[53], a[55]); SQRADDDB; SQRADD(a[54], a[54]);
4973    COMBA_STORE(b[108]);
4974
4975    /* output 109 */
4976    CARRY_FORWARD;
4977    SQRADDSC(a[46], a[63]); SQRADDAC(a[47], a[62]); SQRADDAC(a[48], a[61]); SQRADDAC(a[49], a[60]); SQRADDAC(a[50], a[59]); SQRADDAC(a[51], a[58]); SQRADDAC(a[52], a[57]); SQRADDAC(a[53], a[56]); SQRADDAC(a[54], a[55]); SQRADDDB;
4978    COMBA_STORE(b[109]);
4979
4980    /* output 110 */
4981    CARRY_FORWARD;
4982    SQRADDSC(a[47], a[63]); SQRADDAC(a[48], a[62]); SQRADDAC(a[49], a[61]); SQRADDAC(a[50], a[60]); SQRADDAC(a[51], a[59]); SQRADDAC(a[52], a[58]); SQRADDAC(a[53], a[57]); SQRADDAC(a[54], a[56]); SQRADDDB; SQRADD(a[55], a[55]);
4983    COMBA_STORE(b[110]);
4984
4985    /* output 111 */
4986    CARRY_FORWARD;
4987    SQRADDSC(a[48], a[63]); SQRADDAC(a[49], a[62]); SQRADDAC(a[50], a[61]); SQRADDAC(a[51], a[60]); SQRADDAC(a[52], a[59]); SQRADDAC(a[53], a[58]); SQRADDAC(a[54], a[57]); SQRADDAC(a[55], a[56]); SQRADDDB;
4988    COMBA_STORE(b[111]);
4989
4990    /* output 112 */
4991    CARRY_FORWARD;
4992    SQRADDSC(a[49], a[63]); SQRADDAC(a[50], a[62]); SQRADDAC(a[51], a[61]); SQRADDAC(a[52], a[60]); SQRADDAC(a[53], a[59]); SQRADDAC(a[54], a[58]); SQRADDAC(a[55], a[57]); SQRADDDB; SQRADD(a[56], a[56]);
4993    COMBA_STORE(b[112]);
4994
4995    /* output 113 */
4996    CARRY_FORWARD;
4997    SQRADDSC(a[50], a[63]); SQRADDAC(a[51], a[62]); SQRADDAC(a[52], a[61]); SQRADDAC(a[53], a[60]); SQRADDAC(a[54], a[59]); SQRADDAC(a[55], a[58]); SQRADDAC(a[56], a[57]); SQRADDDB;
4998    COMBA_STORE(b[113]);
4999
5000    /* output 114 */
5001    CARRY_FORWARD;
5002    SQRADDSC(a[51], a[63]); SQRADDAC(a[52], a[62]); SQRADDAC(a[53], a[61]); SQRADDAC(a[54], a[60]); SQRADDAC(a[55], a[59]); SQRADDAC(a[56], a[58]); SQRADDDB; SQRADD(a[57], a[57]);
5003    COMBA_STORE(b[114]);
5004
5005    /* output 115 */
5006    CARRY_FORWARD;
5007    SQRADDSC(a[52], a[63]); SQRADDAC(a[53], a[62]); SQRADDAC(a[54], a[61]); SQRADDAC(a[55], a[60]); SQRADDAC(a[56], a[59]); SQRADDAC(a[57], a[58]); SQRADDDB;
5008    COMBA_STORE(b[115]);
5009
5010    /* output 116 */
5011    CARRY_FORWARD;
5012    SQRADDSC(a[53], a[63]); SQRADDAC(a[54], a[62]); SQRADDAC(a[55], a[61]); SQRADDAC(a[56], a[60]); SQRADDAC(a[57], a[59]); SQRADDDB; SQRADD(a[58], a[58]);
5013    COMBA_STORE(b[116]);
5014
5015    /* output 117 */
5016    CARRY_FORWARD;
5017    SQRADDSC(a[54], a[63]); SQRADDAC(a[55], a[62]); SQRADDAC(a[56], a[61]); SQRADDAC(a[57], a[60]); SQRADDAC(a[58], a[59]); SQRADDDB;
5018    COMBA_STORE(b[117]);
5019
5020    /* output 118 */
5021    CARRY_FORWARD;
5022    SQRADDSC(a[55], a[63]); SQRADDAC(a[56], a[62]); SQRADDAC(a[57], a[61]); SQRADDAC(a[58], a[60]); SQRADDDB; SQRADD(a[59], a[59]);
5023    COMBA_STORE(b[118]);
5024
5025    /* output 119 */
5026    CARRY_FORWARD;
5027    SQRADDSC(a[56], a[63]); SQRADDAC(a[57], a[62]); SQRADDAC(a[58], a[61]); SQRADDAC(a[59], a[60]); SQRADDDB;
5028    COMBA_STORE(b[119]);
5029
5030    /* output 120 */
5031    CARRY_FORWARD;
5032    SQRADDSC(a[57], a[63]); SQRADDAC(a[58], a[62]); SQRADDAC(a[59], a[61]); SQRADDDB; SQRADD(a[60], a[60]);
5033    COMBA_STORE(b[120]);
5034
5035    /* output 121 */
5036    CARRY_FORWARD;
5037    SQRADDSC(a[58], a[63]); SQRADDAC(a[59], a[62]); SQRADDAC(a[60], a[61]); SQRADDDB;
5038    COMBA_STORE(b[121]);
5039
5040    /* output 122 */
5041    CARRY_FORWARD;
5042    SQRADD2(a[59], a[63]); SQRADD2(a[60], a[62]); SQRADD(a[61], a[61]);
5043    COMBA_STORE(b[122]);
5044
5045    /* output 123 */
5046    CARRY_FORWARD;
5047    SQRADD2(a[60], a[63]); SQRADD2(a[61], a[62]);
5048    COMBA_STORE(b[123]);
5049
5050    /* output 124 */
5051    CARRY_FORWARD;
5052    SQRADD2(a[61], a[63]); SQRADD(a[62], a[62]);
5053    COMBA_STORE(b[124]);
5054
5055    /* output 125 */
5056    CARRY_FORWARD;
5057    SQRADD2(a[62], a[63]);
5058    COMBA_STORE(b[125]);
5059
5060    /* output 126 */
5061    CARRY_FORWARD;
5062    SQRADD(a[63], a[63]);
5063    COMBA_STORE(b[126]);
5064    COMBA_STORE2(b[127]);
5065    COMBA_FINI;
5066
5067    B->used = 128;
5068    B->sign = FP_ZPOS;
5069    memcpy(B->dp, b, 128 * sizeof(fp_digit));
5070    fp_clamp(B);
5071 }
5072
5073
5074 #endif
5075
5076 /* End: fp_sqr_comba.c */
5077
5078 /* Start: fp_sqr_comba_generic.c */
5079 /* generic comba squarer */
5080 void fp_sqr_comba(fp_int *A, fp_int *B)
5081 {
5082   int       pa, ix, iz;
5083   fp_digit  c0, c1, c2;
5084   fp_int    tmp, *dst;
5085
5086   /* get size of output and trim */
5087   pa = A->used + A->used;
5088   if (pa >= FP_SIZE) {
5089      pa = FP_SIZE-1;
5090   }
5091
5092   /* number of output digits to produce */
5093   COMBA_START;
5094   CLEAR_CARRY;
5095
5096   if (A == B) {
5097      fp_zero(&tmp);
5098      dst = &tmp;
5099   } else {
5100      fp_zero(B);
5101      dst = B;
5102   }
5103
5104   for (ix = 0; ix < pa; ix++) {
5105       int      tx, ty, iy;
5106       fp_digit *tmpy, *tmpx;
5107
5108       /* get offsets into the two bignums */
5109       ty = MIN(A->used-1, ix);
5110       tx = ix - ty;
5111
5112       /* setup temp aliases */
5113       tmpx = A->dp + tx;
5114       tmpy = A->dp + ty;
5115
5116       /* this is the number of times the loop will iterrate, essentially its
5117          while (tx++ < a->used && ty-- >= 0) { ... }
5118        */
5119       iy = MIN(A->used-tx, ty+1);
5120
5121       /* now for squaring tx can never equal ty
5122        * we halve the distance since they approach at a rate of 2x
5123        * and we have to round because odd cases need to be executed
5124        */
5125       iy = MIN(iy, (ty-tx+1)>>1);
5126
5127       /* forward carries */
5128       CARRY_FORWARD;
5129
5130       /* execute loop */
5131       for (iz = 0; iz < iy; iz++) {
5132           SQRADD2(*tmpx++, *tmpy--);
5133       }
5134
5135       /* even columns have the square term in them */
5136       if ((ix&1) == 0) {
5137           SQRADD(A->dp[ix>>1], A->dp[ix>>1]);
5138       }
5139
5140       /* store it */
5141       COMBA_STORE(dst->dp[ix]);
5142   }
5143   COMBA_STORE2(dst->dp[ix]);
5144
5145   COMBA_FINI;
5146
5147   /* setup dest */
5148   dst->used = pa;
5149   fp_clamp (dst);
5150   if (dst != B) {
5151      fp_copy(dst, B);
5152   }
5153 }
5154
5155 /* End: fp_sqr_comba_generic.c */
5156
5157 /* Start: fp_sqrmod.c */
5158 /* TomsFastMath, a fast ISO C bignum library.
5159  *
5160  * This project is meant to fill in where LibTomMath
5161  * falls short.  That is speed ;-)
5162  *
5163  * This project is public domain and free for all purposes.
5164  *
5165  * Tom St Denis, tomstdenis@iahu.ca
5166  */
5167 #include <tfm.h>
5168
5169 /* c = a * a (mod b) */
5170 int fp_sqrmod(fp_int *a, fp_int *b, fp_int *c)
5171 {
5172   fp_int tmp;
5173   fp_zero(&tmp);
5174   fp_sqr(a, &tmp);
5175   return fp_mod(&tmp, b, c);
5176 }
5177
5178 /* End: fp_sqrmod.c */
5179
5180 /* Start: fp_sub.c */
5181 /* TomsFastMath, a fast ISO C bignum library.
5182  *
5183  * This project is meant to fill in where LibTomMath
5184  * falls short.  That is speed ;-)
5185  *
5186  * This project is public domain and free for all purposes.
5187  *
5188  * Tom St Denis, tomstdenis@iahu.ca
5189  */
5190 #include <tfm.h>
5191
5192 /* c = a - b */
5193 void fp_sub(fp_int *a, fp_int *b, fp_int *c)
5194 {
5195   int     sa, sb;
5196
5197   sa = a->sign;
5198   sb = b->sign;
5199
5200   if (sa != sb) {
5201     /* subtract a negative from a positive, OR */
5202     /* subtract a positive from a negative. */
5203     /* In either case, ADD their magnitudes, */
5204     /* and use the sign of the first number. */
5205     c->sign = sa;
5206     s_fp_add (a, b, c);
5207   } else {
5208     /* subtract a positive from a positive, OR */
5209     /* subtract a negative from a negative. */
5210     /* First, take the difference between their */
5211     /* magnitudes, then... */
5212     if (fp_cmp_mag (a, b) != FP_LT) {
5213       /* Copy the sign from the first */
5214       c->sign = sa;
5215       /* The first has a larger or equal magnitude */
5216       s_fp_sub (a, b, c);
5217     } else {
5218       /* The result has the *opposite* sign from */
5219       /* the first number. */
5220       c->sign = (sa == FP_ZPOS) ? FP_NEG : FP_ZPOS;
5221       /* The second has a larger magnitude */
5222       s_fp_sub (b, a, c);
5223     }
5224   }
5225 }
5226
5227
5228 /* End: fp_sub.c */
5229
5230 /* Start: fp_sub_d.c */
5231 /* TomsFastMath, a fast ISO C bignum library.
5232  *
5233  * This project is meant to fill in where LibTomMath
5234  * falls short.  That is speed ;-)
5235  *
5236  * This project is public domain and free for all purposes.
5237  *
5238  * Tom St Denis, tomstdenis@iahu.ca
5239  */
5240 #include <tfm.h>
5241
5242 /* c = a - b */
5243 void fp_sub_d(fp_int *a, fp_digit b, fp_int *c)
5244 {
5245    fp_int tmp;
5246    fp_set(&tmp, b);
5247    fp_sub(a, &tmp, c);
5248 }
5249
5250 /* End: fp_sub_d.c */
5251
5252 /* Start: fp_submod.c */
5253 /* TomsFastMath, a fast ISO C bignum library.
5254  *
5255  * This project is meant to fill in where LibTomMath
5256  * falls short.  That is speed ;-)
5257  *
5258  * This project is public domain and free for all purposes.
5259  *
5260  * Tom St Denis, tomstdenis@iahu.ca
5261  */
5262 #include <tfm.h>
5263
5264 /* d = a - b (mod c) */
5265 int fp_submod(fp_int *a, fp_int *b, fp_int *c, fp_int *d)
5266 {
5267   fp_int tmp;
5268   fp_zero(&tmp);
5269   fp_sub(a, b, &tmp);
5270   return fp_mod(&tmp, c, d);
5271 }
5272
5273
5274 /* End: fp_submod.c */
5275
5276 /* Start: fp_to_signed_bin.c */
5277 /* TomsFastMath, a fast ISO C bignum library.
5278  *
5279  * This project is meant to fill in where LibTomMath
5280  * falls short.  That is speed ;-)
5281  *
5282  * This project is public domain and free for all purposes.
5283  *
5284  * Tom St Denis, tomstdenis@iahu.ca
5285  */
5286 #include <tfm.h>
5287
5288 void fp_to_signed_bin(fp_int *a, unsigned char *b)
5289 {
5290   fp_to_unsigned_bin (a, b + 1);
5291   b[0] = (unsigned char) ((a->sign == FP_ZPOS) ? 0 : 1);
5292 }
5293
5294 /* End: fp_to_signed_bin.c */
5295
5296 /* Start: fp_to_unsigned_bin.c */
5297 /* TomsFastMath, a fast ISO C bignum library.
5298  *
5299  * This project is meant to fill in where LibTomMath
5300  * falls short.  That is speed ;-)
5301  *
5302  * This project is public domain and free for all purposes.
5303  *
5304  * Tom St Denis, tomstdenis@iahu.ca
5305  */
5306 #include <tfm.h>
5307
5308 void fp_to_unsigned_bin(fp_int *a, unsigned char *b)
5309 {
5310   int     x;
5311   fp_int  t;
5312
5313   fp_init_copy(&t, a);
5314
5315   x = 0;
5316   while (fp_iszero (&t) == FP_NO) {
5317       b[x++] = (unsigned char) (t.dp[0] & 255);
5318       fp_div_2d (&t, 8, &t, NULL);
5319   }
5320   bn_reverse (b, x);
5321 }
5322
5323 /* End: fp_to_unsigned_bin.c */
5324
5325 /* Start: fp_toradix.c */
5326 /* TomsFastMath, a fast ISO C bignum library.
5327  *
5328  * This project is meant to fill in where LibTomMath
5329  * falls short.  That is speed ;-)
5330  *
5331  * This project is public domain and free for all purposes.
5332  *
5333  * Tom St Denis, tomstdenis@iahu.ca
5334  */
5335 #include <tfm.h>
5336
5337 int fp_toradix(fp_int *a, char *str, int radix)
5338 {
5339   int     digs;
5340   fp_int  t;
5341   fp_digit d;
5342   char   *_s = str;
5343
5344   /* check range of the radix */
5345   if (radix < 2 || radix > 64) {
5346     return FP_VAL;
5347   }
5348
5349   /* quick out if its zero */
5350   if (fp_iszero(a) == 1) {
5351      *str++ = '0';
5352      *str = '\0';
5353      return FP_OKAY;
5354   }
5355
5356   fp_init_copy(&t, a);
5357
5358   /* if it is negative output a - */
5359   if (t.sign == FP_NEG) {
5360     ++_s;
5361     *str++ = '-';
5362     t.sign = FP_ZPOS;
5363   }
5364
5365   digs = 0;
5366   while (fp_iszero (&t) == FP_NO) {
5367     fp_div_d (&t, (fp_digit) radix, &t, &d);
5368     *str++ = fp_s_rmap[d];
5369     ++digs;
5370   }
5371
5372   /* reverse the digits of the string.  In this case _s points
5373    * to the first digit [exluding the sign] of the number]
5374    */
5375   bn_reverse ((unsigned char *)_s, digs);
5376
5377   /* append a NULL so the string is properly terminated */
5378   *str = '\0';
5379   return FP_OKAY;
5380 }
5381
5382 /* End: fp_toradix.c */
5383
5384 /* Start: fp_unsigned_bin_size.c */
5385 /* TomsFastMath, a fast ISO C bignum library.
5386  *
5387  * This project is meant to fill in where LibTomMath
5388  * falls short.  That is speed ;-)
5389  *
5390  * This project is public domain and free for all purposes.
5391  *
5392  * Tom St Denis, tomstdenis@iahu.ca
5393  */
5394 #include <tfm.h>
5395
5396 int fp_unsigned_bin_size(fp_int *a)
5397 {
5398   int     size = fp_count_bits (a);
5399   return (size / 8 + ((size & 7) != 0 ? 1 : 0));
5400 }
5401
5402 /* End: fp_unsigned_bin_size.c */
5403
5404 /* Start: s_fp_add.c */
5405 /* TomsFastMath, a fast ISO C bignum library.
5406  *
5407  * This project is meant to fill in where LibTomMath
5408  * falls short.  That is speed ;-)
5409  *
5410  * This project is public domain and free for all purposes.
5411  *
5412  * Tom St Denis, tomstdenis@iahu.ca
5413  */
5414 #include <tfm.h>
5415
5416 /* unsigned addition */
5417 void s_fp_add(fp_int *a, fp_int *b, fp_int *c)
5418 {
5419   int      x, y, oldused;
5420   fp_word  t;
5421
5422   y       = MAX(a->used, b->used);
5423   oldused = c->used;
5424   c->used = y;
5425
5426   t = 0;
5427   for (x = 0; x < y; x++) {
5428       t         += ((fp_word)a->dp[x]) + ((fp_word)b->dp[x]);
5429       c->dp[x]   = (fp_digit)t;
5430       t        >>= DIGIT_BIT;
5431   }
5432   if (t != 0 && x != FP_SIZE) {
5433      c->dp[c->used++] = (fp_digit)t;
5434      ++x;
5435   }
5436
5437   for (; x < oldused; x++) {
5438      c->dp[x] = 0;
5439   }
5440   fp_clamp(c);
5441 }
5442
5443 /* End: s_fp_add.c */
5444
5445 /* Start: s_fp_sub.c */
5446 /* TomsFastMath, a fast ISO C bignum library.
5447  *
5448  * This project is meant to fill in where LibTomMath
5449  * falls short.  That is speed ;-)
5450  *
5451  * This project is public domain and free for all purposes.
5452  *
5453  * Tom St Denis, tomstdenis@iahu.ca
5454  */
5455 #include <tfm.h>
5456
5457 /* unsigned subtraction ||a|| >= ||b|| ALWAYS! */
5458 void s_fp_sub(fp_int *a, fp_int *b, fp_int *c)
5459 {
5460   int      x, oldused;
5461   fp_word  t;
5462
5463   oldused = c->used;
5464   c->used = a->used;
5465   t       = 0;
5466   for (x = 0; x < a->used; x++) {
5467       t         = ((fp_word)a->dp[x]) - (((fp_word)b->dp[x]) + t);
5468       c->dp[x]  = (fp_digit)t;
5469       t         = (t >> DIGIT_BIT) & 1;
5470   }
5471
5472   for (; x < oldused; x++) {
5473      c->dp[x] = 0;
5474   }
5475   fp_clamp(c);
5476 }
5477
5478 /* End: s_fp_sub.c */
5479
5480
5481 /* EOF */