def R2toR4(P): (N, D, E, F) = P return ( GFp2.sub(N, D), GFp2.add(D, N), E )
def R1toR3(P): (X, Y, Z, Ta, Tb) = P return( GFp2.add(X, Y), GFp2.sub(Y, X), Z, GFp2.mul(Ta, Tb) )
def selectpt(c, P1, P2): (N1, D1, E1, F1) = P1 (N2, D2, E2, F2) = P2 return ( GFp2.select(c, N1, N2), GFp2.select(c, D1, D2), GFp2.select(c, E1, E2), GFp2.select(c, F1, F2), )
def toAffine(P): if len(P) == 2: return P if len(P) != 3 and len(P) != 5: raise Exception("Representation unsupported for normalization") zi = GFp2.inv(P[2]) xz = GFp2.mul(P[0], zi) yz = GFp2.mul(P[1], zi) return (xz, yz)
def PointOnCurve(P): (X, Y) = P X2 = GFp2.sqr(X) Y2 = GFp2.sqr(Y) LHS = GFp2.sub(Y2, X2) RHS = GFp2.add(GFp2.one, GFp2.mul(GFp2.mul(d, X2), Y2)) return LHS == RHS
def test_reps(): x = (0, 1) x2 = (0, 2) y = (2, 0) y2 = (4, 0) xy = (2, 1) yx = (2, p1271 - 1) z = (3, 4) z2 = (6, 8) ta = (5, 0) tb = (1, 6) t = (5, 30) td2 = GFp2.mul((2, 0), GFp2.mul(d, t)) r1 = (x, y, z, ta, tb) r2 = (xy, yx, z2, td2) r3 = (xy, yx, z, t) r4 = (x2, y2, z2) test.test("R1toR2", R1toR2(r1), r2) test.test("R1toR3", R1toR3(r1), r3) test.test("R2toR4", R2toR4(r2), r4)
def test_reps(): x = (0, 1) x2 = (0, 2) y = (2, 0) y2 = (4, 0) xy = (2, 1) yx = (2, p1271 - 1) z = (3, 4) z2 = (6, 8) ta = (5, 0) tb = (1, 6) t = (5, 30) td2 = GFp2.mul((2,0), GFp2.mul(d, t)) r1 = (x, y, z, ta, tb) r2 = (xy, yx, z2, td2) r3 = (xy, yx, z, t) r4 = (x2, y2, z2) test.test("R1toR2", R1toR2(r1), r2) test.test("R1toR3", R1toR3(r1), r3) test.test("R2toR4", R2toR4(r2), r4)
def R1toR2(P): (X, Y, Z, Ta, Tb) = P return ( GFp2.add(X, Y), GFp2.sub(Y, X), GFp2.add(Z, Z), GFp2.mul(GFp2.mul(GFp2.two, d), GFp2.mul(Ta, Tb)) )
def decode(B): if len(B) != 32: raise Exception("Malformed point: length {} != 32".format(len(B))) if B[15] & 0x80 != 0x00: raise Exception("Malformed point: reserved bit is not zero") s = B[31] >> 7 B[31] &= 0x7F y0 = GFp.fromLittleEndian(B[:16]) y1 = GFp.fromLittleEndian(B[16:]) if y0 >= p1271 or y1 >= p1271: raise Exception("Malformed point: reserved bit is not zero") y = (y0, y1) y2 = GFp2.sqr(y) (u0, u1) = GFp2.sub(y2, GFp2.one) (v0, v1) = GFp2.add(GFp2.mul(d, y2), GFp2.one) t0 = GFp.add(GFp.mul(u0, v0), GFp.mul(u1, v1)) t1 = GFp.sub(GFp.mul(u1, v0), GFp.mul(u0, v1)) t2 = GFp.add(GFp.sqr(v0), GFp.sqr(v1)) t3 = GFp.add(GFp.sqr(t0), GFp.sqr(t1)) t3 = GFp.mul(GFp.invsqrt(t3), t3) t = GFp.mul(2, GFp.add(t0, t3)) if t == 0: t = GFp.mul(GFp.two, GFp.sub(t0, t3)) a = GFp.invsqrt(GFp.mul(t, GFp.mul(t2, GFp.sqr(t2)))) b = GFp.mul(GFp.mul(a, t2), t) x0 = GFp.mul(b, GFp.half) x1 = GFp.mul(GFp.mul(a, t2), t1) if t != GFp.mul(t2, GFp.sqr(b)): x0, x1 = x1, x0 x = (x0, x1) if sign(x) != s: x = GFp2.neg(x) if not PointOnCurve((x, y)): x = GFp2.conj(x) if not PointOnCurve((x, y)): raise Exception("Point not on curve") return (x, y)
def DBL(P): (X1, Y1, Z1) = P[:3] A = GFp2.sqr(X1) B = GFp2.sqr(Y1) C = GFp2.mul(GFp2.two, GFp2.sqr(Z1)) D = GFp2.add(A, B) E = GFp2.sub(GFp2.sqr(GFp2.add(X1, Y1)), D) F = GFp2.sub(B, A) G = GFp2.sub(C, F) X3 = GFp2.mul(E, G) Y3 = GFp2.mul(D, F) Z3 = GFp2. mul(F, G) Ta3 = E Tb3 = D return (X3, Y3, Z3, Ta3, Tb3)
def ADD_core(P, Q): (N1, D1, E1, F1) = P (N2, D2, Z2, T2) = Q A = GFp2.mul(D1, D2) B = GFp2.mul(N1, N2) C = GFp2.mul(T2, F1) D = GFp2.mul(Z2, E1) E = GFp2.sub(B, A) F = GFp2.sub(D, C) G = GFp2.add(D, C) H = GFp2.add(B, A) X3 = GFp2.mul(E, F) Y3 = GFp2.mul(G, H) Z3 = GFp2.mul(F, G) Ta3 = E Tb3 = H return (X3, Y3, Z3, Ta3, Tb3)
def DBL(P): (X1, Y1, Z1) = P[:3] A = GFp2.sqr(X1) B = GFp2.sqr(Y1) C = GFp2.mul(GFp2.two, GFp2.sqr(Z1)) D = GFp2.add(A, B) E = GFp2.sub(GFp2.sqr(GFp2.add(X1, Y1)), D) F = GFp2.sub(B, A) G = GFp2.sub(C, F) X3 = GFp2.mul(E, G) Y3 = GFp2.mul(D, F) Z3 = GFp2.mul(F, G) Ta3 = E Tb3 = D return (X3, Y3, Z3, Ta3, Tb3)
def tau_dual(P): (X1, Y1, Z1) = P A = GFp2.sqr(X1) B = GFp2.sqr(Y1) C = GFp2.add(A, B) Ta2 = GFp2.sub(B, A) D = GFp2.sub(GFp2.mul(GFp2.two, GFp2.sqr(Z1)), Ta2) Tb2 = GFp2.mul(GFp2.mul(ctaudual, X1), Y1) X2 = GFp2.mul(Tb2, C) Y2 = GFp2.mul(Ta2, D) Z2 = GFp2.mul(C, D) return (X2, Y2, Z2, Ta2, Tb2)
def R2neg(P): (N, D, E, F) = P return (D, N, E, GFp2.neg(F))
def upsilon(P): (X1, Y1, Z1) = P A = GFp2.mul(GFp2.mul(cphi0, X1), Y1) B = GFp2.mul(Y1, Z1) C = GFp2.sqr(Y1) D = GFp2.sqr(Z1) F = GFp2.sqr(D) G = GFp2.sqr(B) H = GFp2.sqr(C) I = GFp2.mul(cphi1, B) J = GFp2.add(C, GFp2.mul(cphi2, D)) K = GFp2.add(GFp2.add(GFp2.mul(cphi8, G), H), GFp2.mul(cphi9, F)) X2 = GFp2.mul(GFp2.add(I, J), GFp2.sub(I, J)) X2 = GFp2.conj(GFp2.mul(GFp2.mul(A, K), X2)) L = GFp2.add(C, GFp2.mul(cphi4, D)) M = GFp2.mul(cphi3, B) N = GFp2.mul(GFp2.add(L, M), GFp2.sub(L, M)) Y2 = GFp2.add(GFp2.add(H, GFp2.mul(cphi6, G)), GFp2.mul(cphi7, F)) Y2 = GFp2.conj(GFp2.mul(GFp2.mul(GFp2.mul(cphi5, D), N), Y2)) Z2 = GFp2.conj(GFp2.mul(GFp2.mul(B, K), N)) return (X2, Y2, Z2)
def R1toAffine(P): (X, Y, Z, Ta, Tb) = P Zi = GFp2.inv(Z) return (GFp2.mul(X, Zi), GFp2.mul(Y, Zi))
def chi(P): (X1, Y1, Z1) = P A = GFp2.conj(X1) B = GFp2.conj(Y1) C = GFp2.sqr(GFp2.conj(Z1)) D = GFp2.sqr(A) F = GFp2.sqr(B) G = GFp2.mul(B, GFp2.add(D, GFp2.mul(cpsi2, C))) H = GFp2.neg(GFp2.add(D, GFp2.mul(cpsi4, C))) X2 = GFp2.mul(GFp2.mul(GFp2.mul(cpsi1, A), C), H) Y2 = GFp2.mul(G, GFp2.add(D, GFp2.mul(cpsi3, C))) Z2 = GFp2.mul(G, H) return (X2, Y2, Z2)
def tau(P): (X1, Y1, Z1) = P A = GFp2.sqr(X1) B = GFp2.sqr(Y1) C = GFp2.add(A, B) D = GFp2.sub(A, B) X2 = GFp2.mul(GFp2.mul(GFp2.mul(ctau, X1), Y1), D) Y2 = GFp2.neg(GFp2.mul(GFp2.add(GFp2.mul(GFp2.two, GFp2.sqr(Z1)), D), C)) Z2 = GFp2.mul(C, D) return (X2, Y2, Z2)
def R1toR2(P): (X, Y, Z, Ta, Tb) = P return (GFp2.add(X, Y), GFp2.sub(Y, X), GFp2.add(Z, Z), GFp2.mul(GFp2.mul(GFp2.two, d), GFp2.mul(Ta, Tb)))
def R1toR3(P): (X, Y, Z, Ta, Tb) = P return (GFp2.add(X, Y), GFp2.sub(Y, X), Z, GFp2.mul(Ta, Tb))
def R2toR4(P): (N, D, E, F) = P return (GFp2.sub(N, D), GFp2.add(D, N), E)
def compare_ops(): opcounts = {} m = getrandbits(256) G = curve4q.AffineToR1(curve4q.Gx, curve4q.Gy) k = '77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a'.decode('hex') u = '0900000000000000000000000000000000000000000000000000000000000000'.decode('hex') G392 = curve4q.MUL_endo(392, G) T_windowed = curve4q.table_windowed(G) T_endo = curve4q.table_endo(G) T392_windowed = curve4q.table_windowed(G392) T392_endo = curve4q.table_endo(G392) # R1toR2 GFp2.ctr_reset() Q = curve4q.R1toR2(G) opcounts["R1toR2"] = GFp2.ctr() # R1toR3 GFp2.ctr_reset() Q = curve4q.R1toR3(G) opcounts["R1toR3"] = GFp2.ctr() # R2toR4 G2 = curve4q.R1toR2(G) GFp2.ctr_reset() Q = curve4q.R2toR4(G2) opcounts["R2toR4"] = GFp2.ctr() # ADD_core P = curve4q.R1toR3(G) Q = curve4q.R1toR2(G) GFp2.ctr_reset() R = curve4q.ADD_core(P, Q) opcounts["ADD_core"] = GFp2.ctr() # ADD P = G Q = curve4q.R1toR2(G) GFp2.ctr_reset() R = curve4q.ADD(P, Q) opcounts["ADD"] = GFp2.ctr() # DBL GFp2.ctr_reset() Q = curve4q.DBL(G) opcounts["DBL"] = GFp2.ctr() # MUL_windowed GFp2.ctr_reset() Q = curve4q.MUL_windowed(m, G) opcounts["MUL_windowed"] = GFp2.ctr() # MUL_windowed_fixed GFp2.ctr_reset() Q = curve4q.MUL_windowed(m, G, table=T_windowed) opcounts["MUL_windowed_fixed"] = GFp2.ctr() # Phi GFp2.ctr_reset() phiP = curve4q.phi(G) opcounts["phi"] = GFp2.ctr() # Psi GFp2.ctr_reset() psiP = curve4q.psi(G) opcounts["psi"] = GFp2.ctr() # MUL_endo GFp2.ctr_reset() mP = curve4q.MUL_endo(m, G) opcounts["MUL_endo"] = GFp2.ctr() # MUL_endo_fixed GFp2.ctr_reset() Q = curve4q.MUL_endo(m, G, table=T_endo) opcounts["MUL_endo_fixed"] = GFp2.ctr() # DH_windowed GFp2.ctr_reset() mP = curve4q.DH_windowed(m, G[:2]) opcounts["DH_windowed"] = GFp2.ctr() # DH_windowed_fixed GFp2.ctr_reset() mP = curve4q.DH_windowed(m, G[:2], table=T392_windowed) opcounts["DH_windowed_fixed"] = GFp2.ctr() # DH_endo GFp2.ctr_reset() mP = curve4q.DH_endo(m, G[:2]) opcounts["DH_endo"] = GFp2.ctr() # DH_endo_fixed GFp2.ctr_reset() mP = curve4q.DH_endo(m, G[:2], table=T392_endo) opcounts["DH_endo_fixed"] = GFp2.ctr() # x25519 GFp25519.ctr_reset() ku = curve25519.x25519(k, u) opcounts["x25519"] = GFp25519.ctr() rows = ["R1toR2", "R1toR3", "R2toR4", "ADD_core", "ADD", "DBL", "phi", "psi", "psiphi", "MUL_windowed", "MUL_windowed_fixed", "MUL_endo", "MUL_endo_fixed", "DH_windowed", "DH_windowed_fixed", "DH_endo", "DH_endo_fixed", "x25519"] print "===== Field operation count =====" print print "{:18s} {:>7s} {:>7s} {:>7s} {:>7s}".format("", "M", "S", "A", "I") for name in rows: if name not in opcounts: continue opctr = opcounts[name] print "{:20s} {:7.1f} {:7.1f} {:7.1f} {:7.1f}".format(name, opctr[2], opctr[1], opctr[0], opctr[3]) print