/* 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); }
/* these next two functions implement elligator squared - http://eprint.iacr.org/2014/043 */ /* Elliptic curve point E in format (0x04,x,y} is converted to form {0x0-,u,v} */ /* Note that u and v are indistinguisible from random strings */ public static int ENCODING(RAND rng, sbyte[] E) { int rn, m, su, sv; sbyte[] T = new sbyte[EFS]; for (int i = 0; i < EFS; i++) { T[i] = E[i + 1]; } BIG u = BIG.fromBytes(T); for (int i = 0; i < EFS; i++) { T[i] = E[i + EFS + 1]; } BIG v = BIG.fromBytes(T); ECP P = new ECP(u, v); if (P.is_infinity()) { return(INVALID_POINT); } BIG p = new BIG(ROM.Modulus); u = BIG.randomnum(p, rng); su = rng.Byte; //if (su<0) su=-su; su %= 2; ECP W = map(u, su); P.sub(W); sv = P.S; rn = unmap(v, P); m = rng.Byte; //if (m<0) m=-m; m %= rn; v.inc(m + 1); E[0] = (sbyte)(su + 2 * sv); u.toBytes(T); for (int i = 0; i < EFS; i++) { E[i + 1] = T[i]; } v.toBytes(T); for (int i = 0; i < EFS; i++) { E[i + EFS + 1] = T[i]; } return(0); }
/* validate public key. Set full=true for fuller check */ public static int PUBLIC_KEY_VALIDATE(bool full, sbyte[] W) { BIG r; ECP WP = ECP.fromBytes(W); int res = 0; r = new BIG(ROM.CURVE_Order); if (WP.is_infinity()) { res = INVALID_PUBLIC_KEY; } if (res == 0 && full) { WP = WP.mul(r); if (!WP.is_infinity()) { res = INVALID_PUBLIC_KEY; } } return(res); }
/* R=R1+R2 in group G1 */ public static int RECOMBINE_G1(sbyte[] R1, sbyte[] R2, sbyte[] R) { ECP P = ECP.fromBytes(R1); ECP Q = ECP.fromBytes(R2); if (P.is_infinity() || Q.is_infinity()) { return(INVALID_POINT); } P.add(Q); P.toBytes(R); return(0); }
/* these next two functions help to implement elligator squared - http://eprint.iacr.org/2014/043 */ /* maps a random u to a point on the curve */ public static ECP map(BIG u, int cb) { ECP P; BIG x = new BIG(u); BIG p = new BIG(ROM.Modulus); x.mod(p); while (true) { P = new ECP(x, cb); if (!P.is_infinity()) { break; } x.inc(1); x.norm(); } return(P); }
public static ECP mapit(sbyte[] h) { BIG q = new BIG(ROM.Modulus); BIG x = BIG.fromBytes(h); x.mod(q); ECP P; while (true) { P = new ECP(x, 0); if (!P.is_infinity()) { break; } x.inc(1); x.norm(); } return(P); }
/* Implement step 2 on client side of MPin protocol */ public static int CLIENT_2(sbyte[] X, sbyte[] Y, sbyte[] SEC) { BIG r = new BIG(ROM.CURVE_Order); ECP P = ECP.fromBytes(SEC); if (P.is_infinity()) { return(INVALID_POINT); } BIG px = BIG.fromBytes(X); BIG py = BIG.fromBytes(Y); px.add(py); px.mod(r); px.rsub(r); PAIR.G1mul(P, px).toBytes(SEC); return(0); }
/* Extract PIN from TOKEN for identity CID */ public static int EXTRACT_PIN(sbyte[] CID, int pin, sbyte[] TOKEN) { ECP P = ECP.fromBytes(TOKEN); if (P.is_infinity()) { return(INVALID_POINT); } sbyte[] h = hashit(0, CID); ECP R = mapit(h); pin %= MAXPIN; R = R.pinmul(pin, PBLEN); P.sub(R); P.toBytes(TOKEN); return(0); }
/* returns u derived from P. Random value in range 1 to return value should then be added to u */ public static int unmap(BIG u, ECP P) { int s = P.S; ECP R; int r = 0; BIG x = P.X; u.copy(x); while (true) { u.dec(1); u.norm(); r++; R = new ECP(u, s); if (!R.is_infinity()) { break; } } return(r); }
/* Test P == Q */ public bool Equals(ECP Q) { if (is_infinity() && Q.is_infinity()) { return(true); } if (is_infinity() || Q.is_infinity()) { return(false); } if (ROM.CURVETYPE == ROM.WEIERSTRASS) { FP zs2 = new FP(z); zs2.sqr(); FP zo2 = new FP(Q.z); zo2.sqr(); FP zs3 = new FP(zs2); zs3.mul(z); FP zo3 = new FP(zo2); zo3.mul(Q.z); zs2.mul(Q.x); zo2.mul(x); if (!zs2.Equals(zo2)) { return(false); } zs3.mul(Q.y); zo3.mul(y); if (!zs3.Equals(zo3)) { return(false); } } else { FP a = new FP(0); FP b = new FP(0); a.copy(x); a.mul(Q.z); a.reduce(); b.copy(Q.x); b.mul(z); b.reduce(); if (!a.Equals(b)) { return(false); } if (ROM.CURVETYPE == ROM.EDWARDS) { a.copy(y); a.mul(Q.z); a.reduce(); b.copy(Q.y); b.mul(z); b.reduce(); if (!a.Equals(b)) { return(false); } } } return(true); }
/* calculate common key on server side */ /* Z=r.A - no time permits involved */ public static int SERVER_KEY(sbyte[] Z, sbyte[] SST, sbyte[] W, sbyte[] xID, sbyte[] xCID, sbyte[] SK) { HASH H = new HASH(); sbyte[] t = new sbyte[EFS]; ECP2 sQ = ECP2.fromBytes(SST); if (sQ.is_infinity()) { return(INVALID_POINT); } ECP R = ECP.fromBytes(Z); if (R.is_infinity()) { return(INVALID_POINT); } ECP U; if (xCID != null) { U = ECP.fromBytes(xCID); } else { U = ECP.fromBytes(xID); } if (U.is_infinity()) { return(INVALID_POINT); } BIG w = BIG.fromBytes(W); U = PAIR.G1mul(U, w); FP12 g = PAIR.ate(sQ, R); g = PAIR.fexp(g); FP4 c = g.trace(); 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); U.X.toBytes(t); H.process_array(t); U.Y.toBytes(t); H.process_array(t); t = H.hash(); for (int i = 0; i < PAS; i++) { SK[i] = t[i]; } return(0); }
/* 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); }