def main(): # Mnemonics can be generated using `chia keys generate_and_print`, or `chia keys generate`. The latter stored # the key in the OS keychain (unencrypted file if linux). mnemonic: str = "neither medal holiday echo link dog sleep idea turkey logic security sword save taxi chapter artwork toddler wealth local mind manual never unlock narrow" seed: bytes = mnemonic_to_seed(mnemonic, passphrase="") master_private_key: PrivateKey = AugSchemeMPL.key_gen(seed) intermediate_sk: PrivateKey = AugSchemeMPL.derive_child_sk( master_private_key, 12381) intermediate_sk = AugSchemeMPL.derive_child_sk(intermediate_sk, 8444) intermediate_sk = AugSchemeMPL.derive_child_sk(intermediate_sk, 2) print( f"Parent public key is: {intermediate_sk.get_g1()}. Please use this within `create_unsigned_tx.py`" ) # If you want to use hardened keys which are more secure against quantum computers, you need to export # The public keys # create_hardened_child_public_keys(mnemonic, 1000) try: with open("tx_3.json", "r") as f: spend_bundle_json = f.read() except Exception: print( "Error: create your transaction (spend bundle) json and put it into the json file." ) return spend_bundle_json_dict: Dict = json.loads(spend_bundle_json) spend_bundle: SpendBundle = SpendBundle.from_json_dict( spend_bundle_json_dict) sign_tx(intermediate_sk, spend_bundle, use_hardened_keys=False)
def sign(args): if args.message is None: print("Please specify the message argument -d") quit() if args.fingerprint is None or args.hd_path is None: print( "Please specify the fingerprint argument -f and hd_path argument -t" ) quit() message = args.message assert message is not None k = Keychain() private_keys = k.get_all_private_keys() fingerprint = args.fingerprint assert fingerprint is not None hd_path = args.hd_path assert hd_path is not None path: List[uint32] = [ uint32(int(i)) for i in hd_path.split("/") if i != "m" ] for sk, _ in private_keys: if sk.get_g1().get_fingerprint() == fingerprint: for c in path: sk = AugSchemeMPL.derive_child_sk(sk, c) print("Public key:", sk.get_g1()) print("Signature:", AugSchemeMPL.sign(sk, bytes(message, "utf-8"))) return print(f"Fingerprint {fingerprint} not found in keychain")
def sign(message: str, fingerprint: int, hd_path: str): k = Keychain() private_keys = k.get_all_private_keys() path: List[uint32] = [uint32(int(i)) for i in hd_path.split("/") if i != "m"] for sk, _ in private_keys: if sk.get_g1().get_fingerprint() == fingerprint: for c in path: sk = AugSchemeMPL.derive_child_sk(sk, c) print("Public key:", sk.get_g1()) print("Signature:", AugSchemeMPL.sign(sk, bytes(message, "utf-8"))) return print(f"Fingerprint {fingerprint} not found in keychain")
def create_hardened_child_public_keys(mnemonic: str, number: int = 5000): """ Creates child public keys, derived from the master private key, using hardened derivation. This method is more secure than public key derivation since it's following the EIP-2333 spec for quantum security. """ seed: bytes = mnemonic_to_seed(mnemonic, passphrase="") master_private_key: PrivateKey = AugSchemeMPL.key_gen(seed) intermediate_sk: PrivateKey = AugSchemeMPL.derive_child_sk( master_private_key, 12381) intermediate_sk = AugSchemeMPL.derive_child_sk(intermediate_sk, 8444) intermediate_sk = AugSchemeMPL.derive_child_sk(intermediate_sk, 2) all_pks: List[G1Element] = [] for i in range(number): child_sk: PrivateKey = AugSchemeMPL.derive_child_sk(intermediate_sk, i) child_pk: G1Element = child_sk.get_g1() all_pks.append(child_pk) with open("child_public_keys.txt", "w") as f: lines = [f"{bytes(pk).hex()}\n" for pk in all_pks] f.writelines(lines)
def test_bip39_eip2333_test_vector(self): kc: Keychain = Keychain(testing=True) kc.delete_all_keys() mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" passphrase = "TREZOR" print("entropy to seed:", mnemonic_to_seed(mnemonic, passphrase).hex()) master_sk = kc.add_private_key(mnemonic, passphrase) tv_master_int = 5399117110774477986698372024995405256382522670366369834617409486544348441851 tv_child_int = 11812940737387919040225825939013910852517748782307378293770044673328955938106 assert master_sk == PrivateKey.from_bytes( tv_master_int.to_bytes(32, "big")) child_sk = AugSchemeMPL.derive_child_sk(master_sk, 0) assert child_sk == PrivateKey.from_bytes( tv_child_int.to_bytes(32, "big"))
def test_readme(): seed: bytes = bytes([ 0, 50, 6, 244, 24, 199, 1, 25, 52, 88, 192, 19, 18, 12, 89, 6, 220, 18, 102, 58, 209, 82, 12, 62, 89, 110, 182, 9, 44, 20, 254, 22, ]) sk: PrivateKey = AugSchemeMPL.key_gen(seed) pk: G1Element = sk.get_g1() message: bytes = bytes([1, 2, 3, 4, 5]) signature: G2Element = AugSchemeMPL.sign(sk, message) ok: bool = AugSchemeMPL.verify(pk, message, signature) assert ok sk_bytes: bytes = bytes(sk) # 32 bytes pk_bytes: bytes = bytes(pk) # 48 bytes signature_bytes: bytes = bytes(signature) # 96 bytes print(sk_bytes.hex(), pk_bytes.hex(), signature_bytes.hex()) sk = PrivateKey.from_bytes(sk_bytes) pk = G1Element.from_bytes(pk_bytes) signature = G2Element.from_bytes(signature_bytes) seed = bytes([1]) + seed[1:] sk1: PrivateKey = AugSchemeMPL.key_gen(seed) seed = bytes([2]) + seed[1:] sk2: PrivateKey = AugSchemeMPL.key_gen(seed) message2: bytes = bytes([1, 2, 3, 4, 5, 6, 7]) pk1: G1Element = sk1.get_g1() sig1: G2Element = AugSchemeMPL.sign(sk1, message) pk2: G1Element = sk2.get_g1() sig2: G2Element = AugSchemeMPL.sign(sk2, message2) agg_sig: G2Element = AugSchemeMPL.aggregate([sig1, sig2]) ok = AugSchemeMPL.aggregate_verify([pk1, pk2], [message, message2], agg_sig) assert ok seed = bytes([3]) + seed[1:] sk3: PrivateKey = AugSchemeMPL.key_gen(seed) pk3: G1Element = sk3.get_g1() message3: bytes = bytes([100, 2, 254, 88, 90, 45, 23]) sig3: G2Element = AugSchemeMPL.sign(sk3, message3) agg_sig_final: G2Element = AugSchemeMPL.aggregate([agg_sig, sig3]) ok = AugSchemeMPL.aggregate_verify([pk1, pk2, pk3], [message, message2, message3], agg_sig_final) assert ok pop_sig1: G2Element = PopSchemeMPL.sign(sk1, message) pop_sig2: G2Element = PopSchemeMPL.sign(sk2, message) pop_sig3: G2Element = PopSchemeMPL.sign(sk3, message) pop1: G2Element = PopSchemeMPL.pop_prove(sk1) pop2: G2Element = PopSchemeMPL.pop_prove(sk2) pop3: G2Element = PopSchemeMPL.pop_prove(sk3) ok = PopSchemeMPL.pop_verify(pk1, pop1) assert ok ok = PopSchemeMPL.pop_verify(pk2, pop2) assert ok ok = PopSchemeMPL.pop_verify(pk3, pop3) assert ok pop_sig_agg: G2Element = PopSchemeMPL.aggregate( [pop_sig1, pop_sig2, pop_sig3]) ok = PopSchemeMPL.fast_aggregate_verify([pk1, pk2, pk3], message, pop_sig_agg) assert ok pop_agg_pk: G1Element = pk1 + pk2 + pk3 ok = PopSchemeMPL.verify(pop_agg_pk, message, pop_sig_agg) assert ok pop_agg_sk: PrivateKey = PrivateKey.aggregate([sk1, sk2, sk3]) ok = PopSchemeMPL.sign(pop_agg_sk, message) == pop_sig_agg assert ok master_sk: PrivateKey = AugSchemeMPL.key_gen(seed) child: PrivateKey = AugSchemeMPL.derive_child_sk(master_sk, 152) grandchild: PrivateKey = AugSchemeMPL.derive_child_sk(child, 952) master_pk: G1Element = master_sk.get_g1() child_u: PrivateKey = AugSchemeMPL.derive_child_sk_unhardened( master_sk, 22) grandchild_u: PrivateKey = AugSchemeMPL.derive_child_sk_unhardened( child_u, 0) child_u_pk: G1Element = AugSchemeMPL.derive_child_pk_unhardened( master_pk, 22) grandchild_u_pk: G1Element = AugSchemeMPL.derive_child_pk_unhardened( child_u_pk, 0) ok = grandchild_u_pk == grandchild_u.get_g1() assert ok
hd_path = input( "Enter the HD path in the form 'm/12381/8444/n/n', or enter Q to quit: " ).lower() if hd_path == "q": quit() verify = input(f"Is this correct path: {hd_path}? (y/n) ").lower() if verify == "y": break k = Keychain() private_keys = k.get_all_private_keys() path: List[uint32] = [uint32(int(i)) for i in hd_path.split("/") if i != "m"] # Derive HD key using path form input for c in path: selected_key = AugSchemeMPL.derive_child_sk(selected_key, c) print("Public key:", selected_key.get_g1()) # get file path file_path = None while True: file_path = input( "Enter the path where you want to save signed alert file, or q to quit: " ) if file_path == "q" or file_path == "Q": quit() file_path = file_path.strip() y_n = input(f"Is this correct path (y/n)?: {file_path} ").lower() if y_n == "y": break f_path: Path = Path(file_path)
def _derive_path(sk: PrivateKey, path: List[int]) -> PrivateKey: for index in path: sk = AugSchemeMPL.derive_child_sk(sk, index) return sk
def sign_tx(intermediate_sk: PrivateKey, spend_bundle: SpendBundle, use_hardened_keys: bool): """ Takes in an unsigned transaction (called a spend bundle in chia), and a 24 word mnemonic (master sk) and generates the aggregate BLS signature for the transaction. """ # This field is the ADDITIONAL_DATA found in the constants additional_data: bytes = bytes.fromhex( "ccd5bb71183532bff220ba46c268991a3ff07eb358e8255a65c30a2dce0e5fbb") puzzle_hash_to_sk: Dict[bytes32, PrivateKey] = {} if use_hardened_keys: # Change this loop to scan more keys if you have more for i in range(5000): child_sk: PrivateKey = AugSchemeMPL.derive_child_sk( intermediate_sk, i) child_pk: G1Element = child_sk.get_g1() puzzle = puzzle_for_pk(child_pk) puzzle_hash = puzzle.get_tree_hash() puzzle_hash_to_sk[puzzle_hash] = child_sk else: # Change this loop to scan more keys if you have more for i in range(5000): child_sk: PrivateKey = AugSchemeMPL.derive_child_sk_unhardened( intermediate_sk, i) child_pk: G1Element = child_sk.get_g1() puzzle = puzzle_for_pk(child_pk) puzzle_hash = puzzle.get_tree_hash() puzzle_hash_to_sk[puzzle_hash] = child_sk aggregate_signature: G2Element = G2Element() for coin_solution in spend_bundle.coin_solutions: if coin_solution.coin.puzzle_hash not in puzzle_hash_to_sk: print( f"Puzzle hash {coin_solution.coin.puzzle_hash} not found for this key." ) return sk: PrivateKey = puzzle_hash_to_sk[coin_solution.coin.puzzle_hash] synthetic_secret_key: PrivateKey = calculate_synthetic_secret_key( sk, DEFAULT_HIDDEN_PUZZLE_HASH) err, conditions_dict, cost = conditions_dict_for_solution( coin_solution.puzzle_reveal, coin_solution.solution, 11000000000) if err or conditions_dict is None: print( f"Sign transaction failed, con:{conditions_dict}, error: {err}" ) return pk_msgs = pkm_pairs_for_conditions_dict( conditions_dict, bytes(coin_solution.coin.name()), additional_data) assert len(pk_msgs) == 1 _, msg = pk_msgs[0] signature = AugSchemeMPL.sign(synthetic_secret_key, msg) aggregate_signature = AugSchemeMPL.aggregate( [aggregate_signature, signature]) new_spend_bundle = SpendBundle(spend_bundle.coin_solutions, aggregate_signature) print("") print("Signed spend bundle JSON:\n") print(json.dumps(new_spend_bundle.to_json_dict()))