int dldp_pgoqGenerator_w(dldp_p* dp, randomGeneratorContext* rgc, mpw* wksp) { /* * Randomly determine a generator over the subgroup with order q */ register size_t size = dp->p.size; mpnfree(&dp->g); mpnsize(&dp->g, size); while (1) { /* get a random value h (stored into g) */ mpbrnd_w(&dp->p, rgc, dp->g.data, wksp); /* first compute h^r mod p (stored in g) */ mpbpowmod_w(&dp->p, size, dp->g.data, dp->r.size, dp->r.data, dp->g.data, wksp); if (mpisone(size, dp->g.data)) continue; return 0; } return -1; }
/* * mppsppdiv_w * needs workspace of (3*size) words */ int mppsppdiv_w(const mpbarrett* p, mpw* wksp) { /* small prime product trial division test */ register size_t size = p->size; if (size > SMALL_PRIMES_PRODUCT_MAX) { mpsetx(size, wksp+size, SMALL_PRIMES_PRODUCT_MAX, mpspprod[SMALL_PRIMES_PRODUCT_MAX-1]); mpgcd_w(size, p->modl, wksp+size, wksp, wksp+2*size); } else { mpgcd_w(size, p->modl, mpspprod[size-1], wksp, wksp+2*size); } return mpisone(size, wksp); }
/* * needs workspace of (7*size+2) words */ int mpbpprime_w(const mpbarrett* b, randomGeneratorContext* r, int t, mpw* wksp) { /* * This test works for candidate probable primes >= 3, which are also not small primes. * * It assumes that b->modl contains the candidate prime * */ size_t size = b->size; /* first test if modl is odd */ if (mpodd(b->size, b->modl)) { /* * Small prime factor test: * * Tables in mpspprod contain multi-precision integers with products of small primes * If the greatest common divisor of this product and the candidate is not one, then * the candidate has small prime factors, or is a small prime. Neither is acceptable when * we are looking for large probable primes =) * */ if (size > SMALL_PRIMES_PRODUCT_MAX) { mpsetx(size, wksp+size, SMALL_PRIMES_PRODUCT_MAX, mpspprod[SMALL_PRIMES_PRODUCT_MAX-1]); mpgcd_w(size, b->modl, wksp+size, wksp, wksp+2*size); } else { mpgcd_w(size, b->modl, mpspprod[size-1], wksp, wksp+2*size); } if (mpisone(size, wksp)) { return mppmilrab_w(b, r, t, wksp); } } return 0; }
/* * needs workspace of (5*size+2) words */ int mppmilraba_w(const mpbarrett* p, const mpw* adata, int s, const mpw* rdata, const mpw* ndata, mpw* wksp) { register size_t size = p->size; register int j = 0; mpbpowmod_w(p, size, adata, size, rdata, wksp, wksp+size); while (1) { if (mpisone(size, wksp)) return (j == 0); if (mpeq(size, wksp, ndata)) return 1; if (++j < s) mpbsqrmod_w(p, size, wksp, wksp, wksp+size); else return 0; } }
/* * 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; }
static int Zmpbinv_w(const mpbarrett* b, size_t xsize, const mpw* xdata, mpw* result, mpw* wksp) { size_t ysize = b->size+1; size_t ubits, vbits; int k = 0; mpw* u = wksp; mpw* v = u+ysize; mpw* A = v+ysize; mpw* B = A+ysize; mpw* C = B+ysize; mpw* D = C+ysize; mpsetx(ysize, u, xsize, xdata); mpsetx(ysize, v, b->size, b->modl); mpsetw(ysize, A, 1); mpzero(ysize, B); mpzero(ysize, C); mpsetw(ysize, D, 1); for (k = 0; mpeven(ysize, u) && mpeven(ysize, v); k++) { mpdivtwo(ysize, u); mpdivtwo(ysize, v); } if (mpeven(ysize, u)) (void) mpadd(ysize, u, v); if (_debug < 0) fprintf(stderr, " u: "), mpfprintln(stderr, ysize, u); if (_debug < 0) fprintf(stderr, " v: "), mpfprintln(stderr, ysize, v); if (_debug < 0) fprintf(stderr, " A: "), mpfprintln(stderr, ysize, A); if (_debug < 0) fprintf(stderr, " B: "), mpfprintln(stderr, ysize, B); if (_debug < 0) fprintf(stderr, " C: "), mpfprintln(stderr, ysize, C); if (_debug < 0) fprintf(stderr, " D: "), mpfprintln(stderr, ysize, D); ubits = vbits = MP_WORDS_TO_BITS(ysize); do { while (mpeven(ysize, v)) { mpsdivtwo(ysize, v); vbits -= 1; if (mpodd(ysize, C)) { (void) mpaddx(ysize, C, b->size, b->modl); (void) mpsubx(ysize, D, xsize, xdata); } mpsdivtwo(ysize, C); mpsdivtwo(ysize, D); if (_debug < 0) fprintf(stderr, "-->> v: "), mpfprintln(stderr, ysize, v); } if (ubits >= vbits) { mpw* swapu; size_t swapi; if (_debug < 0) fprintf(stderr, "--> (swap u <-> v)\n"); swapu = u; u = v; v = swapu; swapi = ubits; ubits = vbits; vbits = swapi; swapu = A; A = C; C = swapu; swapu = B; B = D; D = swapu; } if (!((u[ysize-1] + v[ysize-1]) & 0x3)) { if (_debug < 0) fprintf(stderr, "--> (even parity)\n"); mpadd(ysize, v, u); mpadd(ysize, C, A); mpadd(ysize, D, B); } else { if (_debug < 0) fprintf(stderr, "--> (odd parity)\n"); mpsub(ysize, v, u); mpsub(ysize, C, A); mpsub(ysize, D, B); } if (_debug < 0) fprintf(stderr, " v: "), mpfprintln(stderr, ysize, v); if (_debug < 0) fprintf(stderr, " C: "), mpfprintln(stderr, ysize, C); if (_debug < 0) fprintf(stderr, " D: "), mpfprintln(stderr, ysize, D); vbits++; } while (mpnz(ysize, v)); #ifdef NOTYET if (!mpisone(ysize, u)) return 0; #endif if (result) { mpsetx(b->size, result, ysize, A); /*@-usedef@*/ if (*A & 0x80000000) (void) mpneg(b->size, result); /*@=usedef@*/ while (--k > 0) mpadd(b->size, result, result); } fprintf(stderr, "=== EXIT: "), mpfprintln(stderr, b->size, result); fprintf(stderr, " u: "), mpfprintln(stderr, ysize, u); fprintf(stderr, " v: "), mpfprintln(stderr, ysize, v); fprintf(stderr, " A: "), mpfprintln(stderr, ysize, A); fprintf(stderr, " B: "), mpfprintln(stderr, ysize, B); fprintf(stderr, " C: "), mpfprintln(stderr, ysize, C); fprintf(stderr, " D: "), mpfprintln(stderr, ysize, D); return 1; }
/** * Computes the inverse (modulo b) of x, and returns 1 if x was invertible. * needs workspace of (6*size+6) words * @note xdata and result cannot point to the same area */ static int Xmpbinv_w(const mpbarrett* b, size_t xsize, const mpw* xdata, mpw* result, mpw* wksp) { /* * Fact: if a element of Zn, then a is invertible if and only if gcd(a,n) = 1 * Hence: if b->modl is even, then x must be odd, otherwise the gcd(x,n) >= 2 * * The calling routine must guarantee this condition. */ size_t ysize = b->size+1; mpw* u = wksp; mpw* v = u+ysize; mpw* A = v+ysize; mpw* B = A+ysize; mpw* C = B+ysize; mpw* D = C+ysize; mpsetx(ysize, u, b->size, b->modl); mpsetx(ysize, v, xsize, xdata); mpsetw(ysize, A, 1); mpzero(ysize, B); mpzero(ysize, C); mpsetw(ysize, D, 1); if (_debug < 0) fprintf(stderr, " u: "), mpfprintln(stderr, ysize, u); if (_debug < 0) fprintf(stderr, " v: "), mpfprintln(stderr, ysize, v); if (_debug < 0) fprintf(stderr, " A: "), mpfprintln(stderr, ysize, A); if (_debug < 0) fprintf(stderr, " B: "), mpfprintln(stderr, ysize, B); if (_debug < 0) fprintf(stderr, " C: "), mpfprintln(stderr, ysize, C); if (_debug < 0) fprintf(stderr, " D: "), mpfprintln(stderr, ysize, D); do { while (mpeven(ysize, u)) { mpdivtwo(ysize, u); if (mpodd(ysize, A) || mpodd(ysize, B)) { (void) mpaddx(ysize, A, xsize, xdata); (void) mpsubx(ysize, B, b->size, b->modl); } mpsdivtwo(ysize, A); mpsdivtwo(ysize, B); } while (mpeven(ysize, v)) { mpdivtwo(ysize, v); if (mpodd(ysize, C) || mpodd(ysize, D)) { (void) mpaddx(ysize, C, xsize, xdata); (void) mpsubx(ysize, D, b->size, b->modl); } mpsdivtwo(ysize, C); mpsdivtwo(ysize, D); } if (mpge(ysize, u, v)) { if (_debug < 0) fprintf(stderr, "--> 5 (u >= v)\n"); (void) mpsub(ysize, u, v); (void) mpsub(ysize, A, C); (void) mpsub(ysize, B, D); if (_debug < 0) fprintf(stderr, " u: "), mpfprintln(stderr, ysize, u); if (_debug < 0) fprintf(stderr, " A: "), mpfprintln(stderr, ysize, A); if (_debug < 0) fprintf(stderr, " B: "), mpfprintln(stderr, ysize, B); } else { if (_debug < 0) fprintf(stderr, "--> 5 (u < v)\n"); (void) mpsub(ysize, v, u); (void) mpsub(ysize, C, A); (void) mpsub(ysize, D, B); if (_debug < 0) fprintf(stderr, " v: "), mpfprintln(stderr, ysize, v); if (_debug < 0) fprintf(stderr, " C: "), mpfprintln(stderr, ysize, C); if (_debug < 0) fprintf(stderr, " D: "), mpfprintln(stderr, ysize, D); } } while (mpnz(ysize, u)); if (!mpisone(ysize, v)) return 0; if (result) { mpsetx(b->size, result, ysize, D); /*@-usedef@*/ if (*D & 0x80000000) (void) mpadd(b->size, result, b->modl); /*@=usedef@*/ } fprintf(stderr, "=== EXIT: "), mpfprintln(stderr, b->size, result); fprintf(stderr, " u: "), mpfprintln(stderr, ysize, u); fprintf(stderr, " v: "), mpfprintln(stderr, ysize, v); fprintf(stderr, " A: "), mpfprintln(stderr, ysize, A); fprintf(stderr, " B: "), mpfprintln(stderr, ysize, B); fprintf(stderr, " C: "), mpfprintln(stderr, ysize, C); fprintf(stderr, " D: "), mpfprintln(stderr, ysize, D); return 1; }
static int Ympbinv_w(const mpbarrett* b, size_t xsize, const mpw* xdata, mpw* result, mpw* wksp) { size_t ysize = b->size+1; int k; mpw* u1 = wksp; mpw* u2 = u1+ysize; mpw* u3 = u2+ysize; mpw* v1 = u3+ysize; mpw* v2 = v1+ysize; mpw* v3 = v2+ysize; mpw* t1 = v3+ysize; mpw* t2 = t1+ysize; mpw* t3 = t2+ysize; mpw* u = t3+ysize; mpw* v = u+ysize; mpsetx(ysize, u, xsize, xdata); mpsetx(ysize, v, b->size, b->modl); /* Y1. Find power of 2. */ for (k = 0; mpeven(ysize, u) && mpeven(ysize, v); k++) { mpdivtwo(ysize, u); mpdivtwo(ysize, v); } if (_debug < 0) fprintf(stderr, " u: "), mpfprintln(stderr, ysize, u); if (_debug < 0) fprintf(stderr, " v: "), mpfprintln(stderr, ysize, v); /* Y2. Initialize. */ mpsetw(ysize, u1, 1); if (_debug < 0) fprintf(stderr, " u1: "), mpfprintln(stderr, ysize, u1); mpzero(ysize, u2); if (_debug < 0) fprintf(stderr, " u2: "), mpfprintln(stderr, ysize, u2); mpsetx(ysize, u3, ysize, u); if (_debug < 0) fprintf(stderr, " u3: "), mpfprintln(stderr, ysize, u3); mpsetx(ysize, v1, ysize, v); if (_debug < 0) fprintf(stderr, " v1: "), mpfprintln(stderr, ysize, v1); mpsetw(ysize, v2, 1); (void) mpsub(ysize, v2, u); if (_debug < 0) fprintf(stderr, " v2: "), mpfprintln(stderr, ysize, v2); mpsetx(ysize, v3, ysize, v); if (_debug < 0) fprintf(stderr, " v3: "), mpfprintln(stderr, ysize, v3); if (mpodd(ysize, u)) { mpzero(ysize, t1); if (_debug < 0) fprintf(stderr, " t1: "), mpfprintln(stderr, ysize, t1); mpzero(ysize, t2); mpsubw(ysize, t2, 1); if (_debug < 0) fprintf(stderr, " t2: "), mpfprintln(stderr, ysize, t2); mpzero(ysize, t3); mpsub(ysize, t3, v); if (_debug < 0) fprintf(stderr, " t3: "), mpfprintln(stderr, ysize, t3); goto Y4; } else { mpsetw(ysize, t1, 1); if (_debug < 0) fprintf(stderr, " t1: "), mpfprintln(stderr, ysize, t1); mpzero(ysize, t2); if (_debug < 0) fprintf(stderr, " t2: "), mpfprintln(stderr, ysize, t2); mpsetx(ysize, t3, ysize, u); if (_debug < 0) fprintf(stderr, " t3: "), mpfprintln(stderr, ysize, t3); } do { do { if (mpodd(ysize, t1) || mpodd(ysize, t2)) { mpadd(ysize, t1, v); mpsub(ysize, t2, u); } mpsdivtwo(ysize, t1); mpsdivtwo(ysize, t2); mpsdivtwo(ysize, t3); Y4: if (_debug < 0) fprintf(stderr, " Y4 t3: "), mpfprintln(stderr, ysize, t3); } while (mpeven(ysize, t3)); /* Y5. Reset max(u3,v3). */ if (!(*t3 & 0x80000000)) { if (_debug < 0) fprintf(stderr, "--> Y5 (t3 > 0)\n"); mpsetx(ysize, u1, ysize, t1); if (_debug < 0) fprintf(stderr, " u1: "), mpfprintln(stderr, ysize, u1); mpsetx(ysize, u2, ysize, t2); if (_debug < 0) fprintf(stderr, " u2: "), mpfprintln(stderr, ysize, u2); mpsetx(ysize, u3, ysize, t3); if (_debug < 0) fprintf(stderr, " u3: "), mpfprintln(stderr, ysize, u3); } else { if (_debug < 0) fprintf(stderr, "--> Y5 (t3 <= 0)\n"); mpsetx(ysize, v1, ysize, v); mpsub(ysize, v1, t1); if (_debug < 0) fprintf(stderr, " v1: "), mpfprintln(stderr, ysize, v1); mpsetx(ysize, v2, ysize, u); mpneg(ysize, v2); mpsub(ysize, v2, t2); if (_debug < 0) fprintf(stderr, " v2: "), mpfprintln(stderr, ysize, v2); mpzero(ysize, v3); mpsub(ysize, v3, t3); if (_debug < 0) fprintf(stderr, " v3: "), mpfprintln(stderr, ysize, v3); } /* Y6. Subtract. */ mpsetx(ysize, t1, ysize, u1); mpsub(ysize, t1, v1); mpsetx(ysize, t2, ysize, u2); mpsub(ysize, t2, v2); mpsetx(ysize, t3, ysize, u3); mpsub(ysize, t3, v3); if (*t1 & 0x80000000) { mpadd(ysize, t1, v); mpsub(ysize, t2, u); } if (_debug < 0) fprintf(stderr, "-->Y6 t1: "), mpfprintln(stderr, ysize, t1); if (_debug < 0) fprintf(stderr, " t2: "), mpfprintln(stderr, ysize, t2); if (_debug < 0) fprintf(stderr, " t3: "), mpfprintln(stderr, ysize, t3); } while (mpnz(ysize, t3)); if (!(mpisone(ysize, u3) && mpisone(ysize, v3))) return 0; if (result) { while (--k > 0) mpadd(ysize, u1, u1); mpsetx(b->size, result, ysize, u1); } fprintf(stderr, "=== EXIT: "), mpfprintln(stderr, b->size, result); fprintf(stderr, " u1: "), mpfprintln(stderr, ysize, u1); fprintf(stderr, " u2: "), mpfprintln(stderr, ysize, u2); fprintf(stderr, " u3: "), mpfprintln(stderr, ysize, u3); fprintf(stderr, " v1: "), mpfprintln(stderr, ysize, v1); fprintf(stderr, " v2: "), mpfprintln(stderr, ysize, v2); fprintf(stderr, " v3: "), mpfprintln(stderr, ysize, v3); fprintf(stderr, " t1: "), mpfprintln(stderr, ysize, t1); fprintf(stderr, " t2: "), mpfprintln(stderr, ysize, t2); fprintf(stderr, " t3: "), mpfprintln(stderr, ysize, t3); return 1; }
int dldp_pgonGenerator_w(dldp_p* dp, randomGeneratorContext* rgc, mpw* wksp) { register size_t size = dp->p.size; mpnfree(&dp->g); mpnsize(&dp->g, size); while (1) { mpbrnd_w(&dp->p, rgc, dp->g.data, wksp); if (mpistwo(dp->r.size, dp->r.data)) { /* * A little math here: the only element in the group which has order 2 is (p-1); * the two group elements raised to power two which result in 1 (mod p) are thus (p-1) and 1 * * mpbrnd_w doesn't return 1 or (p-1), so the test where g^2 mod p = 1 can be safely skipped */ /* check g^q mod p*/ mpbpowmod_w(&dp->p, size, dp->g.data, dp->q.size, dp->q.modl, wksp, wksp+size); if (mpisone(size, wksp)) continue; } else { /* we can either compute g^r, g^2q and g^(qr/2) or * we first compute s = r/2, and then compute g^2s, g^2q and g^qs * * hence we first compute t = g^s * then compute t^2 mod p, and test if one * then compute t^q mod p, and test if one * then compute (g^q mod p)^2 mod p, and test if one */ /* compute s = r/2 */ mpsetx(size, wksp, dp->r.size, dp->r.data); mpdivtwo(size, wksp); /* compute t = g^s mod p */ mpbpowmod_w(&dp->p, size, dp->g.data, size, wksp, wksp+size, wksp+2*size); /* compute t^2 mod p = g^2s mod p = g^r mod p*/ mpbsqrmod_w(&dp->p, size, wksp+size, wksp+size, wksp+2*size); if (mpisone(size, wksp+size)) continue; /* compute t^q mod p = g^qs mod p */ mpbpowmod_w(&dp->p, size, wksp, dp->q.size, dp->q.modl, wksp+size, wksp+2*size); if (mpisone(size, wksp+size)) continue; /* compute g^2q mod p */ mpbpowmod_w(&dp->p, size, dp->g.data, dp->q.size, dp->q.modl, wksp, wksp+size); mpbsqrmod_w(&dp->p, size, wksp, wksp+size, wksp+2*size); if (mpisone(size, wksp+size)) continue; } return 0; } return -1; }