/* * this code assumes that a vlong is an integral number of * mpdigits long. */ mpint* vtomp(vlong v, mpint *b) { int s; uvlong uv; if(b == nil) b = mpnew(VLDIGITS*sizeof(mpdigit)); else mpbits(b, VLDIGITS*sizeof(mpdigit)); mpassign(mpzero, b); if(v == 0) return b; if(v < 0){ b->sign = -1; uv = -v; } else uv = v; for(s = 0; s < VLDIGITS && uv != 0; s++){ b->p[s] = uv; uv >>= sizeof(mpdigit)*8; } b->top = s; return b; }
// sum = abs(b1) + abs(b2), i.e., add the magnitudes void mpmagadd(mpint *b1, mpint *b2, mpint *sum) { int m, n; mpint *t; // get the sizes right if(b2->top > b1->top){ t = b1; b1 = b2; b2 = t; } n = b1->top; m = b2->top; if(n == 0){ mpassign(mpzero, sum); return; } if(m == 0){ mpassign(b1, sum); return; } mpbits(sum, (n+1)*Dbits); sum->top = n+1; mpvecadd(b1->p, n, b2->p, m, sum->p); sum->sign = 1; mpnorm(sum); }
// convert a big-endian byte array (most significant byte first) to an mpint mpint* betomp(uchar *p, uint n, mpint *b) { int m, s; mpdigit x; if(b == nil) b = mpnew(0); // dump leading zeros while(*p == 0 && n > 1) { p++; n--; } // get the space mpbits(b, n*8); b->top = DIGITS(n*8); m = b->top-1; // first digit might not be Dbytes long s = ((n-1)*8)%Dbits; x = 0; for(; n > 0; n--) { x |= ((mpdigit)(*p++)) << s; s -= 8; if(s < 0) { b->p[m--] = x; s = Dbits-8; x = 0; } } return b; }
int main() { dldp_p params; mpnumber gq; javalong start, now; int iterations = 0; dldp_pInit(¶ms); mpbsethex(¶ms.p, hp); mpbsethex(¶ms.q, hq); mpnsethex(¶ms.g, hg); mpnzero(&gq); /* get starting time */ start = timestamp(); do { mpbnpowmod(¶ms.p, ¶ms.g, (mpnumber*) ¶ms.q, &gq); now = timestamp(); iterations++; } while (now < (start + (SECONDS * ONE_SECOND))); mpnfree(&gq); printf("(%d bits ^ %d bits) mod (%d bits): %d times in %d seconds\n", (int) mpbits(params.g.size, params.g.data), (int) mpbits(params.q.size, params.q.modl), (int) mpbits(params.p.size, params.p.modl), iterations, SECONDS); dldp_pFree(¶ms); return 0; }
/* * this code assumes that a vlong is an integral number of * mpdigits long. */ mpint* uvtomp(uint64_t v, mpint *b) { int s; if(b == nil) b = mpnew(VLDIGITS*sizeof(mpdigit)); else mpbits(b, VLDIGITS*sizeof(mpdigit)); mpassign(mpzero, b); if(v == 0) return b; for(s = 0; s < VLDIGITS && v != 0; s++){ b->p[s] = v; v >>= sizeof(mpdigit)*8; } b->top = s; return b; }
// generate a probable prime. accuracy is the miller-rabin interations void genprime(mpint *p, int n, int accuracy) { mpdigit x; // generate n random bits with high and low bits set mpbits(p, n); genrandom((uint8_t*)p->p, (n+7)/8); p->top = (n+Dbits-1)/Dbits; x = 1; x <<= ((n-1)%Dbits); p->p[p->top-1] &= (x-1); p->p[p->top-1] |= x; p->p[0] |= 1; // keep icrementing till it looks prime for(;;){ if(probably_prime(p, accuracy)) break; mpadd(p, mptwo, p); } }
// convert a little endian byte array (least significant byte first) to an mpint mpint* letomp(uchar *s, uint n, mpint *b) { int i=0, m = 0; mpdigit x=0; if(b == nil) b = mpnew(0); mpbits(b, 8*n); for(; n > 0; n--){ x |= ((mpdigit)(*s++)) << i; i += 8; if(i == Dbits){ b->p[m++] = x; i = 0; x = 0; } } if(i > 0) b->p[m++] = x; b->top = m; return b; }
void mpmul(mpint *b1, mpint *b2, mpint *prod) { mpint *oprod; oprod = nil; if(prod == b1 || prod == b2){ oprod = prod; prod = mpnew(0); } prod->top = 0; mpbits(prod, (b1->top+b2->top+1)*Dbits); mpvecmul(b1->p, b1->top, b2->p, b2->top, prod->p); prod->top = b1->top+b2->top+1; prod->sign = b1->sign*b2->sign; mpnorm(prod); if(oprod != nil){ mpassign(prod, oprod); mpfree(prod); } }
/* * needs workspace of (8*size+2) words */ void mpprndconone_w(mpbarrett* p, randomGeneratorContext* rc, size_t bits, int t, const mpbarrett* q, const mpnumber* f, mpnumber* r, int cofactor, mpw* wksp) { /* * Generate a prime p with n bits such that p mod q = 1, and p = qr+1 where r = 2s * * Conditions: q > 2 and size(q) < size(p) and size(f) <= size(p) * * Conditions: r must be chosen so that r is even, otherwise p will be even! * * if cofactor == 0, then s will be chosen randomly * if cofactor == 1, then make sure that q does not divide r, i.e.: * q cannot be equal to r, since r is even, and q > 2; hence if q <= r make sure that GCD(q,r) == 1 * if cofactor == 2, then make sure that s is prime * * Optional input f: if f is not null, then search p so that GCD(p-1,f) = 1 */ mpbinit(p, MP_BITS_TO_WORDS(bits + MP_WBITS - 1)); if (p->modl != (mpw*) 0) { size_t sbits = bits - mpbits(q->size, q->modl) - 1; mpbarrett s; mpbzero(&s); mpbinit(&s, MP_BITS_TO_WORDS(sbits + MP_WBITS - 1)); while (1) { mpprndbits(&s, sbits, 0, (mpnumber*) 0, (mpnumber*) 0, rc, wksp); if (cofactor == 1) { mpsetlsb(s.size, s.modl); /* if (q <= s) check if GCD(q,s) != 1 */ if (mplex(q->size, q->modl, s.size, s.modl)) { /* we can find adequate storage for computing the gcd in s->wksp */ mpsetx(s.size, wksp, q->size, q->modl); mpgcd_w(s.size, s.modl, wksp, wksp+s.size, wksp+2*s.size); if (!mpisone(s.size, wksp+s.size)) continue; } } else if (cofactor == 2) { mpsetlsb(s.size, s.modl); } if (cofactor == 2) { /* do a small prime product trial division test on r */ if (!mppsppdiv_w(&s, wksp)) continue; } /* multiply q*s */ mpmul(wksp, s.size, s.modl, q->size, q->modl); /* s.size + q.size may be greater than p.size by 1, but the product will fit exactly into p */ mpsetx(p->size, p->modl, s.size+q->size, wksp); /* multiply by two and add 1 */ mpmultwo(p->size, p->modl); mpaddw(p->size, p->modl, 1); /* test if the product actually contains enough bits */ if (mpbits(p->size, p->modl) < bits) continue; /* do a small prime product trial division test on p */ if (!mppsppdiv_w(p, wksp)) continue; /* if we have an f, do the congruence test */ if (f != (mpnumber*) 0) { mpcopy(p->size, wksp, p->modl); mpsubw(p->size, wksp, 1); mpsetx(p->size, wksp, f->size, f->data); mpgcd_w(p->size, wksp, wksp+p->size, wksp+2*p->size, wksp+3*p->size); if (!mpisone(p->size, wksp+2*p->size)) continue; } /* if cofactor is two, test if s is prime */ if (cofactor == 2) { mpbmu_w(&s, wksp); if (!mppmilrab_w(&s, rc, mpptrials(sbits), wksp)) continue; } /* candidate has passed so far, now we do the probabilistic test on p */ mpbmu_w(p, wksp); if (!mppmilrab_w(p, rc, t, wksp)) continue; mpnset(r, s.size, s.modl); mpmultwo(r->size, r->data); mpbfree(&s); return; } } }
/* * implements IEEE P1363 A.15.6 * * f, min, max are optional */ int mpprndr_w(mpbarrett* p, randomGeneratorContext* rc, size_t bits, int t, const mpnumber* min, const mpnumber* max, const mpnumber* f, mpw* wksp) { /* * Generate a prime into p with the requested number of bits * * Conditions: size(f) <= size(p) * * Optional input min: if min is not null, then search p so that min <= p * Optional input max: if max is not null, then search p so that p <= max * Optional input f: if f is not null, then search p so that GCD(p-1,f) = 1 */ size_t size = MP_BITS_TO_WORDS(bits + MP_WBITS - 1); /* if min has more bits than what was requested for p, bail out */ if (min && (mpbits(min->size, min->data) > bits)) return -1; /* if max has a different number of bits than what was requested for p, bail out */ if (max && (mpbits(max->size, max->data) != bits)) return -1; /* if min is not less than max, bail out */ if (min && max && mpgex(min->size, min->data, max->size, max->data)) return -1; mpbinit(p, size); if (p->modl) { while (1) { /* * Generate a random appropriate candidate prime, and test * it with small prime divisor test BEFORE computing mu */ mpprndbits(p, bits, 1, min, max, rc, wksp); /* do a small prime product trial division test on p */ if (!mppsppdiv_w(p, wksp)) continue; /* if we have an f, do the congruence test */ if (f != (mpnumber*) 0) { mpcopy(size, wksp, p->modl); mpsubw(size, wksp, 1); mpsetx(size, wksp+size, f->size, f->data); mpgcd_w(size, wksp, wksp+size, wksp+2*size, wksp+3*size); if (!mpisone(size, wksp+2*size)) continue; } /* candidate has passed so far, now we do the probabilistic test */ mpbmu_w(p, wksp); if (mppmilrab_w(p, rc, t, wksp)) return 0; } } return -1; }
mpint* mpfactorial(ulong n) { int i; ulong k; unsigned cnt; int max, mmax; mpdigit p, pp[2]; mpint *r, *s, *stk[31]; cnt = 0; max = mmax = -1; p = 1; r = mpnew(0); for(k=2; k<=n; k++) { pp[0] = 0; pp[1] = 0; mpvecdigmuladd(&p, 1, (mpdigit)k, pp); if(pp[1] == 0) /* !overflow */ p = pp[0]; else { cnt++; if((cnt & 1) == 0) { s = stk[max]; mpbits(r, Dbits*(s->top+1+1)); memset(r->p, 0, Dbytes*(s->top+1+1)); mpvecmul(s->p, s->top, &p, 1, r->p); r->sign = 1; r->top = s->top+1+1; /* XXX: norm */ mpassign(r, s); for(i=4; (cnt & (i-1)) == 0; i=i<<1) { mpmul(stk[max], stk[max-1], r); mpassign(r, stk[max-1]); max--; } } else { max++; if(max > mmax) { mmax++; if(max > nelem(stk)) abort(); stk[max] = mpnew(Dbits); } stk[max]->top = 1; stk[max]->p[0] = p; } p = (mpdigit)k; } } if(max < 0) { mpbits(r, Dbits); r->top = 1; r->sign = 1; r->p[0] = p; } else { s = stk[max--]; mpbits(r, Dbits*(s->top+1+1)); memset(r->p, 0, Dbytes*(s->top+1+1)); mpvecmul(s->p, s->top, &p, 1, r->p); r->sign = 1; r->top = s->top+1+1; /* XXX: norm */ } while(max >= 0) mpmul(r, stk[max--], r); for(max=mmax; max>=0; max--) mpfree(stk[max]); mpnorm(r); return r; }
int dsavrfy(const mpbarrett* p, const mpbarrett* q, const mpnumber* g, const mpnumber* hm, const mpnumber* y, const mpnumber* r, const mpnumber* s) { register size_t psize = p->size; register size_t qsize = q->size; register mpw* ptemp; register mpw* qtemp; register mpw* pwksp; register mpw* qwksp; register int rc = 0; /* h(m) shouldn't contain more bits than q */ if (mpbits(hm->size, hm->data) > mpbits(q->size, q->modl)) return rc; /* check 0 < r < q */ if (mpz(r->size, r->data)) return rc; if (mpgex(r->size, r->data, qsize, q->modl)) return rc; /* check 0 < s < q */ if (mpz(s->size, s->data)) return rc; if (mpgex(s->size, s->data, qsize, q->modl)) return rc; ptemp = (mpw*) malloc((6*psize+2)*sizeof(mpw)); if (ptemp == (mpw*) 0) return rc; qtemp = (mpw*) malloc((8*qsize+6)*sizeof(mpw)); if (qtemp == (mpw*) 0) { free(ptemp); return rc; } pwksp = ptemp+2*psize; qwksp = qtemp+2*qsize; mpsetx(qsize, qtemp+qsize, s->size, s->data); /* compute w = inv(s) mod q */ if (mpextgcd_w(qsize, q->modl, qtemp+qsize, qtemp, qwksp)) { /* compute u1 = h(m)*w mod q */ mpbmulmod_w(q, hm->size, hm->data, qsize, qtemp, qtemp+qsize, qwksp); /* compute u2 = r*w mod q */ mpbmulmod_w(q, r->size, r->data, qsize, qtemp, qtemp, qwksp); /* compute g^u1 mod p */ mpbpowmod_w(p, g->size, g->data, qsize, qtemp+qsize, ptemp, pwksp); /* compute y^u2 mod p */ mpbpowmod_w(p, y->size, y->data, qsize, qtemp, ptemp+psize, pwksp); /* multiply mod p */ mpbmulmod_w(p, psize, ptemp, psize, ptemp+psize, ptemp, pwksp); /* modulo q */ mpmod(ptemp+psize, psize, ptemp, qsize, q->modl, pwksp); rc = mpeqx(r->size, r->data, psize, ptemp+psize); } free(qtemp); free(ptemp); return rc; }
size_t mpbbits(const mpbarrett* b) { return mpbits(b->size, b->modl); }
void mpdiv(mpint *dividend, mpint *divisor, mpint *quotient, mpint *remainder) { int j, s, vn, sign; mpdigit qd, *up, *vp, *qp; mpint *u, *v, *t; // divide bv zero if(divisor->top == 0) sysfatal("mpdiv: divide by zero"); // quick check if(mpmagcmp(dividend, divisor) < 0){ if(remainder != nil) mpassign(dividend, remainder); if(quotient != nil) mpassign(mpzero, quotient); return; } // D1: shift until divisor, v, has hi bit set (needed to make trial // divisor accurate) qd = divisor->p[divisor->top-1]; for(s = 0; (qd & mpdighi) == 0; s++) qd <<= 1; u = mpnew((dividend->top+2)*Dbits + s); if(s == 0 && divisor != quotient && divisor != remainder) { mpassign(dividend, u); v = divisor; } else { mpleft(dividend, s, u); v = mpnew(divisor->top*Dbits); mpleft(divisor, s, v); } up = u->p+u->top-1; vp = v->p+v->top-1; vn = v->top; // D1a: make sure high digit of dividend is less than high digit of divisor if(*up >= *vp){ *++up = 0; u->top++; } // storage for multiplies t = mpnew(4*Dbits); qp = nil; if(quotient != nil){ mpbits(quotient, (u->top - v->top)*Dbits); quotient->top = u->top - v->top; qp = quotient->p+quotient->top-1; } // D2, D7: loop on length of dividend for(j = u->top; j > vn; j--){ // D3: calculate trial divisor mpdigdiv(up-1, *vp, &qd); // D3a: rule out trial divisors 2 greater than real divisor if(vn > 1) for(;;){ memset(t->p, 0, 3*Dbytes); // mpvecdigmuladd adds to what's there mpvecdigmuladd(vp-1, 2, qd, t->p); if(mpveccmp(t->p, 3, up-2, 3) > 0) qd--; else break; } // D4: u -= v*qd << j*Dbits sign = mpvecdigmulsub(v->p, vn, qd, up-vn); if(sign < 0){ // D6: trial divisor was too high, add back borrowed // value and decrease divisor mpvecadd(up-vn, vn+1, v->p, vn, up-vn); qd--; } // D5: save quotient digit if(qp != nil) *qp-- = qd; // push top of u down one u->top--; *up-- = 0; } if(qp != nil){ mpnorm(quotient); if(dividend->sign != divisor->sign) quotient->sign = -1; } if(remainder != nil){ mpright(u, s, remainder); // u is the remainder shifted remainder->sign = dividend->sign; } mpfree(t); mpfree(u); if(v != divisor) mpfree(v); }