/* constant time multiply by small integer of length bts - use ladder */ public ECP pinmul(int e, int bts) { if (ROM.CURVETYPE == ROM.MONTGOMERY) { return(this.mul(new BIG(e))); } else { int nb, i, b; ECP P = new ECP(); ECP R0 = new ECP(); ECP R1 = new ECP(); R1.copy(this); for (i = bts - 1; i >= 0; i--) { b = (e >> i) & 1; P.copy(R1); P.add(R0); R0.cswap(R1, b); R1.copy(P); R0.dbl(); R0.cswap(R1, b); } P.copy(R0); P.affine(); return(P); } }
/* IEEE1363 ECDSA Signature Verification. Signature C and D on F is verified using public key W */ public static int ECPVP_DSA(sbyte[] W, sbyte[] F, sbyte[] C, sbyte[] D) { BIG r, gx, gy, f, c, d, h2; int res = 0; ECP G, WP, P; HASH H = new HASH(); H.process_array(F); sbyte[] B = H.hash(); gx = new BIG(ROM.CURVE_Gx); gy = new BIG(ROM.CURVE_Gy); G = new ECP(gx, gy); r = new BIG(ROM.CURVE_Order); c = BIG.fromBytes(C); d = BIG.fromBytes(D); f = BIG.fromBytes(B); if (c.iszilch() || BIG.comp(c, r) >= 0 || d.iszilch() || BIG.comp(d, r) >= 0) { res = INVALID; } if (res == 0) { d.invmodp(r); f.copy(BIG.modmul(f, d, r)); h2 = BIG.modmul(c, d, r); WP = ECP.fromBytes(W); if (WP.is_infinity()) { res = ERROR; } else { P = new ECP(); P.copy(WP); P = P.mul2(h2, G, f); if (P.is_infinity()) { res = INVALID; } else { d = P.X; d.mod(r); if (BIG.comp(d, c) != 0) { res = INVALID; } } } } return(res); }
/* IEEE ECDSA Signature, C and D are signature on F using private key S */ public static int ECPSP_DSA(RAND RNG, sbyte[] S, sbyte[] F, sbyte[] C, sbyte[] D) { sbyte[] T = new sbyte[EFS]; BIG gx, gy, r, s, f, c, d, u, vx; ECP G, V; HASH H = new HASH(); H.process_array(F); sbyte[] B = H.hash(); gx = new BIG(ROM.CURVE_Gx); gy = new BIG(ROM.CURVE_Gy); G = new ECP(gx, gy); r = new BIG(ROM.CURVE_Order); s = BIG.fromBytes(S); f = BIG.fromBytes(B); c = new BIG(0); d = new BIG(0); V = new ECP(); do { u = BIG.randomnum(r, RNG); V.copy(G); V = V.mul(u); vx = V.X; c.copy(vx); c.mod(r); if (c.iszilch()) { continue; } u.invmodp(r); d.copy(BIG.modmul(s, c, r)); d.add(f); d.copy(BIG.modmul(u, d, r)); } while (d.iszilch()); c.toBytes(T); for (int i = 0; i < EFS; i++) { C[i] = T[i]; } d.toBytes(T); for (int i = 0; i < EFS; i++) { D[i] = T[i]; } return(0); }
/* Multiply P by e in group G1 */ public static ECP G1mul(ECP P, BIG e) { ECP R; if (ROM.USE_GLV) { P.affine(); R = new ECP(); R.copy(P); int i, np, nn; ECP Q = new ECP(); Q.copy(P); BIG q = new BIG(ROM.CURVE_Order); FP cru = new FP(new BIG(ROM.CURVE_Cru)); BIG t = new BIG(0); BIG[] u = glv(e); Q.getx().mul(cru); np = u[0].nbits(); t.copy(BIG.modneg(u[0], q)); nn = t.nbits(); if (nn < np) { u[0].copy(t); R.neg(); } np = u[1].nbits(); t.copy(BIG.modneg(u[1], q)); nn = t.nbits(); if (nn < np) { u[1].copy(t); Q.neg(); } R = R.mul2(u[0], Q, u[1]); } else { R = P.mul(e); } return(R); }
/* Constant time select from pre-computed table */ private void select(ECP[] W, int b) { ECP MP = new ECP(); int m = b >> 31; int babs = (b ^ m) - m; babs = (babs - 1) / 2; cmove(W[0], teq(babs, 0)); // conditional move cmove(W[1], teq(babs, 1)); cmove(W[2], teq(babs, 2)); cmove(W[3], teq(babs, 3)); cmove(W[4], teq(babs, 4)); cmove(W[5], teq(babs, 5)); cmove(W[6], teq(babs, 6)); cmove(W[7], teq(babs, 7)); MP.copy(this); MP.neg(); cmove(MP, (int)(m & 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); }