def hash_to_G2(message_hash: Hash32, domain: int) -> G2Uncompressed: x_coordinate = _get_x_coordinate(message_hash, domain) # Test candidate y coordinates until a one is found while 1: y_coordinate_squared = x_coordinate**3 + FQ2( [4, 4]) # The curve is y^2 = x^3 + 4(i + 1) y_coordinate = modular_squareroot_in_FQ2(y_coordinate_squared) if y_coordinate is not None: # Check if quadratic residue found break x_coordinate += FQ2([1, 0]) # Add 1 and try again return multiply( (x_coordinate, y_coordinate, FQ2([1, 0])), G2_cofactor, )
def derive_public_child(master_pubkey_share: bytes, path: bytes, master_pubkey: bytes = None) -> tuple: if not master_pubkey: master_pubkey = master_pubkey_share root_public_key, root_public_chaincode = parse_master_pubkey(master_pubkey) root_pubkey_address = bls_conv.G1_to_pubkey(root_public_key) public_chaincode_address = bls_conv.G1_to_pubkey(root_public_chaincode) h = _hash_to_bls_field( _derivation_format_hash_input(root_pubkey_address, public_chaincode_address, path)) public_key_share, public_chaincode_share = parse_master_pubkey( master_pubkey_share) return bls_curve.add(public_key_share, bls_curve.multiply(public_chaincode_share, h))
def _CoreSign(cls, SK: int, message: bytes, DST: bytes) -> BLSSignature: """ The CoreSign algorithm computes a signature from SK, a secret key, and message, an octet string. Raise `ValidationError` when there is input validation error. """ try: # Inputs validation assert cls._is_valid_privkey(SK) assert cls._is_valid_message(message) except Exception as e: raise ValidationError(e) # Procedure message_point = hash_to_G2(message, DST, cls.xmd_hash_function) signature_point = multiply(message_point, SK) return G2_to_signature(signature_point)
def hash_to_G2(message: bytes, domain: int) -> Tuple[FQ2, FQ2, FQ2]: domain_in_bytes = domain.to_bytes(8, 'big') # Initial candidate x coordinate x_re = big_endian_to_int(hash_eth2(domain_in_bytes + b'\x01' + message)) x_im = big_endian_to_int(hash_eth2(domain_in_bytes + b'\x02' + message)) x_coordinate = FQ2([x_re, x_im]) # x_re + x_im * i # Test candidate y coordinates until a one is found while 1: y_coordinate_squared = x_coordinate**3 + FQ2( [4, 4]) # The curve is y^2 = x^3 + 4(i + 1) y_coordinate = modular_squareroot(y_coordinate_squared) if y_coordinate is not None: # Check if quadratic residue found break x_coordinate += FQ2([1, 0]) # Add 1 and try again return multiply((x_coordinate, y_coordinate, FQ2([1, 0])), G2_cofactor)
def _fft(vals, modulus, roots_of_unity): if len(vals) <= 4 and type(vals[0]) != tuple: #return vals return _simple_ft(vals, modulus, roots_of_unity) elif len(vals) == 1 and type(vals[0]) == tuple: return vals L = _fft(vals[::2], modulus, roots_of_unity[::2]) R = _fft(vals[1::2], modulus, roots_of_unity[::2]) o = [0 for i in vals] for i, (x, y) in enumerate(zip(L, R)): y_times_root = b.multiply( y, roots_of_unity[i]) if type(y) == tuple else y * roots_of_unity[i] o[i] = b.add( x, y_times_root) if type(x) == tuple else (x + y_times_root) % modulus o[i + len(L)] = b.add(x, b.neg(y_times_root)) if type( x) == tuple else (x - y_times_root) % modulus return o
def toeplitz_part2(toeplitz_coefficients, xext_fft): """ Performs the second part of the Toeplitz matrix multiplication algorithm """ # Extend the toeplitz coefficients to get a circulant matrix into which the Toeplitz # matrix is embedded assert is_power_of_two(len(toeplitz_coefficients)) root_of_unity = get_root_of_unity(len(xext_fft)) toeplitz_coefficients_fft = fft(toeplitz_coefficients, MODULUS, root_of_unity, inv=False) hext_fft = [ b.multiply(v, w) for v, w in zip(xext_fft, toeplitz_coefficients_fft) ] return hext_fft
def fft(vals, modulus, root_of_unity, inv=False): rootz = expand_root_of_unity(root_of_unity, modulus) # Fill in vals with zeroes if needed if len(rootz) > len(vals) + 1: vals = vals + [0] * (len(rootz) - len(vals) - 1) if inv: # Inverse FFT invlen = pow(len(vals), modulus - 2, modulus) if type(vals[0]) == tuple: return [ b.multiply(x, invlen) for x in _fft(vals, modulus, rootz[:0:-1]) ] else: return [(x * invlen) % modulus for x in _fft(vals, modulus, rootz[:0:-1])] else: # Regular FFT return _fft(vals, modulus, rootz[:-1])
def semi_toeplitz_fft(toeplitz_coefficients, x): global xext_hat assert len(x) == WIDTH if xext_hat == None: a = time.time() if type(x[0]) == tuple: xext = x + [b.Z1 for a in x] else: xext = x + [0 * a for a in x] xext_hat = fft(xext, MODULUS, ROOT_OF_UNITY2, inv=False) print("Toeplitz preprocessing in %.3f seconds" % (time.time() - a)) text = toeplitz_coefficients[:1] + [0 * a for a in toeplitz_coefficients] + toeplitz_coefficients[:0:-1] text_hat = fft(text, MODULUS, ROOT_OF_UNITY2, inv=False) yext_hat = [None for i in range(2*len(x))] for i in range(len(xext_hat)): if type(xext_hat[0]) == tuple: yext_hat[i] = b.multiply(xext_hat[i], text_hat[i]) else: yext_hat[i] *= text_hat[i] return fft(yext_hat, MODULUS, ROOT_OF_UNITY2, inv=True)[:len(x)]
def execute(cls, stack: MichelsonStack, stdout: List[str], context: AbstractContext): a, b = cast( Tuple[Union[IntType, NatType, MutezType, BLS12_381_FrType, BLS12_381_G1Type, BLS12_381_G2Type], ...], stack.pop2()) res_type, = dispatch_types( type(a), type(b), mapping={ (NatType, NatType): (NatType, ), (NatType, IntType): (IntType, ), (IntType, NatType): (IntType, ), (IntType, IntType): (IntType, ), (MutezType, NatType): (MutezType, ), (NatType, MutezType): (MutezType, ), (NatType, BLS12_381_FrType): (BLS12_381_FrType, ), (IntType, BLS12_381_FrType): (BLS12_381_FrType, ), (BLS12_381_FrType, NatType): (BLS12_381_FrType, ), (BLS12_381_FrType, IntType): (BLS12_381_FrType, ), (BLS12_381_FrType, BLS12_381_FrType): (BLS12_381_FrType, ), (BLS12_381_G1Type, BLS12_381_FrType): (BLS12_381_G1Type, ), (BLS12_381_G2Type, BLS12_381_FrType): (BLS12_381_G2Type, ), }) res_type = cast( Union[Type[IntType], Type[NatType], Type[TimestampType], Type[MutezType], Type[BLS12_381_FrType], Type[BLS12_381_G1Type], Type[BLS12_381_G2Type]], res_type) if issubclass(res_type, IntType): res = res_type.from_value(int(a) * int(b)) # type: ignore else: res = res_type.from_point(bls12_381.multiply( a.to_point(), int(b))) # type: ignore stack.push(res) stdout.append(format_stdout(cls.prim, [a, b], [res])) # type: ignore return cls(stack_items_added=1)
def verify_evaluation(points, commitment, proof, x, y): # Crop the base points to just what we need. We add an additional base point, # which we will use to mix in the _evaluation_ of the polynomial. points, H = points[:2**len(proof.L)], points[2**len(proof.L)] # Powers of x, as in the prover xpowers = [pow(x, i, b.curve_order) for i in range(len(poly))] # Fiat-shamir randomness value r = hash( serialize_point(commitment) + x.to_bytes(32, 'little') + y.to_bytes(32, 'little')) # For security, we randomize H H = b.multiply(H, int.from_bytes(r, 'little') % b.curve_order) # We "mix in" H * the claimed evaluation P(x) = y. Notice that `H * P(x)` equals the # dot-product of `H * powers of x` and the polynomial coefficients, so it has the # "same format" as the polynomial commitment itself. This allows us to verify the # evaluation using the same technique that we use to just prove that the commitment # is valid commitment = b.add(commitment, b.multiply(H, y)) # Track the linear combination so we can generate the final-round point and xpower, # just as before points_coeffs = [1] for i in range(len(proof.L)): # Generate random coefficient for recombining (same as the prover) r = hash(r + serialize_point(proof.L[i]) + serialize_point(proof.R[i])) a = int.from_bytes(r, 'little') % b.curve_order # print('a value: ', a) # Add L and R into the commitment, applying the appropriate coefficients commitment = b.add( proof.L[i], b.add(b.multiply(commitment, a), b.multiply(proof.R[i], a**2))) # print('intermediate commitment:', commitment) # Update the coefficients (as in basic verification above) points_coeffs = sum([[(x * a) % b.curve_order, x] for x in points_coeffs], []) # Finally, we do the linear combination; same one for base points and x powers combined_point = lincomb(points, points_coeffs, b.add, b.Z1) combined_x_powers = sum(p * c for p, c in zip(xpowers, points_coeffs)) # Base case check: base_point * coefficient ?= commitment. Note that here we # have to also mix H * the combined xpower into the final base point return b.eq( b.add(b.multiply(combined_point, proof.tip), b.multiply(H, (proof.tip * combined_x_powers) % b.curve_order)), commitment)
def multiply(self, n: IntOrFE) -> "WrappedCurvePoint": return self.__class__(multiply(self.py_ecc_object, int(n)))
def sign(message_hash: Hash32, privkey: int, domain: int) -> BLSSignature: return G2_to_signature( multiply( hash_to_G2(message_hash, domain), privkey, ))
result_1 = hash_to_G2(message_hash, domain_in_bytes) assert is_on_curve(result_1, b2) def test_decompress_G2_with_no_modular_square_root_found(): with pytest.raises(ValueError, match="Failed to find a modular squareroot"): signature_to_G2(b'\x11' * 96) @pytest.mark.parametrize( 'pt,on_curve,is_infinity', [ # On curve points (G1, True, False), (multiply(G1, 5), True, False), # Infinity point but still on curve (Z1, True, True), # Not on curve ((FQ(5566), FQ(5566), FQ.one()), False, None), ]) def test_G1_compress_and_decompress_flags(pt, on_curve, is_infinity): assert on_curve == is_on_curve(pt, b) z = compress_G1(pt) if on_curve: x = z % POW_2_381 c_flag = (z % 2**384) // POW_2_383 b_flag = (z % POW_2_383) // POW_2_382 a_flag = (z % POW_2_382) // POW_2_381 assert x < q assert c_flag == 1
def sign(message: bytes, privkey: int, domain: int) -> BLSSignature: return BLSSignature( compress_G2(multiply(hash_to_G2(message, domain), privkey)))
def privtopub(k: int) -> BLSPubkey: return BLSPubkey(compress_G1(multiply(G1, k)))
def sign(message: bytes, privkey: int, domain: int) -> Tuple[int, int]: return compress_G2(multiply(hash_to_G2(message, domain), privkey))
def privtopub(k: int) -> int: return compress_G1(multiply(G1, k))
# Alternatively, this can be used to turn an already existing validator into a secret shared validator; # however, if the key was compromised before the split happened, it does not help. from python_ibft.bls_threshold import eval_poly, generate_keys import sys import random import base64 import py_ecc.optimized_bls12_381 as b from py_ecc.bls.g2_primatives import G1_to_pubkey if len(sys.argv) != 2: print("Usage: python privkey_to_threshold.py {privkey_as_hex}") sys.exit(1) privkey = int(sys.argv[1], base=16) printable_pubkey = G1_to_pubkey(b.multiply(b.G1, privkey)).hex() print("Generating threshold keys for validator {0}".format(printable_pubkey)) coefs = [privkey] + [random.randint(0, b.curve_order) for i in range(2)] privkeys = [eval_poly(x, coefs) for x in range(1,5)] printable_pubkeys = [G1_to_pubkey(b.multiply(b.G1, p)).hex() for p in privkeys] printable_privkeys = [base64.encodebytes(p.to_bytes(32, byteorder="big")).decode()[:-1] for p in privkeys] for i, p in enumerate(zip(printable_pubkeys, printable_privkeys)): print("Pubkey {0}:".format(i), p[0]) print("Privkey {0}:".format(i), p[1]) print() print("Copy this into validators.json:")
io = remote(Host, Port) # io = process('./server.py') for i in data: j = dumps({"Name": i["Name"], "Vote": i["Vote"], "Sign": i["Sign"]}) io.recvuntil(b'> ') io.sendline(j) # io.interactive() io.recvuntil(b'reward : ') return io.recvline().strip() order = 52435875175126190479447740508185965837690552500527637822603658699938581184513 m1, m2 = [int(sha256(i).hexdigest(), 16) for i in [b"D", b"R"]] idx, ny = [(i, j) for i, j in enumerate(result) if j["Name"] == 'New York'][0] ny["Sign"] = G2_to_signature( multiply(multiply(signature_to_G2(unhex(ny["Sign"])), invert(m1, order)), m2)).hex() ny["Vote"] = "R" assert bls.Verify(unhex(ny["PK"]), ny["Vote"].encode(), unhex(ny["Sign"])) result[idx] = ny xored_flag = unhex(connect(result).decode()) fake_result = result[:] w = fake_result[idx + 1] ny = fake_result[idx] ny["Sign"] = G2_to_signature( add(signature_to_G2(unhex(ny["Sign"])), multiply(signature_to_G2(unhex(w["Sign"])), 2))).hex() w["Sign"] = G2_to_signature(neg(signature_to_G2(unhex(w["Sign"])))).hex() assert bls.Verify(bls._AggregatePKs([unhex(ny["PK"]), unhex(w["PK"])]), b'R',
def _CoreSign(SK: int, message: bytes, DST: bytes) -> BLSSignature: message_point = hash_to_G2(message, DST) signature_point = multiply(message_point, SK) return G2_to_signature(signature_point)
def singlechecker(agg_pk, agg_sig, msg): final_exp = final_exponentiate( pairing(agg_sig, G1, final_exponentiate=False) * pairing( multiply(G2, hasher(msg)), neg(agg_pk), final_exponentiate=False)) isok = (final_exp == FQ12.one()) return isok
(735), (127409812145), (90768492698215092512159), ] ) def test_sign_verify(privkey): msg = str(privkey).encode('utf-8') pub = G2Basic.SkToPk(privkey) sig = G2Basic._CoreSign(privkey, msg, G2Basic.DST) assert G2Basic._CoreVerify(pub, msg, sig, G2Basic.DST) @pytest.mark.parametrize( 'signature_points,result_point', [ ([multiply(G2, 2), multiply(G2, 3)], multiply(G2, 2 + 3)), ([multiply(G2, 42), multiply(G2, 69)], multiply(G2, 42 + 69)), ] ) def test_aggregate(signature_points, result_point): signatures = [G2_to_signature(pt) for pt in signature_points] result_signature = G2_to_signature(result_point) assert G2Basic.Aggregate(signatures) == result_signature @pytest.mark.parametrize( 'SKs,messages', [ (list(range(1, 6)), list(range(1, 6))), ] )
def hash_to_G2(msg, DST, hash): m = int(hash(msg).hexdigest(), 16) return multiply(G2, m)
def mul(xxx: G1Point, nnn: int) -> G1Point: return bls12_381.multiply(xxx, nnn)
def privtopub(k: int) -> BLSPubkey: return G1_to_pubkey(multiply(G1, k))
def generate_keys(n_parties, t): coefs = [random.randint(0, b.curve_order - 1) for i in range(t + 1)] aggregate_public = G1_to_pubkey(b.multiply(b.G1, coefs[0])) private = [eval_poly(x, coefs) for x in range(1, n_parties + 1)] public = [G1_to_pubkey(b.multiply(b.G1, x)) for x in private] return aggregate_public, public, private
) @pytest.mark.parametrize('sk', [ 42, 69, 31415926, ]) def test_pop(sk): pk = G2ProofOfPossession.PrivToPub(sk) proof = G2ProofOfPossession.PopProve(sk) assert G2ProofOfPossession.PopVerify(pk, proof) @pytest.mark.parametrize('signature_points,result_point', [ ([multiply(G1, 2), multiply(G1, 3)], multiply(G1, 2 + 3)), ([multiply(G1, 42), multiply(G1, 69)], multiply(G1, 42 + 69)), ]) def test_aggregate_pks(signature_points, result_point): signatures = [G1_to_pubkey(pt) for pt in signature_points] result_signature = G1_to_pubkey(result_point) assert G2ProofOfPossession._AggregatePKs(signatures) == result_signature @pytest.mark.parametrize('SKs,message', [ (range(5), b'11' * 48), ]) def test_fast_aggregate_verify(SKs, message): PKs = [G2ProofOfPossession.PrivToPub(sk) for sk in SKs] signatures = [G2ProofOfPossession.Sign(sk, message) for sk in SKs] aggregate_signature = G2ProofOfPossession.Aggregate(signatures)
def __mul__(self, x): assert type(x) in (int, Fp) if type(x) is Fp: x = x.n return SS_BLS12_381(multiply(self.m1, x), multiply(self.m2, x))
def subgroup_check(P: Optimized_Point3D) -> bool: return is_inf(multiply(P, curve_order))
pub = pubkey_to_G1(bytes.fromhex(wow[i]["PK"])) sig = signature_to_G2(bytes.fromhex(wow[i]["Sign"])) print("pubkey check", i, subgroup_check(pub)) print("sig check", i, subgroup_check(sig)) if wow[i]["Vote"] == "D": if ex: ex = False fin = creator(wow[i]["Name"], "D", wow[i]["Sign"]) r.sendline(fin) continue res1 = hasher(b"D") res2 = hasher(b"R") tt = (res2 * inverse(res1, cv)) % cv sigs = signature_to_G2(bytes.fromhex(wow[i]["Sign"])) sigs = multiply(sigs, tt) # do this part only if you want fake flag if cnt == 0: sigs = add(sigs, G2) if cnt == 1: sigs = add(sigs, neg(G2)) # end cnt += 1 sig = G2_to_signature(sigs).hex() wow[i]["Sign"] = sig wow[i]["Vote"] = "R" fin = creator(wow[i]["Name"], "R", wow[i]["Sign"]) pub = pubkey_to_G1(bytes.fromhex(wow[i]["PK"])) sig = signature_to_G2(bytes.fromhex(wow[i]["Sign"])) print("sig check2", i, subgroup_check(sig))