def verify_signature(public_key: str, signing_data: str, signature: str) -> None: """Verifies whether the data signature corresponds to the public key.""" public_key = public_key.strip() if public_key.startswith("0x"): public_key = public_key[2:] bls_public_key = BLSPubkey(bytes.fromhex(public_key)) if not bls_pop._is_valid_pubkey(bls_public_key): raise click.BadParameter("Invalid BLS public key") signature = signature.strip() if signature.startswith("0x"): signature = signature[2:] bls_signature = BLSSignature(bytes.fromhex(signature)) if not bls_pop._is_valid_signature(bls_signature): raise click.BadParameter("Invalid BLS signature") signing_data = signing_data.strip() if signing_data.startswith("0x"): signing_data = signing_data[2:] if bls_pop.Verify(PK=bls_public_key, message=bytes.fromhex(signing_data), signature=bls_signature): click.secho("[+] The signature is valid", fg="green") else: click.secho("[-] The signature is invalid", fg="red")
def get_bls_secret_shares( total: int, threshold: int) -> Tuple[BLSPubkey, List[BLSPubkey], List[int]]: """Generates Shamir's secrets for the BLS keypair.""" coefficients = [randint(0, PRIME - 1) for _ in range(threshold)] private_key_secrets = get_polynomial_points(coefficients, total) public_key_secrets = [ bls_pop.SkToPk(private_key) for private_key in private_key_secrets ] return bls_pop.SkToPk( coefficients[0]), public_key_secrets, private_key_secrets
def sign(horcrux_file: str, horcrux_password: str) -> None: """Unlocks the keystore and signs the data.""" horcrux_file = horcrux_file.strip() if not os.path.exists(horcrux_file): raise click.BadParameter("Horcrux file does not exist.") # read keystore from file with open(horcrux_file, "r") as key_file: keystore = HorcruxPbkdf2Keystore.create_from_json(json.load(key_file)) signing_data = click.prompt(text="Enter hexadecimal encoded data to sign", type=click.STRING).strip() if signing_data.startswith("0x"): signing_data = signing_data[2:] # decrypt and sign data private_key = int.from_bytes(keystore.decrypt(horcrux_password), "big") signature = bls_pop.Sign(private_key, bytes.fromhex(signing_data)) click.echo(f"Signature: {click.style(f'0x{signature.hex()}', fg='green')}") click.echo( f"Horcrux index: {click.style(f'{keystore.index}', fg='green')}") click.echo(f"""Next steps: 1) Retrieve signatures of the same signing data from other horcruxes. 2) Run {click.style('./horcrux.sh reconstruct-signature', fg='blue')} to reconstruct the final signature. {click.style(f'NB! At least {keystore.threshold} signatures are required to reconstruct.', fg='yellow')} """)
def reconstruct_signature(signatures: int) -> None: """Reconstructs BLS signatures using Shamir's secret sharing.""" if signatures <= 0: raise click.BadParameter(message=INVALID_NUMBER) points: Dict[int, BLSSignature] = {} submitted = 0 while True: if submitted == signatures: break index = click.prompt( text=("Enter the horcrux index of the submitted signature " "(can be found in the owner's horcrux file)"), type=click.INT, ) if index in points: click.echo("The signature for such index was already submitted") continue signature = click.prompt( text=("Enter the next hexadecimal encoded BLS signature " f"({submitted + 1}/{signatures})"), type=click.STRING, ).strip() if signature.startswith("0x"): signature = signature[2:] signature = BLSSignature(bytes.fromhex(signature)) if not bls_pop._is_valid_signature(signature): click.secho("The signature is invalid. Please try again.", fg="red") continue points[index] = signature submitted += 1 # reconstruct signature using Shamir's secret sharing reconstructed_signature = reconstruct_shared_bls_signature(points) click.echo( "Reconstructed signature: " f"{click.style(f'0x{reconstructed_signature.hex()}', fg='green')}") click.echo(f"Run {click.style('./horcrux.sh verify-signature', fg='blue')}" f" to verify whether the signature is correct.")
) from py_ecc.optimized_bls12_381 import ( add, curve_order, final_exponentiate, G1, multiply, neg, pairing, Z1, Z2, ) from py_ecc.bls.ciphersuites import G2ProofOfPossession as bls priv = 100 pub = bls.SkToPk(priv) print(pub.hex()) x = pubkey_to_G1(pub) print(x) x2 = add(x, x) print(x2) agg = G1_to_pubkey(x2) print(agg.hex()) v = pubkey_to_G1(agg) print(v)
def process_dispatcher_output( dispatcher_output: List[Dict[str, Any]], my_bls_public_key: BLSPubkey, my_bls_public_key_shares: List[BLSPubkey], my_bls_private_key_shares: List[int], my_rsa_key: RsaKey, my_index: int, ) -> Tuple[BLSPubkey, bytes, int]: """ Processes output from the dispatcher to generate final horcrux BLS private key and shared BLS public key. """ final_public_key_shares = [my_bls_public_key] horcrux_private_key_shares = [my_bls_private_key_shares[my_index]] horcrux_public_key_shares = [my_bls_public_key_shares[my_index]] for encrypted_data in dispatcher_output: # verify the RSA signature ciphertext = bytes.fromhex(encrypted_data["ciphertext"]) signature = bytes.fromhex(encrypted_data["signature"]) if not rsa_verify( RSA.import_key(encrypted_data["sender_rsa_public_key"]), ciphertext, signature, ): raise ValueError("Failed to verify the RSA signature.") data = json.loads( rsa_decrypt( private_key=my_rsa_key, enc_session_key=bytes.fromhex( encrypted_data["enc_session_key"]), nonce=bytes.fromhex(encrypted_data["nonce"]), tag=bytes.fromhex(encrypted_data["tag"]), ciphertext=ciphertext, )) recipient_bls_public_keys = [ bytes.fromhex(pub_key) for pub_key in data["public_key_shares"] ] horcrux_private_key_share = int(data["private_key_share"]) if (bls_pop.SkToPk(horcrux_private_key_share) != recipient_bls_public_keys[my_index]): raise ValueError("Received invalid BLS private key share.") final_public_key_shares.append( BLSPubkey(bytes.fromhex(data["public_key"]))) horcrux_public_key_shares.append( BLSPubkey(recipient_bls_public_keys[my_index])) horcrux_private_key_shares.append(horcrux_private_key_share) final_public_key = bls_pop._AggregatePKs(final_public_key_shares) click.echo("Shared BLS Public Key: " f"{click.style(f'0x{final_public_key.hex()}', fg='green')}") withdrawal_credentials = BLS_WITHDRAWAL_PREFIX withdrawal_credentials += SHA256(final_public_key)[1:] click.echo( "Withdrawal Credentials: " f"{click.style(f'0x{withdrawal_credentials.hex()}', fg='green')}") horcrux_private_key = 0 for private_key_share in horcrux_private_key_shares: horcrux_private_key += private_key_share horcrux_private_key %= PRIME if bls_pop.SkToPk(horcrux_private_key) != bls_pop._AggregatePKs( horcrux_public_key_shares): raise ValueError("Invalid calculated horcrux private key") return final_public_key, withdrawal_credentials, horcrux_private_key
def signature(bls_private_key, signing_root): return G2ProofOfPossession.Sign(bls_private_key, signing_root)
def bls_public_key(bls_private_key): return G2ProofOfPossession.SkToPk(bls_private_key)
def bls_private_key(seed): return G2ProofOfPossession.KeyGen(seed)