try: from hashlib import blake2s except: from pyblake2 import blake2s blake = lambda x: blake2s(x).digest() from py_ecc.optimized_bn128 import G1, G2, neg, add, multiply, FQ, FQ2, FQ12, pairing, \ normalize, field_modulus, b, b2, is_on_curve, curve_order, final_exponentiate def compress_G1(pt): x, y = normalize(pt) return x.n + 2**255 * (y.n % 2) def decompress_G1(p): if p == 0: return (FQ(1), FQ(1), FQ(0)) x = p % 2**255 y_mod_2 = p // 2**255 y = pow((x**3 + b.n) % field_modulus, (field_modulus+1)//4, field_modulus) assert pow(y, 2, field_modulus) == (x**3 + b.n) % field_modulus if y%2 != y_mod_2: y = field_modulus - y return (FQ(x), FQ(y), FQ(1)) # 16th root of unity hex_root = FQ2([21573744529824266246521972077326577680729363968861965890554801909984373949499, 16854739155576650954933913186877292401521110422362946064090026408937773542853]) assert hex_root ** 8 != FQ2([1,0]) assert hex_root ** 16 == FQ2([1,0]) def sqrt_fq2(x): y = x ** ((field_modulus ** 2 + 15) // 32) while y**2 != x: y *= hex_root return y cache = {} def hash_to_G2(m): if m in cache: return cache[m] k2 = m while 1: k1 = blake(k2) k2 = blake(k1) x1 = int.from_bytes(k1, 'big') % field_modulus x2 = int.from_bytes(k2, 'big') % field_modulus x = FQ2([x1, x2]) xcb = x**3 + b2 if xcb ** ((field_modulus ** 2 - 1) // 2) == FQ2([1,0]): break y = sqrt_fq2(xcb) o = multiply((x, y, FQ2([1,0])), 2*field_modulus-curve_order) cache[m] = o return o def compress_G2(pt): assert is_on_curve(pt, b2) x, y = normalize(pt) return (x.coeffs[0] + 2**255 * (y.coeffs[0] % 2), x.coeffs[1]) def decompress_G2(p): x1 = p[0] % 2**255 y1_mod_2 = p[0] // 2**255 x2 = p[1] x = FQ2([x1, x2]) if x == FQ2([0, 0]): return FQ2([1,0]), FQ2([1,0]), FQ2([0,0]) y = sqrt_fq2(x**3 + b2) if y.coeffs[0] % 2 != y1_mod_2: y = y * -1 assert is_on_curve((x, y, FQ2([1,0])), b2) return x, y, FQ2([1,0]) def sign(m, k): return compress_G2(multiply(hash_to_G2(m), k)) def privtopub(k): return compress_G1(multiply(G1, k)) def verify(m, pub, sig): return final_exponentiate(pairing(decompress_G2(sig), G1, False) * \ pairing(hash_to_G2(m), neg(decompress_G1(pub)), False)) == FQ12.one() def aggregate_sigs(sigs): o = FQ2([1,0]), FQ2([1,0]), FQ2([0,0]) for s in sigs: o = add(o, decompress_G2(s)) return compress_G2(o) def aggregate_pubs(pubs): o = FQ(1), FQ(1), FQ(0) for p in pubs: o = add(o, decompress_G1(p)) return compress_G1(o)