Skip to content

Commit

Permalink
minor touchups
Browse files Browse the repository at this point in the history
  • Loading branch information
UdiP committed Dec 8, 2020
1 parent d0dbb13 commit c6006c0
Show file tree
Hide file tree
Showing 6 changed files with 28 additions and 34 deletions.
3 changes: 1 addition & 2 deletions fb_bls_derive_key_and_sign.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def main():
parser.add_argument("key_file",type=str, help="BLS key verification file")
parser.add_argument("--index",type=int, help="derivation index", required=True)
parser.add_argument("--RSA",type=str, help="Private RSA key file")
parser.add_argument("--sign_msg", type=str, help="Sign hex/str message (with private key share)")
parser.add_argument("--sign_msg", type=str, help="Sign message (hex or string) with private key share")
parser.add_argument("--hex", action='store_true', help="Message is hex encoded, signed as bytes")
args = parser.parse_args()

Expand Down Expand Up @@ -44,7 +44,6 @@ def main():
passphrase = getpass.getpass(prompt='Please enter BLS public key integrity passphrase:')

genver.derive_address_and_sign(args.key_file, args.index, passphrase, args.RSA, args.sign_msg, args.hex)


if __name__ == "__main__":
main()
4 changes: 1 addition & 3 deletions fb_bls_generate_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,14 @@ def main():
master_pubkey_integrity_passphrase = getpass.getpass(prompt='Please enter BLS public key integrity passphrase (minimum 8 characters):')


# Set party ids for each RSA key file (allows duplicate, will get different sahres id)
# ids shouldn't be more then 255 bits
# Set party ids for each RSA key file (allows duplicates, each will get different share id)
rsa_keys = dict()
print("Setting ids:")
id = 1
for f in args.RSA_public_keys:
if not os.path.exists(f):
print(f'RSA key: {f} not found.')
exit(-1)
# TODO: open and read rsa_key from file
rsa_keys[id] = f
print(f'id: {id}\tfile: {f}')
id += 1
Expand Down
3 changes: 1 addition & 2 deletions fb_bls_key_verification.py → fb_bls_verify_key.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from utils import genver

def main():
parser = argparse.ArgumentParser() #formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser = argparse.ArgumentParser()
parser.add_argument("key_file",type=str, help="RSA encrypted BLS key file")
parser.add_argument("--RSA", type=str, nargs="?", help="RSA private key file")
args = parser.parse_args()
Expand All @@ -29,7 +29,6 @@ def main():
else:
passphrase = getpass.getpass(prompt='Please enter BLS public key integrity passphrase:')


genver.verify_key_file(args.key_file, passphrase, args.RSA)

if __name__ == "__main__":
Expand Down
2 changes: 1 addition & 1 deletion fb_bls_verify_signature.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from utils import genver

def main():
parser = argparse.ArgumentParser() #formatter_class=argparse.ArgumentDefaultsHelpFormatter)
parser = argparse.ArgumentParser()
parser.add_argument("BLS_signature_files", type=str, nargs="+", help="space seperated list generated BLS signature files")
parser.add_argument("-t", "--threshold", type=int, help="check with any subset of this size (if none, check only all)")
args = parser.parse_args()
Expand Down
3 changes: 1 addition & 2 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
pytest
pycryptodome
termcolor==1.1.0
py_ecc
blspy
py_ecc
47 changes: 23 additions & 24 deletions utils/genver.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@
import py_ecc.optimized_bls12_381 as bls_curve
import py_ecc.bls.g2_primatives as bls_conv

# from blspy import G1Element, G2Element, BasicSchemeMPL

import os
import itertools
import secrets
Expand Down Expand Up @@ -31,7 +29,7 @@ def _sample_random_in_range(range:int):
raise GenVerErrorBasic(f'Suspicious randomness samples')
return val % range

# Return shamir secret shares of value, and value also (poly at 0)
# Return shamir secret shares of value, and also secret value (poly at 0)
def _sample_shares(ids: Sequence[int], threshold:int) -> Tuple[int, int]:

if len(ids) != len(set(ids)):
Expand All @@ -45,15 +43,14 @@ def _sample_shares(ids: Sequence[int], threshold:int) -> Tuple[int, int]:
for i in range(0, threshold):
poly_coeff[i] = _sample_random_in_range(bls_curve.curve_order)

# Evaluate (horner's method) on each id
# Evaluate (Horner's method) on each id
shares = {id : poly_coeff[threshold-1] for id in ids}
for i in range(threshold-2, -1, -1):
for id in shares.keys():
shares[id] = (shares[id]*id + poly_coeff[i]) % bls_curve.curve_order

return shares, poly_coeff[0]


def _prime_mod_inverse(x:int, prime:int):
return pow(x, prime-2, prime)

Expand All @@ -77,6 +74,7 @@ def _interpolate_in_group(group_shares:Dict[int,tuple], group_gen:tuple) -> tupl

return combined_group_element

# Concatenate pubkey_address string to msg (default msg if not given)
def _get_msg_for_address(pubkey_address:bytes, msg:str=None) -> Tuple[bytes,str]:
if msg:
test_message = msg
Expand All @@ -92,7 +90,7 @@ def _compute_scrypt_checksum(scrypt_key:bytes, salt_to_hash:bytes) -> bytes:
def _get_test_path():
return b'test/0'

# parties: dict{ party_id : RSA_pub_file }
# RSA_key_files: dict{ party_id : RSA_pub_file }
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())
Expand Down Expand Up @@ -128,7 +126,7 @@ def generate_bls_key_shares_with_verification(rsa_key_files:Dict[int,str], thres
except:
raise GenVerErrorBasic(f'Unable to sign test message for id {id}')

# Scrypt checksum of public key - to avoid manipulation
# 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)

Expand Down Expand Up @@ -183,8 +181,8 @@ def generate_bls_key_shares_with_verification(rsa_key_files:Dict[int,str], thres

return master_pubkey

# Verify threshold of signature shares from given files can reconstruct verifiable signature on test_message
# passphrase is either for integrity checksum or RSA private key (which derived integrity checksum)
# Verify threshold of signature shares of test message existing in the key_file
# passphrase is either for integrity checksum or RSA private key (which decrypts integrity checksum)
def verify_key_file(key_file:str, passphrase:str, rsa_priv_key_file:str=None):
try:
in_file = open(key_file, "r")
Expand Down Expand Up @@ -262,15 +260,14 @@ def verify_key_file(key_file:str, passphrase:str, rsa_priv_key_file:str=None):
if not test_signature_shares[my_id] == bls_basic.Sign(derived_private_key_share, test_msg):
raise GenVerErrorBasic(f'Modified signature share for my key id {my_id}')
else:
print(colored('No RSA key - did not verify private key share validity!', "cyan"))
print(colored('No RSA key - not verifying private key share validity!', "cyan"))

# After getting scrypt integrity passphrase validate master pubkey wasn't changed
computed_checksum = _compute_scrypt_checksum(integrity_passphrase, master_pubkey)

if not computed_checksum == integrity_checksum:
raise GenVerErrorBasic(f'Failure in validating master public key integrity checksum (perhaps wrong passphrase)')


# Convert to group elements to allow interpolation of signatures
G2_signature_shares = {}
for id, sig in test_signature_shares.items():
Expand All @@ -279,9 +276,7 @@ def verify_key_file(key_file:str, passphrase:str, rsa_priv_key_file:str=None):
except:
raise GenVerErrorBasic(f'Invalid encoding of signature shares for id {id}')

# For each authorized set of the above:
# Combine public keys and compare to address.
# Combine signature shares and verify
# For each authorized set of the above, combine signature shares and verify

print(f'Verifying signing threshold {threshold} out of {len(parties_ids)} parties...')

Expand All @@ -290,7 +285,7 @@ def verify_key_file(key_file:str, passphrase:str, rsa_priv_key_file:str=None):
if not bls_basic.Verify(derived_pubkey_address, test_msg, auth_signature):
raise GenVerErrorBasic(f'Failed verification of combined signature for ids {auth_ids}')

# Verify un-authorized set can't get valid signature (less then threhsold)
# Sanity check: check un-authorized set can't get valid signature (less then threhsold)
for auth_ids in itertools.combinations(parties_ids, threshold-1):
auth_signature = bls_conv.G2_to_signature(_interpolate_in_group({id : G2_signature_shares[id] for id in auth_ids}, bls_curve.G2))
if bls_basic.Verify(derived_pubkey_address, test_msg, auth_signature):
Expand Down Expand Up @@ -324,7 +319,7 @@ def derive_address_and_sign(key_file:str, derivation_index:int, passphrase:str,
except:
raise GenVerErrorBasic(f'Error parsing key file')

# If Given RSA private key, use it to get integrity passphrase (if no file, assume integrity passphrase is given)
# If Given RSA private key, use it to decrypt integrity passphrase (if no file, assume integrity passphrase is given)
if rsa_priv_key_file is None:
integrity_passphrase = bytes(passphrase, 'utf-8')
else:
Expand All @@ -345,18 +340,24 @@ def derive_address_and_sign(key_file:str, derivation_index:int, passphrase:str,
raise GenVerErrorBasic(f'Invalid decryption of integrity passphrase from key file')

if sign_msg:
master_private_key_share = cipher.decrypt(encrypted_private_key_share)
try:
master_private_key_share = cipher.decrypt(encrypted_private_key_share)
except:
raise GenVerErrorBasic(f'Invalid decryption of BLS private key share')

# After getting scrypt integrity passphrase validate master pubkey wasn't changed
computed_checksum = _compute_scrypt_checksum(integrity_passphrase, master_pubkey)

if not computed_checksum == integrity_checksum:
raise GenVerErrorBasic(f'Failure in validating master public key integrity checksum (perhaps wrong passphrase)')

# Derive address at index

derivation_path = index_to_path(derivation_index)
derived_public_key = derive_public_child(master_pubkey, derivation_path)
derived_pubkey_address = bls_conv.G1_to_pubkey(derived_public_key)

# Sign message (and write to file) if given
out_data = {}
if sign_msg:
derived_private_key_share = derive_private_child(master_private_key_share, derivation_path, master_pubkey)
Expand Down Expand Up @@ -389,6 +390,9 @@ def derive_address_and_sign(key_file:str, derivation_index:int, passphrase:str,
return

def verify_signature_files(signature_files:Sequence[str], threshold:int=None) -> bool:

# Get data from signature share file

parties_ids = []
signature_shares = {}
master_pubkey = None
Expand Down Expand Up @@ -461,18 +465,13 @@ def verify_signature_files(signature_files:Sequence[str], threshold:int=None) ->
print("Message:", colored(msg_str, "green"))
print("Public Key:", colored(derived_pubkey_address.hex(), "green"))

auth_signature = None
# Verify joining threshold singature shares gives a valid signature
auth_signature = b''
for auth_ids in itertools.combinations(parties_ids, threshold):
auth_signature = bls_conv.G2_to_signature(_interpolate_in_group({id : G2_signature_shares[id] for id in auth_ids}, bls_curve.G2))

if not bls_basic.Verify(derived_pubkey_address, msg_bytes, auth_signature):
print(f'Derived PubKey: {derived_pubkey_address.hex()}')
print(f'Signature: {auth_signature.hex()}')
print(f'Message Hex: {msg_bytes.hex()}')
raise GenVerErrorBasic(f'Failed verification of combined signature for id {auth_ids}.')

# if not BasicSchemeMPL.verify(G1Element(derived_pubkey_address), msg_bytes , G2Element(auth_signature)):
# raise GenVerErrorBasic(f'Failed verification of combined signature for ids {auth_ids} (Chia)')

print("Signature:", colored(auth_signature.hex(), "green"))
print(colored("Success!", "green"))
Expand Down

0 comments on commit c6006c0

Please sign in to comment.