From 4b439169aa92694e5a15e8da6ab675ed03a17de4 Mon Sep 17 00:00:00 2001 From: Tom St Denis Date: Thu, 6 Apr 2006 19:49:03 +0000 Subject: [PATCH] added tomsfastmath-0.09 --- changes.txt | 10 + demo/test.c | 2 +- doc/tfm.pdf | Bin 125056 -> 123719 bytes fp_exptmod.c | 4 +- fp_montgomery_reduce.c | 837 +++++++------- fp_mul.c | 115 +- fp_mul_comba.c | 652 ++++++++++- fp_sqr.c | 95 +- fp_sqr_comba.c | 776 ++++++++++++- makefile | 10 +- makefile.shared | 11 +- pre_gen/mpi.c | 2479 ++++++++++++++++++++++++++++++---------- tfm.dvi | Bin 51616 -> 51612 bytes tfm.h | 27 +- tfm.log | 18 +- tfm.tex | 2 +- 16 files changed, 3868 insertions(+), 1170 deletions(-) diff --git a/changes.txt b/changes.txt index eca86d4..0ec3dbc 100644 --- a/changes.txt +++ b/changes.txt @@ -1,3 +1,13 @@ +April 4th, 2006 +0.09 -- Bruce Guenter suggested I use --tag=CC for libtool builds where the compiler may think it's C++. + -- Added support for k=1 in exptmod for RSA exponents. Makes it more competitive with other libraries + -- added cutoffs to the comba32 sqr/mul code to better handle 640, 786 and 896 bit operands (e.g. for RSA-1280, RSA-1536 and RSA-1792), really no effect + for 64-bit boxes as these represent 1280, 1536 and 1792 bit operands (not likely to be invoked). + -- Removed karatsuba from the mul/sqr since they're not useful and slow. + -- added 20, 24 and 28 digit multipliers for oddsized RSA support. You can easily disable them by uncommenting the TFM_SQRXX and TFM_MULXX lines in + tfm.h to save space. Now GMP and TFM are roughly the same speed on the Pentium-M for RSA with LTC. + -- unrolled SSE2 code and optimize for platforms with load/store pipes (e.g. can store and load in a cycle). Got 4% or so boost on my Dothan laptop (marginal improvement on a P4 Prescott) + Jan 26th, 2006 0.08 -- Fixed a bug in the generic mult/sqr where we overflowed by one digit diff --git a/demo/test.c b/demo/test.c index e8f89ff..28c84d1 100644 --- a/demo/test.c +++ b/demo/test.c @@ -213,7 +213,7 @@ t1 = TIMFUNC(); sleep(1); printf("Ticks per second: %llu\n", TIMFUNC() - t1); -goto multtime; +goto monttime; /* do some timings... */ printf("Addition:\n"); for (t = 2; t <= FP_SIZE/2; t += 2) { diff --git a/doc/tfm.pdf b/doc/tfm.pdf index 9abc1189433e11bdf196e0c23eb39587c9b127ab..c643a5008afecff45a580b8952a2710e3dc345d6 100644 GIT binary patch literal 123719 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 z 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ÓJ*f&?o6Ko(5+&mRfx!|bo}(6vSiSv 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 SuZKG~CXJ-5tUFJS^nU - -/******************************************************************/ -#if defined(TFM_X86) -/* x86-32 code */ - -#define MONT_START -#define MONT_FINI -#define LOOP_END -#define LOOP_START \ - mu = c[x] * mp - -#define INNERMUL \ -asm( \ - "movl %5,%%eax \n\t" \ - "mull %4 \n\t" \ - "addl %1,%%eax \n\t" \ - "adcl $0,%%edx \n\t" \ - "addl %%eax,%0 \n\t" \ - "adcl $0,%%edx \n\t" \ - "movl %%edx,%1 \n\t" \ -:"=g"(_c[LO]), "=r"(cy) \ -:"0"(_c[LO]), "1"(cy), "g"(mu), "g"(*tmpm++) \ -: "%eax", "%edx", "%cc") - -#define PROPCARRY \ -asm( \ - "addl %1,%0 \n\t" \ - "setb %%al \n\t" \ - "movzbl %%al,%1 \n\t" \ -:"=g"(_c[LO]), "=r"(cy) \ -:"0"(_c[LO]), "1"(cy) \ -: "%eax", "%cc") - -/******************************************************************/ -#elif defined(TFM_X86_64) -/* x86-64 code */ - -#define MONT_START -#define MONT_FINI -#define LOOP_END -#define LOOP_START \ - mu = c[x] * mp - -#define INNERMUL \ -asm( \ - "movq %5,%%rax \n\t" \ - "mulq %4 \n\t" \ - "addq %1,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "addq %%rax,%0 \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rdx,%1 \n\t" \ -:"=g"(_c[LO]), "=r"(cy) \ -:"0"(_c[LO]), "1"(cy), "r"(mu), "r"(*tmpm++) \ -: "%rax", "%rdx", "%cc") - -#ifdef TFM_HUGE - -#define INNERMUL8 \ - asm( \ - "movq 0(%5),%%rax \n\t" \ - "movq 0(%2),%%r10 \n\t" \ - "movq 0x8(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x8(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x10(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x10(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x8(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x18(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x18(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x10(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x20(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x20(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x18(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x28(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x28(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x20(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x30(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x30(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x28(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x38(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x38(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x30(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x38(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ -:"=r"(_c), "=r"(cy) \ -: "0"(_c), "1"(cy), "g"(mu), "r"(tmpm)\ -: "%rax", "%rdx", "%r10", "%r11", "%cc") - -#endif - - -#define PROPCARRY \ -asm( \ - "addq %1,%0 \n\t" \ - "setb %%al \n\t" \ - "movzbq %%al,%1 \n\t" \ -:"=g"(_c[LO]), "=r"(cy) \ -:"0"(_c[LO]), "1"(cy) \ -: "%rax", "%cc") - -/******************************************************************/ -#elif defined(TFM_SSE2) -/* SSE2 code (assumes 32-bit fp_digits) */ -/* XMM register assignments: - * xmm0 *tmpm++, then Mu * (*tmpm++) - * xmm1 c[x], then Mu - * xmm2 mp - * xmm3 cy - * xmm4 _c[LO] - */ - -#define MONT_START \ - asm("movd %0,%%mm2"::"g"(mp)) - -#define MONT_FINI \ - asm("emms") - -#define LOOP_START \ -asm( \ -"movd %0,%%mm1 \n\t" \ -"pxor %%mm3,%%mm3 \n\t" \ -"pmuludq %%mm2,%%mm1 \n\t" \ -:: "g"(c[x])) - -/* pmuludq on mmx registers does a 32x32->64 multiply. */ -#define INNERMUL \ -asm( \ - "movd %1,%%mm4 \n\t" \ - "movd %2,%%mm0 \n\t" \ - "paddq %%mm4,%%mm3 \n\t" \ - "pmuludq %%mm1,%%mm0 \n\t" \ - "paddq %%mm0,%%mm3 \n\t" \ - "movd %%mm3,%0 \n\t" \ - "psrlq $32, %%mm3 \n\t" \ -:"=g"(_c[LO]) : "0"(_c[LO]), "g"(*tmpm++) ); - -#define LOOP_END \ -asm( "movd %%mm3,%0 \n" :"=r"(cy)) - -#define PROPCARRY \ -asm( \ - "addl %1,%0 \n\t" \ - "setb %%al \n\t" \ - "movzbl %%al,%1 \n\t" \ -:"=g"(_c[LO]), "=r"(cy) \ -:"0"(_c[LO]), "1"(cy) \ -: "%eax", "%cc") - -/******************************************************************/ -#elif defined(TFM_ARM) - /* ARMv4 code */ - -#define MONT_START -#define MONT_FINI -#define LOOP_END -#define LOOP_START \ - mu = c[x] * mp - -#define INNERMUL \ -asm( \ - " LDR r0,%1 \n\t" \ - " ADDS r0,r0,%0 \n\t" \ - " MOVCS %0,#1 \n\t" \ - " MOVCC %0,#0 \n\t" \ - " UMLAL r0,%0,%3,%4 \n\t" \ - " STR r0,%1 \n\t" \ -:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(*tmpm++),"1"(_c[0]):"r0","%cc"); - -#define PROPCARRY \ -asm( \ - " LDR r0,%1 \n\t" \ - " ADDS r0,r0,%0 \n\t" \ - " STR r0,%1 \n\t" \ - " MOVCS %0,#1 \n\t" \ - " MOVCC %0,#0 \n\t" \ -:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"r0","%cc"); - -#elif defined(TFM_PPC32) - -/* PPC32 */ -#define MONT_START -#define MONT_FINI -#define LOOP_END -#define LOOP_START \ - mu = c[x] * mp - -#define INNERMUL \ -asm( \ - " mullw 16,%3,%4 \n\t" \ - " mulhwu 17,%3,%4 \n\t" \ - " addc 16,16,%0 \n\t" \ - " addze 17,17 \n\t" \ - " lwz 18,%1 \n\t" \ - " addc 16,16,18 \n\t" \ - " addze %0,17 \n\t" \ - " stw 16,%1 \n\t" \ -:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "18","%cc"); ++tmpm; - -#define PROPCARRY \ -asm( \ - " lwz 16,%1 \n\t" \ - " addc 16,16,%0 \n\t" \ - " stw 16,%1 \n\t" \ - " xor %0,%0,%0 \n\t" \ - " addze %0,%0 \n\t" \ -:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"16","%cc"); - -/******************************************************************/ -#else - -/* ISO C code */ -#define MONT_START -#define MONT_FINI -#define LOOP_END -#define LOOP_START \ - mu = c[x] * mp - -#define INNERMUL \ - do { fp_word t; \ - _c[0] = t = ((fp_word)_c[0] + (fp_word)cy) + \ - (((fp_word)mu) * ((fp_word)*tmpm++)); \ - cy = (t >> DIGIT_BIT); \ - } while (0) - -#define PROPCARRY \ - do { fp_digit t = _c[0] += cy; cy = (t < cy); } while (0) - -#endif -/******************************************************************/ - - -#define LO 0 - -/* computes x/R == x (mod N) via Montgomery Reduction */ -void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) -{ - fp_digit c[FP_SIZE], *_c, *tmpm, mu; - int oldused, x, y, pa; - - /* bail if too large */ - if (m->used > (FP_SIZE/2)) { - return; - } - -#if defined(USE_MEMSET) - /* now zero the buff */ - memset(c, 0, sizeof c); -#endif - pa = m->used; - - /* copy the input */ - oldused = a->used; - for (x = 0; x < oldused; x++) { - c[x] = a->dp[x]; - } -#if !defined(USE_MEMSET) - for (; x < 2*pa+3; x++) { - c[x] = 0; - } -#endif - MONT_START; - - for (x = 0; x < pa; x++) { - fp_digit cy = 0; - /* get Mu for this round */ - LOOP_START; - _c = c + x; - tmpm = m->dp; - y = 0; - #if defined(TFM_X86_64) && defined(TFM_HUGE) - for (; y < (pa & ~7); y += 8) { - INNERMUL8; - _c += 8; - tmpm += 8; - } - #endif - - for (; y < pa; y++) { - INNERMUL; - ++_c; - } - LOOP_END; - while (cy) { - PROPCARRY; - ++_c; - } - } - - /* now copy out */ - _c = c + pa; - tmpm = a->dp; - for (x = 0; x < pa+1; x++) { - *tmpm++ = *_c++; - } - - for (; x < oldused; x++) { - *tmpm++ = 0; - } - - MONT_FINI; - - a->used = pa+1; - fp_clamp(a); - - /* if A >= m then A = A - m */ - if (fp_cmp_mag (a, m) != FP_LT) { - s_fp_sub (a, m, a); - } -} - - -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* TomsFastMath, a fast ISO C bignum library. + * + * This project is meant to fill in where LibTomMath + * falls short. That is speed ;-) + * + * This project is public domain and free for all purposes. + * + * Tom St Denis, tomstdenis@gmail.com + */ +#include + +/******************************************************************/ +#if defined(TFM_X86) && !defined(TFM_SSE2) +/* x86-32 code */ + +#define MONT_START +#define MONT_FINI +#define LOOP_END +#define LOOP_START \ + mu = c[x] * mp + +#define INNERMUL \ +asm( \ + "movl %5,%%eax \n\t" \ + "mull %4 \n\t" \ + "addl %1,%%eax \n\t" \ + "adcl $0,%%edx \n\t" \ + "addl %%eax,%0 \n\t" \ + "adcl $0,%%edx \n\t" \ + "movl %%edx,%1 \n\t" \ +:"=g"(_c[LO]), "=r"(cy) \ +:"0"(_c[LO]), "1"(cy), "g"(mu), "g"(*tmpm++) \ +: "%eax", "%edx", "%cc") + +#define PROPCARRY \ +asm( \ + "addl %1,%0 \n\t" \ + "setb %%al \n\t" \ + "movzbl %%al,%1 \n\t" \ +:"=g"(_c[LO]), "=r"(cy) \ +:"0"(_c[LO]), "1"(cy) \ +: "%eax", "%cc") + +/******************************************************************/ +#elif defined(TFM_X86_64) +/* x86-64 code */ + +#define MONT_START +#define MONT_FINI +#define LOOP_END +#define LOOP_START \ + mu = c[x] * mp + +#define INNERMUL \ +asm( \ + "movq %5,%%rax \n\t" \ + "mulq %4 \n\t" \ + "addq %1,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "addq %%rax,%0 \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rdx,%1 \n\t" \ +:"=g"(_c[LO]), "=r"(cy) \ +:"0"(_c[LO]), "1"(cy), "r"(mu), "r"(*tmpm++) \ +: "%rax", "%rdx", "%cc") + +#define INNERMUL8 \ + asm( \ + "movq 0(%5),%%rax \n\t" \ + "movq 0(%2),%%r10 \n\t" \ + "movq 0x8(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x8(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x10(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x10(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x8(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x18(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x18(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x10(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x20(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x20(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x18(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x28(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x28(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x20(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x30(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x30(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x28(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x38(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x38(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x30(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x38(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ +:"=r"(_c), "=r"(cy) \ +: "0"(_c), "1"(cy), "g"(mu), "r"(tmpm)\ +: "%rax", "%rdx", "%r10", "%r11", "%cc") + + +#define PROPCARRY \ +asm( \ + "addq %1,%0 \n\t" \ + "setb %%al \n\t" \ + "movzbq %%al,%1 \n\t" \ +:"=g"(_c[LO]), "=r"(cy) \ +:"0"(_c[LO]), "1"(cy) \ +: "%rax", "%cc") + +/******************************************************************/ +#elif defined(TFM_SSE2) +/* SSE2 code (assumes 32-bit fp_digits) */ +/* XMM register assignments: + * xmm0 *tmpm++, then Mu * (*tmpm++) + * xmm1 c[x], then Mu + * xmm2 mp + * xmm3 cy + * xmm4 _c[LO] + */ + +#define MONT_START \ + asm("movd %0,%%mm2"::"g"(mp)) + +#define MONT_FINI \ + asm("emms") + +#define LOOP_START \ +asm( \ +"movd %0,%%mm1 \n\t" \ +"pxor %%mm3,%%mm3 \n\t" \ +"pmuludq %%mm2,%%mm1 \n\t" \ +:: "g"(c[x])) + +/* pmuludq on mmx registers does a 32x32->64 multiply. */ +#define INNERMUL \ +asm( \ + "movd %1,%%mm4 \n\t" \ + "movd %2,%%mm0 \n\t" \ + "paddq %%mm4,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm0 \n\t" \ + "paddq %%mm0,%%mm3 \n\t" \ + "movd %%mm3,%0 \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +:"=g"(_c[LO]) : "0"(_c[LO]), "g"(*tmpm++) ); + +#define INNERMUL8 \ +asm( \ + "movd 0(%1),%%mm4 \n\t" \ + "movd 0(%2),%%mm0 \n\t" \ + "paddq %%mm4,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm0 \n\t" \ + "movd 4(%2),%%mm5 \n\t" \ + "paddq %%mm0,%%mm3 \n\t" \ + "movd 4(%1),%%mm6 \n\t" \ + "movd %%mm3,0(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm6,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm5 \n\t" \ + "movd 8(%2),%%mm6 \n\t" \ + "paddq %%mm5,%%mm3 \n\t" \ + "movd 8(%1),%%mm7 \n\t" \ + "movd %%mm3,4(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm7,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm6 \n\t" \ + "movd 12(%2),%%mm7 \n\t" \ + "paddq %%mm6,%%mm3 \n\t" \ + "movd 12(%1),%%mm5 \n\t" \ + "movd %%mm3,8(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm5,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm7 \n\t" \ + "movd 16(%2),%%mm5 \n\t" \ + "paddq %%mm7,%%mm3 \n\t" \ + "movd 16(%1),%%mm6 \n\t" \ + "movd %%mm3,12(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm6,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm5 \n\t" \ + "movd 20(%2),%%mm6 \n\t" \ + "paddq %%mm5,%%mm3 \n\t" \ + "movd 20(%1),%%mm7 \n\t" \ + "movd %%mm3,16(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm7,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm6 \n\t" \ + "movd 24(%2),%%mm7 \n\t" \ + "paddq %%mm6,%%mm3 \n\t" \ + "movd 24(%1),%%mm5 \n\t" \ + "movd %%mm3,20(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm5,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm7 \n\t" \ + "movd 28(%2),%%mm5 \n\t" \ + "paddq %%mm7,%%mm3 \n\t" \ + "movd 28(%1),%%mm6 \n\t" \ + "movd %%mm3,24(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm6,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm5 \n\t" \ + "paddq %%mm5,%%mm3 \n\t" \ + "movd %%mm3,28(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +:"=r"(_c) : "0"(_c), "g"(tmpm) ); + +#define LOOP_END \ +asm( "movd %%mm3,%0 \n" :"=r"(cy)) + +#define PROPCARRY \ +asm( \ + "addl %1,%0 \n\t" \ + "setb %%al \n\t" \ + "movzbl %%al,%1 \n\t" \ +:"=g"(_c[LO]), "=r"(cy) \ +:"0"(_c[LO]), "1"(cy) \ +: "%eax", "%cc") + +/******************************************************************/ +#elif defined(TFM_ARM) + /* ARMv4 code */ + +#define MONT_START +#define MONT_FINI +#define LOOP_END +#define LOOP_START \ + mu = c[x] * mp + +#define INNERMUL \ +asm( \ + " LDR r0,%1 \n\t" \ + " ADDS r0,r0,%0 \n\t" \ + " MOVCS %0,#1 \n\t" \ + " MOVCC %0,#0 \n\t" \ + " UMLAL r0,%0,%3,%4 \n\t" \ + " STR r0,%1 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(*tmpm++),"1"(_c[0]):"r0","%cc"); + +#define PROPCARRY \ +asm( \ + " LDR r0,%1 \n\t" \ + " ADDS r0,r0,%0 \n\t" \ + " STR r0,%1 \n\t" \ + " MOVCS %0,#1 \n\t" \ + " MOVCC %0,#0 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"r0","%cc"); + +#elif defined(TFM_PPC32) + +/* PPC32 */ +#define MONT_START +#define MONT_FINI +#define LOOP_END +#define LOOP_START \ + mu = c[x] * mp + +#define INNERMUL \ +asm( \ + " mullw 16,%3,%4 \n\t" \ + " mulhwu 17,%3,%4 \n\t" \ + " addc 16,16,%0 \n\t" \ + " addze 17,17 \n\t" \ + " lwz 18,%1 \n\t" \ + " addc 16,16,18 \n\t" \ + " addze %0,17 \n\t" \ + " stw 16,%1 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "18","%cc"); ++tmpm; + +#define PROPCARRY \ +asm( \ + " lwz 16,%1 \n\t" \ + " addc 16,16,%0 \n\t" \ + " stw 16,%1 \n\t" \ + " xor %0,%0,%0 \n\t" \ + " addze %0,%0 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"16","%cc"); + +/******************************************************************/ +#else + +/* ISO C code */ +#define MONT_START +#define MONT_FINI +#define LOOP_END +#define LOOP_START \ + mu = c[x] * mp + +#define INNERMUL \ + do { fp_word t; \ + _c[0] = t = ((fp_word)_c[0] + (fp_word)cy) + \ + (((fp_word)mu) * ((fp_word)*tmpm++)); \ + cy = (t >> DIGIT_BIT); \ + } while (0) + +#define PROPCARRY \ + do { fp_digit t = _c[0] += cy; cy = (t < cy); } while (0) + +#endif +/******************************************************************/ + + +#define LO 0 + +/* computes x/R == x (mod N) via Montgomery Reduction */ +void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) +{ + fp_digit c[FP_SIZE], *_c, *tmpm, mu; + int oldused, x, y, pa; + + /* bail if too large */ + if (m->used > (FP_SIZE/2)) { + return; + } + +#if defined(USE_MEMSET) + /* now zero the buff */ + memset(c, 0, sizeof c); +#endif + pa = m->used; + + /* copy the input */ + oldused = a->used; + for (x = 0; x < oldused; x++) { + c[x] = a->dp[x]; + } +#if !defined(USE_MEMSET) + for (; x < 2*pa+3; x++) { + c[x] = 0; + } +#endif + MONT_START; + + for (x = 0; x < pa; x++) { + fp_digit cy = 0; + /* get Mu for this round */ + LOOP_START; + _c = c + x; + tmpm = m->dp; + y = 0; + #if (defined(TFM_SSE2) || defined(TFM_X86_64)) + for (; y < (pa & ~7); y += 8) { + INNERMUL8; + _c += 8; + tmpm += 8; + } + #endif + + for (; y < pa; y++) { + INNERMUL; + ++_c; + } + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + } + + /* now copy out */ + _c = c + pa; + tmpm = a->dp; + for (x = 0; x < pa+1; x++) { + *tmpm++ = *_c++; + } + + for (; x < oldused; x++) { + *tmpm++ = 0; + } + + MONT_FINI; + + a->used = pa+1; + fp_clamp(a); + + /* if A >= m then A = A - m */ + if (fp_cmp_mag (a, m) != FP_LT) { + s_fp_sub (a, m, a); + } +} + + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ diff --git a/fp_mul.c b/fp_mul.c index 79d52c1..81ec7bf 100644 --- a/fp_mul.c +++ b/fp_mul.c @@ -12,8 +12,7 @@ /* c = a * b */ void fp_mul(fp_int *A, fp_int *B, fp_int *C) { - int r, y, yy, s; - fp_int ac, bd, comp, amb, cmd, t1, t2; + int y, yy; /* call generic if we're out of range */ if (A->used + B->used > FP_SIZE) { @@ -23,8 +22,6 @@ void fp_mul(fp_int *A, fp_int *B, fp_int *C) y = MAX(A->used, B->used); yy = MIN(A->used, B->used); - if (yy <= 8 || y <= 64) { - /* pick a comba (unrolled 4/8/16/32 x or rolled) based on the size of the largest input. We also want to avoid doing excess mults if the inputs are not close to the next power of two. That is, for example, @@ -37,6 +34,24 @@ void fp_mul(fp_int *A, fp_int *B, fp_int *C) return; } #endif +#if defined(TFM_MUL20) + if (y <= 20) { + fp_mul_comba20(A,B,C); + return; + } +#endif +#if defined(TFM_MUL24) + if (yy >= 16 && y <= 24) { + fp_mul_comba24(A,B,C); + return; + } +#endif +#if defined(TFM_MUL28) + if (yy >= 20 && y <= 28) { + fp_mul_comba28(A,B,C); + return; + } +#endif #if defined(TFM_MUL32) if (yy >= 24 && y <= 32) { fp_mul_comba32(A,B,C); @@ -56,98 +71,6 @@ void fp_mul(fp_int *A, fp_int *B, fp_int *C) } #endif fp_mul_comba(A,B,C); - } else { - /* do the karatsuba action - - if A = ab and B = cd for ||a|| = r we need to solve - - ac*r^2 + ((a+b)(c+d) - (ac + bd))*r + bd - - So we solve for the three products then we form the final result with careful shifting - and addition. - -Obvious points of optimization - -- "ac" parts can be memcpy'ed with an offset [all you have to do is zero upto the next 8 digits] -- Similarly the "bd" parts can be memcpy'ed and zeroed to 8 -- - - */ - /* get our value of r */ - r = yy >> 1; - - /* now solve for ac */ -// fp_copy(A, &t1); fp_rshd(&t1, r); - for (s = 0; s < A->used - r; s++) { - t1.dp[s] = A->dp[s+r]; - } - for (; s < FP_SIZE; s++) { - t1.dp[s] = 0; - } - if (A->used >= r) { - t1.used = A->used - r; - } else { - t1.used = 0; - } - t1.sign = 0; - -// fp_copy(B, &t2); fp_rshd(&t2, r); - for (s = 0; s < B->used - r; s++) { - t2.dp[s] = B->dp[s+r]; - } - for (; s < FP_SIZE; s++) { - t2.dp[s] = 0; - } - if (B->used >= r) { - t2.used = B->used - r; - } else { - t2.used = 0; - } - t2.sign = 0; - - fp_copy(&t1, &amb); fp_copy(&t2, &cmd); - fp_zero(&ac); - fp_mul(&t1, &t2, &ac); - - /* now solve for bd */ -// fp_mod_2d(A, r * DIGIT_BIT, &t1); -// fp_mod_2d(B, r * DIGIT_BIT, &t2); - for (s = 0; s < r; s++) { - t1.dp[s] = A->dp[s]; - t2.dp[s] = B->dp[s]; - } - for (; s < FP_SIZE; s++) { - t1.dp[s] = 0; - t2.dp[s] = 0; - } - t1.used = r; - t2.used = r; - fp_clamp(&t1); - fp_clamp(&t2); - - s_fp_add(&amb, &t1, &amb); s_fp_add(&cmd, &t2, &cmd); - fp_zero(&bd); - fp_mul(&t1, &t2, &bd); - - /* now get the (a+b)(c+d) term */ - fp_zero(&comp); - fp_mul(&amb, &cmd, &comp); - - /* now solve the system, do the middle term first */ - s_fp_sub(&comp, &ac, &comp); - s_fp_sub(&comp, &bd, &comp); - fp_lshd(&comp, r); - - /* leading term */ - fp_lshd(&ac, r+r); - - /* now sum them together */ - s = A->sign ^ B->sign; - fp_zero(C); - fp_add(&ac, &comp, C); - fp_add(&bd, C, C); - C->sign = C->used ? s : FP_ZPOS; - } } diff --git a/fp_mul_comba.c b/fp_mul_comba.c index 4b572b6..e86589b 100644 --- a/fp_mul_comba.c +++ b/fp_mul_comba.c @@ -117,18 +117,18 @@ asm ( \ asm("emms"); /* this should multiply i and j */ - #define MULADD(i, j) \ - asm( \ - "movd %6,%%mm0 \n\t" \ - "movd %7,%%mm1 \n\t" \ - "pmuludq %%mm1,%%mm0\n\t" \ - "movd %%mm0,%%eax \n\t" \ - "psrlq $32,%%mm0 \n\t" \ - "addl %%eax,%0 \n\t" \ - "movd %%mm0,%%eax \n\t" \ - "adcl %%eax,%1 \n\t" \ - "adcl $0,%2 \n\t" \ - :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%cc"); +#define MULADD(i, j) \ +asm( \ + "movd %6,%%mm0 \n\t" \ + "movd %7,%%mm1 \n\t" \ + "pmuludq %%mm1,%%mm0\n\t" \ + "movd %%mm0,%%eax \n\t" \ + "psrlq $32,%%mm0 \n\t" \ + "addl %%eax,%0 \n\t" \ + "movd %%mm0,%%eax \n\t" \ + "adcl %%eax,%1 \n\t" \ + "adcl $0,%2 \n\t" \ + :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%cc"); #elif defined(TFM_ARM) /* ARM code */ @@ -1499,7 +1499,9 @@ void fp_mul_comba_small(fp_int *A, fp_int *B, fp_int *C) void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C) { fp_digit c0, c1, c2, at[64]; + int out_size; + out_size = A->used + B->used; memcpy(at, A->dp, 32 * sizeof(fp_digit)); memcpy(at+32, B->dp, 32 * sizeof(fp_digit)); COMBA_START; @@ -1660,6 +1662,10 @@ void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C) COMBA_FORWARD; 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]); COMBA_STORE(C->dp[38]); + + /* early out at 40 digits, 40*32==1280, or two 640 bit operands */ + if (out_size <= 40) { COMBA_STORE2(C->dp[39]); C->used = 40; C->sign = A->sign ^ B->sign; fp_clamp(C); COMBA_FINI; return; } + /* 39 */ COMBA_FORWARD; 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]); @@ -1692,6 +1698,10 @@ void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C) COMBA_FORWARD; 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]); COMBA_STORE(C->dp[46]); + + /* early out at 48 digits, 48*32==1536, or two 768 bit operands */ + if (out_size <= 48) { COMBA_STORE2(C->dp[47]); C->used = 48; C->sign = A->sign ^ B->sign; fp_clamp(C); COMBA_FINI; return; } + /* 47 */ COMBA_FORWARD; 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]); @@ -1724,6 +1734,10 @@ void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C) COMBA_FORWARD; 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]); COMBA_STORE(C->dp[54]); + + /* early out at 56 digits, 56*32==1792, or two 896 bit operands */ + if (out_size <= 56) { COMBA_STORE2(C->dp[55]); C->used = 56; C->sign = A->sign ^ B->sign; fp_clamp(C); COMBA_FINI; return; } + /* 55 */ COMBA_FORWARD; 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]); @@ -2686,7 +2700,621 @@ void fp_mul_comba48(fp_int *A, fp_int *B, fp_int *C) } #endif +#ifdef TFM_MUL20 +void fp_mul_comba20(fp_int *A, fp_int *B, fp_int *C) +{ + fp_digit c0, c1, c2, at[40]; + + memcpy(at, A->dp, 20 * sizeof(fp_digit)); + memcpy(at+20, B->dp, 20 * sizeof(fp_digit)); + COMBA_START; + COMBA_CLEAR; + /* 0 */ + MULADD(at[0], at[20]); + COMBA_STORE(C->dp[0]); + /* 1 */ + COMBA_FORWARD; + MULADD(at[0], at[21]); MULADD(at[1], at[20]); + COMBA_STORE(C->dp[1]); + /* 2 */ + COMBA_FORWARD; + MULADD(at[0], at[22]); MULADD(at[1], at[21]); MULADD(at[2], at[20]); + COMBA_STORE(C->dp[2]); + /* 3 */ + COMBA_FORWARD; + MULADD(at[0], at[23]); MULADD(at[1], at[22]); MULADD(at[2], at[21]); MULADD(at[3], at[20]); + COMBA_STORE(C->dp[3]); + /* 4 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[4]); + /* 5 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[5]); + /* 6 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[6]); + /* 7 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[7]); + /* 8 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[8]); + /* 9 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[9]); + /* 10 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[10]); + /* 11 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[11]); + /* 12 */ + COMBA_FORWARD; + MULADD(at[0], at[32]); 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]); + COMBA_STORE(C->dp[12]); + /* 13 */ + COMBA_FORWARD; + MULADD(at[0], at[33]); MULADD(at[1], at[32]); 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]); + COMBA_STORE(C->dp[13]); + /* 14 */ + COMBA_FORWARD; + MULADD(at[0], at[34]); MULADD(at[1], at[33]); MULADD(at[2], at[32]); 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]); + COMBA_STORE(C->dp[14]); + /* 15 */ + COMBA_FORWARD; + MULADD(at[0], at[35]); MULADD(at[1], at[34]); MULADD(at[2], at[33]); MULADD(at[3], at[32]); 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]); + COMBA_STORE(C->dp[15]); + /* 16 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[20]); + COMBA_STORE(C->dp[16]); + /* 17 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[21]); MULADD(at[17], at[20]); + COMBA_STORE(C->dp[17]); + /* 18 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[22]); MULADD(at[17], at[21]); MULADD(at[18], at[20]); + COMBA_STORE(C->dp[18]); + /* 19 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[23]); MULADD(at[17], at[22]); MULADD(at[18], at[21]); MULADD(at[19], at[20]); + COMBA_STORE(C->dp[19]); + /* 20 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[24]); MULADD(at[17], at[23]); MULADD(at[18], at[22]); MULADD(at[19], at[21]); + COMBA_STORE(C->dp[20]); + /* 21 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[25]); MULADD(at[17], at[24]); MULADD(at[18], at[23]); MULADD(at[19], at[22]); + COMBA_STORE(C->dp[21]); + /* 22 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[26]); MULADD(at[17], at[25]); MULADD(at[18], at[24]); MULADD(at[19], at[23]); + COMBA_STORE(C->dp[22]); + /* 23 */ + COMBA_FORWARD; + 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]); MULADD(at[12], at[31]); MULADD(at[13], at[30]); MULADD(at[14], at[29]); MULADD(at[15], at[28]); MULADD(at[16], at[27]); MULADD(at[17], at[26]); MULADD(at[18], at[25]); MULADD(at[19], at[24]); + COMBA_STORE(C->dp[23]); + /* 24 */ + COMBA_FORWARD; + 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]); MULADD(at[13], at[31]); MULADD(at[14], at[30]); MULADD(at[15], at[29]); MULADD(at[16], at[28]); MULADD(at[17], at[27]); MULADD(at[18], at[26]); MULADD(at[19], at[25]); + COMBA_STORE(C->dp[24]); + /* 25 */ + COMBA_FORWARD; + 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]); MULADD(at[14], at[31]); MULADD(at[15], at[30]); MULADD(at[16], at[29]); MULADD(at[17], at[28]); MULADD(at[18], at[27]); MULADD(at[19], at[26]); + COMBA_STORE(C->dp[25]); + /* 26 */ + COMBA_FORWARD; + 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]); MULADD(at[15], at[31]); MULADD(at[16], at[30]); MULADD(at[17], at[29]); MULADD(at[18], at[28]); MULADD(at[19], at[27]); + COMBA_STORE(C->dp[26]); + /* 27 */ + COMBA_FORWARD; + 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]); MULADD(at[16], at[31]); MULADD(at[17], at[30]); MULADD(at[18], at[29]); MULADD(at[19], at[28]); + COMBA_STORE(C->dp[27]); + /* 28 */ + COMBA_FORWARD; + 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]); MULADD(at[17], at[31]); MULADD(at[18], at[30]); MULADD(at[19], at[29]); + COMBA_STORE(C->dp[28]); + /* 29 */ + COMBA_FORWARD; + 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]); MULADD(at[18], at[31]); MULADD(at[19], at[30]); + COMBA_STORE(C->dp[29]); + /* 30 */ + COMBA_FORWARD; + 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]); MULADD(at[19], at[31]); + COMBA_STORE(C->dp[30]); + /* 31 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[31]); + /* 32 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[32]); + /* 33 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[33]); + /* 34 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[34]); + /* 35 */ + COMBA_FORWARD; + MULADD(at[16], at[39]); MULADD(at[17], at[38]); MULADD(at[18], at[37]); MULADD(at[19], at[36]); + COMBA_STORE(C->dp[35]); + /* 36 */ + COMBA_FORWARD; + MULADD(at[17], at[39]); MULADD(at[18], at[38]); MULADD(at[19], at[37]); + COMBA_STORE(C->dp[36]); + /* 37 */ + COMBA_FORWARD; + MULADD(at[18], at[39]); MULADD(at[19], at[38]); + COMBA_STORE(C->dp[37]); + /* 38 */ + COMBA_FORWARD; + MULADD(at[19], at[39]); + COMBA_STORE(C->dp[38]); + COMBA_STORE2(C->dp[39]); + C->used = 40; + C->sign = A->sign ^ B->sign; + fp_clamp(C); + COMBA_FINI; +} +#endif + +#ifdef TFM_MUL28 +void fp_mul_comba28(fp_int *A, fp_int *B, fp_int *C) +{ + fp_digit c0, c1, c2, at[56]; + + memcpy(at, A->dp, 28 * sizeof(fp_digit)); + memcpy(at+28, B->dp, 28 * sizeof(fp_digit)); + COMBA_START; + + COMBA_CLEAR; + /* 0 */ + MULADD(at[0], at[28]); + COMBA_STORE(C->dp[0]); + /* 1 */ + COMBA_FORWARD; + MULADD(at[0], at[29]); MULADD(at[1], at[28]); + COMBA_STORE(C->dp[1]); + /* 2 */ + COMBA_FORWARD; + MULADD(at[0], at[30]); MULADD(at[1], at[29]); MULADD(at[2], at[28]); + COMBA_STORE(C->dp[2]); + /* 3 */ + COMBA_FORWARD; + MULADD(at[0], at[31]); MULADD(at[1], at[30]); MULADD(at[2], at[29]); MULADD(at[3], at[28]); + COMBA_STORE(C->dp[3]); + /* 4 */ + COMBA_FORWARD; + MULADD(at[0], at[32]); MULADD(at[1], at[31]); MULADD(at[2], at[30]); MULADD(at[3], at[29]); MULADD(at[4], at[28]); + COMBA_STORE(C->dp[4]); + /* 5 */ + COMBA_FORWARD; + MULADD(at[0], at[33]); MULADD(at[1], at[32]); MULADD(at[2], at[31]); MULADD(at[3], at[30]); MULADD(at[4], at[29]); MULADD(at[5], at[28]); + COMBA_STORE(C->dp[5]); + /* 6 */ + COMBA_FORWARD; + MULADD(at[0], at[34]); MULADD(at[1], at[33]); MULADD(at[2], at[32]); MULADD(at[3], at[31]); MULADD(at[4], at[30]); MULADD(at[5], at[29]); MULADD(at[6], at[28]); + COMBA_STORE(C->dp[6]); + /* 7 */ + COMBA_FORWARD; + MULADD(at[0], at[35]); MULADD(at[1], at[34]); MULADD(at[2], at[33]); MULADD(at[3], at[32]); MULADD(at[4], at[31]); MULADD(at[5], at[30]); MULADD(at[6], at[29]); MULADD(at[7], at[28]); + COMBA_STORE(C->dp[7]); + /* 8 */ + COMBA_FORWARD; + 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]); MULADD(at[5], at[31]); MULADD(at[6], at[30]); MULADD(at[7], at[29]); MULADD(at[8], at[28]); + COMBA_STORE(C->dp[8]); + /* 9 */ + COMBA_FORWARD; + 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]); MULADD(at[6], at[31]); MULADD(at[7], at[30]); MULADD(at[8], at[29]); MULADD(at[9], at[28]); + COMBA_STORE(C->dp[9]); + /* 10 */ + COMBA_FORWARD; + 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]); MULADD(at[7], at[31]); MULADD(at[8], at[30]); MULADD(at[9], at[29]); MULADD(at[10], at[28]); + COMBA_STORE(C->dp[10]); + /* 11 */ + COMBA_FORWARD; + 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]); MULADD(at[8], at[31]); MULADD(at[9], at[30]); MULADD(at[10], at[29]); MULADD(at[11], at[28]); + COMBA_STORE(C->dp[11]); + /* 12 */ + COMBA_FORWARD; + 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]); MULADD(at[9], at[31]); MULADD(at[10], at[30]); MULADD(at[11], at[29]); MULADD(at[12], at[28]); + COMBA_STORE(C->dp[12]); + /* 13 */ + COMBA_FORWARD; + 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]); MULADD(at[10], at[31]); MULADD(at[11], at[30]); MULADD(at[12], at[29]); MULADD(at[13], at[28]); + COMBA_STORE(C->dp[13]); + /* 14 */ + COMBA_FORWARD; + 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]); MULADD(at[11], at[31]); MULADD(at[12], at[30]); MULADD(at[13], at[29]); MULADD(at[14], at[28]); + COMBA_STORE(C->dp[14]); + /* 15 */ + COMBA_FORWARD; + 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]); MULADD(at[12], at[31]); MULADD(at[13], at[30]); MULADD(at[14], at[29]); MULADD(at[15], at[28]); + COMBA_STORE(C->dp[15]); + /* 16 */ + COMBA_FORWARD; + 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]); MULADD(at[13], at[31]); MULADD(at[14], at[30]); MULADD(at[15], at[29]); MULADD(at[16], at[28]); + COMBA_STORE(C->dp[16]); + /* 17 */ + COMBA_FORWARD; + 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]); MULADD(at[14], at[31]); MULADD(at[15], at[30]); MULADD(at[16], at[29]); MULADD(at[17], at[28]); + COMBA_STORE(C->dp[17]); + /* 18 */ + COMBA_FORWARD; + 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]); MULADD(at[15], at[31]); MULADD(at[16], at[30]); MULADD(at[17], at[29]); MULADD(at[18], at[28]); + COMBA_STORE(C->dp[18]); + /* 19 */ + COMBA_FORWARD; + 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]); MULADD(at[16], at[31]); MULADD(at[17], at[30]); MULADD(at[18], at[29]); MULADD(at[19], at[28]); + COMBA_STORE(C->dp[19]); + /* 20 */ + COMBA_FORWARD; + 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]); MULADD(at[17], at[31]); MULADD(at[18], at[30]); MULADD(at[19], at[29]); MULADD(at[20], at[28]); + COMBA_STORE(C->dp[20]); + /* 21 */ + COMBA_FORWARD; + 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]); MULADD(at[18], at[31]); MULADD(at[19], at[30]); MULADD(at[20], at[29]); MULADD(at[21], at[28]); + COMBA_STORE(C->dp[21]); + /* 22 */ + COMBA_FORWARD; + 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]); MULADD(at[19], at[31]); MULADD(at[20], at[30]); MULADD(at[21], at[29]); MULADD(at[22], at[28]); + COMBA_STORE(C->dp[22]); + /* 23 */ + COMBA_FORWARD; + 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]); MULADD(at[20], at[31]); MULADD(at[21], at[30]); MULADD(at[22], at[29]); MULADD(at[23], at[28]); + COMBA_STORE(C->dp[23]); + /* 24 */ + COMBA_FORWARD; + 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]); MULADD(at[21], at[31]); MULADD(at[22], at[30]); MULADD(at[23], at[29]); MULADD(at[24], at[28]); + COMBA_STORE(C->dp[24]); + /* 25 */ + COMBA_FORWARD; + 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]); MULADD(at[22], at[31]); MULADD(at[23], at[30]); MULADD(at[24], at[29]); MULADD(at[25], at[28]); + COMBA_STORE(C->dp[25]); + /* 26 */ + COMBA_FORWARD; + 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]); MULADD(at[23], at[31]); MULADD(at[24], at[30]); MULADD(at[25], at[29]); MULADD(at[26], at[28]); + COMBA_STORE(C->dp[26]); + /* 27 */ + COMBA_FORWARD; + 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]); MULADD(at[24], at[31]); MULADD(at[25], at[30]); MULADD(at[26], at[29]); MULADD(at[27], at[28]); + COMBA_STORE(C->dp[27]); + /* 28 */ + COMBA_FORWARD; + 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]); MULADD(at[25], at[31]); MULADD(at[26], at[30]); MULADD(at[27], at[29]); + COMBA_STORE(C->dp[28]); + /* 29 */ + COMBA_FORWARD; + 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]); MULADD(at[26], at[31]); MULADD(at[27], at[30]); + COMBA_STORE(C->dp[29]); + /* 30 */ + COMBA_FORWARD; + 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]); MULADD(at[27], at[31]); + COMBA_STORE(C->dp[30]); + /* 31 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[31]); + /* 32 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[32]); + /* 33 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[33]); + /* 34 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[34]); + /* 35 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[35]); + /* 36 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[36]); + /* 37 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[37]); + /* 38 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[38]); + /* 39 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[39]); + /* 40 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[40]); + /* 41 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[41]); + /* 42 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[42]); + /* 43 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[43]); + /* 44 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[44]); + /* 45 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[45]); + /* 46 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[46]); + /* 47 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[47]); + /* 48 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[48]); + /* 49 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[49]); + /* 50 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[50]); + /* 51 */ + COMBA_FORWARD; + MULADD(at[24], at[55]); MULADD(at[25], at[54]); MULADD(at[26], at[53]); MULADD(at[27], at[52]); + COMBA_STORE(C->dp[51]); + /* 52 */ + COMBA_FORWARD; + MULADD(at[25], at[55]); MULADD(at[26], at[54]); MULADD(at[27], at[53]); + COMBA_STORE(C->dp[52]); + /* 53 */ + COMBA_FORWARD; + MULADD(at[26], at[55]); MULADD(at[27], at[54]); + COMBA_STORE(C->dp[53]); + /* 54 */ + COMBA_FORWARD; + MULADD(at[27], at[55]); + COMBA_STORE(C->dp[54]); + COMBA_STORE2(C->dp[55]); + C->used = 56; + C->sign = A->sign ^ B->sign; + fp_clamp(C); + COMBA_FINI; +} +#endif + +#ifdef TFM_MUL24 +void fp_mul_comba24(fp_int *A, fp_int *B, fp_int *C) +{ + fp_digit c0, c1, c2, at[48]; + + memcpy(at, A->dp, 24 * sizeof(fp_digit)); + memcpy(at+24, B->dp, 24 * sizeof(fp_digit)); + COMBA_START; + + COMBA_CLEAR; + /* 0 */ + MULADD(at[0], at[24]); + COMBA_STORE(C->dp[0]); + /* 1 */ + COMBA_FORWARD; + MULADD(at[0], at[25]); MULADD(at[1], at[24]); + COMBA_STORE(C->dp[1]); + /* 2 */ + COMBA_FORWARD; + MULADD(at[0], at[26]); MULADD(at[1], at[25]); MULADD(at[2], at[24]); + COMBA_STORE(C->dp[2]); + /* 3 */ + COMBA_FORWARD; + MULADD(at[0], at[27]); MULADD(at[1], at[26]); MULADD(at[2], at[25]); MULADD(at[3], at[24]); + COMBA_STORE(C->dp[3]); + /* 4 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[4]); + /* 5 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[5]); + /* 6 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[6]); + /* 7 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[7]); + /* 8 */ + COMBA_FORWARD; + MULADD(at[0], at[32]); 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]); + COMBA_STORE(C->dp[8]); + /* 9 */ + COMBA_FORWARD; + MULADD(at[0], at[33]); MULADD(at[1], at[32]); 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]); + COMBA_STORE(C->dp[9]); + /* 10 */ + COMBA_FORWARD; + MULADD(at[0], at[34]); MULADD(at[1], at[33]); MULADD(at[2], at[32]); 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]); + COMBA_STORE(C->dp[10]); + /* 11 */ + COMBA_FORWARD; + MULADD(at[0], at[35]); MULADD(at[1], at[34]); MULADD(at[2], at[33]); MULADD(at[3], at[32]); 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]); + COMBA_STORE(C->dp[11]); + /* 12 */ + COMBA_FORWARD; + 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]); 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]); + COMBA_STORE(C->dp[12]); + /* 13 */ + COMBA_FORWARD; + 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]); 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]); + COMBA_STORE(C->dp[13]); + /* 14 */ + COMBA_FORWARD; + 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]); 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]); + COMBA_STORE(C->dp[14]); + /* 15 */ + COMBA_FORWARD; + 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]); 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]); + COMBA_STORE(C->dp[15]); + /* 16 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[24]); + COMBA_STORE(C->dp[16]); + /* 17 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[25]); MULADD(at[17], at[24]); + COMBA_STORE(C->dp[17]); + /* 18 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[26]); MULADD(at[17], at[25]); MULADD(at[18], at[24]); + COMBA_STORE(C->dp[18]); + /* 19 */ + COMBA_FORWARD; + 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]); MULADD(at[12], at[31]); MULADD(at[13], at[30]); MULADD(at[14], at[29]); MULADD(at[15], at[28]); MULADD(at[16], at[27]); MULADD(at[17], at[26]); MULADD(at[18], at[25]); MULADD(at[19], at[24]); + COMBA_STORE(C->dp[19]); + /* 20 */ + COMBA_FORWARD; + 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]); MULADD(at[13], at[31]); MULADD(at[14], at[30]); MULADD(at[15], at[29]); MULADD(at[16], at[28]); MULADD(at[17], at[27]); MULADD(at[18], at[26]); MULADD(at[19], at[25]); MULADD(at[20], at[24]); + COMBA_STORE(C->dp[20]); + /* 21 */ + COMBA_FORWARD; + 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]); MULADD(at[14], at[31]); MULADD(at[15], at[30]); MULADD(at[16], at[29]); MULADD(at[17], at[28]); MULADD(at[18], at[27]); MULADD(at[19], at[26]); MULADD(at[20], at[25]); MULADD(at[21], at[24]); + COMBA_STORE(C->dp[21]); + /* 22 */ + COMBA_FORWARD; + 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]); MULADD(at[15], at[31]); MULADD(at[16], at[30]); MULADD(at[17], at[29]); MULADD(at[18], at[28]); MULADD(at[19], at[27]); MULADD(at[20], at[26]); MULADD(at[21], at[25]); MULADD(at[22], at[24]); + COMBA_STORE(C->dp[22]); + /* 23 */ + COMBA_FORWARD; + 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]); MULADD(at[16], at[31]); MULADD(at[17], at[30]); MULADD(at[18], at[29]); MULADD(at[19], at[28]); MULADD(at[20], at[27]); MULADD(at[21], at[26]); MULADD(at[22], at[25]); MULADD(at[23], at[24]); + COMBA_STORE(C->dp[23]); + /* 24 */ + COMBA_FORWARD; + 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]); MULADD(at[17], at[31]); MULADD(at[18], at[30]); MULADD(at[19], at[29]); MULADD(at[20], at[28]); MULADD(at[21], at[27]); MULADD(at[22], at[26]); MULADD(at[23], at[25]); + COMBA_STORE(C->dp[24]); + /* 25 */ + COMBA_FORWARD; + 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]); MULADD(at[18], at[31]); MULADD(at[19], at[30]); MULADD(at[20], at[29]); MULADD(at[21], at[28]); MULADD(at[22], at[27]); MULADD(at[23], at[26]); + COMBA_STORE(C->dp[25]); + /* 26 */ + COMBA_FORWARD; + 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]); MULADD(at[19], at[31]); MULADD(at[20], at[30]); MULADD(at[21], at[29]); MULADD(at[22], at[28]); MULADD(at[23], at[27]); + COMBA_STORE(C->dp[26]); + /* 27 */ + COMBA_FORWARD; + 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]); MULADD(at[20], at[31]); MULADD(at[21], at[30]); MULADD(at[22], at[29]); MULADD(at[23], at[28]); + COMBA_STORE(C->dp[27]); + /* 28 */ + COMBA_FORWARD; + 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]); MULADD(at[21], at[31]); MULADD(at[22], at[30]); MULADD(at[23], at[29]); + COMBA_STORE(C->dp[28]); + /* 29 */ + COMBA_FORWARD; + 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]); MULADD(at[22], at[31]); MULADD(at[23], at[30]); + COMBA_STORE(C->dp[29]); + /* 30 */ + COMBA_FORWARD; + 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]); MULADD(at[23], at[31]); + COMBA_STORE(C->dp[30]); + /* 31 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[31]); + /* 32 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[32]); + /* 33 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[33]); + /* 34 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[34]); + /* 35 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[35]); + /* 36 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[36]); + /* 37 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[37]); + /* 38 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[38]); + /* 39 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[39]); + /* 40 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[40]); + /* 41 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[41]); + /* 42 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[42]); + /* 43 */ + COMBA_FORWARD; + MULADD(at[20], at[47]); MULADD(at[21], at[46]); MULADD(at[22], at[45]); MULADD(at[23], at[44]); + COMBA_STORE(C->dp[43]); + /* 44 */ + COMBA_FORWARD; + MULADD(at[21], at[47]); MULADD(at[22], at[46]); MULADD(at[23], at[45]); + COMBA_STORE(C->dp[44]); + /* 45 */ + COMBA_FORWARD; + MULADD(at[22], at[47]); MULADD(at[23], at[46]); + COMBA_STORE(C->dp[45]); + /* 46 */ + COMBA_FORWARD; + MULADD(at[23], at[47]); + COMBA_STORE(C->dp[46]); + COMBA_STORE2(C->dp[47]); + C->used = 48; + C->sign = A->sign ^ B->sign; + fp_clamp(C); + COMBA_FINI; +} +#endif /* $Source$ */ /* $Revision$ */ /* $Date$ */ + diff --git a/fp_sqr.c b/fp_sqr.c index b3c8191..ddc67b2 100644 --- a/fp_sqr.c +++ b/fp_sqr.c @@ -12,8 +12,7 @@ /* b = a*a */ void fp_sqr(fp_int *A, fp_int *B) { - int r, y, s; - fp_int aa, bb, comp, amb, t1; + int y; /* call generic if we're out of range */ if (A->used + A->used > FP_SIZE) { @@ -22,14 +21,30 @@ void fp_sqr(fp_int *A, fp_int *B) } y = A->used; - if (y <= 64) { - #if defined(TFM_SMALL_SET) if (y <= 16) { fp_sqr_comba_small(A,B); return; } #endif +#if defined(TFM_SQR20) + if (y <= 20) { + fp_sqr_comba20(A,B); + return; + } +#endif +#if defined(TFM_SQR24) + if (y <= 24) { + fp_sqr_comba24(A,B); + return; + } +#endif +#if defined(TFM_SQR28) + if (y <= 28) { + fp_sqr_comba28(A,B); + return; + } +#endif #if defined(TFM_SQR32) if (y <= 32) { fp_sqr_comba32(A,B); @@ -49,78 +64,6 @@ void fp_sqr(fp_int *A, fp_int *B) } #endif fp_sqr_comba(A, B); - } else { - /* do the karatsuba action - - if A = ab ||a|| = r we need to solve - - a^2*r^2 + (-(a-b)^2 + a^2 + b^2)*r + b^2 - - So we solve for the three products then we form the final result with careful shifting - and addition. - -Obvious points of optimization - -- "ac" parts can be memcpy'ed with an offset [all you have to do is zero upto the next 8 digits] -- Similarly the "bd" parts can be memcpy'ed and zeroed to 8 -- - - */ - /* get our value of r */ - r = y >> 1; - - /* now solve for ac */ -// fp_copy(A, &t1); fp_rshd(&t1, r); - for (s = 0; s < A->used - r; s++) { - t1.dp[s] = A->dp[s+r]; - } - for (; s < FP_SIZE; s++) { - t1.dp[s] = 0; - } - if (A->used >= r) { - t1.used = A->used - r; - } else { - t1.used = 0; - } - t1.sign = A->sign; - fp_copy(&t1, &amb); - fp_zero(&aa); - fp_sqr(&t1, &aa); - - /* now solve for bd */ -// fp_mod_2d(A, r * DIGIT_BIT, &t1); - for (s = 0; s < r; s++) { - t1.dp[s] = A->dp[s]; - } - for (; s < FP_SIZE; s++) { - t1.dp[s] = 0; - } - t1.used = r; - fp_clamp(&t1); - - fp_sub(&amb, &t1, &amb); - fp_zero(&bb); - fp_sqr(&t1, &bb); - - /* now get the (a-b) term */ - fp_zero(&comp); - fp_sqr(&amb, &comp); - - /* now solve the system, do the middle term first */ - comp.sign ^= 1; - fp_add(&comp, &aa, &comp); - fp_add(&comp, &bb, &comp); - fp_lshd(&comp, r); - - /* leading term */ - fp_lshd(&aa, r+r); - - /* now sum them together */ - fp_zero(B); - fp_add(&aa, &comp, B); - fp_add(&bb, B, B); - B->sign = FP_ZPOS; - } } diff --git a/fp_sqr_comba.c b/fp_sqr_comba.c index 57f2804..8e3c86b 100644 --- a/fp_sqr_comba.c +++ b/fp_sqr_comba.c @@ -1,4 +1,4 @@ -/* TomsFastMath, a fast ISO C bignum library. +/* * * This project is meant to fill in where LibTomMath * falls short. That is speed ;-) @@ -1949,6 +1949,9 @@ void fp_sqr_comba_small(fp_int *A, fp_int *B) void fp_sqr_comba32(fp_int *A, fp_int *B) { fp_digit *a, b[64], c0, c1, c2, sc0, sc1, sc2; + int out_size; + + out_size = A->used + A->used; a = A->dp; COMBA_START; @@ -2150,6 +2153,9 @@ void fp_sqr_comba32(fp_int *A, fp_int *B) 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]); COMBA_STORE(b[38]); + /* early out at 40 digits, 40*32==1280, or 640 bit operands */ + if (out_size <= 40) { COMBA_STORE2(b[39]); memcpy(B->dp, b, 40 * sizeof(fp_digit)); B->used = 40; B->sign = FP_ZPOS; fp_clamp(B); COMBA_FINI; return; } + /* output 39 */ CARRY_FORWARD; 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; @@ -2190,6 +2196,9 @@ void fp_sqr_comba32(fp_int *A, fp_int *B) 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]); COMBA_STORE(b[46]); + /* early out at 48 digits, 48*32==1536, or 768 bit operands */ + if (out_size <= 48) { COMBA_STORE2(b[47]); memcpy(B->dp, b, 48 * sizeof(fp_digit)); B->used = 48; B->sign = FP_ZPOS; fp_clamp(B); COMBA_FINI; return; } + /* output 47 */ CARRY_FORWARD; 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; @@ -2230,6 +2239,9 @@ void fp_sqr_comba32(fp_int *A, fp_int *B) 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]); COMBA_STORE(b[54]); + /* early out at 56 digits, 56*32==1280, or 896 bit operands */ + if (out_size <= 56) { COMBA_STORE2(b[55]); memcpy(B->dp, b, 56 * sizeof(fp_digit)); B->used = 56; B->sign = FP_ZPOS; fp_clamp(B); COMBA_FINI; return; } + /* output 55 */ CARRY_FORWARD; SQRADDSC(a[24], a[31]); SQRADDAC(a[25], a[30]); SQRADDAC(a[26], a[29]); SQRADDAC(a[27], a[28]); SQRADDDB; @@ -3429,6 +3441,768 @@ void fp_sqr_comba48(fp_int *A, fp_int *B) #endif +#ifdef TFM_SQR20 +void fp_sqr_comba20(fp_int *A, fp_int *B) +{ + fp_digit *a, b[40], c0, c1, c2, sc0, sc1, sc2; + + a = A->dp; + COMBA_START; + + /* clear carries */ + CLEAR_CARRY; + + /* output 0 */ + SQRADD(a[0],a[0]); + COMBA_STORE(b[0]); + + /* output 1 */ + CARRY_FORWARD; + SQRADD2(a[0], a[1]); + COMBA_STORE(b[1]); + + /* output 2 */ + CARRY_FORWARD; + SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]); + COMBA_STORE(b[2]); + + /* output 3 */ + CARRY_FORWARD; + SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]); + COMBA_STORE(b[3]); + + /* output 4 */ + CARRY_FORWARD; + SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]); + COMBA_STORE(b[4]); + + /* output 5 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; + COMBA_STORE(b[5]); + + /* output 6 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); + COMBA_STORE(b[6]); + + /* output 7 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; + COMBA_STORE(b[7]); + + /* output 8 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[8]); + + /* output 9 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[9]); + + /* output 10 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[10]); + + /* output 11 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[11]); + + /* output 12 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[12]); + + /* output 13 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[13]); + + /* output 14 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[14]); + + /* output 15 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[15]); + + /* output 16 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[16]); + + /* output 17 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[17]); + + /* output 18 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[18]); + + /* output 19 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[19]); + + /* output 20 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[20]); + + /* output 21 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[21]); + + /* output 22 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[22]); + + /* output 23 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[23]); + + /* output 24 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[24]); + + /* output 25 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[25]); + + /* output 26 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[26]); + + /* output 27 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[27]); + + /* output 28 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[28]); + + /* output 29 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[29]); + + /* output 30 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[30]); + + /* output 31 */ + CARRY_FORWARD; + SQRADDSC(a[12], a[19]); SQRADDAC(a[13], a[18]); SQRADDAC(a[14], a[17]); SQRADDAC(a[15], a[16]); SQRADDDB; + COMBA_STORE(b[31]); + + /* output 32 */ + CARRY_FORWARD; + SQRADDSC(a[13], a[19]); SQRADDAC(a[14], a[18]); SQRADDAC(a[15], a[17]); SQRADDDB; SQRADD(a[16], a[16]); + COMBA_STORE(b[32]); + + /* output 33 */ + CARRY_FORWARD; + SQRADDSC(a[14], a[19]); SQRADDAC(a[15], a[18]); SQRADDAC(a[16], a[17]); SQRADDDB; + COMBA_STORE(b[33]); + + /* output 34 */ + CARRY_FORWARD; + SQRADD2(a[15], a[19]); SQRADD2(a[16], a[18]); SQRADD(a[17], a[17]); + COMBA_STORE(b[34]); + + /* output 35 */ + CARRY_FORWARD; + SQRADD2(a[16], a[19]); SQRADD2(a[17], a[18]); + COMBA_STORE(b[35]); + + /* output 36 */ + CARRY_FORWARD; + SQRADD2(a[17], a[19]); SQRADD(a[18], a[18]); + COMBA_STORE(b[36]); + + /* output 37 */ + CARRY_FORWARD; + SQRADD2(a[18], a[19]); + COMBA_STORE(b[37]); + + /* output 38 */ + CARRY_FORWARD; + SQRADD(a[19], a[19]); + COMBA_STORE(b[38]); + COMBA_STORE2(b[39]); + COMBA_FINI; + + B->used = 40; + B->sign = FP_ZPOS; + memcpy(B->dp, b, 40 * sizeof(fp_digit)); + fp_clamp(B); +} +#endif + +#ifdef TFM_SQR24 +void fp_sqr_comba24(fp_int *A, fp_int *B) +{ + fp_digit *a, b[48], c0, c1, c2, sc0, sc1, sc2; + + a = A->dp; + COMBA_START; + + /* clear carries */ + CLEAR_CARRY; + + /* output 0 */ + SQRADD(a[0],a[0]); + COMBA_STORE(b[0]); + + /* output 1 */ + CARRY_FORWARD; + SQRADD2(a[0], a[1]); + COMBA_STORE(b[1]); + + /* output 2 */ + CARRY_FORWARD; + SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]); + COMBA_STORE(b[2]); + + /* output 3 */ + CARRY_FORWARD; + SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]); + COMBA_STORE(b[3]); + + /* output 4 */ + CARRY_FORWARD; + SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]); + COMBA_STORE(b[4]); + + /* output 5 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; + COMBA_STORE(b[5]); + + /* output 6 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); + COMBA_STORE(b[6]); + + /* output 7 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; + COMBA_STORE(b[7]); + + /* output 8 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[8]); + + /* output 9 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[9]); + + /* output 10 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[10]); + + /* output 11 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[11]); + + /* output 12 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[12]); + + /* output 13 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[13]); + + /* output 14 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[14]); + + /* output 15 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[15]); + + /* output 16 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[16]); + + /* output 17 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[17]); + + /* output 18 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[18]); + + /* output 19 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[19]); + + /* output 20 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[20]); + + /* output 21 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[21]); + + /* output 22 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[22]); + + /* output 23 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[23]); + + /* output 24 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[24]); + + /* output 25 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[25]); + + /* output 26 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[26]); + + /* output 27 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[27]); + + /* output 28 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[28]); + + /* output 29 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[29]); + + /* output 30 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[30]); + + /* output 31 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[31]); + + /* output 32 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[32]); + + /* output 33 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[33]); + + /* output 34 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[34]); + + /* output 35 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[35]); + + /* output 36 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[36]); + + /* output 37 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[37]); + + /* output 38 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[38]); + + /* output 39 */ + CARRY_FORWARD; + SQRADDSC(a[16], a[23]); SQRADDAC(a[17], a[22]); SQRADDAC(a[18], a[21]); SQRADDAC(a[19], a[20]); SQRADDDB; + COMBA_STORE(b[39]); + + /* output 40 */ + CARRY_FORWARD; + SQRADDSC(a[17], a[23]); SQRADDAC(a[18], a[22]); SQRADDAC(a[19], a[21]); SQRADDDB; SQRADD(a[20], a[20]); + COMBA_STORE(b[40]); + + /* output 41 */ + CARRY_FORWARD; + SQRADDSC(a[18], a[23]); SQRADDAC(a[19], a[22]); SQRADDAC(a[20], a[21]); SQRADDDB; + COMBA_STORE(b[41]); + + /* output 42 */ + CARRY_FORWARD; + SQRADD2(a[19], a[23]); SQRADD2(a[20], a[22]); SQRADD(a[21], a[21]); + COMBA_STORE(b[42]); + + /* output 43 */ + CARRY_FORWARD; + SQRADD2(a[20], a[23]); SQRADD2(a[21], a[22]); + COMBA_STORE(b[43]); + + /* output 44 */ + CARRY_FORWARD; + SQRADD2(a[21], a[23]); SQRADD(a[22], a[22]); + COMBA_STORE(b[44]); + + /* output 45 */ + CARRY_FORWARD; + SQRADD2(a[22], a[23]); + COMBA_STORE(b[45]); + + /* output 46 */ + CARRY_FORWARD; + SQRADD(a[23], a[23]); + COMBA_STORE(b[46]); + COMBA_STORE2(b[47]); + COMBA_FINI; + + B->used = 48; + B->sign = FP_ZPOS; + memcpy(B->dp, b, 48 * sizeof(fp_digit)); + fp_clamp(B); +} +#endif + +#ifdef TFM_SQR28 +void fp_sqr_comba28(fp_int *A, fp_int *B) +{ + fp_digit *a, b[56], c0, c1, c2, sc0, sc1, sc2; + + a = A->dp; + COMBA_START; + + /* clear carries */ + CLEAR_CARRY; + + /* output 0 */ + SQRADD(a[0],a[0]); + COMBA_STORE(b[0]); + + /* output 1 */ + CARRY_FORWARD; + SQRADD2(a[0], a[1]); + COMBA_STORE(b[1]); + + /* output 2 */ + CARRY_FORWARD; + SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]); + COMBA_STORE(b[2]); + + /* output 3 */ + CARRY_FORWARD; + SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]); + COMBA_STORE(b[3]); + + /* output 4 */ + CARRY_FORWARD; + SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]); + COMBA_STORE(b[4]); + + /* output 5 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; + COMBA_STORE(b[5]); + + /* output 6 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); + COMBA_STORE(b[6]); + + /* output 7 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; + COMBA_STORE(b[7]); + + /* output 8 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[8]); + + /* output 9 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[9]); + + /* output 10 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[10]); + + /* output 11 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[11]); + + /* output 12 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[12]); + + /* output 13 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[13]); + + /* output 14 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[14]); + + /* output 15 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[15]); + + /* output 16 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[16]); + + /* output 17 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[17]); + + /* output 18 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[18]); + + /* output 19 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[19]); + + /* output 20 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[20]); + + /* output 21 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[21]); + + /* output 22 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[22]); + + /* output 23 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[23]); + + /* output 24 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[24]); + + /* output 25 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[25]); + + /* output 26 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[26]); + + /* output 27 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[27]); + + /* output 28 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[28]); + + /* output 29 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[29]); + + /* output 30 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[30]); + + /* output 31 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[31]); + + /* output 32 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[32]); + + /* output 33 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[33]); + + /* output 34 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[34]); + + /* output 35 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[35]); + + /* output 36 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[36]); + + /* output 37 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[37]); + + /* output 38 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[38]); + + /* output 39 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[39]); + + /* output 40 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[40]); + + /* output 41 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[41]); + + /* output 42 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[42]); + + /* output 43 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[43]); + + /* output 44 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[44]); + + /* output 45 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[45]); + + /* output 46 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[46]); + + /* output 47 */ + CARRY_FORWARD; + SQRADDSC(a[20], a[27]); SQRADDAC(a[21], a[26]); SQRADDAC(a[22], a[25]); SQRADDAC(a[23], a[24]); SQRADDDB; + COMBA_STORE(b[47]); + + /* output 48 */ + CARRY_FORWARD; + SQRADDSC(a[21], a[27]); SQRADDAC(a[22], a[26]); SQRADDAC(a[23], a[25]); SQRADDDB; SQRADD(a[24], a[24]); + COMBA_STORE(b[48]); + + /* output 49 */ + CARRY_FORWARD; + SQRADDSC(a[22], a[27]); SQRADDAC(a[23], a[26]); SQRADDAC(a[24], a[25]); SQRADDDB; + COMBA_STORE(b[49]); + + /* output 50 */ + CARRY_FORWARD; + SQRADD2(a[23], a[27]); SQRADD2(a[24], a[26]); SQRADD(a[25], a[25]); + COMBA_STORE(b[50]); + + /* output 51 */ + CARRY_FORWARD; + SQRADD2(a[24], a[27]); SQRADD2(a[25], a[26]); + COMBA_STORE(b[51]); + + /* output 52 */ + CARRY_FORWARD; + SQRADD2(a[25], a[27]); SQRADD(a[26], a[26]); + COMBA_STORE(b[52]); + + /* output 53 */ + CARRY_FORWARD; + SQRADD2(a[26], a[27]); + COMBA_STORE(b[53]); + + /* output 54 */ + CARRY_FORWARD; + SQRADD(a[27], a[27]); + COMBA_STORE(b[54]); + COMBA_STORE2(b[55]); + COMBA_FINI; + + B->used = 56; + B->sign = FP_ZPOS; + memcpy(B->dp, b, 56 * sizeof(fp_digit)); + fp_clamp(B); +} +#endif + /* $Source$ */ /* $Revision$ */ /* $Date$ */ diff --git a/makefile b/makefile index 534cbcd..3207ff1 100644 --- a/makefile +++ b/makefile @@ -1,7 +1,7 @@ #makefile for TomsFastMath # # -VERSION=0.08 +VERSION=0.09 CFLAGS += -Wall -W -Wshadow -I./ @@ -11,7 +11,7 @@ endif ifndef IGNORE_SPEED -CFLAGS += -O3 -funroll-all-loops +CFLAGS += -O3 -funroll-loops #profiling #PROF=-pg -g @@ -88,7 +88,7 @@ install: $(LIBNAME) install -g $(GROUP) -o $(USER) $(LIBNAME) $(DESTDIR)$(LIBPATH) install -g $(GROUP) -o $(USER) $(HEADERS) $(DESTDIR)$(INCPATH) -mtest/mtest: mtest/mtest.c +mtest/mtest: mtest/mtest.o cd mtest ; CFLAGS="$(CFLAGS) -I../" MAKE=${MAKE} ${MAKE} mtest test: $(LIBNAME) demo/test.o mtest/mtest @@ -148,5 +148,5 @@ zipup: no_oops docs clean mv -f tfm* ~ ; rm -rf tomsfastmath-$(VERSION) # $Source: /cvs/libtom/tomsfastmath/makefile,v $ -# $Revision: 1.24 $ -# $Date: 2005/11/18 06:58:52 $ +# $Revision: 1.27 $ +# $Date: 2006/04/05 02:58:05 $ diff --git a/makefile.shared b/makefile.shared index d42acc8..7b945bc 100644 --- a/makefile.shared +++ b/makefile.shared @@ -1,9 +1,9 @@ #makefile for TomsFastMath # # -VERSION=0:8 +VERSION=0:9 -CC=libtool --mode=compile gcc +CC=libtool --mode=compile --tag=CC gcc CFLAGS += -Wall -W -Wshadow -I./ @@ -87,7 +87,8 @@ $(LIBNAME): $(OBJECTS) libtool --silent --mode=link gcc $(CFLAGS) `find . -type f | grep "[.]lo" | xargs` -o $(LIBNAME) -rpath $(LIBPATH) -version-info $(VERSION) install: $(LIBNAME) - libtool --silent --mode=install install -c $(LIBNAME) $(LIBPATH)/$(LIBNAME) + install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(LIBPATH) + libtool --silent --mode=install install -c $(LIBNAME) $(DESTDIR)$(LIBPATH)/$(LIBNAME) install -d -g $(GROUP) -o $(USER) $(DESTDIR)$(INCPATH) install -g $(GROUP) -o $(USER) $(HEADERS) $(DESTDIR)$(INCPATH) @@ -104,6 +105,6 @@ stest: $(LIBNAME) demo/stest.o $(CC) $(CFLAGS) demo/stest.o $(LIBNAME_S) -o stest # $Source: /cvs/libtom/tomsfastmath/makefile.shared,v $ -# $Revision: 1.9 $ -# $Date: 2005/11/18 06:58:52 $ +# $Revision: 1.13 $ +# $Date: 2006/03/04 21:33:57 $ diff --git a/pre_gen/mpi.c b/pre_gen/mpi.c index 8ff3159..84cf9d5 100644 --- a/pre_gen/mpi.c +++ b/pre_gen/mpi.c @@ -837,8 +837,8 @@ static int _fp_exptmod(fp_int * G, fp_int * X, fp_int * P, fp_int * Y) /* find window size */ x = fp_count_bits (X); - if (x <= 7) { - winsize = 2; + if (x <= 21) { + winsize = 1; } else if (x <= 36) { winsize = 3; } else if (x <= 140) { @@ -1690,393 +1690,456 @@ void fp_montgomery_calc_normalization(fp_int *a, fp_int *b) /* End: fp_montgomery_calc_normalization.c */ /* Start: fp_montgomery_reduce.c */ -/* TomsFastMath, a fast ISO C bignum library. - * - * This project is meant to fill in where LibTomMath - * falls short. That is speed ;-) - * - * This project is public domain and free for all purposes. - * - * Tom St Denis, tomstdenis@gmail.com - */ -#include - -/******************************************************************/ -#if defined(TFM_X86) -/* x86-32 code */ - -#define MONT_START -#define MONT_FINI -#define LOOP_END -#define LOOP_START \ - mu = c[x] * mp - -#define INNERMUL \ -asm( \ - "movl %5,%%eax \n\t" \ - "mull %4 \n\t" \ - "addl %1,%%eax \n\t" \ - "adcl $0,%%edx \n\t" \ - "addl %%eax,%0 \n\t" \ - "adcl $0,%%edx \n\t" \ - "movl %%edx,%1 \n\t" \ -:"=g"(_c[LO]), "=r"(cy) \ -:"0"(_c[LO]), "1"(cy), "g"(mu), "g"(*tmpm++) \ -: "%eax", "%edx", "%cc") - -#define PROPCARRY \ -asm( \ - "addl %1,%0 \n\t" \ - "setb %%al \n\t" \ - "movzbl %%al,%1 \n\t" \ -:"=g"(_c[LO]), "=r"(cy) \ -:"0"(_c[LO]), "1"(cy) \ -: "%eax", "%cc") - -/******************************************************************/ -#elif defined(TFM_X86_64) -/* x86-64 code */ - -#define MONT_START -#define MONT_FINI -#define LOOP_END -#define LOOP_START \ - mu = c[x] * mp - -#define INNERMUL \ -asm( \ - "movq %5,%%rax \n\t" \ - "mulq %4 \n\t" \ - "addq %1,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "addq %%rax,%0 \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rdx,%1 \n\t" \ -:"=g"(_c[LO]), "=r"(cy) \ -:"0"(_c[LO]), "1"(cy), "r"(mu), "r"(*tmpm++) \ -: "%rax", "%rdx", "%cc") - -#ifdef TFM_HUGE - -#define INNERMUL8 \ - asm( \ - "movq 0(%5),%%rax \n\t" \ - "movq 0(%2),%%r10 \n\t" \ - "movq 0x8(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x8(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x10(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x10(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x8(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x18(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x18(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x10(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x20(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x20(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x18(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x28(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x28(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x20(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x30(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x30(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x28(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "movq 0x38(%5),%%r11 \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq 0x38(%2),%%r10 \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x30(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ - "movq %%r11,%%rax \n\t" \ - "mulq %4 \n\t" \ - "addq %%r10,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "addq %3,%%rax \n\t" \ - "adcq $0,%%rdx \n\t" \ - "movq %%rax,0x38(%0) \n\t" \ - "movq %%rdx,%1 \n\t" \ - \ -:"=r"(_c), "=r"(cy) \ -: "0"(_c), "1"(cy), "g"(mu), "r"(tmpm)\ -: "%rax", "%rdx", "%r10", "%r11", "%cc") - -#endif - - -#define PROPCARRY \ -asm( \ - "addq %1,%0 \n\t" \ - "setb %%al \n\t" \ - "movzbq %%al,%1 \n\t" \ -:"=g"(_c[LO]), "=r"(cy) \ -:"0"(_c[LO]), "1"(cy) \ -: "%rax", "%cc") - -/******************************************************************/ -#elif defined(TFM_SSE2) -/* SSE2 code (assumes 32-bit fp_digits) */ -/* XMM register assignments: - * xmm0 *tmpm++, then Mu * (*tmpm++) - * xmm1 c[x], then Mu - * xmm2 mp - * xmm3 cy - * xmm4 _c[LO] - */ - -#define MONT_START \ - asm("movd %0,%%mm2"::"g"(mp)) - -#define MONT_FINI \ - asm("emms") - -#define LOOP_START \ -asm( \ -"movd %0,%%mm1 \n\t" \ -"pxor %%mm3,%%mm3 \n\t" \ -"pmuludq %%mm2,%%mm1 \n\t" \ -:: "g"(c[x])) - -/* pmuludq on mmx registers does a 32x32->64 multiply. */ -#define INNERMUL \ -asm( \ - "movd %1,%%mm4 \n\t" \ - "movd %2,%%mm0 \n\t" \ - "paddq %%mm4,%%mm3 \n\t" \ - "pmuludq %%mm1,%%mm0 \n\t" \ - "paddq %%mm0,%%mm3 \n\t" \ - "movd %%mm3,%0 \n\t" \ - "psrlq $32, %%mm3 \n\t" \ -:"=g"(_c[LO]) : "0"(_c[LO]), "g"(*tmpm++) ); - -#define LOOP_END \ -asm( "movd %%mm3,%0 \n" :"=r"(cy)) - -#define PROPCARRY \ -asm( \ - "addl %1,%0 \n\t" \ - "setb %%al \n\t" \ - "movzbl %%al,%1 \n\t" \ -:"=g"(_c[LO]), "=r"(cy) \ -:"0"(_c[LO]), "1"(cy) \ -: "%eax", "%cc") - -/******************************************************************/ -#elif defined(TFM_ARM) - /* ARMv4 code */ - -#define MONT_START -#define MONT_FINI -#define LOOP_END -#define LOOP_START \ - mu = c[x] * mp - -#define INNERMUL \ -asm( \ - " LDR r0,%1 \n\t" \ - " ADDS r0,r0,%0 \n\t" \ - " MOVCS %0,#1 \n\t" \ - " MOVCC %0,#0 \n\t" \ - " UMLAL r0,%0,%3,%4 \n\t" \ - " STR r0,%1 \n\t" \ -:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(*tmpm++),"1"(_c[0]):"r0","%cc"); - -#define PROPCARRY \ -asm( \ - " LDR r0,%1 \n\t" \ - " ADDS r0,r0,%0 \n\t" \ - " STR r0,%1 \n\t" \ - " MOVCS %0,#1 \n\t" \ - " MOVCC %0,#0 \n\t" \ -:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"r0","%cc"); - -#elif defined(TFM_PPC32) - -/* PPC32 */ -#define MONT_START -#define MONT_FINI -#define LOOP_END -#define LOOP_START \ - mu = c[x] * mp - -#define INNERMUL \ -asm( \ - " mullw 16,%3,%4 \n\t" \ - " mulhwu 17,%3,%4 \n\t" \ - " addc 16,16,%0 \n\t" \ - " addze 17,17 \n\t" \ - " lwz 18,%1 \n\t" \ - " addc 16,16,18 \n\t" \ - " addze %0,17 \n\t" \ - " stw 16,%1 \n\t" \ -:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "18","%cc"); ++tmpm; - -#define PROPCARRY \ -asm( \ - " lwz 16,%1 \n\t" \ - " addc 16,16,%0 \n\t" \ - " stw 16,%1 \n\t" \ - " xor %0,%0,%0 \n\t" \ - " addze %0,%0 \n\t" \ -:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"16","%cc"); - -/******************************************************************/ -#else - -/* ISO C code */ -#define MONT_START -#define MONT_FINI -#define LOOP_END -#define LOOP_START \ - mu = c[x] * mp - -#define INNERMUL \ - do { fp_word t; \ - _c[0] = t = ((fp_word)_c[0] + (fp_word)cy) + \ - (((fp_word)mu) * ((fp_word)*tmpm++)); \ - cy = (t >> DIGIT_BIT); \ - } while (0) - -#define PROPCARRY \ - do { fp_digit t = _c[0] += cy; cy = (t < cy); } while (0) - -#endif -/******************************************************************/ - - -#define LO 0 - -/* computes x/R == x (mod N) via Montgomery Reduction */ -void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) -{ - fp_digit c[FP_SIZE], *_c, *tmpm, mu; - int oldused, x, y, pa; - - /* bail if too large */ - if (m->used > (FP_SIZE/2)) { - return; - } - -#if defined(USE_MEMSET) - /* now zero the buff */ - memset(c, 0, sizeof c); -#endif - pa = m->used; - - /* copy the input */ - oldused = a->used; - for (x = 0; x < oldused; x++) { - c[x] = a->dp[x]; - } -#if !defined(USE_MEMSET) - for (; x < 2*pa+3; x++) { - c[x] = 0; - } -#endif - MONT_START; - - for (x = 0; x < pa; x++) { - fp_digit cy = 0; - /* get Mu for this round */ - LOOP_START; - _c = c + x; - tmpm = m->dp; - y = 0; - #if defined(TFM_X86_64) && defined(TFM_HUGE) - for (; y < (pa & ~7); y += 8) { - INNERMUL8; - _c += 8; - tmpm += 8; - } - #endif - - for (; y < pa; y++) { - INNERMUL; - ++_c; - } - LOOP_END; - while (cy) { - PROPCARRY; - ++_c; - } - } - - /* now copy out */ - _c = c + pa; - tmpm = a->dp; - for (x = 0; x < pa+1; x++) { - *tmpm++ = *_c++; - } - - for (; x < oldused; x++) { - *tmpm++ = 0; - } - - MONT_FINI; - - a->used = pa+1; - fp_clamp(a); - - /* if A >= m then A = A - m */ - if (fp_cmp_mag (a, m) != FP_LT) { - s_fp_sub (a, m, a); - } -} - - -/* $Source$ */ -/* $Revision$ */ -/* $Date$ */ +/* TomsFastMath, a fast ISO C bignum library. + * + * This project is meant to fill in where LibTomMath + * falls short. That is speed ;-) + * + * This project is public domain and free for all purposes. + * + * Tom St Denis, tomstdenis@gmail.com + */ +#include + +/******************************************************************/ +#if defined(TFM_X86) && !defined(TFM_SSE2) +/* x86-32 code */ + +#define MONT_START +#define MONT_FINI +#define LOOP_END +#define LOOP_START \ + mu = c[x] * mp + +#define INNERMUL \ +asm( \ + "movl %5,%%eax \n\t" \ + "mull %4 \n\t" \ + "addl %1,%%eax \n\t" \ + "adcl $0,%%edx \n\t" \ + "addl %%eax,%0 \n\t" \ + "adcl $0,%%edx \n\t" \ + "movl %%edx,%1 \n\t" \ +:"=g"(_c[LO]), "=r"(cy) \ +:"0"(_c[LO]), "1"(cy), "g"(mu), "g"(*tmpm++) \ +: "%eax", "%edx", "%cc") + +#define PROPCARRY \ +asm( \ + "addl %1,%0 \n\t" \ + "setb %%al \n\t" \ + "movzbl %%al,%1 \n\t" \ +:"=g"(_c[LO]), "=r"(cy) \ +:"0"(_c[LO]), "1"(cy) \ +: "%eax", "%cc") + +/******************************************************************/ +#elif defined(TFM_X86_64) +/* x86-64 code */ + +#define MONT_START +#define MONT_FINI +#define LOOP_END +#define LOOP_START \ + mu = c[x] * mp + +#define INNERMUL \ +asm( \ + "movq %5,%%rax \n\t" \ + "mulq %4 \n\t" \ + "addq %1,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "addq %%rax,%0 \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rdx,%1 \n\t" \ +:"=g"(_c[LO]), "=r"(cy) \ +:"0"(_c[LO]), "1"(cy), "r"(mu), "r"(*tmpm++) \ +: "%rax", "%rdx", "%cc") + +#define INNERMUL8 \ + asm( \ + "movq 0(%5),%%rax \n\t" \ + "movq 0(%2),%%r10 \n\t" \ + "movq 0x8(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x8(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x10(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x10(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x8(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x18(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x18(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x10(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x20(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x20(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x18(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x28(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x28(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x20(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x30(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x30(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x28(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "movq 0x38(%5),%%r11 \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq 0x38(%2),%%r10 \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x30(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ + "movq %%r11,%%rax \n\t" \ + "mulq %4 \n\t" \ + "addq %%r10,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "addq %3,%%rax \n\t" \ + "adcq $0,%%rdx \n\t" \ + "movq %%rax,0x38(%0) \n\t" \ + "movq %%rdx,%1 \n\t" \ + \ +:"=r"(_c), "=r"(cy) \ +: "0"(_c), "1"(cy), "g"(mu), "r"(tmpm)\ +: "%rax", "%rdx", "%r10", "%r11", "%cc") + + +#define PROPCARRY \ +asm( \ + "addq %1,%0 \n\t" \ + "setb %%al \n\t" \ + "movzbq %%al,%1 \n\t" \ +:"=g"(_c[LO]), "=r"(cy) \ +:"0"(_c[LO]), "1"(cy) \ +: "%rax", "%cc") + +/******************************************************************/ +#elif defined(TFM_SSE2) +/* SSE2 code (assumes 32-bit fp_digits) */ +/* XMM register assignments: + * xmm0 *tmpm++, then Mu * (*tmpm++) + * xmm1 c[x], then Mu + * xmm2 mp + * xmm3 cy + * xmm4 _c[LO] + */ + +#define MONT_START \ + asm("movd %0,%%mm2"::"g"(mp)) + +#define MONT_FINI \ + asm("emms") + +#define LOOP_START \ +asm( \ +"movd %0,%%mm1 \n\t" \ +"pxor %%mm3,%%mm3 \n\t" \ +"pmuludq %%mm2,%%mm1 \n\t" \ +:: "g"(c[x])) + +/* pmuludq on mmx registers does a 32x32->64 multiply. */ +#define INNERMUL \ +asm( \ + "movd %1,%%mm4 \n\t" \ + "movd %2,%%mm0 \n\t" \ + "paddq %%mm4,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm0 \n\t" \ + "paddq %%mm0,%%mm3 \n\t" \ + "movd %%mm3,%0 \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +:"=g"(_c[LO]) : "0"(_c[LO]), "g"(*tmpm++) ); + +#define INNERMUL8 \ +asm( \ + "movd 0(%1),%%mm4 \n\t" \ + "movd 0(%2),%%mm0 \n\t" \ + "paddq %%mm4,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm0 \n\t" \ + "movd 4(%2),%%mm5 \n\t" \ + "paddq %%mm0,%%mm3 \n\t" \ + "movd 4(%1),%%mm6 \n\t" \ + "movd %%mm3,0(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm6,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm5 \n\t" \ + "movd 8(%2),%%mm6 \n\t" \ + "paddq %%mm5,%%mm3 \n\t" \ + "movd 8(%1),%%mm7 \n\t" \ + "movd %%mm3,4(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm7,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm6 \n\t" \ + "movd 12(%2),%%mm7 \n\t" \ + "paddq %%mm6,%%mm3 \n\t" \ + "movd 12(%1),%%mm5 \n\t" \ + "movd %%mm3,8(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm5,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm7 \n\t" \ + "movd 16(%2),%%mm5 \n\t" \ + "paddq %%mm7,%%mm3 \n\t" \ + "movd 16(%1),%%mm6 \n\t" \ + "movd %%mm3,12(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm6,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm5 \n\t" \ + "movd 20(%2),%%mm6 \n\t" \ + "paddq %%mm5,%%mm3 \n\t" \ + "movd 20(%1),%%mm7 \n\t" \ + "movd %%mm3,16(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm7,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm6 \n\t" \ + "movd 24(%2),%%mm7 \n\t" \ + "paddq %%mm6,%%mm3 \n\t" \ + "movd 24(%1),%%mm5 \n\t" \ + "movd %%mm3,20(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm5,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm7 \n\t" \ + "movd 28(%2),%%mm5 \n\t" \ + "paddq %%mm7,%%mm3 \n\t" \ + "movd 28(%1),%%mm6 \n\t" \ + "movd %%mm3,24(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +\ + "paddq %%mm6,%%mm3 \n\t" \ + "pmuludq %%mm1,%%mm5 \n\t" \ + "paddq %%mm5,%%mm3 \n\t" \ + "movd %%mm3,28(%0) \n\t" \ + "psrlq $32, %%mm3 \n\t" \ +:"=r"(_c) : "0"(_c), "g"(tmpm) ); + +#define LOOP_END \ +asm( "movd %%mm3,%0 \n" :"=r"(cy)) + +#define PROPCARRY \ +asm( \ + "addl %1,%0 \n\t" \ + "setb %%al \n\t" \ + "movzbl %%al,%1 \n\t" \ +:"=g"(_c[LO]), "=r"(cy) \ +:"0"(_c[LO]), "1"(cy) \ +: "%eax", "%cc") + +/******************************************************************/ +#elif defined(TFM_ARM) + /* ARMv4 code */ + +#define MONT_START +#define MONT_FINI +#define LOOP_END +#define LOOP_START \ + mu = c[x] * mp + +#define INNERMUL \ +asm( \ + " LDR r0,%1 \n\t" \ + " ADDS r0,r0,%0 \n\t" \ + " MOVCS %0,#1 \n\t" \ + " MOVCC %0,#0 \n\t" \ + " UMLAL r0,%0,%3,%4 \n\t" \ + " STR r0,%1 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(*tmpm++),"1"(_c[0]):"r0","%cc"); + +#define PROPCARRY \ +asm( \ + " LDR r0,%1 \n\t" \ + " ADDS r0,r0,%0 \n\t" \ + " STR r0,%1 \n\t" \ + " MOVCS %0,#1 \n\t" \ + " MOVCC %0,#0 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"r0","%cc"); + +#elif defined(TFM_PPC32) + +/* PPC32 */ +#define MONT_START +#define MONT_FINI +#define LOOP_END +#define LOOP_START \ + mu = c[x] * mp + +#define INNERMUL \ +asm( \ + " mullw 16,%3,%4 \n\t" \ + " mulhwu 17,%3,%4 \n\t" \ + " addc 16,16,%0 \n\t" \ + " addze 17,17 \n\t" \ + " lwz 18,%1 \n\t" \ + " addc 16,16,18 \n\t" \ + " addze %0,17 \n\t" \ + " stw 16,%1 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"r"(mu),"r"(tmpm[0]),"1"(_c[0]):"16", "17", "18","%cc"); ++tmpm; + +#define PROPCARRY \ +asm( \ + " lwz 16,%1 \n\t" \ + " addc 16,16,%0 \n\t" \ + " stw 16,%1 \n\t" \ + " xor %0,%0,%0 \n\t" \ + " addze %0,%0 \n\t" \ +:"=r"(cy),"=m"(_c[0]):"0"(cy),"1"(_c[0]):"16","%cc"); + +/******************************************************************/ +#else + +/* ISO C code */ +#define MONT_START +#define MONT_FINI +#define LOOP_END +#define LOOP_START \ + mu = c[x] * mp + +#define INNERMUL \ + do { fp_word t; \ + _c[0] = t = ((fp_word)_c[0] + (fp_word)cy) + \ + (((fp_word)mu) * ((fp_word)*tmpm++)); \ + cy = (t >> DIGIT_BIT); \ + } while (0) + +#define PROPCARRY \ + do { fp_digit t = _c[0] += cy; cy = (t < cy); } while (0) + +#endif +/******************************************************************/ + + +#define LO 0 + +/* computes x/R == x (mod N) via Montgomery Reduction */ +void fp_montgomery_reduce(fp_int *a, fp_int *m, fp_digit mp) +{ + fp_digit c[FP_SIZE], *_c, *tmpm, mu; + int oldused, x, y, pa; + + /* bail if too large */ + if (m->used > (FP_SIZE/2)) { + return; + } + +#if defined(USE_MEMSET) + /* now zero the buff */ + memset(c, 0, sizeof c); +#endif + pa = m->used; + + /* copy the input */ + oldused = a->used; + for (x = 0; x < oldused; x++) { + c[x] = a->dp[x]; + } +#if !defined(USE_MEMSET) + for (; x < 2*pa+3; x++) { + c[x] = 0; + } +#endif + MONT_START; + + for (x = 0; x < pa; x++) { + fp_digit cy = 0; + /* get Mu for this round */ + LOOP_START; + _c = c + x; + tmpm = m->dp; + y = 0; + #if (defined(TFM_SSE2) || defined(TFM_X86_64)) + for (; y < (pa & ~7); y += 8) { + INNERMUL8; + _c += 8; + tmpm += 8; + } + #endif + + for (; y < pa; y++) { + INNERMUL; + ++_c; + } + LOOP_END; + while (cy) { + PROPCARRY; + ++_c; + } + } + + /* now copy out */ + _c = c + pa; + tmpm = a->dp; + for (x = 0; x < pa+1; x++) { + *tmpm++ = *_c++; + } + + for (; x < oldused; x++) { + *tmpm++ = 0; + } + + MONT_FINI; + + a->used = pa+1; + fp_clamp(a); + + /* if A >= m then A = A - m */ + if (fp_cmp_mag (a, m) != FP_LT) { + s_fp_sub (a, m, a); + } +} + + +/* $Source$ */ +/* $Revision$ */ +/* $Date$ */ /* End: fp_montgomery_reduce.c */ @@ -2147,8 +2210,7 @@ int fp_montgomery_setup(fp_int *a, fp_digit *rho) /* c = a * b */ void fp_mul(fp_int *A, fp_int *B, fp_int *C) { - int r, y, yy, s; - fp_int ac, bd, comp, amb, cmd, t1, t2; + int y, yy; /* call generic if we're out of range */ if (A->used + B->used > FP_SIZE) { @@ -2158,8 +2220,6 @@ void fp_mul(fp_int *A, fp_int *B, fp_int *C) y = MAX(A->used, B->used); yy = MIN(A->used, B->used); - if (yy <= 8 || y <= 64) { - /* pick a comba (unrolled 4/8/16/32 x or rolled) based on the size of the largest input. We also want to avoid doing excess mults if the inputs are not close to the next power of two. That is, for example, @@ -2172,6 +2232,24 @@ void fp_mul(fp_int *A, fp_int *B, fp_int *C) return; } #endif +#if defined(TFM_MUL20) + if (y <= 20) { + fp_mul_comba20(A,B,C); + return; + } +#endif +#if defined(TFM_MUL24) + if (yy >= 16 && y <= 24) { + fp_mul_comba24(A,B,C); + return; + } +#endif +#if defined(TFM_MUL28) + if (yy >= 20 && y <= 28) { + fp_mul_comba28(A,B,C); + return; + } +#endif #if defined(TFM_MUL32) if (yy >= 24 && y <= 32) { fp_mul_comba32(A,B,C); @@ -2191,98 +2269,6 @@ void fp_mul(fp_int *A, fp_int *B, fp_int *C) } #endif fp_mul_comba(A,B,C); - } else { - /* do the karatsuba action - - if A = ab and B = cd for ||a|| = r we need to solve - - ac*r^2 + ((a+b)(c+d) - (ac + bd))*r + bd - - So we solve for the three products then we form the final result with careful shifting - and addition. - -Obvious points of optimization - -- "ac" parts can be memcpy'ed with an offset [all you have to do is zero upto the next 8 digits] -- Similarly the "bd" parts can be memcpy'ed and zeroed to 8 -- - - */ - /* get our value of r */ - r = yy >> 1; - - /* now solve for ac */ -// fp_copy(A, &t1); fp_rshd(&t1, r); - for (s = 0; s < A->used - r; s++) { - t1.dp[s] = A->dp[s+r]; - } - for (; s < FP_SIZE; s++) { - t1.dp[s] = 0; - } - if (A->used >= r) { - t1.used = A->used - r; - } else { - t1.used = 0; - } - t1.sign = 0; - -// fp_copy(B, &t2); fp_rshd(&t2, r); - for (s = 0; s < B->used - r; s++) { - t2.dp[s] = B->dp[s+r]; - } - for (; s < FP_SIZE; s++) { - t2.dp[s] = 0; - } - if (B->used >= r) { - t2.used = B->used - r; - } else { - t2.used = 0; - } - t2.sign = 0; - - fp_copy(&t1, &amb); fp_copy(&t2, &cmd); - fp_zero(&ac); - fp_mul(&t1, &t2, &ac); - - /* now solve for bd */ -// fp_mod_2d(A, r * DIGIT_BIT, &t1); -// fp_mod_2d(B, r * DIGIT_BIT, &t2); - for (s = 0; s < r; s++) { - t1.dp[s] = A->dp[s]; - t2.dp[s] = B->dp[s]; - } - for (; s < FP_SIZE; s++) { - t1.dp[s] = 0; - t2.dp[s] = 0; - } - t1.used = r; - t2.used = r; - fp_clamp(&t1); - fp_clamp(&t2); - - s_fp_add(&amb, &t1, &amb); s_fp_add(&cmd, &t2, &cmd); - fp_zero(&bd); - fp_mul(&t1, &t2, &bd); - - /* now get the (a+b)(c+d) term */ - fp_zero(&comp); - fp_mul(&amb, &cmd, &comp); - - /* now solve the system, do the middle term first */ - s_fp_sub(&comp, &ac, &comp); - s_fp_sub(&comp, &bd, &comp); - fp_lshd(&comp, r); - - /* leading term */ - fp_lshd(&ac, r+r); - - /* now sum them together */ - s = A->sign ^ B->sign; - fp_zero(C); - fp_add(&ac, &comp, C); - fp_add(&bd, C, C); - C->sign = C->used ? s : FP_ZPOS; - } } @@ -2534,18 +2520,18 @@ asm ( \ asm("emms"); /* this should multiply i and j */ - #define MULADD(i, j) \ - asm( \ - "movd %6,%%mm0 \n\t" \ - "movd %7,%%mm1 \n\t" \ - "pmuludq %%mm1,%%mm0\n\t" \ - "movd %%mm0,%%eax \n\t" \ - "psrlq $32,%%mm0 \n\t" \ - "addl %%eax,%0 \n\t" \ - "movd %%mm0,%%eax \n\t" \ - "adcl %%eax,%1 \n\t" \ - "adcl $0,%2 \n\t" \ - :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%cc"); +#define MULADD(i, j) \ +asm( \ + "movd %6,%%mm0 \n\t" \ + "movd %7,%%mm1 \n\t" \ + "pmuludq %%mm1,%%mm0\n\t" \ + "movd %%mm0,%%eax \n\t" \ + "psrlq $32,%%mm0 \n\t" \ + "addl %%eax,%0 \n\t" \ + "movd %%mm0,%%eax \n\t" \ + "adcl %%eax,%1 \n\t" \ + "adcl $0,%2 \n\t" \ + :"=r"(c0), "=r"(c1), "=r"(c2): "0"(c0), "1"(c1), "2"(c2), "m"(i), "m"(j) :"%eax","%cc"); #elif defined(TFM_ARM) /* ARM code */ @@ -3916,7 +3902,9 @@ void fp_mul_comba_small(fp_int *A, fp_int *B, fp_int *C) void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C) { fp_digit c0, c1, c2, at[64]; + int out_size; + out_size = A->used + B->used; memcpy(at, A->dp, 32 * sizeof(fp_digit)); memcpy(at+32, B->dp, 32 * sizeof(fp_digit)); COMBA_START; @@ -4077,6 +4065,10 @@ void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C) COMBA_FORWARD; 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]); COMBA_STORE(C->dp[38]); + + /* early out at 40 digits, 40*32==1280, or two 640 bit operands */ + if (out_size <= 40) { COMBA_STORE2(C->dp[39]); C->used = 40; C->sign = A->sign ^ B->sign; fp_clamp(C); COMBA_FINI; return; } + /* 39 */ COMBA_FORWARD; 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]); @@ -4109,6 +4101,10 @@ void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C) COMBA_FORWARD; 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]); COMBA_STORE(C->dp[46]); + + /* early out at 48 digits, 48*32==1536, or two 768 bit operands */ + if (out_size <= 48) { COMBA_STORE2(C->dp[47]); C->used = 48; C->sign = A->sign ^ B->sign; fp_clamp(C); COMBA_FINI; return; } + /* 47 */ COMBA_FORWARD; 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]); @@ -4141,6 +4137,10 @@ void fp_mul_comba32(fp_int *A, fp_int *B, fp_int *C) COMBA_FORWARD; 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]); COMBA_STORE(C->dp[54]); + + /* early out at 56 digits, 56*32==1792, or two 896 bit operands */ + if (out_size <= 56) { COMBA_STORE2(C->dp[55]); C->used = 56; C->sign = A->sign ^ B->sign; fp_clamp(C); COMBA_FINI; return; } + /* 55 */ COMBA_FORWARD; 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]); @@ -5103,11 +5103,625 @@ void fp_mul_comba48(fp_int *A, fp_int *B, fp_int *C) } #endif +#ifdef TFM_MUL20 +void fp_mul_comba20(fp_int *A, fp_int *B, fp_int *C) +{ + fp_digit c0, c1, c2, at[40]; + + memcpy(at, A->dp, 20 * sizeof(fp_digit)); + memcpy(at+20, B->dp, 20 * sizeof(fp_digit)); + COMBA_START; + COMBA_CLEAR; + /* 0 */ + MULADD(at[0], at[20]); + COMBA_STORE(C->dp[0]); + /* 1 */ + COMBA_FORWARD; + MULADD(at[0], at[21]); MULADD(at[1], at[20]); + COMBA_STORE(C->dp[1]); + /* 2 */ + COMBA_FORWARD; + MULADD(at[0], at[22]); MULADD(at[1], at[21]); MULADD(at[2], at[20]); + COMBA_STORE(C->dp[2]); + /* 3 */ + COMBA_FORWARD; + MULADD(at[0], at[23]); MULADD(at[1], at[22]); MULADD(at[2], at[21]); MULADD(at[3], at[20]); + COMBA_STORE(C->dp[3]); + /* 4 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[4]); + /* 5 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[5]); + /* 6 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[6]); + /* 7 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[7]); + /* 8 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[8]); + /* 9 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[9]); + /* 10 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[10]); + /* 11 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[11]); + /* 12 */ + COMBA_FORWARD; + MULADD(at[0], at[32]); 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]); + COMBA_STORE(C->dp[12]); + /* 13 */ + COMBA_FORWARD; + MULADD(at[0], at[33]); MULADD(at[1], at[32]); 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]); + COMBA_STORE(C->dp[13]); + /* 14 */ + COMBA_FORWARD; + MULADD(at[0], at[34]); MULADD(at[1], at[33]); MULADD(at[2], at[32]); 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]); + COMBA_STORE(C->dp[14]); + /* 15 */ + COMBA_FORWARD; + MULADD(at[0], at[35]); MULADD(at[1], at[34]); MULADD(at[2], at[33]); MULADD(at[3], at[32]); 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]); + COMBA_STORE(C->dp[15]); + /* 16 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[20]); + COMBA_STORE(C->dp[16]); + /* 17 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[21]); MULADD(at[17], at[20]); + COMBA_STORE(C->dp[17]); + /* 18 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[22]); MULADD(at[17], at[21]); MULADD(at[18], at[20]); + COMBA_STORE(C->dp[18]); + /* 19 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[23]); MULADD(at[17], at[22]); MULADD(at[18], at[21]); MULADD(at[19], at[20]); + COMBA_STORE(C->dp[19]); + /* 20 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[24]); MULADD(at[17], at[23]); MULADD(at[18], at[22]); MULADD(at[19], at[21]); + COMBA_STORE(C->dp[20]); + /* 21 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[25]); MULADD(at[17], at[24]); MULADD(at[18], at[23]); MULADD(at[19], at[22]); + COMBA_STORE(C->dp[21]); + /* 22 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[26]); MULADD(at[17], at[25]); MULADD(at[18], at[24]); MULADD(at[19], at[23]); + COMBA_STORE(C->dp[22]); + /* 23 */ + COMBA_FORWARD; + 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]); MULADD(at[12], at[31]); MULADD(at[13], at[30]); MULADD(at[14], at[29]); MULADD(at[15], at[28]); MULADD(at[16], at[27]); MULADD(at[17], at[26]); MULADD(at[18], at[25]); MULADD(at[19], at[24]); + COMBA_STORE(C->dp[23]); + /* 24 */ + COMBA_FORWARD; + 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]); MULADD(at[13], at[31]); MULADD(at[14], at[30]); MULADD(at[15], at[29]); MULADD(at[16], at[28]); MULADD(at[17], at[27]); MULADD(at[18], at[26]); MULADD(at[19], at[25]); + COMBA_STORE(C->dp[24]); + /* 25 */ + COMBA_FORWARD; + 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]); MULADD(at[14], at[31]); MULADD(at[15], at[30]); MULADD(at[16], at[29]); MULADD(at[17], at[28]); MULADD(at[18], at[27]); MULADD(at[19], at[26]); + COMBA_STORE(C->dp[25]); + /* 26 */ + COMBA_FORWARD; + 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]); MULADD(at[15], at[31]); MULADD(at[16], at[30]); MULADD(at[17], at[29]); MULADD(at[18], at[28]); MULADD(at[19], at[27]); + COMBA_STORE(C->dp[26]); + /* 27 */ + COMBA_FORWARD; + 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]); MULADD(at[16], at[31]); MULADD(at[17], at[30]); MULADD(at[18], at[29]); MULADD(at[19], at[28]); + COMBA_STORE(C->dp[27]); + /* 28 */ + COMBA_FORWARD; + 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]); MULADD(at[17], at[31]); MULADD(at[18], at[30]); MULADD(at[19], at[29]); + COMBA_STORE(C->dp[28]); + /* 29 */ + COMBA_FORWARD; + 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]); MULADD(at[18], at[31]); MULADD(at[19], at[30]); + COMBA_STORE(C->dp[29]); + /* 30 */ + COMBA_FORWARD; + 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]); MULADD(at[19], at[31]); + COMBA_STORE(C->dp[30]); + /* 31 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[31]); + /* 32 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[32]); + /* 33 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[33]); + /* 34 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[34]); + /* 35 */ + COMBA_FORWARD; + MULADD(at[16], at[39]); MULADD(at[17], at[38]); MULADD(at[18], at[37]); MULADD(at[19], at[36]); + COMBA_STORE(C->dp[35]); + /* 36 */ + COMBA_FORWARD; + MULADD(at[17], at[39]); MULADD(at[18], at[38]); MULADD(at[19], at[37]); + COMBA_STORE(C->dp[36]); + /* 37 */ + COMBA_FORWARD; + MULADD(at[18], at[39]); MULADD(at[19], at[38]); + COMBA_STORE(C->dp[37]); + /* 38 */ + COMBA_FORWARD; + MULADD(at[19], at[39]); + COMBA_STORE(C->dp[38]); + COMBA_STORE2(C->dp[39]); + C->used = 40; + C->sign = A->sign ^ B->sign; + fp_clamp(C); + COMBA_FINI; +} +#endif + +#ifdef TFM_MUL28 +void fp_mul_comba28(fp_int *A, fp_int *B, fp_int *C) +{ + fp_digit c0, c1, c2, at[56]; + + memcpy(at, A->dp, 28 * sizeof(fp_digit)); + memcpy(at+28, B->dp, 28 * sizeof(fp_digit)); + COMBA_START; + + COMBA_CLEAR; + /* 0 */ + MULADD(at[0], at[28]); + COMBA_STORE(C->dp[0]); + /* 1 */ + COMBA_FORWARD; + MULADD(at[0], at[29]); MULADD(at[1], at[28]); + COMBA_STORE(C->dp[1]); + /* 2 */ + COMBA_FORWARD; + MULADD(at[0], at[30]); MULADD(at[1], at[29]); MULADD(at[2], at[28]); + COMBA_STORE(C->dp[2]); + /* 3 */ + COMBA_FORWARD; + MULADD(at[0], at[31]); MULADD(at[1], at[30]); MULADD(at[2], at[29]); MULADD(at[3], at[28]); + COMBA_STORE(C->dp[3]); + /* 4 */ + COMBA_FORWARD; + MULADD(at[0], at[32]); MULADD(at[1], at[31]); MULADD(at[2], at[30]); MULADD(at[3], at[29]); MULADD(at[4], at[28]); + COMBA_STORE(C->dp[4]); + /* 5 */ + COMBA_FORWARD; + MULADD(at[0], at[33]); MULADD(at[1], at[32]); MULADD(at[2], at[31]); MULADD(at[3], at[30]); MULADD(at[4], at[29]); MULADD(at[5], at[28]); + COMBA_STORE(C->dp[5]); + /* 6 */ + COMBA_FORWARD; + MULADD(at[0], at[34]); MULADD(at[1], at[33]); MULADD(at[2], at[32]); MULADD(at[3], at[31]); MULADD(at[4], at[30]); MULADD(at[5], at[29]); MULADD(at[6], at[28]); + COMBA_STORE(C->dp[6]); + /* 7 */ + COMBA_FORWARD; + MULADD(at[0], at[35]); MULADD(at[1], at[34]); MULADD(at[2], at[33]); MULADD(at[3], at[32]); MULADD(at[4], at[31]); MULADD(at[5], at[30]); MULADD(at[6], at[29]); MULADD(at[7], at[28]); + COMBA_STORE(C->dp[7]); + /* 8 */ + COMBA_FORWARD; + 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]); MULADD(at[5], at[31]); MULADD(at[6], at[30]); MULADD(at[7], at[29]); MULADD(at[8], at[28]); + COMBA_STORE(C->dp[8]); + /* 9 */ + COMBA_FORWARD; + 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]); MULADD(at[6], at[31]); MULADD(at[7], at[30]); MULADD(at[8], at[29]); MULADD(at[9], at[28]); + COMBA_STORE(C->dp[9]); + /* 10 */ + COMBA_FORWARD; + 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]); MULADD(at[7], at[31]); MULADD(at[8], at[30]); MULADD(at[9], at[29]); MULADD(at[10], at[28]); + COMBA_STORE(C->dp[10]); + /* 11 */ + COMBA_FORWARD; + 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]); MULADD(at[8], at[31]); MULADD(at[9], at[30]); MULADD(at[10], at[29]); MULADD(at[11], at[28]); + COMBA_STORE(C->dp[11]); + /* 12 */ + COMBA_FORWARD; + 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]); MULADD(at[9], at[31]); MULADD(at[10], at[30]); MULADD(at[11], at[29]); MULADD(at[12], at[28]); + COMBA_STORE(C->dp[12]); + /* 13 */ + COMBA_FORWARD; + 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]); MULADD(at[10], at[31]); MULADD(at[11], at[30]); MULADD(at[12], at[29]); MULADD(at[13], at[28]); + COMBA_STORE(C->dp[13]); + /* 14 */ + COMBA_FORWARD; + 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]); MULADD(at[11], at[31]); MULADD(at[12], at[30]); MULADD(at[13], at[29]); MULADD(at[14], at[28]); + COMBA_STORE(C->dp[14]); + /* 15 */ + COMBA_FORWARD; + 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]); MULADD(at[12], at[31]); MULADD(at[13], at[30]); MULADD(at[14], at[29]); MULADD(at[15], at[28]); + COMBA_STORE(C->dp[15]); + /* 16 */ + COMBA_FORWARD; + 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]); MULADD(at[13], at[31]); MULADD(at[14], at[30]); MULADD(at[15], at[29]); MULADD(at[16], at[28]); + COMBA_STORE(C->dp[16]); + /* 17 */ + COMBA_FORWARD; + 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]); MULADD(at[14], at[31]); MULADD(at[15], at[30]); MULADD(at[16], at[29]); MULADD(at[17], at[28]); + COMBA_STORE(C->dp[17]); + /* 18 */ + COMBA_FORWARD; + 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]); MULADD(at[15], at[31]); MULADD(at[16], at[30]); MULADD(at[17], at[29]); MULADD(at[18], at[28]); + COMBA_STORE(C->dp[18]); + /* 19 */ + COMBA_FORWARD; + 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]); MULADD(at[16], at[31]); MULADD(at[17], at[30]); MULADD(at[18], at[29]); MULADD(at[19], at[28]); + COMBA_STORE(C->dp[19]); + /* 20 */ + COMBA_FORWARD; + 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]); MULADD(at[17], at[31]); MULADD(at[18], at[30]); MULADD(at[19], at[29]); MULADD(at[20], at[28]); + COMBA_STORE(C->dp[20]); + /* 21 */ + COMBA_FORWARD; + 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]); MULADD(at[18], at[31]); MULADD(at[19], at[30]); MULADD(at[20], at[29]); MULADD(at[21], at[28]); + COMBA_STORE(C->dp[21]); + /* 22 */ + COMBA_FORWARD; + 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]); MULADD(at[19], at[31]); MULADD(at[20], at[30]); MULADD(at[21], at[29]); MULADD(at[22], at[28]); + COMBA_STORE(C->dp[22]); + /* 23 */ + COMBA_FORWARD; + 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]); MULADD(at[20], at[31]); MULADD(at[21], at[30]); MULADD(at[22], at[29]); MULADD(at[23], at[28]); + COMBA_STORE(C->dp[23]); + /* 24 */ + COMBA_FORWARD; + 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]); MULADD(at[21], at[31]); MULADD(at[22], at[30]); MULADD(at[23], at[29]); MULADD(at[24], at[28]); + COMBA_STORE(C->dp[24]); + /* 25 */ + COMBA_FORWARD; + 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]); MULADD(at[22], at[31]); MULADD(at[23], at[30]); MULADD(at[24], at[29]); MULADD(at[25], at[28]); + COMBA_STORE(C->dp[25]); + /* 26 */ + COMBA_FORWARD; + 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]); MULADD(at[23], at[31]); MULADD(at[24], at[30]); MULADD(at[25], at[29]); MULADD(at[26], at[28]); + COMBA_STORE(C->dp[26]); + /* 27 */ + COMBA_FORWARD; + 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]); MULADD(at[24], at[31]); MULADD(at[25], at[30]); MULADD(at[26], at[29]); MULADD(at[27], at[28]); + COMBA_STORE(C->dp[27]); + /* 28 */ + COMBA_FORWARD; + 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]); MULADD(at[25], at[31]); MULADD(at[26], at[30]); MULADD(at[27], at[29]); + COMBA_STORE(C->dp[28]); + /* 29 */ + COMBA_FORWARD; + 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]); MULADD(at[26], at[31]); MULADD(at[27], at[30]); + COMBA_STORE(C->dp[29]); + /* 30 */ + COMBA_FORWARD; + 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]); MULADD(at[27], at[31]); + COMBA_STORE(C->dp[30]); + /* 31 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[31]); + /* 32 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[32]); + /* 33 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[33]); + /* 34 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[34]); + /* 35 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[35]); + /* 36 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[36]); + /* 37 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[37]); + /* 38 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[38]); + /* 39 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[39]); + /* 40 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[40]); + /* 41 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[41]); + /* 42 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[42]); + /* 43 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[43]); + /* 44 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[44]); + /* 45 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[45]); + /* 46 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[46]); + /* 47 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[47]); + /* 48 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[48]); + /* 49 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[49]); + /* 50 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[50]); + /* 51 */ + COMBA_FORWARD; + MULADD(at[24], at[55]); MULADD(at[25], at[54]); MULADD(at[26], at[53]); MULADD(at[27], at[52]); + COMBA_STORE(C->dp[51]); + /* 52 */ + COMBA_FORWARD; + MULADD(at[25], at[55]); MULADD(at[26], at[54]); MULADD(at[27], at[53]); + COMBA_STORE(C->dp[52]); + /* 53 */ + COMBA_FORWARD; + MULADD(at[26], at[55]); MULADD(at[27], at[54]); + COMBA_STORE(C->dp[53]); + /* 54 */ + COMBA_FORWARD; + MULADD(at[27], at[55]); + COMBA_STORE(C->dp[54]); + COMBA_STORE2(C->dp[55]); + C->used = 56; + C->sign = A->sign ^ B->sign; + fp_clamp(C); + COMBA_FINI; +} +#endif + +#ifdef TFM_MUL24 +void fp_mul_comba24(fp_int *A, fp_int *B, fp_int *C) +{ + fp_digit c0, c1, c2, at[48]; + + memcpy(at, A->dp, 24 * sizeof(fp_digit)); + memcpy(at+24, B->dp, 24 * sizeof(fp_digit)); + COMBA_START; + + COMBA_CLEAR; + /* 0 */ + MULADD(at[0], at[24]); + COMBA_STORE(C->dp[0]); + /* 1 */ + COMBA_FORWARD; + MULADD(at[0], at[25]); MULADD(at[1], at[24]); + COMBA_STORE(C->dp[1]); + /* 2 */ + COMBA_FORWARD; + MULADD(at[0], at[26]); MULADD(at[1], at[25]); MULADD(at[2], at[24]); + COMBA_STORE(C->dp[2]); + /* 3 */ + COMBA_FORWARD; + MULADD(at[0], at[27]); MULADD(at[1], at[26]); MULADD(at[2], at[25]); MULADD(at[3], at[24]); + COMBA_STORE(C->dp[3]); + /* 4 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[4]); + /* 5 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[5]); + /* 6 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[6]); + /* 7 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[7]); + /* 8 */ + COMBA_FORWARD; + MULADD(at[0], at[32]); 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]); + COMBA_STORE(C->dp[8]); + /* 9 */ + COMBA_FORWARD; + MULADD(at[0], at[33]); MULADD(at[1], at[32]); 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]); + COMBA_STORE(C->dp[9]); + /* 10 */ + COMBA_FORWARD; + MULADD(at[0], at[34]); MULADD(at[1], at[33]); MULADD(at[2], at[32]); 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]); + COMBA_STORE(C->dp[10]); + /* 11 */ + COMBA_FORWARD; + MULADD(at[0], at[35]); MULADD(at[1], at[34]); MULADD(at[2], at[33]); MULADD(at[3], at[32]); 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]); + COMBA_STORE(C->dp[11]); + /* 12 */ + COMBA_FORWARD; + 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]); 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]); + COMBA_STORE(C->dp[12]); + /* 13 */ + COMBA_FORWARD; + 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]); 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]); + COMBA_STORE(C->dp[13]); + /* 14 */ + COMBA_FORWARD; + 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]); 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]); + COMBA_STORE(C->dp[14]); + /* 15 */ + COMBA_FORWARD; + 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]); 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]); + COMBA_STORE(C->dp[15]); + /* 16 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[24]); + COMBA_STORE(C->dp[16]); + /* 17 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[25]); MULADD(at[17], at[24]); + COMBA_STORE(C->dp[17]); + /* 18 */ + COMBA_FORWARD; + 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]); 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]); MULADD(at[16], at[26]); MULADD(at[17], at[25]); MULADD(at[18], at[24]); + COMBA_STORE(C->dp[18]); + /* 19 */ + COMBA_FORWARD; + 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]); MULADD(at[12], at[31]); MULADD(at[13], at[30]); MULADD(at[14], at[29]); MULADD(at[15], at[28]); MULADD(at[16], at[27]); MULADD(at[17], at[26]); MULADD(at[18], at[25]); MULADD(at[19], at[24]); + COMBA_STORE(C->dp[19]); + /* 20 */ + COMBA_FORWARD; + 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]); MULADD(at[13], at[31]); MULADD(at[14], at[30]); MULADD(at[15], at[29]); MULADD(at[16], at[28]); MULADD(at[17], at[27]); MULADD(at[18], at[26]); MULADD(at[19], at[25]); MULADD(at[20], at[24]); + COMBA_STORE(C->dp[20]); + /* 21 */ + COMBA_FORWARD; + 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]); MULADD(at[14], at[31]); MULADD(at[15], at[30]); MULADD(at[16], at[29]); MULADD(at[17], at[28]); MULADD(at[18], at[27]); MULADD(at[19], at[26]); MULADD(at[20], at[25]); MULADD(at[21], at[24]); + COMBA_STORE(C->dp[21]); + /* 22 */ + COMBA_FORWARD; + 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]); MULADD(at[15], at[31]); MULADD(at[16], at[30]); MULADD(at[17], at[29]); MULADD(at[18], at[28]); MULADD(at[19], at[27]); MULADD(at[20], at[26]); MULADD(at[21], at[25]); MULADD(at[22], at[24]); + COMBA_STORE(C->dp[22]); + /* 23 */ + COMBA_FORWARD; + 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]); MULADD(at[16], at[31]); MULADD(at[17], at[30]); MULADD(at[18], at[29]); MULADD(at[19], at[28]); MULADD(at[20], at[27]); MULADD(at[21], at[26]); MULADD(at[22], at[25]); MULADD(at[23], at[24]); + COMBA_STORE(C->dp[23]); + /* 24 */ + COMBA_FORWARD; + 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]); MULADD(at[17], at[31]); MULADD(at[18], at[30]); MULADD(at[19], at[29]); MULADD(at[20], at[28]); MULADD(at[21], at[27]); MULADD(at[22], at[26]); MULADD(at[23], at[25]); + COMBA_STORE(C->dp[24]); + /* 25 */ + COMBA_FORWARD; + 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]); MULADD(at[18], at[31]); MULADD(at[19], at[30]); MULADD(at[20], at[29]); MULADD(at[21], at[28]); MULADD(at[22], at[27]); MULADD(at[23], at[26]); + COMBA_STORE(C->dp[25]); + /* 26 */ + COMBA_FORWARD; + 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]); MULADD(at[19], at[31]); MULADD(at[20], at[30]); MULADD(at[21], at[29]); MULADD(at[22], at[28]); MULADD(at[23], at[27]); + COMBA_STORE(C->dp[26]); + /* 27 */ + COMBA_FORWARD; + 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]); MULADD(at[20], at[31]); MULADD(at[21], at[30]); MULADD(at[22], at[29]); MULADD(at[23], at[28]); + COMBA_STORE(C->dp[27]); + /* 28 */ + COMBA_FORWARD; + 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]); MULADD(at[21], at[31]); MULADD(at[22], at[30]); MULADD(at[23], at[29]); + COMBA_STORE(C->dp[28]); + /* 29 */ + COMBA_FORWARD; + 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]); MULADD(at[22], at[31]); MULADD(at[23], at[30]); + COMBA_STORE(C->dp[29]); + /* 30 */ + COMBA_FORWARD; + 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]); MULADD(at[23], at[31]); + COMBA_STORE(C->dp[30]); + /* 31 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[31]); + /* 32 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[32]); + /* 33 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[33]); + /* 34 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[34]); + /* 35 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[35]); + /* 36 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[36]); + /* 37 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[37]); + /* 38 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[38]); + /* 39 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[39]); + /* 40 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[40]); + /* 41 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[41]); + /* 42 */ + COMBA_FORWARD; + 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]); + COMBA_STORE(C->dp[42]); + /* 43 */ + COMBA_FORWARD; + MULADD(at[20], at[47]); MULADD(at[21], at[46]); MULADD(at[22], at[45]); MULADD(at[23], at[44]); + COMBA_STORE(C->dp[43]); + /* 44 */ + COMBA_FORWARD; + MULADD(at[21], at[47]); MULADD(at[22], at[46]); MULADD(at[23], at[45]); + COMBA_STORE(C->dp[44]); + /* 45 */ + COMBA_FORWARD; + MULADD(at[22], at[47]); MULADD(at[23], at[46]); + COMBA_STORE(C->dp[45]); + /* 46 */ + COMBA_FORWARD; + MULADD(at[23], at[47]); + COMBA_STORE(C->dp[46]); + COMBA_STORE2(C->dp[47]); + C->used = 48; + C->sign = A->sign ^ B->sign; + fp_clamp(C); + COMBA_FINI; +} +#endif /* $Source$ */ /* $Revision$ */ /* $Date$ */ + /* End: fp_mul_comba.c */ /* Start: fp_mul_d.c */ @@ -5723,8 +6337,7 @@ int fp_signed_bin_size(fp_int *a) /* b = a*a */ void fp_sqr(fp_int *A, fp_int *B) { - int r, y, s; - fp_int aa, bb, comp, amb, t1; + int y; /* call generic if we're out of range */ if (A->used + A->used > FP_SIZE) { @@ -5733,14 +6346,30 @@ void fp_sqr(fp_int *A, fp_int *B) } y = A->used; - if (y <= 64) { - #if defined(TFM_SMALL_SET) if (y <= 16) { fp_sqr_comba_small(A,B); return; } #endif +#if defined(TFM_SQR20) + if (y <= 20) { + fp_sqr_comba20(A,B); + return; + } +#endif +#if defined(TFM_SQR24) + if (y <= 24) { + fp_sqr_comba24(A,B); + return; + } +#endif +#if defined(TFM_SQR28) + if (y <= 28) { + fp_sqr_comba28(A,B); + return; + } +#endif #if defined(TFM_SQR32) if (y <= 32) { fp_sqr_comba32(A,B); @@ -5760,78 +6389,6 @@ void fp_sqr(fp_int *A, fp_int *B) } #endif fp_sqr_comba(A, B); - } else { - /* do the karatsuba action - - if A = ab ||a|| = r we need to solve - - a^2*r^2 + (-(a-b)^2 + a^2 + b^2)*r + b^2 - - So we solve for the three products then we form the final result with careful shifting - and addition. - -Obvious points of optimization - -- "ac" parts can be memcpy'ed with an offset [all you have to do is zero upto the next 8 digits] -- Similarly the "bd" parts can be memcpy'ed and zeroed to 8 -- - - */ - /* get our value of r */ - r = y >> 1; - - /* now solve for ac */ -// fp_copy(A, &t1); fp_rshd(&t1, r); - for (s = 0; s < A->used - r; s++) { - t1.dp[s] = A->dp[s+r]; - } - for (; s < FP_SIZE; s++) { - t1.dp[s] = 0; - } - if (A->used >= r) { - t1.used = A->used - r; - } else { - t1.used = 0; - } - t1.sign = A->sign; - fp_copy(&t1, &amb); - fp_zero(&aa); - fp_sqr(&t1, &aa); - - /* now solve for bd */ -// fp_mod_2d(A, r * DIGIT_BIT, &t1); - for (s = 0; s < r; s++) { - t1.dp[s] = A->dp[s]; - } - for (; s < FP_SIZE; s++) { - t1.dp[s] = 0; - } - t1.used = r; - fp_clamp(&t1); - - fp_sub(&amb, &t1, &amb); - fp_zero(&bb); - fp_sqr(&t1, &bb); - - /* now get the (a-b) term */ - fp_zero(&comp); - fp_sqr(&amb, &comp); - - /* now solve the system, do the middle term first */ - comp.sign ^= 1; - fp_add(&comp, &aa, &comp); - fp_add(&comp, &bb, &comp); - fp_lshd(&comp, r); - - /* leading term */ - fp_lshd(&aa, r+r); - - /* now sum them together */ - fp_zero(B); - fp_add(&aa, &comp, B); - fp_add(&bb, B, B); - B->sign = FP_ZPOS; - } } @@ -5842,7 +6399,7 @@ Obvious points of optimization /* End: fp_sqr.c */ /* Start: fp_sqr_comba.c */ -/* TomsFastMath, a fast ISO C bignum library. +/* * * This project is meant to fill in where LibTomMath * falls short. That is speed ;-) @@ -7793,6 +8350,9 @@ void fp_sqr_comba_small(fp_int *A, fp_int *B) void fp_sqr_comba32(fp_int *A, fp_int *B) { fp_digit *a, b[64], c0, c1, c2, sc0, sc1, sc2; + int out_size; + + out_size = A->used + A->used; a = A->dp; COMBA_START; @@ -7994,6 +8554,9 @@ void fp_sqr_comba32(fp_int *A, fp_int *B) 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]); COMBA_STORE(b[38]); + /* early out at 40 digits, 40*32==1280, or 640 bit operands */ + if (out_size <= 40) { COMBA_STORE2(b[39]); memcpy(B->dp, b, 40 * sizeof(fp_digit)); B->used = 40; B->sign = FP_ZPOS; fp_clamp(B); COMBA_FINI; return; } + /* output 39 */ CARRY_FORWARD; 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; @@ -8034,6 +8597,9 @@ void fp_sqr_comba32(fp_int *A, fp_int *B) 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]); COMBA_STORE(b[46]); + /* early out at 48 digits, 48*32==1536, or 768 bit operands */ + if (out_size <= 48) { COMBA_STORE2(b[47]); memcpy(B->dp, b, 48 * sizeof(fp_digit)); B->used = 48; B->sign = FP_ZPOS; fp_clamp(B); COMBA_FINI; return; } + /* output 47 */ CARRY_FORWARD; 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; @@ -8074,6 +8640,9 @@ void fp_sqr_comba32(fp_int *A, fp_int *B) 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]); COMBA_STORE(b[54]); + /* early out at 56 digits, 56*32==1280, or 896 bit operands */ + if (out_size <= 56) { COMBA_STORE2(b[55]); memcpy(B->dp, b, 56 * sizeof(fp_digit)); B->used = 56; B->sign = FP_ZPOS; fp_clamp(B); COMBA_FINI; return; } + /* output 55 */ CARRY_FORWARD; SQRADDSC(a[24], a[31]); SQRADDAC(a[25], a[30]); SQRADDAC(a[26], a[29]); SQRADDAC(a[27], a[28]); SQRADDDB; @@ -9273,6 +9842,768 @@ void fp_sqr_comba48(fp_int *A, fp_int *B) #endif +#ifdef TFM_SQR20 +void fp_sqr_comba20(fp_int *A, fp_int *B) +{ + fp_digit *a, b[40], c0, c1, c2, sc0, sc1, sc2; + + a = A->dp; + COMBA_START; + + /* clear carries */ + CLEAR_CARRY; + + /* output 0 */ + SQRADD(a[0],a[0]); + COMBA_STORE(b[0]); + + /* output 1 */ + CARRY_FORWARD; + SQRADD2(a[0], a[1]); + COMBA_STORE(b[1]); + + /* output 2 */ + CARRY_FORWARD; + SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]); + COMBA_STORE(b[2]); + + /* output 3 */ + CARRY_FORWARD; + SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]); + COMBA_STORE(b[3]); + + /* output 4 */ + CARRY_FORWARD; + SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]); + COMBA_STORE(b[4]); + + /* output 5 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; + COMBA_STORE(b[5]); + + /* output 6 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); + COMBA_STORE(b[6]); + + /* output 7 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; + COMBA_STORE(b[7]); + + /* output 8 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[8]); + + /* output 9 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[9]); + + /* output 10 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[10]); + + /* output 11 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[11]); + + /* output 12 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[12]); + + /* output 13 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[13]); + + /* output 14 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[14]); + + /* output 15 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[15]); + + /* output 16 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[16]); + + /* output 17 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[17]); + + /* output 18 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[18]); + + /* output 19 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[19]); + + /* output 20 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[20]); + + /* output 21 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[21]); + + /* output 22 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[22]); + + /* output 23 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[23]); + + /* output 24 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[24]); + + /* output 25 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[25]); + + /* output 26 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[26]); + + /* output 27 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[27]); + + /* output 28 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[28]); + + /* output 29 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[29]); + + /* output 30 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[30]); + + /* output 31 */ + CARRY_FORWARD; + SQRADDSC(a[12], a[19]); SQRADDAC(a[13], a[18]); SQRADDAC(a[14], a[17]); SQRADDAC(a[15], a[16]); SQRADDDB; + COMBA_STORE(b[31]); + + /* output 32 */ + CARRY_FORWARD; + SQRADDSC(a[13], a[19]); SQRADDAC(a[14], a[18]); SQRADDAC(a[15], a[17]); SQRADDDB; SQRADD(a[16], a[16]); + COMBA_STORE(b[32]); + + /* output 33 */ + CARRY_FORWARD; + SQRADDSC(a[14], a[19]); SQRADDAC(a[15], a[18]); SQRADDAC(a[16], a[17]); SQRADDDB; + COMBA_STORE(b[33]); + + /* output 34 */ + CARRY_FORWARD; + SQRADD2(a[15], a[19]); SQRADD2(a[16], a[18]); SQRADD(a[17], a[17]); + COMBA_STORE(b[34]); + + /* output 35 */ + CARRY_FORWARD; + SQRADD2(a[16], a[19]); SQRADD2(a[17], a[18]); + COMBA_STORE(b[35]); + + /* output 36 */ + CARRY_FORWARD; + SQRADD2(a[17], a[19]); SQRADD(a[18], a[18]); + COMBA_STORE(b[36]); + + /* output 37 */ + CARRY_FORWARD; + SQRADD2(a[18], a[19]); + COMBA_STORE(b[37]); + + /* output 38 */ + CARRY_FORWARD; + SQRADD(a[19], a[19]); + COMBA_STORE(b[38]); + COMBA_STORE2(b[39]); + COMBA_FINI; + + B->used = 40; + B->sign = FP_ZPOS; + memcpy(B->dp, b, 40 * sizeof(fp_digit)); + fp_clamp(B); +} +#endif + +#ifdef TFM_SQR24 +void fp_sqr_comba24(fp_int *A, fp_int *B) +{ + fp_digit *a, b[48], c0, c1, c2, sc0, sc1, sc2; + + a = A->dp; + COMBA_START; + + /* clear carries */ + CLEAR_CARRY; + + /* output 0 */ + SQRADD(a[0],a[0]); + COMBA_STORE(b[0]); + + /* output 1 */ + CARRY_FORWARD; + SQRADD2(a[0], a[1]); + COMBA_STORE(b[1]); + + /* output 2 */ + CARRY_FORWARD; + SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]); + COMBA_STORE(b[2]); + + /* output 3 */ + CARRY_FORWARD; + SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]); + COMBA_STORE(b[3]); + + /* output 4 */ + CARRY_FORWARD; + SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]); + COMBA_STORE(b[4]); + + /* output 5 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; + COMBA_STORE(b[5]); + + /* output 6 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); + COMBA_STORE(b[6]); + + /* output 7 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; + COMBA_STORE(b[7]); + + /* output 8 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[8]); + + /* output 9 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[9]); + + /* output 10 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[10]); + + /* output 11 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[11]); + + /* output 12 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[12]); + + /* output 13 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[13]); + + /* output 14 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[14]); + + /* output 15 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[15]); + + /* output 16 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[16]); + + /* output 17 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[17]); + + /* output 18 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[18]); + + /* output 19 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[19]); + + /* output 20 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[20]); + + /* output 21 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[21]); + + /* output 22 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[22]); + + /* output 23 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[23]); + + /* output 24 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[24]); + + /* output 25 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[25]); + + /* output 26 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[26]); + + /* output 27 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[27]); + + /* output 28 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[28]); + + /* output 29 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[29]); + + /* output 30 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[30]); + + /* output 31 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[31]); + + /* output 32 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[32]); + + /* output 33 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[33]); + + /* output 34 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[34]); + + /* output 35 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[35]); + + /* output 36 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[36]); + + /* output 37 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[37]); + + /* output 38 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[38]); + + /* output 39 */ + CARRY_FORWARD; + SQRADDSC(a[16], a[23]); SQRADDAC(a[17], a[22]); SQRADDAC(a[18], a[21]); SQRADDAC(a[19], a[20]); SQRADDDB; + COMBA_STORE(b[39]); + + /* output 40 */ + CARRY_FORWARD; + SQRADDSC(a[17], a[23]); SQRADDAC(a[18], a[22]); SQRADDAC(a[19], a[21]); SQRADDDB; SQRADD(a[20], a[20]); + COMBA_STORE(b[40]); + + /* output 41 */ + CARRY_FORWARD; + SQRADDSC(a[18], a[23]); SQRADDAC(a[19], a[22]); SQRADDAC(a[20], a[21]); SQRADDDB; + COMBA_STORE(b[41]); + + /* output 42 */ + CARRY_FORWARD; + SQRADD2(a[19], a[23]); SQRADD2(a[20], a[22]); SQRADD(a[21], a[21]); + COMBA_STORE(b[42]); + + /* output 43 */ + CARRY_FORWARD; + SQRADD2(a[20], a[23]); SQRADD2(a[21], a[22]); + COMBA_STORE(b[43]); + + /* output 44 */ + CARRY_FORWARD; + SQRADD2(a[21], a[23]); SQRADD(a[22], a[22]); + COMBA_STORE(b[44]); + + /* output 45 */ + CARRY_FORWARD; + SQRADD2(a[22], a[23]); + COMBA_STORE(b[45]); + + /* output 46 */ + CARRY_FORWARD; + SQRADD(a[23], a[23]); + COMBA_STORE(b[46]); + COMBA_STORE2(b[47]); + COMBA_FINI; + + B->used = 48; + B->sign = FP_ZPOS; + memcpy(B->dp, b, 48 * sizeof(fp_digit)); + fp_clamp(B); +} +#endif + +#ifdef TFM_SQR28 +void fp_sqr_comba28(fp_int *A, fp_int *B) +{ + fp_digit *a, b[56], c0, c1, c2, sc0, sc1, sc2; + + a = A->dp; + COMBA_START; + + /* clear carries */ + CLEAR_CARRY; + + /* output 0 */ + SQRADD(a[0],a[0]); + COMBA_STORE(b[0]); + + /* output 1 */ + CARRY_FORWARD; + SQRADD2(a[0], a[1]); + COMBA_STORE(b[1]); + + /* output 2 */ + CARRY_FORWARD; + SQRADD2(a[0], a[2]); SQRADD(a[1], a[1]); + COMBA_STORE(b[2]); + + /* output 3 */ + CARRY_FORWARD; + SQRADD2(a[0], a[3]); SQRADD2(a[1], a[2]); + COMBA_STORE(b[3]); + + /* output 4 */ + CARRY_FORWARD; + SQRADD2(a[0], a[4]); SQRADD2(a[1], a[3]); SQRADD(a[2], a[2]); + COMBA_STORE(b[4]); + + /* output 5 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[5]); SQRADDAC(a[1], a[4]); SQRADDAC(a[2], a[3]); SQRADDDB; + COMBA_STORE(b[5]); + + /* output 6 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[6]); SQRADDAC(a[1], a[5]); SQRADDAC(a[2], a[4]); SQRADDDB; SQRADD(a[3], a[3]); + COMBA_STORE(b[6]); + + /* output 7 */ + CARRY_FORWARD; + SQRADDSC(a[0], a[7]); SQRADDAC(a[1], a[6]); SQRADDAC(a[2], a[5]); SQRADDAC(a[3], a[4]); SQRADDDB; + COMBA_STORE(b[7]); + + /* output 8 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[8]); + + /* output 9 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[9]); + + /* output 10 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[10]); + + /* output 11 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[11]); + + /* output 12 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[12]); + + /* output 13 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[13]); + + /* output 14 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[14]); + + /* output 15 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[15]); + + /* output 16 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[16]); + + /* output 17 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[17]); + + /* output 18 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[18]); + + /* output 19 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[19]); + + /* output 20 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[20]); + + /* output 21 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[21]); + + /* output 22 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[22]); + + /* output 23 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[23]); + + /* output 24 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[24]); + + /* output 25 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[25]); + + /* output 26 */ + CARRY_FORWARD; + 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]); + COMBA_STORE(b[26]); + + /* output 27 */ + CARRY_FORWARD; + 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; + COMBA_STORE(b[27]); + + /* output 28 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[28]); + + /* output 29 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[29]); + + /* output 30 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[30]); + + /* output 31 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[31]); + + /* output 32 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[32]); + + /* output 33 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[33]); + + /* output 34 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[34]); + + /* output 35 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[35]); + + /* output 36 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[36]); + + /* output 37 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[37]); + + /* output 38 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[38]); + + /* output 39 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[39]); + + /* output 40 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[40]); + + /* output 41 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[41]); + + /* output 42 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[42]); + + /* output 43 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[43]); + + /* output 44 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[44]); + + /* output 45 */ + CARRY_FORWARD; + SQRADDSC(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; + COMBA_STORE(b[45]); + + /* output 46 */ + CARRY_FORWARD; + SQRADDSC(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]); + COMBA_STORE(b[46]); + + /* output 47 */ + CARRY_FORWARD; + SQRADDSC(a[20], a[27]); SQRADDAC(a[21], a[26]); SQRADDAC(a[22], a[25]); SQRADDAC(a[23], a[24]); SQRADDDB; + COMBA_STORE(b[47]); + + /* output 48 */ + CARRY_FORWARD; + SQRADDSC(a[21], a[27]); SQRADDAC(a[22], a[26]); SQRADDAC(a[23], a[25]); SQRADDDB; SQRADD(a[24], a[24]); + COMBA_STORE(b[48]); + + /* output 49 */ + CARRY_FORWARD; + SQRADDSC(a[22], a[27]); SQRADDAC(a[23], a[26]); SQRADDAC(a[24], a[25]); SQRADDDB; + COMBA_STORE(b[49]); + + /* output 50 */ + CARRY_FORWARD; + SQRADD2(a[23], a[27]); SQRADD2(a[24], a[26]); SQRADD(a[25], a[25]); + COMBA_STORE(b[50]); + + /* output 51 */ + CARRY_FORWARD; + SQRADD2(a[24], a[27]); SQRADD2(a[25], a[26]); + COMBA_STORE(b[51]); + + /* output 52 */ + CARRY_FORWARD; + SQRADD2(a[25], a[27]); SQRADD(a[26], a[26]); + COMBA_STORE(b[52]); + + /* output 53 */ + CARRY_FORWARD; + SQRADD2(a[26], a[27]); + COMBA_STORE(b[53]); + + /* output 54 */ + CARRY_FORWARD; + SQRADD(a[27], a[27]); + COMBA_STORE(b[54]); + COMBA_STORE2(b[55]); + COMBA_FINI; + + B->used = 56; + B->sign = FP_ZPOS; + memcpy(B->dp, b, 56 * sizeof(fp_digit)); + fp_clamp(B); +} +#endif + /* $Source$ */ /* $Revision$ */ /* $Date$ */ diff --git a/tfm.dvi b/tfm.dvi index 25ea658bec9d8f27e694a0f948c5af4ad26fddbc..51930f7d7940efabaf1fb943e36a2488685268a6 100644 GIT binary patch delta 384 zcmZ25nR(7+<_U^?CVB=YRz^mq7TpXC42+W>>Z(i(p3bCxapId|M$5?wjPVj3-My0- zx_R^*3yLyxrZK--VWKnH$iTpCvS6a=W+5gCW=4+52@BLF2Uv+r)^+Ba{BE!G=04Us zMaCbK^AoKmzww6%6{yc(W4r}d$rlF^&e7v!V!Q@a=`neqK{2Bz|6Q1DD#-n1}@l}RKm)r09J03VaLXJ z9xk&rZ$2xd$K?N=)|)4keBokL0?Jr#K2UGR#Tc~tev_Er z^Cqk*Dore^oW}fWg^}szi;Tg{jC_;p>(wUrCyH#2XI-wy_-}H7fz{+^{(PJL)i<*- zK7h;G>KQRH-T}()X7q#$rWx+xU@~L{>&a*0+ni(7z`^(zCOtWxm2a|GocLxR=Xf5* zV<1(VpZP!MWo(73u+`(+EEX5U%(xsV>oIv_;%r7InB?a6q!Ly}HLy0b3_CW)t8kh1 zdGlEr{eUuRlN%O@Ztg1i!o{euxxT)Vi!lN&YSMLzh4Iqn|9uu5j5pw-#nYd0FbV=q zvfey(K{z|3F