/* Pollards kangaroos used to return PIN error */ public static int KANGAROO(sbyte[] E, sbyte[] F) { FP12 ge = FP12.fromBytes(E); FP12 gf = FP12.fromBytes(F); int[] distance = new int[TS]; FP12 t = new FP12(gf); FP12[] table = new FP12[TS]; int i, j, m, s, dn, dm, res, steps; s = 1; for (m = 0; m < TS; m++) { distance[m] = s; table[m] = new FP12(t); s *= 2; t.usqr(); } t.one(); dn = 0; for (j = 0; j < TRAP; j++) { i = t.geta().geta().A.lastbits(8) % TS; t.mul(table[i]); dn += distance[i]; } gf.copy(t); gf.conj(); steps = 0; dm = 0; res = 0; while (dm - dn < MAXPIN) { steps++; if (steps > 4 * TRAP) { break; } i = ge.geta().geta().A.lastbits(8) % TS; ge.mul(table[i]); dm += distance[i]; if (ge.Equals(t)) { res = dm - dn; break; } if (ge.Equals(gf)) { res = dn - dm; break; } } if (steps > 4 * TRAP || dm - dn >= MAXPIN) { res = 0; } // Trap Failed - probable invalid token return(res); }
/* test group membership */ /* with GT-Strong curve, now only check that m!=1, conj(m)*m==1, and m.m^{p^4}=m^{p^2} */ public static bool GTmember(FP12 m) { if (m.isunity()) { return(false); } FP12 r = new FP12(m); r.conj(); r.mul(m); if (!r.isunity()) { return(false); } FP2 f = new FP2(new BIG(ROM.CURVE_Fra), new BIG(ROM.CURVE_Frb)); r.copy(m); r.frob(f); r.frob(f); FP12 w = new FP12(r); w.frob(f); w.frob(f); w.mul(m); if (!ROM.GT_STRONG) { if (!w.Equals(r)) { return(false); } BIG x = new BIG(ROM.CURVE_Bnx); r.copy(m); w = r.pow(x); w = w.pow(x); r.copy(w); r.sqr(); r.mul(w); r.sqr(); w.copy(m); w.frob(f); } return(w.Equals(r)); }
/* p=q0^u0.q1^u1.q2^u2.q3^u3 */ /* Timing attack secure, but not cache attack secure */ public static FP12 pow4(FP12[] q, BIG[] u) { int i, j, nb, m; int[] a = new int[4]; FP12[] g = new FP12[8]; FP12[] s = new FP12[2]; FP12 c = new FP12(1); FP12 p = new FP12(0); BIG[] t = new BIG[4]; BIG mt = new BIG(0); sbyte[] w = new sbyte[ROM.NLEN * ROM.BASEBITS + 1]; for (i = 0; i < 4; i++) { t[i] = new BIG(u[i]); } s[0] = new FP12(0); s[1] = new FP12(0); g[0] = new FP12(q[0]); s[0].copy(q[1]); s[0].conj(); g[0].mul(s[0]); g[1] = new FP12(g[0]); g[2] = new FP12(g[0]); g[3] = new FP12(g[0]); g[4] = new FP12(q[0]); g[4].mul(q[1]); g[5] = new FP12(g[4]); g[6] = new FP12(g[4]); g[7] = new FP12(g[4]); s[1].copy(q[2]); s[0].copy(q[3]); s[0].conj(); s[1].mul(s[0]); s[0].copy(s[1]); s[0].conj(); g[1].mul(s[0]); g[2].mul(s[1]); g[5].mul(s[0]); g[6].mul(s[1]); s[1].copy(q[2]); s[1].mul(q[3]); s[0].copy(s[1]); s[0].conj(); g[0].mul(s[0]); g[3].mul(s[1]); g[4].mul(s[0]); g[7].mul(s[1]); /* if power is even add 1 to power, and add q to correction */ for (i = 0; i < 4; i++) { if (t[i].parity() == 0) { t[i].inc(1); t[i].norm(); c.mul(q[i]); } mt.add(t[i]); mt.norm(); } c.conj(); nb = 1 + mt.nbits(); /* convert exponent to signed 1-bit window */ for (j = 0; j < nb; j++) { for (i = 0; i < 4; i++) { a[i] = (t[i].lastbits(2) - 2); t[i].dec(a[i]); t[i].norm(); t[i].fshr(1); } w[j] = (sbyte)(8 * a[0] + 4 * a[1] + 2 * a[2] + a[3]); } w[nb] = (sbyte)(8 * t[0].lastbits(2) + 4 * t[1].lastbits(2) + 2 * t[2].lastbits(2) + t[3].lastbits(2)); p.copy(g[(w[nb] - 1) / 2]); for (i = nb - 1; i >= 0; i--) { m = w[i] >> 7; j = (w[i] ^ m) - m; // j=abs(w[i]) j = (j - 1) / 2; s[0].copy(g[j]); s[1].copy(g[j]); s[1].conj(); p.usqr(); p.mul(s[m & 1]); } p.mul(c); // apply correction p.reduce(); return(p); }
/* calculate common key on client side */ /* wCID = w.(A+AT) */ public static int CLIENT_KEY(sbyte[] G1, sbyte[] G2, int pin, sbyte[] R, sbyte[] X, sbyte[] wCID, sbyte[] CK) { HASH H = new HASH(); sbyte[] t = new sbyte[EFS]; FP12 g1 = FP12.fromBytes(G1); FP12 g2 = FP12.fromBytes(G2); BIG z = BIG.fromBytes(R); BIG x = BIG.fromBytes(X); ECP W = ECP.fromBytes(wCID); if (W.is_infinity()) { return(INVALID_POINT); } W = PAIR.G1mul(W, x); FP2 f = new FP2(new BIG(ROM.CURVE_Fra), new BIG(ROM.CURVE_Frb)); BIG r = new BIG(ROM.CURVE_Order); BIG q = new BIG(ROM.Modulus); BIG m = new BIG(q); m.mod(r); BIG a = new BIG(z); a.mod(m); BIG b = new BIG(z); b.div(m); g2.pinpow(pin, PBLEN); g1.mul(g2); FP4 c = g1.trace(); g2.copy(g1); g2.frob(f); FP4 cp = g2.trace(); g1.conj(); g2.mul(g1); FP4 cpm1 = g2.trace(); g2.mul(g1); FP4 cpm2 = g2.trace(); c = c.xtr_pow2(cp, cpm1, cpm2, a, b); c.geta().A.toBytes(t); H.process_array(t); c.geta().B.toBytes(t); H.process_array(t); c.getb().A.toBytes(t); H.process_array(t); c.getb().B.toBytes(t); H.process_array(t); W.X.toBytes(t); H.process_array(t); W.Y.toBytes(t); H.process_array(t); t = H.hash(); for (int i = 0; i < PAS; i++) { CK[i] = t[i]; } return(0); }
/* final exponentiation - keep separate for multi-pairings and to avoid thrashing stack */ public static FP12 fexp(FP12 m) { FP2 f = new FP2(new BIG(ROM.CURVE_Fra), new BIG(ROM.CURVE_Frb)); BIG x = new BIG(ROM.CURVE_Bnx); FP12 r = new FP12(m); FP12 x0, x1, x2, x3, x4, x5; /* Easy part of final exp */ FP12 lv = new FP12(r); lv.inverse(); r.conj(); r.mul(lv); lv.copy(r); r.frob(f); r.frob(f); r.mul(lv); /* Hard part of final exp */ lv.copy(r); lv.frob(f); x0 = new FP12(lv); x0.frob(f); lv.mul(r); x0.mul(lv); x0.frob(f); x1 = new FP12(r); x1.conj(); x4 = r.pow(x); x3 = new FP12(x4); x3.frob(f); x2 = x4.pow(x); x5 = new FP12(x2); x5.conj(); lv = x2.pow(x); x2.frob(f); r.copy(x2); r.conj(); x4.mul(r); x2.frob(f); r.copy(lv); r.frob(f); lv.mul(r); lv.usqr(); lv.mul(x4); lv.mul(x5); r.copy(x3); r.mul(x5); r.mul(lv); lv.mul(x2); r.usqr(); r.mul(lv); r.usqr(); lv.copy(r); lv.mul(x1); r.mul(x0); lv.usqr(); r.mul(lv); r.reduce(); return(r); }