def test_edge_case_sign_Fq2(): q = default_ec.q a = Fq(q, 62323) test_case_1 = Fq2(q, a, Fq(q, 0)) test_case_2 = Fq2(q, -a, Fq(q, 0)) assert sign_Fq2(test_case_1) != sign_Fq2(test_case_2) test_case_3 = Fq2(q, Fq(q, 0), a) test_case_4 = Fq2(q, Fq(q, 0), -a) assert sign_Fq2(test_case_3) != sign_Fq2(test_case_4)
def setUp(self): self.a1 = Fq(48, 199) self.b1 = Fq(50, 199) self.c1 = Fq(62, 199) self.A1 = EC.get_point_from_x(self.a1) self.B1 = EC.get_point_from_x(self.b1) self.a2 = Fq2(self.b1, self.a1) self.b2 = Fq2(self.b1, self.c1) self.A2 = TwistedEC.get_point_from_x(self.a2) self.B2 = TwistedEC.get_point_from_x(self.b2) self.g1 = EC.from_affine(g1_x, g1_y) self.g2 = TwistedEC.from_affine(g2_x, g2_y)
def main(): for Pinf in ((F1_zero, F1_one, F1_zero), (F2_zero, F2_one, F2_zero)): test_ell(Pinf) sys.stdout.write('.') sys.stdout.flush() for _ in range(0, 32): sys.stdout.write('.') sys.stdout.flush() test_ell(opt_swu_map(Fq(p, random.getrandbits(380)))) test_ell( opt_swu2_map( Fq2(p, random.getrandbits(380), random.getrandbits(380)))) for (ell2, invals) in ((False, invalid_inputs_1), (True, invalid_inputs_2)): curve_name = "E2" if ell2 else "E1" for (idx, inval) in enumerate(invals): try: deserialize(binascii.unhexlify(inval), ell2) except DeserError: sys.stdout.write('*') sys.stdout.flush() else: raise DeserError( "expected failed deserialization of #%d on %s" % (idx, curve_name)) sys.stdout.write('\n')
def test_fields(): a = Fq(17, 30) b = Fq(17, -18) c = Fq2(17, a, b) d = Fq2(17, a + a, -5) e = c * d f = e * d assert f != e e_sq = e * e e_sqrt = e_sq.modsqrt() assert pow(e_sqrt, 2) == e_sq a2 = Fq( 172487123095712930573140951348, 3012492130751239573498573249085723940848571098237509182375, ) b2 = Fq(172487123095712930573140951348, 3432984572394572309458723045723849) c2 = Fq2(172487123095712930573140951348, a2, b2) assert b2 != c2 g = Fq6(17, c, d, d * d * c) h = Fq6(17, a + a * c, c * b * a, b * b * d * 21) i = Fq12(17, g, h) assert ~(~i) == i assert (~(i.root)) * i.root == Fq6.one(17) x = Fq12(17, Fq6.zero(17), i.root) assert (~x) * x == Fq12.one(17) j = Fq6(17, a + a * c, Fq2.zero(17), Fq2.zero(17)) j2 = Fq6(17, a + a * c, Fq2.zero(17), Fq2.one(17)) assert j == (a + a * c) assert j2 != (a + a * c) assert j != j2 # Test frob_coeffs one = Fq(default_ec.q, 1) two = one + one a = Fq2(default_ec.q, two, two) b = Fq6(default_ec.q, a, a, a) c = Fq12(default_ec.q, b, b) for base in (a, b, c): for expo in range(1, base.extension): assert base.qi_power(expo) == pow(base, pow(default_ec.q, expo))
def run_tests(): import random from curve_ops import psi for _ in range(0, 128): t1 = Fq2(p, random.getrandbits(380), random.getrandbits(380)) t2 = Fq2(p, random.getrandbits(380), random.getrandbits(380)) # make sure each helper function actually returns a point on the curve for t in (t1, t2): P = osswu2_help(t) Pp = from_jacobian(P) assert Pp[0]**3 + Ell2p_a * Pp[0] + Ell2p_b == Pp[1]**2 P = iso3(P) Pp = from_jacobian(P) assert Pp[0]**3 + Fq2(p, 4, 4) == Pp[1]**2 P = psi(P) Pp = from_jacobian(P) assert Pp[0]**3 + Fq2(p, 4, 4) == Pp[1]**2 P = clear_h2(P) Pp = from_jacobian(P) assert Pp[0]**3 + Fq2(p, 4, 4) == Pp[1]**2 # now test end-to-end P = opt_swu2_map(t1, t2) Pp = from_jacobian(P) assert Pp[0]**3 + Fq2(p, 4, 4) == Pp[1]**2 sys.stdout.write('.') sys.stdout.flush() sys.stdout.write("\n")
def hash_to_point_prehashed_Fq2(m, ec=default_ec_twist): if type(m) != bytes: m = m.encode("utf-8") t0_0 = Fq(ec.q, int.from_bytes(hash512(m + b"G2_0_c0"), "big")) t0_1 = Fq(ec.q, int.from_bytes(hash512(m + b"G2_0_c1"), "big")) t1_0 = Fq(ec.q, int.from_bytes(hash512(m + b"G2_1_c0"), "big")) t1_1 = Fq(ec.q, int.from_bytes(hash512(m + b"G2_1_c1"), "big")) t0 = Fq2(ec.q, t0_0, t0_1) t1 = Fq2(ec.q, t1_0, t1_1) P = sw_encode(t0, ec, Fq2) + sw_encode(t1, ec, Fq2) # This is the cofactor multiplication, done in a more # efficient way. See page 11 of "Efficient hash maps # to G2 on BLS curves" by Budrioni and Pintore. x = -ec.x psi2P = psi(psi(2 * P, ec), ec) t0 = x * P t1 = x * t0 t2 = (t1 + t0) - P t3 = psi((x + 1) * P, ec) return t2 - t3 + psi2P
def from_bytes(buffer, aggregation_info=None): use_big_y = buffer[0] & 0x80 buffer = bytes([buffer[0] & 0x1f]) + buffer[1:] x0 = int.from_bytes(buffer[:48], "big") x1 = int.from_bytes(buffer[48:], "big") x = Fq2(default_ec.q, Fq(default_ec.q, x0), Fq(default_ec.q, x1)) ys = y_for_x(x, default_ec_twist, Fq2) y = ys[0] if ((use_big_y and ys[1][1] > default_ec.q // 2) or (not use_big_y and ys[1][1] < default_ec.q // 2)): y = ys[1] return Signature(AffinePoint(x, y, False, default_ec_twist) .to_jacobian(), aggregation_info)
def from_bytes(buffer): use_big_y = buffer[0] & 0x80 prepend = buffer[0] & 0x40 if not prepend: raise "Should have prepend bit set" buffer = bytes([buffer[0] & 0x1f]) + buffer[1:] x0 = int.from_bytes(buffer[:48], "big") x1 = int.from_bytes(buffer[48:], "big") x = Fq2(default_ec.q, Fq(default_ec.q, x0), Fq(default_ec.q, x1)) ys = y_for_x(x, default_ec_twist, Fq2) y = ys[0] if ((use_big_y and ys[1][1] > default_ec.q // 2) or (not use_big_y and ys[1][1] < default_ec.q // 2)): y = ys[1] return PrependSignature( AffinePoint(x, y, False, default_ec_twist).to_jacobian())
def from_bytes(buffer, aggregation_info=None): use_big_y = buffer[0] & 0x80 prepend = buffer[0] & 0x40 if prepend: raise Exception("Should not have prepend bit set") buffer = bytes([buffer[0] & 0x1F]) + buffer[1:] x0 = int.from_bytes(buffer[:48], "big") x1 = int.from_bytes(buffer[48:], "big") x = Fq2(default_ec.q, Fq(default_ec.q, x0), Fq(default_ec.q, x1)) ys = y_for_x(x, default_ec_twist, Fq2) y = ys[0] if (use_big_y and ys[1][1] > default_ec.q // 2) or ( not use_big_y and ys[1][1] < default_ec.q // 2): y = ys[1] return Signature( AffinePoint(x, y, False, default_ec_twist).to_jacobian(), aggregation_info)
def setUp(self): self.a1 = Fq(3, 11) self.b1 = Fq(4, 11) self.c1 = Fq(7, 11) self.d1 = Fq(12, 11) self.e1 = Fq(2, 11) self.f1 = Fq(9, 11) self.g1 = Fq(6, 11) self.a2 = Fq2(self.a1, self.b1) self.b2 = Fq2(self.b1, self.c1) self.c2 = Fq2(self.c1, self.d1) self.d2 = Fq2(self.d1, self.e1) self.e2 = Fq2(self.e1, self.f1) self.f2 = Fq2(self.f1, self.g1) self.a6 = Fq6(self.a2, self.b2, self.c2) self.b6 = Fq6(self.b2, self.c2, self.d2) self.c6 = Fq6(self.d2, self.e2, self.f2) self.a12 = Fq12(self.a6, self.b6) self.b12 = Fq12(self.b6, self.c6)
import sys from consts import p, q from fields import Fq, Fq2 if sys.version_info[0] < 3: sys.exit("This script requires Python3 or PyPy3") ### ## generators for BLS signatures ### # I'd rather have these in consts, but then we'd get an import cycle, consts <-> fields g1gen = (Fq(p, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb), Fq(p, 0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1), Fq.one(p)) g2gen = (Fq2(p, 0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8, 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e), Fq2(p, 0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801, 0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be), Fq2.one(p)) ### ## Basic curve operations ### # Jacobian coordinates def from_jacobian(P): z3inv = ~(P[2] ** 3) return (P[0] * P[2] * z3inv, P[1] * z3inv) # point equality or co-z repr def _point_eq_coz(P, Q, coZ): (X1, Y1, Z1) = P
import random from fields import Fq1, Fq2 from curve import Curve, Point from weil import miller_loop, weil_pairing random.seed(1234) print("\n\n1. Testing Fq1 and Fq2 inverse", end='') Fq1.set_q(631) Fq2.set_q(2**255 - 19) for i in range(10): a1 = Fq1(random.randrange(1, Fq1.Q)) b1 = Fq1.one() // a1 assert a1 * b1 == Fq1.one() a2 = Fq2(random.randrange(1, Fq2.Q), random.randrange(1, Fq2.Q)) b2 = Fq2.one() // a2 res = a2 * b2 assert a2 * b2 == Fq2.one() print("...passed\n\n") Curve.set_a_b(30, 34) P = Point(x=Fq1(36), y=Fq1(60)) Q = Point(x=Fq1(121), y=Fq1(387)) S = Point(x=Fq1(0), y=Fq1(36)) print("group1 = [", end='') for i in range(1, 5): g = Curve.multiply(P, i) print("(Affine {:3} {:3}), ".format(g.x.q, g.y.q), end='') print("")
from ec import JacobianPoint, default_ec_twist, eval_iso from fields import Fq, Fq2, roots_of_unity from hash_to_field import Hp2 def sgn0(x: Fq2) -> int: # https://tools.ietf.org/html/draft-irtf-cfrg-hash-to-curve-07#section-4.1 sign_0: int = x[0].value % 2 zero_0: bool = x[0] == 0 sign_1: int = x[1].value % 2 return sign_0 or (zero_0 and sign_1) # distinguished non-square in Fp2 for SWU map xi_2 = Fq2(q, -2, -1) # 3-isogenous curve parameters Ell2p_a = Fq2(q, 0, 240) Ell2p_b = Fq2(q, 1012, 1012) # eta values, used for computing sqrt(g(X1(t))) # For details on how to compute, see ../sage-impl/opt_sswu_g2.sage ev1 = 0x699BE3B8C6870965E5BF892AD5D2CC7B0E85A117402DFD83B7F4A947E02D978498255A2AAEC0AC627B5AFBDF1BF1C90 ev2 = 0x8157CD83046453F5DD0972B6E3949E4288020B5B8A9CC99CA07E27089A2CE2436D965026ADAD3EF7BABA37F2183E9B5 ev3 = 0xAB1C2FFDD6C253CA155231EB3E71BA044FD562F6F72BC5BAD5EC46A0B7A3B0247CF08CE6C6317F40EDBC653A72DEE17 ev4 = 0xAA404866706722864480885D68AD0CCAC1967C7544B447873CC37E0181271E006DF72162A3D3E0287BF597FBF7F8FC1 etas = (Fq2(q, ev1, ev2), Fq2(q, q - ev2, ev1), Fq2(q, ev3, ev4), Fq2(q, q - ev4, ev3)) del ev1, ev2, ev3, ev4
def decompress(point): greatest = point >> 2 * q_bits x_c0 = Fq(point & (2**q_bits - 1), q) x_c1 = Fq((point >> q_bits) & (2**q_bits - 1), q) x = Fq2(x_c0, x_c1) return TwistedEC.get_point_from_x(x, greatest)
def g2_map(alpha: bytes, dst=None): return opt_swu2_map(*(Fq2(q, *hh) for hh in Hp2(alpha, 2, dst)))
def map2curve_osswu2(alpha, dst=None): t1 = Fq2(p, *Hp2(alpha, 0, dst)) t2 = Fq2(p, *Hp2(alpha, 1, dst)) return opt_swu2_map(t1, t2)
def qi_x(x): return Fq2(p, k_qi_x * x[0], p - k_qi_x * x[1])
def map2curve_osswu2(alpha, dst=None): return opt_swu2_map(*(Fq2(p, *hh) for hh in Hp2(alpha, 2, dst)))
def _from_bytes_F2(data): assert len(data) == 96 return Fq2(p, _from_bytes_F1(data[48:]), _from_bytes_F1(data[:48]))
def _gx2(x): return pow(x, 3) + Fq2(p, 4, 4)
def qi_y(y): return Fq2(p, k_qi_y * (y[0] + y[1]), k_qi_y * (y[0] - y[1]))
from fields import Fq, Fq2 # BLS parameter used to generate the other parameters # Spec is found here: https://github.com/zkcrypto/pairing/tree/master/src/bls12_381 x = -0xD201000000010000 # 381 bit prime # Also see fields:bls12381_q q = 0x1A0111EA397FE69A4B1BA7B6434BACD764774B84F38512BF6730D2A0F6B0F6241EABFFFEB153FFFFB9FEFFFFFFFFAAAB # a,b and a2, b2, define the elliptic curve and twisted curve. # y^2 = x^3 + 4 # y^2 = x^3 + 4(u + 1) a = Fq(q, 0) b = Fq(q, 4) a_twist = Fq2(q, 0, 0) b_twist = Fq2(q, 4, 4) # The generators for g1 and g2 gx = Fq( q, 0x17F1D3A73197D7942695638C4FA9AC0FC3688C4F9774B905A14E3A3F171BAC586C55E83FF97A1AEFFB3AF00ADB22C6BB, ) gy = Fq( q, 0x08B3F481E3AAA0F1A09E30ED741D8AE4FCF5E095D5D00AF600DB18CB2C04B3EDD03CC744A2888AE40CAA232946C5E7E1, ) g2x = Fq2( q, 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160,
q) # G2 g2_x0 = Fq( 352701069587466618187139116011060144890029952792775240219908644239793785735715026873347600343865175952761926303160, q) g2_x1 = Fq( 3059144344244213709971259814753781636986470325476647558659373206291635324768958432433509563104347017837885763365758, q) g2_y0 = Fq( 1985150602287291935568054521177171638300868978215655730859378665066344726373823718423869104263333984641494340347905, q) g2_y1 = Fq( 927553665492332455747201965776037880757740193453592970025027978793976877002675564980949289727957565575433344219582, q) g2_x = Fq2(g2_x0, g2_x1) g2_y = Fq2(g2_y0, g2_y1) # BLS Params BLS_x = 0xd201000000010000 BLS_negative = True # Frobenius map coefficients # Fq(-1)**(((q**0) - 1) // 2), Fq(-1)**(((q**1) - 1) // 2) FROB_FQ2 = ( Fq(1, q), Fq( 4002409555221667393417789825735904156556882819939007885332058136124031650490837864442687629129015664037894272559786, q)) # tuple(Fq2.all_one_poly(q) ** (((q ** i) - 1) // 3) for i in range(0, 6)) FROB_FQ6_C1 = (
Q = point_double(Q) return Q ### ## Fast cofactor clearing using the untwist-Frobenius-twist Endomorphism ### # We use the version given in section 4.1 of # Budroni and Pintore, "Efficient hash maps to G2 on BLS curves," # ePrint 2017/419 https://eprint.iacr.org/2017/419 # NOTE: this impl works for affine coordinates. See ../src/test/g2_test.sage for a version # that works for Jacobian projective coordinates without computing an inversion. # # constants for Psi, the untwist-Frobenius-twist endomorphism iwsc = 0xd0088f51cbff34d258dd3db21a5d66bb23ba5c279c2895fb39869507b587b120f55ffff58a9ffffdcff7fffffffd556 iwsc = Fq2(p, iwsc, iwsc - 1) k_qi_x = Fq( p, 0x1a0111ea397fe699ec02408663d4de85aa0d857d89759ad4897d29650fb85f9b409427eb4f49fffd8bfd00000000aaad ) k_qi_y = Fq( p, 0x6af0e0437ff400b6831e36d6bd17ffe48395dabc2d3435e77f76e17009241c5ee67992f72ec05f4c81084fbede3cc09 ) onei = Fq2(p, 1, 1) # shortcut Frobenius evaluations that avoid going all the way to Fq12 def qi_x(x): return Fq2(p, k_qi_x * x[0], p - k_qi_x * x[1])
#!/usr/bin/python # # (C) 2019 Riad S. Wahby <*****@*****.**> # # pure Python implementation of optimized simplified SWU map to BLS12-381 G2 from consts import g2suite, p from curve_ops import clear_h2, eval_iso, from_jacobian, point_add from fields import Fq2, sgn0, roots_of_unity from hash_to_field import Hp2 from util import get_cmdline_options, print_g2_hex, print_tv_hash # distinguished non-square in Fp2 for SWU map xi_2 = Fq2(p, 1, 1) # 3-isogenous curve parameters Ell2p_a = Fq2(p, 0, 240) Ell2p_b = Fq2(p, 1012, 1012) # eta values, used for computing sqrt(g(X1(t))) ev1 = 0x2c4a7244a026bd3e305cc456ad9e235ed85f8b53954258ec8186bb3d4eccef7c4ee7b8d4b9e063a6c88d0aa3e03ba01 ev2 = 0x85fa8cd9105715e641892a0f9a4bb2912b58b8d32f26594c60679cc7973076dc6638358daf3514d6426a813ae01f51a etas = (Fq2(p, ev1, 0), Fq2(p, 0, ev1), Fq2(p, ev2, ev2), Fq2(p, ev2, p - ev2)) del ev1, ev2 ### ## Simplified SWU map, optimized and adapted to Ell2' ### # This function maps an element of Fp^2 to the curve Ell2', 3-isogenous to Ell2. def osswu2_help(t):
## generators for BLS signatures ### # I'd rather have these in consts, but then we'd get an import cycle, consts <-> fields g1gen = ( Fq( p, 0x17f1d3a73197d7942695638c4fa9ac0fc3688c4f9774b905a14e3a3f171bac586c55e83ff97a1aeffb3af00adb22c6bb ), Fq( p, 0x08b3f481e3aaa0f1a09e30ed741d8ae4fcf5e095d5d00af600db18cb2c04b3edd03cc744a2888ae40caa232946c5e7e1 ), Fq.one(p)) g2gen = ( Fq2( p, 0x024aa2b2f08f0a91260805272dc51051c6e47ad4fa403b02b4510b647ae3d1770bac0326a805bbefd48056c8c121bdb8, 0x13e02b6052719f607dacd3a088274f65596bd0d09920b61ab5da61bbdc7f5049334cf11213945d57e5ac7d055d042b7e ), Fq2( p, 0x0ce5d527727d6e118cc9cdc6da2e351aadfd9baa8cbdd3a76d429a695160d12c923ac9cc3baca289e193548608b82801, 0x0606c4a02ea734cc32acd2b02bc28b99cb3e287e85a763af267492ab572e99ab3f370d275cec1da1aaa9075ff05f79be ), Fq2.one(p)) ### ## Basic curve operations ### # Jacobian coordinates def from_jacobian(P): z3inv = ~(P[2]**3)