/* this=this^e */ public FP12 pow(BIG e) { norm(); e.norm(); FP12 w = new FP12(this); BIG z = new BIG(e); FP12 r = new FP12(1); while (true) { int bt = z.parity(); z.fshr(1); if (bt == 1) { r.mul(w); } if (z.iszilch()) { break; } w.usqr(); } r.reduce(); return(r); }
/* return this^e mod m */ public virtual BIG powmod(BIG e, BIG m) { int bt; norm(); e.norm(); BIG a = new BIG(1); BIG z = new BIG(e); BIG s = new BIG(this); while (true) { bt = z.parity(); z.fshr(1); if (bt == 1) { a = modmul(a, s, m); } if (z.iszilch()) { break; } s = modsqr(s, m); } return(a); }
/* return this^e mod Modulus */ public FP pow(BIG e) { int bt; FP r = new FP(1); e.norm(); x.norm(); FP m = new FP(this); while (true) { bt = e.parity(); e.fshr(1); if (bt == 1) { r.mul(m); } if (e.iszilch()) { break; } m.sqr(); } r.x.mod(p); return(r); }
/* 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); }
/* Jacobi Symbol (this/p). Returns 0, 1 or -1 */ public virtual int jacobi(BIG p) { int n8, k, m = 0; BIG t = new BIG(0); BIG x = new BIG(0); BIG n = new BIG(0); BIG zilch = new BIG(0); BIG one = new BIG(1); if (p.parity() == 0 || comp(this, zilch) == 0 || comp(p, one) <= 0) { return(0); } norm(); x.copy(this); n.copy(p); x.mod(p); while (comp(n, one) > 0) { if (comp(x, zilch) == 0) { return(0); } n8 = n.lastbits(3); k = 0; while (x.parity() == 0) { k++; x.shr(1); } if (k % 2 == 1) { m += (n8 * n8 - 1) / 8; } m += (n8 - 1) * (x.lastbits(2) - 1) / 4; t.copy(n); t.mod(x); n.copy(x); x.copy(t); m %= 2; } if (m == 0) { return(1); } else { return(-1); } }
/* this/=2 mod Modulus */ public void div2() { x.norm(); if (x.parity() == 0) { x.fshr(1); } else { x.add(p); x.norm(); x.fshr(1); } }
/* 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 e.this+f.Q */ public ECP mul2(BIG e, ECP Q, BIG f) { BIG te = new BIG(); BIG tf = new BIG(); BIG mt = new BIG(); ECP S = new ECP(); ECP T = new ECP(); ECP C = new ECP(); ECP[] W = new ECP[8]; sbyte[] w = new sbyte[1 + (ROM.NLEN * ROM.BASEBITS + 1) / 2]; int i, s, ns, nb; sbyte a, b; affine(); Q.affine(); te.copy(e); tf.copy(f); // precompute table W[1] = new ECP(); W[1].copy(this); W[1].sub(Q); W[2] = new ECP(); W[2].copy(this); W[2].add(Q); S.copy(Q); S.dbl(); W[0] = new ECP(); W[0].copy(W[1]); W[0].sub(S); W[3] = new ECP(); W[3].copy(W[2]); W[3].add(S); T.copy(this); T.dbl(); W[5] = new ECP(); W[5].copy(W[1]); W[5].add(T); W[6] = new ECP(); W[6].copy(W[2]); W[6].add(T); W[4] = new ECP(); W[4].copy(W[5]); W[4].sub(S); W[7] = new ECP(); W[7].copy(W[6]); W[7].add(S); // convert the table to affine if (ROM.CURVETYPE == ROM.WEIERSTRASS) { multiaffine(8, W); } // if multiplier is odd, add 2, else add 1 to multiplier, and add 2P or P to correction s = te.parity(); te.inc(1); te.norm(); ns = te.parity(); mt.copy(te); mt.inc(1); mt.norm(); te.cmove(mt, s); T.cmove(this, ns); C.copy(T); s = tf.parity(); tf.inc(1); tf.norm(); ns = tf.parity(); mt.copy(tf); mt.inc(1); mt.norm(); tf.cmove(mt, s); S.cmove(Q, ns); C.add(S); mt.copy(te); mt.add(tf); mt.norm(); nb = 1 + (mt.nbits() + 1) / 2; // convert exponent to signed 2-bit window for (i = 0; i < nb; i++) { a = (sbyte)(te.lastbits(3) - 4); te.dec(a); te.norm(); te.fshr(2); b = (sbyte)(tf.lastbits(3) - 4); tf.dec(b); tf.norm(); tf.fshr(2); w[i] = (sbyte)(4 * a + b); } w[nb] = (sbyte)(4 * te.lastbits(3) + tf.lastbits(3)); S.copy(W[(w[nb] - 1) / 2]); for (i = nb - 1; i >= 0; i--) { T.select(W, w[i]); S.dbl(); S.dbl(); S.add(T); } S.sub(C); // apply correction S.affine(); return(S); }
/* this=1/this mod p. Binary method */ public virtual void invmodp(BIG p) { mod(p); BIG u = new BIG(this); BIG v = new BIG(p); BIG x1 = new BIG(1); BIG x2 = new BIG(0); BIG t = new BIG(0); BIG one = new BIG(1); while (comp(u, one) != 0 && comp(v, one) != 0) { while (u.parity() == 0) { u.shr(1); if (x1.parity() != 0) { x1.add(p); x1.norm(); } x1.shr(1); } while (v.parity() == 0) { v.shr(1); if (x2.parity() != 0) { x2.add(p); x2.norm(); } x2.shr(1); } 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); } }
/* P*=e */ public ECP2 mul(BIG e) { /* fixed size windows */ int i, b, nb, m, s, ns; BIG mt = new BIG(); BIG t = new BIG(); ECP2 P = new ECP2(); ECP2 Q = new ECP2(); ECP2 C = new ECP2(); ECP2[] W = new ECP2[8]; sbyte[] w = new sbyte[1 + (ROM.NLEN * ROM.BASEBITS + 3) / 4]; if (is_infinity()) { return(new ECP2()); } affine(); /* precompute table */ Q.copy(this); Q.dbl(); W[0] = new ECP2(); W[0].copy(this); for (i = 1; i < 8; i++) { W[i] = new ECP2(); W[i].copy(W[i - 1]); W[i].add(Q); } /* convert the table to affine */ 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); P.affine(); return(P); }
/* r=ck^a.cl^n using XTR double exponentiation method on traces of FP12s. See Stam thesis. */ public FP4 xtr_pow2(FP4 ck, FP4 ckml, FP4 ckm2l, BIG a, BIG b) { a.norm(); b.norm(); BIG e = new BIG(a); BIG d = new BIG(b); BIG w = new BIG(0); FP4 cu = new FP4(ck); // can probably be passed in w/o copying FP4 cv = new FP4(this); FP4 cumv = new FP4(ckml); FP4 cum2v = new FP4(ckm2l); FP4 r = new FP4(0); FP4 t = new FP4(0); int f2 = 0; while (d.parity() == 0 && e.parity() == 0) { d.fshr(1); e.fshr(1); f2++; } while (BIG.comp(d, e) != 0) { if (BIG.comp(d, e) > 0) { w.copy(e); w.imul(4); w.norm(); if (BIG.comp(d, w) <= 0) { w.copy(d); d.copy(e); e.rsub(w); e.norm(); t.copy(cv); t.xtr_A(cu, cumv, cum2v); cum2v.copy(cumv); cum2v.conj(); cumv.copy(cv); cv.copy(cu); cu.copy(t); } else if (d.parity() == 0) { d.fshr(1); r.copy(cum2v); r.conj(); t.copy(cumv); t.xtr_A(cu, cv, r); cum2v.copy(cumv); cum2v.xtr_D(); cumv.copy(t); cu.xtr_D(); } else if (e.parity() == 1) { d.sub(e); d.norm(); d.fshr(1); t.copy(cv); t.xtr_A(cu, cumv, cum2v); cu.xtr_D(); cum2v.copy(cv); cum2v.xtr_D(); cum2v.conj(); cv.copy(t); } else { w.copy(d); d.copy(e); d.fshr(1); e.copy(w); t.copy(cumv); t.xtr_D(); cumv.copy(cum2v); cumv.conj(); cum2v.copy(t); cum2v.conj(); t.copy(cv); t.xtr_D(); cv.copy(cu); cu.copy(t); } } if (BIG.comp(d, e) < 0) { w.copy(d); w.imul(4); w.norm(); if (BIG.comp(e, w) <= 0) { e.sub(d); e.norm(); t.copy(cv); t.xtr_A(cu, cumv, cum2v); cum2v.copy(cumv); cumv.copy(cu); cu.copy(t); } else if (e.parity() == 0) { w.copy(d); d.copy(e); d.fshr(1); e.copy(w); t.copy(cumv); t.xtr_D(); cumv.copy(cum2v); cumv.conj(); cum2v.copy(t); cum2v.conj(); t.copy(cv); t.xtr_D(); cv.copy(cu); cu.copy(t); } else if (d.parity() == 1) { w.copy(e); e.copy(d); w.sub(d); w.norm(); d.copy(w); d.fshr(1); t.copy(cv); t.xtr_A(cu, cumv, cum2v); cumv.conj(); cum2v.copy(cu); cum2v.xtr_D(); cum2v.conj(); cu.copy(cv); cu.xtr_D(); cv.copy(t); } else { d.fshr(1); r.copy(cum2v); r.conj(); t.copy(cumv); t.xtr_A(cu, cv, r); cum2v.copy(cumv); cum2v.xtr_D(); cumv.copy(t); cu.xtr_D(); } } } r.copy(cv); r.xtr_A(cu, cumv, cum2v); for (int i = 0; i < f2; i++) { r.xtr_D(); } r = r.xtr_pow(d); return(r); }