void zHex2Dec(z *u, z *v) { //convert u[] in hex to v[] in decimal by repeatedly dividing //u by 1e9 = 0x3b9aca00 //the remainder of the ith division is the ith decimal digit. //when the quotient = 0, stop z a,b; fp_digit r = 0; int su = abs(u->size); int approx_words = (int)((double)su * 1.5); //because decimal takes more room than hex to store zInit(&a); zInit(&b); if (v->alloc < approx_words) zGrow(v,approx_words); zClear(v); if (a.alloc < approx_words) { zGrow(&a,approx_words); zClear(&a); } if (b.alloc < approx_words) { zGrow(&b,approx_words); zClear(&b); } zCopy(u,&a); v->size = 1; do { r = zShortDiv(&a,MAX_DEC_WORD,&b); v->val[v->size - 1] = r; v->size++; zCopy(&b,&a); } while (zCompare(&a,&zZero) != 0); v->size--; if (u->size < 0) v->size *= -1; zFree(&a); zFree(&b); return; }
void monty_init(z *n) { //for a input modulus n, initialize constants for //montogomery representation //this assumes that n is relatively prime to 2, i.e. is odd. z g, b, q, r; //global montyconst structure zInit(&montyconst.nhat); zInit(&montyconst.r); zInit(&montyconst.rhat); zInit(&montyconst.one); if (abs(n->size) <= 16) { fp_montgomery_setup(n,&montyconst.nhat.val[0]); fp_montgomery_calc_normalization(&montyconst.r,n); montyconst.one.val[0] = 1; montyconst.one.size = 1; to_monty(&montyconst.one,n); TFM_MONTY = 1; return; } else TFM_MONTY = 0; zInit(&g); zInit(&b); zInit(&q); zInit(&r); b.val[1]=1; b.size=2; //find r = b^t > N, where b = 2 ^32 if (montyconst.r.alloc < n->size + 1) zGrow(&montyconst.r,n->size + 1); zClear(&montyconst.r); montyconst.r.size = n->size + 1; montyconst.r.val[montyconst.r.size - 1] = 1; //find nhat = -n^-1 mod b //nhat = -(n^-1 mod b) mod b = b - n^-1 mod b //since b is 2^32, this can be simplified, and made faster. xGCD(n,&b,&montyconst.nhat,&montyconst.rhat,&g); zSub(&b,&montyconst.nhat,&q); zCopy(&q,&montyconst.nhat); zCopy(&zOne,&montyconst.one); to_monty(&montyconst.one,n); zFree(&g); zFree(&b); zFree(&q); zFree(&r); return; }
void zCopy(z *src, z *dest) { //physically copy the digits of u into the digits of v int su = abs(src->size); if (src == dest) return; if (dest->alloc < su) zGrow(dest,su); memcpy(dest->val,src->val,su * sizeof(fp_digit)); dest->size = src->size; dest->type = src->type; return; }
void zDec2Hex(z *u, z *v) { //convert u[] in dec to v[] in hex by multiplying the ith digit by (1e9)*i //and adding to the previous digits z a,b,vv; int i,su = abs(u->size); zInit(&a); zInit(&b); zInit(&vv); if (v->alloc < su) zGrow(v,su); if (a.alloc < su) { zGrow(&a,su); zClear(&a); } if (b.alloc < su) { zGrow(&b,su); zClear(&b); } if (vv.alloc < su) { zGrow(&vv,su); zClear(&vv); } vv.size = su; //a holds the value of (1e9)*i a.size = 1; a.val[0] = 1; for (i=0;i<su;i++) { zShortMul(&a,u->val[i],&b); zAdd(&vv,&b,&vv); zShortMul(&a,MAX_DEC_WORD,&a); } //v may have unused high order limbs for (i=su-1;i>=0;i--) { if (vv.val[i] != 0) break; } vv.size = i+1; if (u->size < 0) vv.size *= -1; if (vv.size == 0) vv.size = 1; zCopy(&vv,v); zFree(&vv); zFree(&a); zFree(&b); return; }
void zREDC(z *T, z *n) { /* from handbook of applied cryptography, ch. 14 INPUT: integers m = (mn-1 . . .m1m0)b with gcd(m; b) = 1, R = b^n,m' = -m^-1 mod b, and T = (t2n-1 . . . t1t0)b <mR. OUTPUT: TR^-1 mod m, the reduction of T mod m in montgomery representation... 1. A=T . (Notation: A = (a2n-1 . . . a1a0)b.) 2. For i from 0 to (n - 1) do the following: 2.1 ui=ai*m' mod b. 2.2 A=A + ui*m*b^i. 3. A=A/b^n. 4. If A > m then A=A-m. 5. Return(A). */ int i,j,ix,su; fp_digit nhat = montyconst.nhat.val[0], ui,k; z mtmp3; if (TFM_MONTY == 1) { fp_montgomery_reduce(T,n,montyconst.nhat.val[0]); return; } //printf("shouldn't get to here\n"); zInit(&mtmp3); if (mtmp3.alloc < n->size * 2) zGrow(&mtmp3,n->size * 2); //T needs to have allocated montyconst.n.size + T.size if (T->alloc < n->size + T->size) zGrow(T,n->size + T->size + 1); for (i=0;i<n->size;i++) { //the mod b happens automatically because only the //lower 32 bits of the product is returned. ui = T->val[i] * nhat; //ui = a1*nhat mod b //zShortMul(&montyconst.n,ui,&mtmp3); //t1 = ui * n //short mul k=0; su = n->size; for (ix=0;ix<su;++ix) spMulAdd(n->val[ix],ui,0,k,&mtmp3.val[ix],&k); //if still have a carry, add a digit to w if (k) { mtmp3.val[su]=k; su++; } //check for significant digits. only necessary if v or u = 0? for (ix = su - 1;ix>=0;--ix) { if (mtmp3.val[ix] != 0) break; } mtmp3.size = ix+1; for (j=mtmp3.size - 1;j>=0;j--) //t1 *= b^i mtmp3.val[j+i] = mtmp3.val[j]; mtmp3.size += i; zAdd(T,&mtmp3,T); //A += t1 } for (j=0; j<T->size; j++) //A /= b^n T->val[j] = T->val[j+n->size]; T->size -= n->size; if (zCompare(T,n) > 0) //if A > n, A = A-n zSub(T,n,T); if (T->size == 0) zCopy(n,T); zFree(&mtmp3); return; }
void fp_mul_comba(z *A, z *B, z *C) { int ix, iy, iz, tx, ty, pa, sA, sB; fp_digit c0, c1, c2, *tmpx, *tmpy; z *dst; z loc; COMBA_START; COMBA_CLEAR; /* get size of output and trim */ sA = abs(A->size); sB = abs(B->size); pa = sA + sB; if (A == C || B == C) { zInit(&loc); //dst = &atmp1; dst = &loc; } else { dst = C; } if (dst->alloc < pa) zGrow(dst,pa + LIMB_BLKSZ); zClear(dst); for (ix = 0; ix < pa; ix++) { /* get offsets into the two bignums */ ty = MIN(ix, sB-1); tx = ix - ty; /* setup temp aliases */ tmpx = A->val + tx; tmpy = B->val + ty; /* this is the number of times the loop will iterrate, essentially its while (tx++ < a->used && ty-- >= 0) { ... } */ iy = MIN(sA-tx, ty+1); /* execute loop */ COMBA_FORWARD; for (iz = 0; iz < iy; ++iz) { MULADD(*tmpx++, *tmpy--); } /* store term */ COMBA_STORE(dst->val[ix]); } COMBA_FINI; dst->size = pa; if ((A->size * B->size) < 0) dst->size *= -1; fp_clamp(dst); if (dst != C) { zCopy(dst, C); zFree(&loc); } }
void fp_sqr_comba(z *A, z *B) { int pa, ix, iz, sA; fp_digit c0, c1, c2; z *dst; z loc; #ifdef TFM_ISO uint64 tt; #endif /* get size of output and trim */ sA = abs(A->size); pa = sA + sA; /* number of output digits to produce */ COMBA_START; CLEAR_CARRY; if (A == B) { //zClear(&atmp1); zInit(&loc); //dst = &atmp1; dst = &loc; } else { zClear(B); dst = B; } if (dst->alloc < pa) { zGrow(dst,pa + LIMB_BLKSZ); } zClear(dst); for (ix = 0; ix < pa; ix++) { int tx, ty, iy; fp_digit *tmpy, *tmpx; /* get offsets into the two bignums */ ty = MIN(sA-1, ix); tx = ix - ty; /* setup temp aliases */ tmpx = A->val + tx; tmpy = A->val + ty; /* this is the number of times the loop will iterrate, while (tx++ < a->used && ty-- >= 0) { ... } */ iy = MIN(sA-tx, ty+1); /* now for squaring tx can never equal ty * we halve the distance since they approach * at a rate of 2x and we have to round because * odd cases need to be executed */ iy = MIN(iy, (ty-tx+1)>>1); /* forward carries */ CARRY_FORWARD; /* execute loop */ for (iz = 0; iz < iy; iz++) { SQRADD2(*tmpx++, *tmpy--); } /* even columns have the square term in them */ if ((ix&1) == 0) { SQRADD(A->val[ix>>1],A->val[ix>>1]); } /* store it */ COMBA_STORE(dst->val[ix]); }