#include #if defined(TFM_X86) #define COMBA_START /* clear the chaining variables */ #define COMBA_CLEAR \ c0 = c1 = c2 = 0; /* forward the carry to the next digit */ #define COMBA_FORWARD \ do { c0 = c1; c1 = c2; c2 = 0; } while (0); /* store the first sum */ #define COMBA_STORE(x) \ x = c0; /* store the second sum [carry] */ #define COMBA_STORE2(x) \ x = c1; /* anything you need at the end */ #define COMBA_FINI /* this should multiply i and j */ #define MULADD(i, j) \ asm( \ "movl %6,%%eax \n\t" \ "mull %7 \n\t" \ "addl %%eax,%0 \n\t" \ "adcl %%edx,%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","%edx","%cc"); #endif /* generic PxQ multiplier */ void fp_mul_comba(fp_int *A, fp_int *B, fp_int *C) { int ix, iy, iz, tx, ty, pa; fp_digit c0, c1, c2, *tmpx, *tmpy; fp_int tmp, *dst; COMBA_START; COMBA_CLEAR; /* get size of output and trim */ pa = A->used + B->used; if (pa >= FP_SIZE) { pa = FP_SIZE-1; } if (A == C || B == C) { fp_zero(&tmp); dst = &tmp; } else { fp_zero(C); dst = C; } for (ix = 0; ix < pa; ix++) { /* get offsets into the two bignums */ ty = MIN(ix, B->used-1); tx = ix - ty; /* setup temp aliases */ tmpx = A->dp + tx; tmpy = B->dp + ty; /* this is the number of times the loop will iterrate, essentially its while (tx++ < a->used && ty-- >= 0) { ... } */ iy = MIN(A->used-tx, ty+1); /* execute loop */ COMBA_FORWARD; for (iz = 0; iz < iy; ++iz) { MULADD(*tmpx++, *tmpy--); } /* store term */ COMBA_STORE(dst->dp[ix]); } /* store final carry */ COMBA_STORE2(dst->dp[ix]); COMBA_FINI; dst->used = pa; fp_clamp(dst); dst->sign = dst->used ? A->sign ^ B->sign : FP_ZPOS; fp_copy(dst, C); }