/* this =this^e mod p using side-channel resistant Montgomery Ladder, for short e */ public void skpow(BIG e, FF p) { int i, b, n = p.length; FF R0 = new FF(n); FF R1 = new FF(n); FF ND = p.invmod2m(); mod(p); R0.one(); R1.copy(this); R0.nres(p); R1.nres(p); for (i = 8 * ROM.MODBYTES - 1; i >= 0; i--) { b = e.bit(i); copy(R0); modmul(R1, p, ND); cswap(R0, R1, b); R0.modsqr(p, ND); R1.copy(this); cswap(R0, R1, b); } copy(R0); redc(p, ND); }
/* quick and dirty check for common factor with n */ public bool cfactor(int s) { int r, n = length; int g; FF x = new FF(n); FF y = new FF(n); y.set(s); x.copy(this); x.norm(); do { x.sub(y); x.norm(); while (!x.iszilch() && x.parity() == 0) { x.shr(); } } while (comp(x, y) > 0); g = (int)x.v[0].get(0); r = igcd(s, g); if (r > 1) { return(true); } return(false); }
/* Set r=this mod b */ /* this is of length - 2*n */ /* r,b is of length - n */ public FF dmod(FF b) { int k, n = b.length; FF m = new FF(2 * n); FF x = new FF(2 * n); FF r = new FF(n); x.copy(this); x.norm(); m.dsucopy(b); k = 256 * n; while (k > 0) { m.shr(); if (comp(x, m) >= 0) { x.sub(m); x.norm(); } k--; } r.copy(x); r.mod(b); return(r); }
/* return low part of product this*y */ public void lmul(FF y) { int n = length; FF t = new FF(2 * n); FF x = new FF(n); x.copy(this); karmul_lower(0, x, 0, y, 0, t, 0, n); }
/* U=1/a mod 2^m - Arazi & Qi */ private FF invmod2m() { int i, n = length; FF b = new FF(n); FF c = new FF(n); FF U = new FF(n); FF t; U.zero(); U.v[0].copy(v[0]); U.v[0].invmod2m(); for (i = 1; i < n; i <<= 1) { b.copy(this); b.mod2m(i); t = mul(U, b); t.shrw(i); b.copy(t); c.copy(this); c.shrw(i); c.mod2m(i); c.lmul(U); c.mod2m(i); b.add(c); b.norm(); b.lmul(U); b.mod2m(i); c.one(); c.shlw(i); b.revsub(c); b.norm(); b.shlw(i); U.add(b); } U.norm(); return(U); }
/* double exponentiation r=x^e.y^f mod p */ public void pow2(BIG e, FF y, BIG f, FF p) { int i, eb, fb, n = p.length; FF xn = new FF(n); FF yn = new FF(n); FF xy = new FF(n); FF ND = p.invmod2m(); xn.copy(this); yn.copy(y); xn.nres(p); yn.nres(p); xy.copy(xn); xy.modmul(yn, p, ND); one(); nres(p); for (i = 8 * ROM.MODBYTES - 1; i >= 0; i--) { eb = e.bit(i); fb = f.bit(i); modsqr(p, ND); if (eb == 1) { if (fb == 1) { modmul(xy, p, ND); } else { modmul(xn, p, ND); } } else { if (fb == 1) { modmul(yn, p, ND); } } } redc(p, ND); }
/* raise to an integer power - right-to-left method */ public void power(int e, FF p) { int n = p.length; FF w = new FF(n); FF ND = p.invmod2m(); bool f = true; w.copy(this); w.nres(p); if (e == 2) { copy(w); modsqr(p, ND); } else { for (; ;) { if (e % 2 == 1) { if (f) { copy(w); } else { modmul(w, p, ND); } f = false; } e >>= 1; if (e == 0) { break; } w.modsqr(p, ND); } } redc(p, ND); }
/* this=this^e mod p, faster but not side channel resistant */ public void pow(FF e, FF p) { int i, b, n = p.length; FF w = new FF(n); FF ND = p.invmod2m(); w.copy(this); one(); nres(p); w.nres(p); for (i = 8 * ROM.MODBYTES * n - 1; i >= 0; i--) { modsqr(p, ND); b = e.v[i / 256].bit(i % 256); if (b == 1) { modmul(w, p, ND); } } redc(p, ND); }
/* generate an RSA key pair */ public static void KEY_PAIR(RAND rng, int e, rsa_private_key PRIV, rsa_public_key PUB) { // IEEE1363 A16.11/A16.12 more or less int n = PUB.n.getlen() / 2; FF t = new FF(n); FF p1 = new FF(n); FF q1 = new FF(n); for (;;) { PRIV.p.random(rng); while (PRIV.p.lastbits(2) != 3) { PRIV.p.inc(1); } while (!FF.prime(PRIV.p, rng)) { PRIV.p.inc(4); } p1.copy(PRIV.p); p1.dec(1); if (p1.cfactor(e)) { continue; } break; } for (;;) { PRIV.q.random(rng); while (PRIV.q.lastbits(2) != 3) { PRIV.q.inc(1); } while (!FF.prime(PRIV.q, rng)) { PRIV.q.inc(4); } q1.copy(PRIV.q); q1.dec(1); if (q1.cfactor(e)) { continue; } break; } PUB.n = FF.mul(PRIV.p, PRIV.q); PUB.e = e; t.copy(p1); t.shr(); PRIV.dp.set(e); PRIV.dp.invmodp(t); if (PRIV.dp.parity() == 0) { PRIV.dp.add(t); } PRIV.dp.norm(); t.copy(q1); t.shr(); PRIV.dq.set(e); PRIV.dq.invmodp(t); if (PRIV.dq.parity() == 0) { PRIV.dq.add(t); } PRIV.dq.norm(); PRIV.c.copy(PRIV.p); PRIV.c.invmodp(PRIV.q); return; }
/* Set return=1/this mod p. Binary method - a<p on entry */ public void invmodp(FF p) { int n = p.length; FF u = new FF(n); FF v = new FF(n); FF x1 = new FF(n); FF x2 = new FF(n); FF t = new FF(n); FF one = new FF(n); one.one(); u.copy(this); v.copy(p); x1.copy(one); x2.zero(); // reduce n in here as well! while (comp(u, one) != 0 && comp(v, one) != 0) { while (u.parity() == 0) { u.shr(); if (x1.parity() != 0) { x1.add(p); x1.norm(); } x1.shr(); } while (v.parity() == 0) { v.shr(); if (x2.parity() != 0) { x2.add(p); x2.norm(); } x2.shr(); } if (comp(u, v) >= 0) { u.sub(v); u.norm(); if (comp(x1, x2) >= 0) { x1.sub(x2); } else { t.copy(p); t.sub(x2); x1.add(t); } x1.norm(); } else { v.sub(u); v.norm(); if (comp(x2, x1) >= 0) { x2.sub(x1); } else { t.copy(p); t.sub(x1); x2.add(t); } x2.norm(); } } if (comp(u, one) == 0) { copy(x1); } else { copy(x2); } }
/* Miller-Rabin test for primality. Slow. */ public static bool prime(FF p, RAND rng) { int i, j, s = 0, n = p.length; bool loop; FF d = new FF(n); FF x = new FF(n); FF unity = new FF(n); FF nm1 = new FF(n); int sf = 4849845; // 3*5*.. *19 p.norm(); if (p.cfactor(sf)) { return(false); } unity.one(); nm1.copy(p); nm1.sub(unity); nm1.norm(); d.copy(nm1); while (d.parity() == 0) { d.shr(); s++; } if (s == 0) { return(false); } for (i = 0; i < 10; i++) { x.randomnum(p, rng); x.pow(d, p); if (comp(x, unity) == 0 || comp(x, nm1) == 0) { continue; } loop = false; for (j = 1; j < s; j++) { x.power(2, p); if (comp(x, unity) == 0) { return(false); } if (comp(x, nm1) == 0) { loop = true; break; } } if (loop) { continue; } return(false); } return(true); }