def test_sanity_tests(): seed = bytes.fromhex( "1077a46dc8545d372f22d9e110ae6c5c2bf7620fe9c4c911f5404d112233e1aa270567dd3554092e051ba3ba86c303590b0309116ac89964ff284db2219d7511" ) first_bip32 = BIP32.from_seed(seed) sec_bip32 = BIP32.from_xpriv( "xprv9s21ZrQH143K3o4KUs47P2x9afhH31ekMo2foNTYwrU9wwZ8g5EatR9bn6YmCacdvnHWMnPFUqieQrnunrzuF5UfgGbhbEW43zRnhpPDBUL" ) assert first_bip32.get_master_xpriv() == sec_bip32.get_master_xpriv() assert first_bip32.get_master_xpub() == sec_bip32.get_master_xpub() # Fuzz it a bit for i in range(50): path = [int.from_bytes(os.urandom(3), "big") for _ in range(5)] h_path = [ HARDENED_INDEX + int.from_bytes(os.urandom(3), "big") for _ in range(5) ] mixed_path = [int.from_bytes(os.urandom(3), "big") for _ in range(5)] for i in mixed_path: if int.from_bytes(os.urandom(32), "big") % 2: i += HARDENED_INDEX assert first_bip32.get_xpriv_from_path( path) == sec_bip32.get_xpriv_from_path(path) assert first_bip32.get_xpub_from_path( path) == sec_bip32.get_xpub_from_path(path) assert first_bip32.get_xpriv_from_path( h_path) == sec_bip32.get_xpriv_from_path(h_path) assert first_bip32.get_xpub_from_path( h_path) == sec_bip32.get_xpub_from_path(h_path) assert first_bip32.get_xpriv_from_path( mixed_path) == sec_bip32.get_xpriv_from_path(mixed_path) assert first_bip32.get_xpub_from_path( mixed_path) == sec_bip32.get_xpub_from_path(mixed_path) # Taken from iancoleman's website bip32 = BIP32.from_seed( bytes.fromhex( "ac8c2377e5cde867d7e420fbe04d8906309b70d51b8fe58d6844930621a9bc223929155dcfebb4da9d62c86ec0d15adf936a663f4f0cf39cbb0352e7dac073d6" )) assert bip32.get_master_xpriv() == bip32.get_xpriv_from_path( [] ) == "xprv9s21ZrQH143K2GzaKJsW7DQsxeDpY3zqgusaSx6owWGC19k4mhwnVAsm4qPsCw43NkY2h1BzVLyxWHt9NKF86QRyBj53vModdGcNxtpD6KX" assert bip32.get_master_xpub() == bip32.get_xpub_from_path( [] ) == "xpub661MyMwAqRbcEm53RLQWUMMcWg4JwWih48oBFLWRVqoAsx5DKFG32yCEv8iH29TWpmo5KTcpsjXcea6Zx4Hc6PAbGnHjEDCf3yHbj7qdpnf" # Sanity checks for m/0'/0'/14/0'/18 xpriv = bip32.get_xpriv_from_path( [HARDENED_INDEX, HARDENED_INDEX, 14, HARDENED_INDEX, 18]) xpub = bip32.get_xpub_from_path( [HARDENED_INDEX, HARDENED_INDEX, 14, HARDENED_INDEX, 18]) assert xpriv == "xprvA2YVbLvEeKaPedw7F6RLwG3RgYnTq1xGCyDNMgZNWdEQnSUBQmKEuLyA6TSPsggt5xvyJHLD9L25tNLpQiP4Q8ZkQNo8ueAgeYj5zYq8hSm" assert xpub == "xpub6FXqzrT8Uh8gs81aM7xMJPzAEacxEUg7aC8yA4xz4xmPfEoKxJdVT9Hdwm3LwVQrSos2rhGDt8aGGHvdLr5LLAjK8pXFkbSpzGoGTXjd4z9" # Now if we our master is m/0'/0'/14, we should derive the same keys for # m/0'/18 ! xpriv2 = bip32.get_xpriv_from_path([HARDENED_INDEX, HARDENED_INDEX, 14]) assert xpriv2 == "xprv9yQJmvQMywM5i7UNuZ4RQ1A9rEMwAJCExPardkmBCB46S3vBqNEatSwLUrwLNLHBu1Kd9aGxGKDD5YAfs6hRzpYthciAHjtGadxgV2PeqY9" bip32 = BIP32.from_xpriv(xpriv2) assert bip32.get_master_xpriv() == xpriv2 assert bip32.get_xpriv_from_path([HARDENED_INDEX, 18]) == xpriv assert bip32.get_xpub_from_path([HARDENED_INDEX, 18]) == xpub
def parse_key(key: str) -> BIP32: """ Try to parse an extended key, whether it is in xpub, xpriv or mnemonic format. """ try: private_key = BIP32.from_xpriv(key) print('🔑 Read master private key successfully') return private_key except Exception: pass try: public_key = BIP32.from_xpub(key) print('🔑 Read master public key successfully') return public_key except Exception: pass try: language = Mnemonic.detect_language(key) seed = Mnemonic(language).to_seed(key) private_key = BIP32.from_seed(seed) print('🔑 Read mnemonic successfully') return private_key except Exception: pass raise ValueError( 'The key is invalid or the format isn\'t recognized. Make sure it\'s a mnemonic, xpriv or xpub.' )
def test_vector_3(): seed = bytes.fromhex( "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be" ) bip32 = BIP32.from_seed(seed) # Chain m assert ( bip32.get_xpub_from_path([]) == "xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13" ) assert ( bip32.get_xpriv_from_path([]) == "xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6" ) assert (bip32.get_xpub_from_path("m") == bip32.get_xpub_from_path([])) assert (bip32.get_xpriv_from_path("m") == bip32.get_xpriv_from_path([])) # Chain m/0H assert ( bip32.get_xpub_from_path([HARDENED_INDEX]) == "xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y" ) assert ( bip32.get_xpriv_from_path([HARDENED_INDEX]) == "xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L" ) assert (bip32.get_xpub_from_path("m/0H") == bip32.get_xpub_from_path( [HARDENED_INDEX])) assert (bip32.get_xpriv_from_path("m/0H") == bip32.get_xpriv_from_path( [HARDENED_INDEX]))
def Init(self, request, context): node = Node() node.hsm_secret = request.hsm_secret.data # on chain wallet hkdf = HKDF(key=node.hsm_secret) r = hkdf.extract_key(info='bip32 seed'.encode(), length=32) logger.debug("bip32_key seed: %s" % r.hex()) node.bip32_key = BIP32.from_seed(r, network=self.network) # node pubkey, node msg sign r = hkdf.extract_key(info='nodeid'.encode(), length=32) node.node_privkey = r node.node_pk = r logger.info("new node privkey %s" % r.hex()) node_pk = coincurve.PrivateKey(secret=r) node.pubkey = node_pk.public_key.format() node.nodeid = binascii.hexlify(node.pubkey) logger.info("new node id %s" % node.nodeid) # channel secret_base node.secret_base = hkdf.extract_key(info='peer seed'.encode(), length=32) logger.debug("new channel secret base %s" % node.secret_base.hex()) if not self.nodes.get(node.pubkey) or request.coldstart: self.nodes[node.pubkey] = node reply = remotesigner_pb2.InitReply() reply.node_id.data = node.pubkey return reply
def test_vector_1(): seed = bytes.fromhex("000102030405060708090a0b0c0d0e0f") bip32 = BIP32.from_seed(seed) # Chain m assert ( bip32.get_master_xpub() == "xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" ) assert ( bip32.get_master_xpriv() == "xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" ) # Chain m/0H assert ( bip32.get_xpub_from_path([HARDENED_INDEX]) == "xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw" ) assert ( bip32.get_xpriv_from_path([HARDENED_INDEX]) == "xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7" ) # m/0H/1 assert ( bip32.get_xpub_from_path([HARDENED_INDEX, 1]) == "xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ" ) assert ( bip32.get_xpriv_from_path([HARDENED_INDEX, 1]) == "xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs" ) # m/0H/1/2H assert ( bip32.get_xpub_from_path([HARDENED_INDEX, 1, HARDENED_INDEX + 2]) == "xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5" ) assert ( bip32.get_xpriv_from_path([HARDENED_INDEX, 1, HARDENED_INDEX + 2]) == "xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM" ) # m/0H/1/2H/2 assert ( bip32.get_xpub_from_path([HARDENED_INDEX, 1, HARDENED_INDEX + 2, 2]) == "xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV" ) assert ( bip32.get_xpriv_from_path([HARDENED_INDEX, 1, HARDENED_INDEX + 2, 2]) == "xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334" ) # m/0H/1/2H/2/1000000000 assert ( bip32.get_xpub_from_path( [HARDENED_INDEX, 1, HARDENED_INDEX + 2, 2, 1000000000]) == "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy" ) assert ( bip32.get_xpriv_from_path( [HARDENED_INDEX, 1, HARDENED_INDEX + 2, 2, 1000000000]) == "xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76" )
def get_address(words, strange=10): address_list = [] mnemo = Mnemonic("english") seed = mnemo.to_seed(words, passphrase="") bip32 = BIP32.from_seed(seed) for i in range(0, strange): path = "m/44'/313'/0'/0/%i" % i pab_key = bip32.get_pubkey_from_path(path) key = zilkey.ZilKey(public_key=pab_key.hex()) address_list.append(key.address) return address_list
def __init__(self, mnemonic: str, language: str = "english", passphrase: str = ""): """ BIP44 HD wallet with a master mnemonic. :param mnemonic (str): The master mnemonic to derive keys :param language (str, optional): The mnemonic's language, default: "english" :param passphrase (str, optional): The mnemonic's passphrase, default: "" """ self._seed = Mnemonic(language).to_seed(mnemonic, passphrase) self._bip32 = BIP32.from_seed(self._seed)
def create_wallet(testnet=False): path = "m/44'/1'/0'/0/0" if testnet else "m/44'/0'/0'/0/0" mnemo = Mnemonic("english") words = mnemo.generate() seed = mnemo.to_seed(words, passphrase="") bip32 = BIP32.from_seed(seed) privkey = bip32.get_privkey_from_path(path) pubkey = base64.b64encode(bip32.get_pubkey_from_path(path)).decode('utf-8') definition = ['sig', {"pubkey": pubkey}] print(f"privkey: {privkey}") print(f"pubkey: {pubkey}") print(f"address: {get_chash_160(definition)}")
def from_mnemonic(cls, words: str, path="m/44'/494'/0'/0/0") -> PrivateKey: """ Create a PrivateKey instance from a given mnemonic phrase and a HD derivation path. If path is not given, default to Band's HD prefix 494 and all other indexes being zeroes. :param words: the mnemonic phrase for recover private key :param path: the HD path that follows the BIP32 standard :return: Initialized PrivateKey object """ seed = Mnemonic("english").to_seed(words) self = cls(_error_do_not_use_init_directly=True) self.signing_key = SigningKey.from_string( BIP32.from_seed(seed).get_privkey_from_path(path), curve=SECP256k1, hashfunc=hashlib.sha256, ) return self
def get_wallets(self, emergency_privkeys=None): """Get 4 vaults, one for each stakeholder. Spin up the servers.""" bip32s = [BIP32.from_seed(os.urandom(32), "test") for _ in range(4)] xpubs = [bip32.get_master_xpub() for bip32 in bip32s] if emergency_privkeys is None: emergency_privkeys = [CKey(os.urandom(32)) for _ in range(4)] emergency_pubkeys = [k.pub for k in emergency_privkeys] self.vaults = [] # Generate some random 'OK' addresses acked_addresses = [self.bitcoind.getnewaddress() for _ in range(5)] for bip32 in bip32s: xpriv = bip32.get_master_xpriv() conf = self.bitcoind.rpc.__btc_conf_file__ cosigner_url = "http://localhost:{}".format(self.cosigning_port) sigserv_url = "http://localhost:{}".format(self.sigserver_port) self.vaults.append( Vault(xpriv, xpubs, emergency_pubkeys, conf, cosigner_url, sigserv_url, acked_addresses)) return self.vaults
def test_vector_2(): seed = bytes.fromhex( "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542" ) bip32 = BIP32.from_seed(seed) # Chain m assert ( bip32.get_master_xpub() == "xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB" ) assert ( bip32.get_master_xpriv() == "xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U" ) # Chain m/0 assert ( bip32.get_xpub_from_path([0]) == "xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH" ) assert ( bip32.get_xpriv_from_path([0]) == "xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt" ) assert (bip32.get_xpriv_from_path("m/0") == bip32.get_xpriv_from_path([0])) assert (bip32.get_xpub_from_path("m/0") == bip32.get_xpub_from_path([0])) # Chain m/0/2147483647H assert ( bip32.get_xpub_from_path([0, HARDENED_INDEX + 2147483647]) == "xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a" ) assert ( bip32.get_xpriv_from_path([0, HARDENED_INDEX + 2147483647]) == "xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9" ) assert (bip32.get_xpub_from_path("m/0/2147483647H") == bip32.get_xpub_from_path([0, HARDENED_INDEX + 2147483647])) assert (bip32.get_xpriv_from_path("m/0/2147483647H") == bip32.get_xpriv_from_path([0, HARDENED_INDEX + 2147483647])) # Chain m/0/2147483647H/1 assert ( bip32.get_xpub_from_path([0, HARDENED_INDEX + 2147483647, 1]) == "xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon" ) assert ( bip32.get_xpriv_from_path([0, HARDENED_INDEX + 2147483647, 1]) == "xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef" ) assert (bip32.get_xpub_from_path("m/0/2147483647H/1") == bip32.get_xpub_from_path([0, HARDENED_INDEX + 2147483647, 1])) assert (bip32.get_xpriv_from_path("m/0/2147483647H/1") == bip32.get_xpriv_from_path([0, HARDENED_INDEX + 2147483647, 1])) # Chain m/0/2147483647H/1/2147483646H assert ( bip32.get_xpub_from_path( [0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646]) == "xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL" ) assert ( bip32.get_xpriv_from_path( [0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646]) == "xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc" ) assert (bip32.get_xpub_from_path( "m/0/2147483647H/1/2147483646H") == bip32.get_xpub_from_path( [0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646])) assert (bip32.get_xpriv_from_path( "m/0/2147483647H/1/2147483646H") == bip32.get_xpriv_from_path( [0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646])) # Chain m/0/2147483647H/1/2147483646H/2 assert ( bip32.get_xpub_from_path([ 0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646, 2 ]) == "xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt" ) assert ( bip32.get_xpriv_from_path([ 0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646, 2 ]) == "xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j" ) assert (bip32.get_xpub_from_path( "m/0/2147483647H/1/2147483646H/2") == bip32.get_xpub_from_path([ 0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646, 2 ])) assert (bip32.get_xpriv_from_path( "m/0/2147483647H/1/2147483646H/2") == bip32.get_xpriv_from_path([ 0, HARDENED_INDEX + 2147483647, 1, HARDENED_INDEX + 2147483646, 2 ]))
def test_sanity_tests(): seed = bytes.fromhex( "1077a46dc8545d372f22d9e110ae6c5c2bf7620fe9c4c911f5404d112233e1aa270567dd3554092e051ba3ba86c303590b0309116ac89964ff284db2219d7511" ) first_bip32 = BIP32.from_seed(seed) sec_bip32 = BIP32.from_xpriv( "xprv9s21ZrQH143K3o4KUs47P2x9afhH31ekMo2foNTYwrU9wwZ8g5EatR9bn6YmCacdvnHWMnPFUqieQrnunrzuF5UfgGbhbEW43zRnhpPDBUL" ) assert first_bip32.get_master_xpriv() == sec_bip32.get_master_xpriv() assert first_bip32.get_master_xpub() == sec_bip32.get_master_xpub() # Fuzz it a bit for i in range(50): path = [int.from_bytes(os.urandom(3), "big") for _ in range(5)] h_path = [ HARDENED_INDEX + int.from_bytes(os.urandom(3), "big") for _ in range(5) ] mixed_path = [int.from_bytes(os.urandom(3), "big") for _ in range(5)] for i in mixed_path: if int.from_bytes(os.urandom(32), "big") % 2: i += HARDENED_INDEX assert first_bip32.get_xpriv_from_path( path) == sec_bip32.get_xpriv_from_path(path) assert first_bip32.get_xpub_from_path( path) == sec_bip32.get_xpub_from_path(path) assert first_bip32.get_xpriv_from_path( h_path) == sec_bip32.get_xpriv_from_path(h_path) assert first_bip32.get_xpub_from_path( h_path) == sec_bip32.get_xpub_from_path(h_path) assert first_bip32.get_xpriv_from_path( mixed_path) == sec_bip32.get_xpriv_from_path(mixed_path) assert first_bip32.get_xpub_from_path( mixed_path) == sec_bip32.get_xpub_from_path(mixed_path) # Taken from iancoleman's website bip32 = BIP32.from_seed( bytes.fromhex( "ac8c2377e5cde867d7e420fbe04d8906309b70d51b8fe58d6844930621a9bc223929155dcfebb4da9d62c86ec0d15adf936a663f4f0cf39cbb0352e7dac073d6" )) assert bip32.get_master_xpriv() == bip32.get_xpriv_from_path( [] ) == "xprv9s21ZrQH143K2GzaKJsW7DQsxeDpY3zqgusaSx6owWGC19k4mhwnVAsm4qPsCw43NkY2h1BzVLyxWHt9NKF86QRyBj53vModdGcNxtpD6KX" assert bip32.get_master_xpub() == bip32.get_xpub_from_path( [] ) == "xpub661MyMwAqRbcEm53RLQWUMMcWg4JwWih48oBFLWRVqoAsx5DKFG32yCEv8iH29TWpmo5KTcpsjXcea6Zx4Hc6PAbGnHjEDCf3yHbj7qdpnf" # Sanity checks for m/0'/0'/14/0'/18 xpriv = bip32.get_xpriv_from_path( [HARDENED_INDEX, HARDENED_INDEX, 14, HARDENED_INDEX, 18]) xpub = bip32.get_xpub_from_path( [HARDENED_INDEX, HARDENED_INDEX, 14, HARDENED_INDEX, 18]) assert xpriv == "xprvA2YVbLvEeKaPedw7F6RLwG3RgYnTq1xGCyDNMgZNWdEQnSUBQmKEuLyA6TSPsggt5xvyJHLD9L25tNLpQiP4Q8ZkQNo8ueAgeYj5zYq8hSm" assert xpub == "xpub6FXqzrT8Uh8gs81aM7xMJPzAEacxEUg7aC8yA4xz4xmPfEoKxJdVT9Hdwm3LwVQrSos2rhGDt8aGGHvdLr5LLAjK8pXFkbSpzGoGTXjd4z9" # Now if we our master is m/0'/0'/14, we should derive the same keys for # m/0'/18 ! xpriv2 = bip32.get_xpriv_from_path([HARDENED_INDEX, HARDENED_INDEX, 14]) assert xpriv2 == "xprv9yQJmvQMywM5i7UNuZ4RQ1A9rEMwAJCExPardkmBCB46S3vBqNEatSwLUrwLNLHBu1Kd9aGxGKDD5YAfs6hRzpYthciAHjtGadxgV2PeqY9" bip32 = BIP32.from_xpriv(xpriv2) assert bip32.get_master_xpriv() == xpriv2 assert bip32.get_xpriv_from_path([HARDENED_INDEX, 18]) == xpriv assert bip32.get_xpub_from_path([HARDENED_INDEX, 18]) == xpub # We should recognize the networks.. # .. for xprivs: bip32 = BIP32.from_xpriv( "xprv9wHokC2KXdTSpEepFcu53hMDUHYfAtTaLEJEMyxBPAMf78hJg17WhL5FyeDUQH5KWmGjGgEb2j74gsZqgupWpPbZgP6uFmP8MYEy5BNbyET" ) assert bip32.network == "main" bip32 = BIP32.from_xpriv( "tprv8ZgxMBicQKsPeCBsMzQCCb5JcW4S49MVL3EwhdZMF1RF71rgisZU4ZRvrHX6PZQEiNUABDLvYqpx8Lsccq8aGGR59qHAoLoE3iXYuDa8JTP" ) assert bip32.network == "test" # .. for xpubs: bip32 = BIP32.from_xpub( "xpub6AHA9hZDN11k2ijHMeS5QqHx2KP9aMBRhTDqANMnwVtdyw2TDYRmF8PjpvwUFcL1Et8Hj59S3gTSMcUQ5gAqTz3Wd8EsMTmF3DChhqPQBnU" ) assert bip32.network == "main" bip32 = BIP32.from_xpub( "tpubD6NzVbkrYhZ4WN3WiKRjeo2eGyYNiKNg8vcQ1UjLNJJaDvoFhmR1XwJsbo5S4vicSPoWQBThR3Rt8grXtP47c1AnoiXMrEmFdRZupxJzH1j" ) assert bip32.network == "test" # We should create valid network encoding.. assert BIP32.from_seed(os.urandom(32), "test").get_master_xpub().startswith("tpub") assert BIP32.from_seed(os.urandom(32), "test").get_master_xpriv().startswith("tprv") assert BIP32.from_seed(os.urandom(32), "main").get_master_xpub().startswith("xpub") assert BIP32.from_seed(os.urandom(32), "main").get_master_xpriv().startswith("xprv")
def setup_device(self, mnemonic, passphrase, wallet_manager, testnet): seed = Mnemonic.to_seed(mnemonic) xprv = seed_to_hd_master_key(seed, testnet=testnet) wallet_name = os.path.join(wallet_manager.cli_path + '_hotstorage', self.alias) wallet_manager.cli.createwallet(wallet_name, False, True) cli = wallet_manager.cli.wallet(wallet_name) # TODO: Maybe more than 1000? Maybe add mechanism to add more later. ## NOTE: This will work only on the network the device was added, so hot devices should be filtered out by network. coin = int(testnet) cli.importmulti([ { 'desc': AddChecksum('sh(wpkh({}/49h/{}h/0h/0/*))'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'}, { 'desc': AddChecksum('sh(wpkh({}/49h/{}h/0h/1/*))'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'}, { 'desc': AddChecksum('wpkh({}/84h/{}h/0h/0/*)'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'}, { 'desc': AddChecksum('wpkh({}/84h/{}h/0h/1/*)'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'}, { 'desc': AddChecksum('sh(wpkh({}/48h/{}h/0h/1h/0/*))'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'}, { 'desc': AddChecksum('sh(wpkh({}/48h/{}h/0h/1h/1/*))'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'}, { 'desc': AddChecksum('wpkh({}/48h/{}h/0h/2h/0/*)'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'}, { 'desc': AddChecksum('wpkh({}/48h/{}h/0h/2h/1/*)'.format(xprv, coin)), 'range': 1000, 'timestamp': 'now'}, ]) if passphrase: cli.encryptwallet(passphrase) bip32 = BIP32.from_seed(seed) xpubs = "" master_fpr = get_xpub_fingerprint(bip32.get_xpub_from_path('m/0h')).hex() if not testnet: # Nested Segwit xpub = bip32.get_xpub_from_path('m/49h/0h/0h') ypub = convert_xpub_prefix(xpub, b'\x04\x9d\x7c\xb2') xpubs += "[%s/49'/0'/0']%s\n" % (master_fpr, ypub) # native Segwit xpub = bip32.get_xpub_from_path('m/84h/0h/0h') zpub = convert_xpub_prefix(xpub, b'\x04\xb2\x47\x46') xpubs += "[%s/84'/0'/0']%s\n" % (master_fpr, zpub) # Multisig nested Segwit xpub = bip32.get_xpub_from_path('m/48h/0h/0h/1h') Ypub = convert_xpub_prefix(xpub, b'\x02\x95\xb4\x3f') xpubs += "[%s/48'/0'/0'/1']%s\n" % (master_fpr, Ypub) # Multisig native Segwit xpub = bip32.get_xpub_from_path('m/48h/0h/0h/2h') Zpub = convert_xpub_prefix(xpub, b'\x02\xaa\x7e\xd3') xpubs += "[%s/48'/0'/0'/2']%s\n" % (master_fpr, Zpub) else: # Testnet nested Segwit xpub = bip32.get_xpub_from_path('m/49h/1h/0h') upub = convert_xpub_prefix(xpub, b'\x04\x4a\x52\x62') xpubs += "[%s/49'/1'/0']%s\n" % (master_fpr, upub) # Testnet native Segwit xpub = bip32.get_xpub_from_path('m/84h/1h/0h') vpub = convert_xpub_prefix(xpub, b'\x04\x5f\x1c\xf6') xpubs += "[%s/84'/1'/0']%s\n" % (master_fpr, vpub) # Testnet multisig nested Segwit xpub = bip32.get_xpub_from_path('m/48h/1h/0h/1h') Upub = convert_xpub_prefix(xpub, b'\x02\x42\x89\xef') xpubs += "[%s/48'/1'/0'/1']%s\n" % (master_fpr, Upub) # Testnet multisig native Segwit xpub = bip32.get_xpub_from_path('m/48h/1h/0h/2h') Vpub = convert_xpub_prefix(xpub, b'\x02\x57\x54\x83') xpubs += "[%s/48'/1'/0'/2']%s\n" % (master_fpr, Vpub) keys, failed = Key.parse_xpubs(xpubs) if len(failed) > 0: # TODO: This should never occur, but just in case, we must make sure to catch it properly so it doesn't crash the app no matter what. raise Exception("Failed to parse these xpubs:\n" + "\n".join(failed)) else: self.add_keys(keys)