/* 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); }
/* r=x^n using XTR method on traces of FP12s */ public FP4 xtr_pow(BIG n) { FP4 a = new FP4(3); FP4 b = new FP4(this); FP4 c = new FP4(b); c.xtr_D(); FP4 t = new FP4(0); FP4 r = new FP4(0); n.norm(); int par = n.parity(); BIG v = new BIG(n); v.fshr(1); if (par == 0) { v.dec(1); v.norm(); } int nb = v.nbits(); for (int i = nb - 1; i >= 0; i--) { if (v.bit(i) != 1) { t.copy(b); conj(); c.conj(); b.xtr_A(a, this, c); conj(); c.copy(t); c.xtr_D(); a.xtr_D(); } else { t.copy(a); t.conj(); a.copy(b); a.xtr_D(); b.xtr_A(c, this, t); c.xtr_D(); } } if (par == 0) { r.copy(c); } else { r.copy(b); } r.reduce(); return(r); }
/* Optimal R-ate pairing */ public static FP12 ate(ECP2 P, ECP Q) { FP2 f = new FP2(new BIG(ROM.CURVE_Fra), new BIG(ROM.CURVE_Frb)); BIG x = new BIG(ROM.CURVE_Bnx); BIG n = new BIG(x); ECP2 K = new ECP2(); FP12 lv; n.pmul(6); n.dec(2); n.norm(); P.affine(); Q.affine(); FP Qx = new FP(Q.getx()); FP Qy = new FP(Q.gety()); ECP2 A = new ECP2(); FP12 r = new FP12(1); A.copy(P); int nb = n.nbits(); for (int i = nb - 2; i >= 1; i--) { lv = line(A, A, Qx, Qy); r.smul(lv); if (n.bit(i) == 1) { lv = line(A, P, Qx, Qy); r.smul(lv); } r.sqr(); } lv = line(A, A, Qx, Qy); r.smul(lv); /* R-ate fixup */ r.conj(); K.copy(P); K.frob(f); A.neg(); lv = line(A, K, Qx, Qy); r.smul(lv); K.frob(f); K.neg(); lv = line(A, K, Qx, Qy); r.smul(lv); return(r); }
/* 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); }
/* return e.this */ public ECP mul(BIG e) { if (e.iszilch() || is_infinity()) { return(new ECP()); } ECP P = new ECP(); if (ROM.CURVETYPE == ROM.MONTGOMERY) { /* use Ladder */ int nb, i, b; ECP D = new ECP(); ECP R0 = new ECP(); R0.copy(this); ECP R1 = new ECP(); R1.copy(this); R1.dbl(); D.copy(this); D.affine(); nb = e.nbits(); for (i = nb - 2; i >= 0; i--) { b = e.bit(i); P.copy(R1); P.dadd(R0, D); R0.cswap(R1, b); R1.copy(P); R0.dbl(); R0.cswap(R1, b); } P.copy(R0); } else { // fixed size windows int i, b, nb, m, s, ns; BIG mt = new BIG(); BIG t = new BIG(); ECP Q = new ECP(); ECP C = new ECP(); ECP[] W = new ECP[8]; sbyte[] w = new sbyte[1 + (ROM.NLEN * ROM.BASEBITS + 3) / 4]; affine(); // precompute table Q.copy(this); Q.dbl(); W[0] = new ECP(); W[0].copy(this); for (i = 1; i < 8; i++) { W[i] = new ECP(); W[i].copy(W[i - 1]); W[i].add(Q); } // convert the table to affine if (ROM.CURVETYPE == ROM.WEIERSTRASS) { multiaffine(8, W); } // make exponent odd - add 2P if even, P if odd t.copy(e); s = t.parity(); t.inc(1); t.norm(); ns = t.parity(); mt.copy(t); mt.inc(1); mt.norm(); t.cmove(mt, s); Q.cmove(this, ns); C.copy(Q); nb = 1 + (t.nbits() + 3) / 4; // convert exponent to signed 4-bit window for (i = 0; i < nb; i++) { w[i] = (sbyte)(t.lastbits(5) - 16); t.dec(w[i]); t.norm(); t.fshr(4); } w[nb] = (sbyte)t.lastbits(5); P.copy(W[(w[nb] - 1) / 2]); for (i = nb - 1; i >= 0; i--) { Q.select(W, w[i]); P.dbl(); P.dbl(); P.dbl(); P.dbl(); P.add(Q); } P.sub(C); // apply correction } P.affine(); return(P); }
/* return NAF value as +/- 1, 3 or 5. x and x3 should be normed. * nbs is number of bits processed, and nzs is number of trailing 0s detected */ public static int[] nafbits(BIG x, BIG x3, int i) { int[] n = new int[3]; int nb = x3.bit(i) - x.bit(i); int j; n[1] = 1; n[0] = 0; if (nb == 0) { n[0] = 0; return(n); } if (i == 0) { n[0] = nb; return(n); } if (nb > 0) { n[0] = 1; } else { n[0] = (-1); } for (j = i - 1; j > 0; j--) { n[1]++; n[0] *= 2; nb = x3.bit(j) - x.bit(j); if (nb > 0) { n[0] += 1; } if (nb < 0) { n[0] -= 1; } if (n[0] > 5 || n[0] < -5) { break; } } if (n[0] % 2 != 0 && j != 0) { // backtrack if (nb > 0) { n[0] = (n[0] - 1) / 2; } if (nb < 0) { n[0] = (n[0] + 1) / 2; } n[1]--; } while (n[0] % 2 == 0) { // remove trailing zeros n[0] /= 2; n[2]++; n[1]--; } return(n); }