def add_mixed_hmv( pt1, pt2: Optimized_Point3D[Optimized_Field] ) -> Optimized_Point3D[Optimized_Field]: x1, y1, z1 = pt1 x2, y2, z2 = pt2 assert z2 == FQ2.one() T1 = z1 * z1 T2 = T1 * z1 T1 = T1 * x2 T2 = T2 * y2 T1 = T1 - x1 T2 = T2 - y1 if T1 == FQ2.zero(): if T2 == FQ2.zero(): return double(pt1) return inf z3 = z1 * T1 T3 = T1 * T1 T4 = T3 * T1 T3 = T3 * x1 T1 = 2 * T3 x3 = T2 * T2 x3 = x3 - T1 x3 = x3 - T4 T3 = T3 - x3 T3 = T3 * T2 T4 = T4 * y1 y3 = T3 - T4 return (x3, y3, z3)
def test_aggregate_pubkeys(BLSG2): pk1, pk2, pk3 = rand_pubkey(), rand_pubkey(), rand_pubkey() _agg = pubkey_to_g2(agg_pubs([pk1, pk2, pk3])) agg = BLSG2.aggregatePubkeys( [pubkey_to_sol(pk1), pubkey_to_sol(pk2), pubkey_to_sol(pk3),] ) assert FQ2(agg[0]) == _agg[0] assert FQ2(agg[1]) == _agg[1]
def FQP_point_to_FQ2_point(pt: Tuple[FQP, FQP, FQP]) -> Tuple[FQ2, FQ2, FQ2]: """ Transform FQP to FQ2 for type hinting. """ return ( FQ2(pt[0].coeffs), FQ2(pt[1].coeffs), FQ2(pt[2].coeffs), )
def _try_sqrt_in_fp2(a: FQ2) -> FQ2: a1 = a**P_MINUS3_OVER4 alpha = a1 * a1 * a x0 = a1 * a if alpha == FQ2([-1, 0]): return FQ2((x0.coeffs[1], x0.coeffs[0])) alpha = alpha + FQ2.one() alpha = alpha**P_MINUS1_OVER2 return alpha * x0
def pubkey_to_g2(pub: Pubkey) -> G2Point: g2 = ( FQ2([big_endian_to_int(pub[:32]), big_endian_to_int(pub[32:64])]), FQ2([big_endian_to_int(pub[64:96]), big_endian_to_int(pub[96:])]), FQ2.one(), ) assert is_valid_g2_point(g2) return g2
def hash_to_G2(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) return multiply((x, y, FQ2([1,0])), 2*field_modulus-curve_order)
def signature_to_G2(signature: Signature) -> G2Point: g2 = ( FQ2([ big_endian_to_int(signature[:32]), big_endian_to_int(signature[32:64]) ]), FQ2([ big_endian_to_int(signature[64:96]), big_endian_to_int(signature[96:]) ]), FQ2.one(), ) assert is_g2_on_curve(g2) return g2
def normalize( pt: Optimized_Point3D[Optimized_Field], ) -> Optimized_Point3D[Optimized_Field]: x1, y1, z1 = pt z = z1.inv() z2 = z * z x3 = x1 * z2 y3 = y1 * z2 * z return (x3, y3, FQ2.one())
def decompress_G2(p: bytes) -> Tuple[FQP, FQP, FQP]: 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 = FQ2((y * -1).coeffs) assert is_on_curve((x, y, FQ2([1, 0])), b2) return x, y, FQ2([1, 0])
def hash_to_G2(m: bytes) -> Tuple[FQ2, FQ2, FQ2]: """ WARNING: this function has not been standardized yet. """ 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 map_to_g2(raw_hash: FQ2) -> G2Point: one = FQ2.one() x = raw_hash while True: y = x * x * x + b2 y = sqrt(y) if y is not None: break x += one h = multiply((x, y, one), COFACTOR_G2) assert is_on_curve(h, b2) return h
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 _normalize(p1): x, y = normalize(p1) return (x, y, FQ2.one())
def sqrt_fq2(x: FQP) -> FQ2: y = x**((field_modulus**2 + 15) // 32) while y**2 != x: y *= HEX_ROOT return FQ2(y.coeffs)
from typing import ( # noqa: F401 Dict, Iterable, Tuple, Union, ) from py_ecc.optimized_bn128 import ( # NOQA G1, G2, Z1, Z2, neg, add, multiply, FQ, FQ2, FQ12, FQP, pairing, normalize, field_modulus, b, b2, is_on_curve, curve_order, final_exponentiate) from eth.utils.blake import blake from eth.utils.bn128 import ( FQP_point_to_FQ2_point, ) CACHE = {} # type: Dict[bytes, Tuple[FQ2, FQ2, FQ2]] # 16th root of unity HEX_ROOT = FQ2([ 21573744529824266246521972077326577680729363968861965890554801909984373949499, 16854739155576650954933913186877292401521110422362946064090026408937773542853 ]) assert HEX_ROOT**8 != FQ2([1, 0]) assert HEX_ROOT**16 == FQ2([1, 0]) def compress_G1(pt: Tuple[FQ, FQ, FQ]) -> int: x, y = normalize(pt) return x.n + 2**255 * (y.n % 2) def decompress_G1(p: int) -> Tuple[FQ, FQ, FQ]: if p == 0: return (FQ(1), FQ(1), FQ(0)) x = p % 2**255
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)
from py_ecc.optimized_bn128 import FQ2, b2 as B from py_ecc.typing import Optimized_Field, Optimized_Point3D inf = (FQ2.zero(), FQ2.one(), FQ2.zero()) def double( pt: Optimized_Point3D[Optimized_Field], ) -> Optimized_Point3D[Optimized_Field]: x, y, z = pt A = x * x B = y * y C = B * B t = x + B D = 2 * (t * t - A - C) E = 3 * A F = E * E x3 = F - 2 * D y3 = E * (D - x3) - 8 * C z3 = 2 * z * y return (x3, y3, z3) def add( pt1, pt2: Optimized_Point3D[Optimized_Field] ) -> Optimized_Point3D[Optimized_Field]: x1, y1, z1 = pt1 x2, y2, z2 = pt2 Z1Z1 = z1 * z1 Z2Z2 = z2 * z2 U1 = x1 * Z2Z2
def sol_to_g2(a): return [ FQ2(a[0]), FQ2(a[1]), FQ2(a[2]), ]
def sol_to_fq(a): return FQ2([a[0], a[1]])
def _normalize(p1) -> Optimized_Point3D[Optimized_Field]: x, y = normalize(p1) return (x, y, FQ2.one())
def sign(msg: Message, priv: PrivateKey) -> Signature: x, y = normalize(multiply(hash_to_g2(msg), priv)) g2 = (x, y, FQ2.one()) return G2_to_signature(g2)
def priv_to_pub(priv: PrivateKey) -> Pubkey: x, y = normalize(multiply(G2, priv)) g2 = (x, y, FQ2.one()) return g2_to_pubkey(g2)
def hash_ORBLS(msg: bytes) -> FQ2: x_re = big_endian_to_int(_hash(msg, b"\x01")) x_im = big_endian_to_int(_hash(msg, b"\x02")) return FQ2([x_re, x_im])