def test_aggregate_verify(SKs, messages, result): PKs = [G2Basic.SkToPk(SK) for SK in SKs] messages = [bytes(msg) for msg in messages] signatures = [G2Basic.Sign(SK, msg) for SK, msg in zip(SKs, messages)] aggregate_signature = G2Basic.Aggregate(signatures) assert G2Basic.AggregateVerify(PKs, messages, aggregate_signature) == result
def test_core_aggregate_verify(SKs, messages): PKs = [G2Basic.SkToPk(sk) for sk in SKs] messages = [bytes(msg) for msg in messages] signatures = [ G2Basic._CoreSign(sk, msg, G2Basic.DST) for sk, msg in zip(SKs, messages) ] aggregate_signature = G2Basic.Aggregate(signatures) assert G2Basic._CoreAggregateVerify(PKs, messages, aggregate_signature, G2Basic.DST)
def derive_private_child(master_private_key_share: bytes, path: bytes, master_pubkey: bytes = None) -> int: root_private_key_share, root_private_chaincode_share = parse_master_private_key( master_private_key_share) if master_pubkey: 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) else: root_pubkey_address = bls_basic.SkToPk(root_private_key_share) public_chaincode_address = bls_basic.SkToPk( root_private_chaincode_share) h = _hash_to_bls_field( _derivation_format_hash_input(root_pubkey_address, public_chaincode_address, path)) derived_private = (root_private_key_share + root_private_chaincode_share * h) % bls_curve.curve_order return derived_private
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)
from py_ecc.optimized_bls12_381 import ( G1, G2, multiply, ) from py_ecc.bls.g2_primatives import ( G1_to_pubkey, G2_to_signature, ) from py_ecc.bls import G2Basic @pytest.mark.parametrize( 'pubkey,success', [ (G2Basic.SkToPk(42), True), (b'\x11' * 48, False), ] ) def test_key_validate(pubkey, success): assert G2Basic.KeyValidate(pubkey) == success @pytest.mark.parametrize( 'privkey', [ (1), (5), (124), (735), (127409812145),
def test_sk_to_pk(privkey, success): if success: G2Basic.SkToPk(privkey) else: with pytest.raises(ValidationError): G2Basic.SkToPk(privkey)
) def test_aggregate(signatures, success): if success: G2Basic.Aggregate(signatures) else: with pytest.raises(ValidationError): G2Basic.Aggregate(signatures) SAMPLE_MESSAGE = b'helloworld' @pytest.mark.parametrize( 'pubkey, message, signature, result', [ (G2Basic.SkToPk(1), SAMPLE_MESSAGE, G2Basic.Sign(1, SAMPLE_MESSAGE), True), (G2Basic.SkToPk(2), SAMPLE_MESSAGE, G2Basic.Sign(1, SAMPLE_MESSAGE), False), (G2Basic.SkToPk(1), SAMPLE_MESSAGE, Z2_SIGNATURE, False), (Z1_PUBKEY, SAMPLE_MESSAGE, G2Basic.Sign(1, SAMPLE_MESSAGE), False), (Z1_PUBKEY, SAMPLE_MESSAGE, Z2_SIGNATURE, False), ( b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', # noqa: E501 SAMPLE_MESSAGE, b'\x40\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00', # noqa: E501 False, ), ] ) def test_verify(pubkey, message, signature, result): assert G2Basic.Verify(pubkey, message, signature) == result
def generate_bls_key_shares_with_verification(rsa_key_files:Dict[int,str], threshold:int, integrity_passphrase:str): parties_ids = list(rsa_key_files.keys()) # Generate and Shamir secret share root private key with related public keys and shares root_private_key_shares, root_private_key = _sample_shares(parties_ids, threshold) root_public_key = bls_conv.pubkey_to_G1(bls_basic.SkToPk(root_private_key)) root_public_key_shares = {id : bls_conv.pubkey_to_G1(bls_basic.SkToPk(val)) for id, val in root_private_key_shares.items()} # Generate and Shamir secret share private chaincode with related public chaincode private_chaincode_shares, private_chaincode = _sample_shares(parties_ids, threshold) public_chaincode = bls_conv.pubkey_to_G1(bls_basic.SkToPk(private_chaincode)) # Set master public key and private key shares master_pubkey = get_master_pubkey(root_public_key, public_chaincode) master_private_key_shares = {id : get_master_private_key(root_private_key_shares[id], private_chaincode_shares[id]) for id in parties_ids} # Senity check: verify all authorized set of keys (threshold size) generate the same root public key as above for auth_ids in itertools.combinations(parties_ids, threshold): curr_public_key = _interpolate_in_group({id : root_public_key_shares[id] for id in auth_ids}, bls_curve.G1) if not bls_curve.eq(root_public_key, curr_public_key): raise GenVerErrorBasic(f'Invalid Shamir secret sharing of public key for parties {auth_ids}') # Sign test message with each private key share, derived at test path test_derivation_path = _get_test_path() derived_pubkey_address = bls_conv.G1_to_pubkey(derive_public_child(master_pubkey, _get_test_path())) signature_shares = {} for id in parties_ids: try: derived_private_key_share = derive_private_child(master_private_key_shares[id], test_derivation_path, master_pubkey) test_msg, _ = _get_msg_for_address(derived_pubkey_address) signature_shares[id] = bls_basic.Sign(derived_private_key_share, test_msg) except: raise GenVerErrorBasic(f'Unable to sign test message for id {id}') # Scrypt checksum of public key - to avoid manipulation and brute-force integrity_passphrase = bytes(integrity_passphrase,'utf-8') scrypt_checksum = _compute_scrypt_checksum(integrity_passphrase, master_pubkey) # Encrypt master private key shares and (common) integrity passphrase encrypted_master_private_key_shares = {} encrypted_integrity_passphrase = {} for id, rsa_key_file in rsa_key_files.items(): try: rsa_key = RSA.importKey(open(rsa_key_file, 'r').read()) cipher = PKCS1_OAEP.new(rsa_key) except: raise GenVerErrorBasic(f'Reading RSA key file {rsa_key_file}') if rsa_key.n.bit_length() < 4096: GenVerErrorBasic(f'RSA key is too short: {rsa_key.n.bit_length()}, should be at least 4096 bits') try: encrypted_master_private_key_shares[id] = cipher.encrypt(master_private_key_shares[id]) encrypted_integrity_passphrase[id] = cipher.encrypt(integrity_passphrase) except: raise GenVerErrorBasic(f'Unable to encrypt master private key share for id {id}') # Prepare data to output to file data = {} data['master_pubkey'] = master_pubkey.hex() # Ingerity check for master public key data['integrity_checksum'] = scrypt_checksum.hex() data['threshold'] = threshold data['parties'] = {} for id in parties_ids: party = {} party['test_signature_share'] = signature_shares[id].hex() party['encrypted_master_private_key_share'] = encrypted_master_private_key_shares[id].hex() party['encrypted_integrity_passphrase'] = encrypted_integrity_passphrase[id].hex() data['parties'][id] = party # Output file for each party id (key id) for id in parties_ids: data['key_id'] = id # Write to file key_filename = f'id_{id}_fireblocks_bls_key_{master_pubkey[:4].hex()}.json' try: ver_file = open(key_filename, 'w+') json.dump(data, ver_file, indent=4) ver_file.close() print("Generated file:", colored(f'{key_filename}', "green")) except ValueError: raise GenVerErrorBasic(f'Error writing key file for id {id}') return master_pubkey