// find a prime p of length n and a generator alpha of Z^*_p // Alg 4.86 Menezes et al () Handbook, p.164 void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy) { mpint *q, *b; q = mpnew(n-1); while(1){ genprime(q, n-1, accuracy); mpleft(q, 1, p); mpadd(p, mpone, p); // p = 2*q+1 if(probably_prime(p, accuracy)) break; } // now find a generator alpha of the multiplicative // group Z*_p of order p-1=2q b = mpnew(0); while(1){ mprand(n, genrandom, alpha); mpmod(alpha, p, alpha); mpmul(alpha, alpha, b); mpmod(b, p, b); if(mpcmp(b, mpone) == 0) continue; mpexp(alpha, q, p, b); if(mpcmp(b, mpone) != 0) break; } mpfree(b); mpfree(q); }
void testshift(char *str) { mpint *b1, *b2; int i; b1 = strtomp(str, nil, 16, nil); malloccheck(); fprint(2, "A"); b2 = mpnew(0); fprint(2, "B"); malloccheck(); mpleft(b1, 20, b2); fprint(2, "C"); malloccheck(); mpfree(b1); fprint(2, "D"); malloccheck(); mpfree(b2); }
void ecadd(ECdomain *dom, ECpoint *a, ECpoint *b, ECpoint *s) { mpint *l, *k, *sx, *sy; if(a->inf && b->inf){ s->inf = 1; return; } if(a->inf){ ecassign(dom, b, s); return; } if(b->inf){ ecassign(dom, a, s); return; } if(mpcmp(a->x, b->x) == 0 && (mpcmp(a->y, mpzero) == 0 || mpcmp(a->y, b->y) != 0)){ s->inf = 1; return; } l = mpnew(0); k = mpnew(0); sx = mpnew(0); sy = mpnew(0); if(mpcmp(a->x, b->x) == 0 && mpcmp(a->y, b->y) == 0){ mpadd(mpone, mptwo, k); mpmul(a->x, a->x, l); mpmul(l, k, l); mpadd(l, dom->a, l); mpleft(a->y, 1, k); mpmod(k, dom->p, k); mpinvert(k, dom->p, k); mpmul(k, l, l); mpmod(l, dom->p, l); mpleft(a->x, 1, k); mpmul(l, l, sx); mpsub(sx, k, sx); mpmod(sx, dom->p, sx); mpsub(a->x, sx, sy); mpmul(l, sy, sy); mpsub(sy, a->y, sy); mpmod(sy, dom->p, sy); mpassign(sx, s->x); mpassign(sy, s->y); mpfree(sx); mpfree(sy); mpfree(l); mpfree(k); return; } mpsub(b->y, a->y, l); mpmod(l, dom->p, l); mpsub(b->x, a->x, k); mpmod(k, dom->p, k); mpinvert(k, dom->p, k); mpmul(k, l, l); mpmod(l, dom->p, l); mpmul(l, l, sx); mpsub(sx, a->x, sx); mpsub(sx, b->x, sx); mpmod(sx, dom->p, sx); mpsub(a->x, sx, sy); mpmul(sy, l, sy); mpsub(sy, a->y, sy); mpmod(sy, dom->p, sy); mpassign(sx, s->x); mpassign(sy, s->y); mpfree(sx); mpfree(sy); mpfree(l); mpfree(k); }
// extended binary gcd // // For a anv b it solves, v = gcd(a,b) and finds x and y s.t. // ax + by = v // // Handbook of Applied Cryptography, Menezes et al, 1997, pg 608. void mpextendedgcd(mpint *a, mpint *b, mpint *v, mpint *x, mpint *y) { mpint *u, *A, *B, *C, *D; int g; if(a->top == 0){ mpassign(b, v); mpassign(mpone, y); mpassign(mpzero, x); return; } if(b->top == 0){ mpassign(a, v); mpassign(mpone, x); mpassign(mpzero, y); return; } g = 0; a = mpcopy(a); b = mpcopy(b); while(iseven(a) && iseven(b)){ mpright(a, 1, a); mpright(b, 1, b); g++; } u = mpcopy(a); mpassign(b, v); A = mpcopy(mpone); B = mpcopy(mpzero); C = mpcopy(mpzero); D = mpcopy(mpone); for(;;) { // print("%B %B %B %B %B %B\n", u, v, A, B, C, D); while(iseven(u)){ mpright(u, 1, u); if(!iseven(A) || !iseven(B)) { mpadd(A, b, A); mpsub(B, a, B); } mpright(A, 1, A); mpright(B, 1, B); } // print("%B %B %B %B %B %B\n", u, v, A, B, C, D); while(iseven(v)){ mpright(v, 1, v); if(!iseven(C) || !iseven(D)) { mpadd(C, b, C); mpsub(D, a, D); } mpright(C, 1, C); mpright(D, 1, D); } // print("%B %B %B %B %B %B\n", u, v, A, B, C, D); if(mpcmp(u, v) >= 0){ mpsub(u, v, u); mpsub(A, C, A); mpsub(B, D, B); } else { mpsub(v, u, v); mpsub(C, A, C); mpsub(D, B, D); } if(u->top == 0) break; } mpassign(C, x); mpassign(D, y); mpleft(v, g, v); mpfree(A); mpfree(B); mpfree(C); mpfree(D); mpfree(u); mpfree(a); mpfree(b); }
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); }