def test_fingerprint() -> None: seed = "bfc4cbaad0ff131aa97fa30a48d09ae7df914bcc083af1e07793cd0a7c61a03f65d622848209ad3366a419f4718a80ec9037df107d8d12c19b83202de00a40ad" xprv = rootxprv_from_seed(seed) pf = fingerprint(xprv) # xprv is automatically converted to xpub child_key = derive(xprv, 0x80000000) pf2 = BIP32KeyData.deserialize(child_key).parent_fingerprint assert pf == pf2
def test_vector3(self): """BIP32 test vector 3 https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki """ xkey_version = _PRV_VERSIONS[0] seed = "4b381541583be4423346c643850da4b320e46a87ae3d2a4e6da11eba819cd4acba45d239319ac14f863b8d5ab5a0d0c64d2e8a1e7d1457df2e5a3c51c73235be" rootxprv = rootxprv_from_seed(seed, xkey_version) self.assertEqual( rootxprv, b"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6" ) rootxpub = xpub_from_xprv(rootxprv) # neutering self.assertEqual( rootxpub, b"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13" ) xprv = rootxprv xpub = rootxpub xprv = derive(xprv, ".") # private relative self.assertEqual( xprv, b"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6" ) xprv = derive(rootxprv, "m") # private absolute self.assertEqual( xprv, b"xprv9s21ZrQH143K25QhxbucbDDuQ4naNntJRi4KUfWT7xo4EKsHt2QJDu7KXp1A3u7Bi1j8ph3EGsZ9Xvz9dGuVrtHHs7pXeTzjuxBrCmmhgC6" ) xpub = derive(xpub, ".") # public relative self.assertEqual( xpub, b"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13" ) xpub = derive(rootxpub, "m") # public absolute self.assertEqual( xpub, b"xpub661MyMwAqRbcEZVB4dScxMAdx6d4nFc9nvyvH3v4gJL378CSRZiYmhRoP7mBy6gSPSCYk6SzXPTf3ND1cZAceL7SfJ1Z3GC8vBgp2epUt13" ) xprv = derive(xprv, "./0'") # private relative self.assertEqual( xprv, b"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L" ) xprv = derive(rootxprv, "m/0'") # private absolute self.assertEqual( xprv, b"xprv9uPDJpEQgRQfDcW7BkF7eTya6RPxXeJCqCJGHuCJ4GiRVLzkTXBAJMu2qaMWPrS7AANYqdq6vcBcBUdJCVVFceUvJFjaPdGZ2y9WACViL4L" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub68NZiKmJWnxxS6aaHmn81bvJeTESw724CRDs6HbuccFQN9Ku14VQrADWgqbhhTHBaohPX4CjNLf9fq9MYo6oDaPPLPxSb7gwQN3ih19Zm4Y" )
def test_bips_pr905() -> None: "https://github.com/bitcoin/bips/pull/905" seed = "57fb1e450b8afb95c62afbcd49e4100d6790e0822b8905608679180ac34ca0bd45bf7ccc6c5f5218236d0eb93afc78bd117b9f02a6b7df258ea182dfaef5aad7" xroot = rootxprv_from_seed(seed) der_path = "m/44H/60H/0H" xprv = b"xprv9yqXG1Cns3YEQi6fsCJ7NGV5sHPiyZcbgLVst61dbLYyn7qy1G9aFtRmaYp481ounqnVf9Go2ymQ4gmxZLEwYSRhU868aDk4ZxzGvqHJVhe" assert derive(xroot, der_path) == xprv xpub = b"xpub6CpsfWjghR6XdCB8yDq7jQRpRKEDP2LT3ZRUgURF9g5xevB7YoTpogkFRqq5nQtVSN8YCMZo2CD8u4zCaxRv85ctCWmzEi9gQ5DBhBFaTNo" assert xpub_from_xprv(xprv) == xpub
def test_bip39_vectors(): """BIP32 test vectors from BIP39 https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki """ filename = path.join(data_folder, "bip39_test_vectors.json") with open(filename, "r") as f: test_vectors = json.load(f)["english"] # test_vector[0] and [1], i.e. entropy and mnemonic, are tested in bip39 for _, _, seed, key in test_vectors: assert rootxprv_from_seed(seed) == key.encode("ascii")
def test_exceptions() -> None: with pytest.raises(ValueError, match="not a private or public key: "): # invalid checksum xprv = "xppp9s21ZrQH143K2oxHiQ5f7D7WYgXD9h6HAXDBuMoozDGGiYHWsq7TLBj2yvGuHTLSPCaFmUyN1v3fJRiY2A4YuNSrqQMPVLZKt76goL6LP7L" p2pkh(xprv) xpub = "xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy" with pytest.raises(ValueError, match="not a private key: "): bip32.xpub_from_xprv(xpub) xpub_dict = bip32.deserialize(xpub) xpub_dict = bip32.deserialize(xpub_dict) xpub_dict["chain_code"] = (xpub_dict["chain_code"])[:-1] with pytest.raises(ValueError, match="invalid chain code length: "): xpub_dict = bip32.deserialize(xpub_dict) xpub_dict = bip32.deserialize(xpub) xpub_dict[ "chain_code"] = "length is 32 but not a chaincode" # type: ignore with pytest.raises(ValueError, match="invalid chain code"): xpub_dict = bip32.deserialize(xpub_dict) seed = "5b56c417303faa3fcba7e57400e120a0" with pytest.raises(ValueError, match="unknown private key version: "): version = b"\x04\x88\xAD\xE5" bip32.rootxprv_from_seed(seed, version) with pytest.raises(ValueError, match="too many bits for seed: "): bip32.rootxprv_from_seed(seed * 5) with pytest.raises(ValueError, match="too few bits for seed: "): bip32.rootxprv_from_seed(seed[:-2])
def test_p2pkh_from_wif(self): seed = b"00" * 32 # better be random rxprv = bip32.rootxprv_from_seed(seed) path = "m/0h/0h/12" xprv = bip32.derive(rxprv, path) wif = wif_from_xprv(xprv) self.assertEqual( wif, b'KyLk7s6Z1FtgYEVp3bPckPVnXvLUWNCcVL6wNt3gaT96EmzTKZwP') address = p2pkh_from_wif(wif) xpub = bip32.xpub_from_xprv(xprv) address2 = slip32.address_from_xpub(xpub) self.assertEqual(address, address2) self.assertRaises(ValueError, wif_from_xprv, xpub)
def test_bip32_vectors(): """BIP32 test vectors https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki """ filename = path.join(data_folder, "bip32_test_vectors.json") with open(filename, "r") as f: test_vectors = json.load(f) for seed in test_vectors: mxprv = rootxprv_from_seed(seed) for der_path, xpub, xprv in test_vectors[seed]: assert xprv == derive(mxprv, der_path).decode() assert xpub == xpub_from_xprv(xprv).decode()
def test_bip39_vectors(self): """BIP32 test vectors from BIP39 https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki """ file = "bip39_test_vectors.json" filename = path.join(path.dirname(__file__), "data", file) with open(filename, 'r') as f: test_vectors = json.load(f)["english"] f.closed for test_vector in test_vectors: seed = test_vector[2] rootxprv = rootxprv_from_seed(seed) self.assertEqual(rootxprv, test_vector[3].encode('ascii'))
def test_bip32_vectors(self): """BIP32 test vector 3 https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki """ fname = "bip32_test_vectors.json" filename = path.join(path.dirname(__file__), "test_data", fname) with open(filename, "r") as f: test_vectors = json.load(f) for seed in test_vectors: mxprv = rootxprv_from_seed(seed) for der_path, xpub, xprv in test_vectors[seed]: self.assertEqual(xprv, derive(mxprv, der_path).decode()) self.assertEqual(xpub, xpub_from_xprv(xprv).decode())
def test_p2pkh_from_wif() -> None: seed = b"00" * 32 # better be a documented test case rxprv = bip32.rootxprv_from_seed(seed) path = "m/0h/0h/12" xprv = bip32.derive(rxprv, path) wif = wif_from_prvkey(xprv) assert wif == b"KyLk7s6Z1FtgYEVp3bPckPVnXvLUWNCcVL6wNt3gaT96EmzTKZwP" pubkey, _ = pubkeyinfo_from_prvkey(wif) address = p2pkh(pubkey) xpub = bip32.xpub_from_xprv(xprv) address2 = slip132.address_from_xpub(xpub) assert address == address2 err_msg = "not a private key: " with pytest.raises(ValueError, match=err_msg): wif_from_prvkey(xpub)
def test_p2pkh_from_wif() -> None: seed = b"\x00" * 32 # better be a documented test case rxprv = bip32.rootxprv_from_seed(seed) path = "m/0h/0h/12" xprv = bip32.derive(rxprv, path) wif = wif_from_prvkey(xprv) assert wif == b"L2L1dqRmkmVtwStNf5wg8nnGaRn3buoQr721XShM4VwDbTcn9bpm" pubkey, _ = pubkeyinfo_from_prvkey(wif) address = p2pkh(pubkey) xpub = bip32.xpub_from_xprv(xprv) address2 = slip132.address_from_xpub(xpub) assert address == address2 err_msg = "not a private key: " with pytest.raises(ValueError, match=err_msg): wif_from_prvkey(xpub)
def test_bip39_vectors(self): """BIP32 test vectors from BIP39 https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki """ filename = "bip39_test_vectors.json" path_to_filename = os.path.join(os.path.dirname(__file__), "./data/", filename) with open(path_to_filename, 'r') as f: test_vectors = json.load(f)["english"] f.closed xkey_version = bip32.PRV_VERSION[0] for test_vector in test_vectors: seed = test_vector[2] rootxprv = bip32.rootxprv_from_seed(seed, xkey_version) self.assertEqual(rootxprv.decode(), test_vector[3])
def test_altnet(self): # non-bitcoin address version addr_version = 0x46.to_bytes(1, 'big') rootxprv = b'xprv9s21ZrQH143K2oxHiQ5f7D7WYgXD9h6HAXDBuMoozDGGiYHWsq7TLBj2yvGuHTLSPCaFmUyN1v3fJRiY2A4YuNSrqQMPVLZKt76goL6LP7L' # m/0'/0'/5' receive = b'VUqyLGVdUADWEqDqL2DeUBAcbPQwZfWDDY' indexes = [0x80000000, 0x80000000, 0x80000005] addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv( bip32.derive(rootxprv, indexes)), addr_version) self.assertEqual(addr, receive) path = "m/0'/0'/5'" addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv( bip32.derive(rootxprv, path)), addr_version) self.assertEqual(addr, receive) # m/0'/1'/1' change = b'VMg6DpX7SQUsoECdpXJ8Bv6R7p11PfwHwy' indexes = [0x80000000, 0x80000001, 0x80000001] addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv( bip32.derive(rootxprv, indexes)), addr_version) self.assertEqual(addr, change) path = "m/0'/1'/1'" addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv( bip32.derive(rootxprv, path)), addr_version) self.assertEqual(addr, change) xkey_version = bip32.PRV_VERSION[0] seed = "5b56c417303faa3fcba7e57400e120a0ca83ec5a4fc9ffba757fbe63fbd77a89a1a3be4c67196f57c39a88b76373733891bfaba16ed27a813ceed498804c0570" rootxprv = bip32.rootxprv_from_seed(seed, xkey_version) self.assertEqual(rootxprv, b'xprv9s21ZrQH143K3t4UZrNgeA3w861fwjYLaGwmPtQyPMmzshV2owVpfBSd2Q7YsHZ9j6i6ddYjb5PLtUdMZn8LhvuCVhGcQntq5rn7JVMqnie') indexes = [0x80000000, 0, 0] # receive addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv( bip32.derive(rootxprv, indexes)), addr_version) self.assertEqual(addr, b'VTpEhLjvGYE16pLcNrMY53gQB9bbhn581W') indexes = [0x80000000, 1, 0] # change addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv( bip32.derive(rootxprv, indexes)), addr_version) self.assertEqual(addr, b'VRtaZvAe4s29aB3vuXyq7GYEpahsQet2B1')
def test_derive_from_account() -> None: seed = "bfc4cbaad0ff131aa97fa30a48d09ae7df914bcc083af1e07793cd0a7c61a03f65d622848209ad3366a419f4718a80ec9037df107d8d12c19b83202de00a40ad" rmxprv = bip32.rootxprv_from_seed(seed) der_path = "m / 44 h / 0 h" mxpub = bip32.xpub_from_xprv(bip32.derive(rmxprv, der_path)) test_vectors = [ [0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2], ] for branch, index in test_vectors: full_path = der_path + f"/{branch}/{index}" addr = p2pkh(bip32.derive(rmxprv, full_path)).decode() assert addr == p2pkh(bip32.derive_from_account(mxpub, branch, index)).decode() errmsg = "invalid private derivation at branch level" with pytest.raises(ValueError, match=errmsg): bip32.derive_from_account(mxpub, 0x80000000, 0, True) errmsg = "invalid branch: " with pytest.raises(ValueError, match=errmsg): bip32.derive_from_account(mxpub, 2, 0) errmsg = "invalid private derivation at address index level" with pytest.raises(ValueError, match=errmsg): bip32.derive_from_account(mxpub, 0, 0x80000000) der_path = "m / 44 h / 0" mxpub = bip32.xpub_from_xprv(bip32.derive(rmxprv, der_path)) errmsg = "public derivation at account level" with pytest.raises(UserWarning, match=errmsg): bip32.derive_from_account(mxpub, 0, 0)
def test_mainnet(self): # bitcoin core derivation style rootxprv = "xprv9s21ZrQH143K2ZP8tyNiUtgoezZosUkw9hhir2JFzDhcUWKz8qFYk3cxdgSFoCMzt8E2Ubi1nXw71TLhwgCfzqFHfM5Snv4zboSebePRmLS" # m / 0h / 0h / 463h addr1 = b"1DyfBWxhVLmrJ7keyiHeMbt7N3UdeGU4G5" indexes = [0x80000000, 0x80000000, 0x800001CF] addr = p2pkh(xpub_from_xprv(derive(rootxprv, indexes))) self.assertEqual(addr, addr1) path = "m / 0h / 0h / 463h" addr = p2pkh(xpub_from_xprv(derive(rootxprv, path))) self.assertEqual(addr, addr1) # m / 0h / 0h / 267h addr2 = b"11x2mn59Qy43DjisZWQGRResjyQmgthki" indexes = [0x80000000, 0x80000000, 0x8000010B] addr = p2pkh(xpub_from_xprv(derive(rootxprv, indexes))) self.assertEqual(addr, addr2) path = "M / 0H / 0h // 267' / " addr = p2pkh(xpub_from_xprv(derive(rootxprv, path))) self.assertEqual(addr, addr2) seed = "bfc4cbaad0ff131aa97fa30a48d09ae7df914bcc083af1e07793cd0a7c61a03f65d622848209ad3366a419f4718a80ec9037df107d8d12c19b83202de00a40ad" xprv = rootxprv_from_seed(seed) xpub = "xpub661MyMwAqRbcFMYjmw8C6dJV97a4oLss6hb3v9wTQn2X48msQB61RCaLGtNhzgPCWPaJu7SvuB9EBSFCL43kTaFJC3owdaMka85uS154cEh" self.assertEqual(xpub_from_xprv(xprv).decode(), xpub) ind = "./0/0" addr = p2pkh(xpub_from_xprv(derive(xprv, ind))) self.assertEqual(addr, b"1FcfDbWwGs1PmyhMVpCAhoTfMnmSuptH6g") ind = "./0/1" addr = p2pkh(xpub_from_xprv(derive(xprv, ind))) self.assertEqual(addr, b"1K5GjYkZnPFvMDTGaQHTrVnd8wjmrtfR5x") ind = "./0/2" addr = p2pkh(xpub_from_xprv(derive(xprv, ind))) self.assertEqual(addr, b"1PQYX2uN7NYFd7Hq22ECMzfDcKhtrHmkfi") ind = "./1/0" addr = p2pkh(xpub_from_xprv(derive(xprv, ind))) self.assertEqual(addr, b"1BvSYpojWoWUeaMLnzbkK55v42DbizCoyq") ind = "./1/1" addr = p2pkh(xpub_from_xprv(derive(xprv, ind))) self.assertEqual(addr, b"1NXB59hF4QzYpFrB7o6usLBjbk2D3ZqxAL") ind = "./1/2" addr = p2pkh(xpub_from_xprv(derive(xprv, ind))) self.assertEqual(addr, b"16NLYkKtvYhW1Jp86tbocku3gxWcvitY1w") # version/key mismatch in extended parent key temp = b58decode(rootxprv) bad_xprv = b58encode(temp[0:45] + b"\x01" + temp[46:], 78) self.assertRaises(ValueError, derive, bad_xprv, 1) # derive(bad_xprv, 1) # version/key mismatch in extended parent key xpub = xpub_from_xprv(rootxprv) temp = b58decode(xpub) bad_xpub = b58encode(temp[0:45] + b"\x00" + temp[46:], 78) self.assertRaises(ValueError, derive, bad_xpub, 1) # derive(bad_xpub, 1) # no private/hardened derivation from pubkey self.assertRaises(ValueError, derive, xpub, 0x80000000)
def test_mainnet_versions(self): # data cross-checked with Electrum and # https://jlopp.github.io/xpub-converter/ # 128 bits raw_entr = bytes.fromhex("6" * 32) # 12 words mnemonic = bip39.mnemonic_from_entropy(raw_entr, "en") seed = bip39.seed_from_mnemonic(mnemonic, "") # p2pkh BIP44 # m / 44h / coin_typeh / accounth / change / address_index path = "m/44h/0h/0h" version = NETWORKS["mainnet"]["bip32_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "xpub6C3uWu5Go5q62JzJpbjyCLYRGLYvexFeiepZTsYZ6SRexARkNfjG7GKtQVuGR3KHsyKsAwv7Hz3iNucPp6pfHiLvBczyK1j5CtBtpHB3NKx" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external address = p2pkh(xpub_ext) exp_address = b"1DDKKVHoFWGfctyEEJvrusqq6ipEaieGCq" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal address = p2pkh(xpub_int) exp_address = b"1FhKoffreKHzhtBMVW9NSsg3ZF148JPGoR" self.assertEqual(address, exp_address) # legacy segwit (p2wsh-p2sh) # m / 49h / coin_typeh / accounth / change / address_index path = "m/49h/0h/0h" version = NETWORKS["mainnet"]["slip32_p2wsh_p2sh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "ypub6YBGdYufCVeoPVmNXfdrWhaBCXsQoLKNetNmD9bPTrKmnKVmiyU8f1uJqwGdmBb8kbAZpHoYfXQTLbWpkXc4skQDAreeCUXdbX9k8vtiHsN" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external address = p2wpkh_p2sh(xpub_ext) exp_address = b"3FmNAiTCWe5kPMgc4dtSgEdY8VuaCiJEH8" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal address = p2wpkh_p2sh(xpub_int) exp_address = b"34FLgkoRYX5Q5fqiZCZDwsK5GpXxmFuLJN" self.assertEqual(address, exp_address) # legacy segwit (p2wpkh-p2sh) # m / 49h / coin_typeh / accounth / change / address_index path = "m/49h/0h/0h" version = NETWORKS["mainnet"]["slip32_p2wpkh_p2sh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "Ypub6j5Mkne6mTDAp4vkUL6qLmuyvKug1gzxyA2S8QrvqdABQW4gVNrQk8mEeeE7Kcp2z4EYgsofYjnxTm8b3km22EWt1Km3bszdVFRcipc6rXu" self.assertEqual(xpub.decode(), exp) # native segwit (p2wpkh) # m / 84h / coin_typeh / accounth / change / address_index path = "m/84h/0h/0h" version = NETWORKS["mainnet"]["slip32_p2wpkh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "zpub6qg3Uc1BAQkQvcBUYMmZHSzbsshSon3FvJ8yvH3ZZMjFNvJkwSji8UUwghiF3wvpvSvcNWVP8kfUhc2V2RwGp6pTC3ouj6njj956f26TniN" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external address = p2wpkh(xpub_ext) exp_address = b"bc1q0hy024867ednvuhy9en4dggflt5w9unw4ztl5a" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal address = p2wpkh(xpub_int) exp_address = b"bc1qy4x03jyl88h2zeg7l287xhv2xrwk4c3ztfpjd2" self.assertEqual(address, exp_address) # native segwit (p2wsh) # m / 84h / coin_typeh / accounth / change / address_index path = "m/84h/0h/0h" version = NETWORKS["mainnet"]["slip32_p2wsh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "Zpub72a8bqjcjNJnMBLrV2EY7XLQbfji28irEZneqYK6w8Zf16sfhr7zDbLsVQficP9j9uzbF6VW1y3ypmeFKf6Dxaw82WvK8WFjcsLyEvMNZjF" self.assertEqual(xpub.decode(), exp)
def test_testnet_versions(self): # data cross-checked with Electrum and # https://jlopp.github.io/xpub-converter/ # 128 bits raw_entr = bytes.fromhex("6" * 32) # 12 words mnemonic = bip39.mnemonic_from_entropy(raw_entr, "en") seed = bip39.seed_from_mnemonic(mnemonic, "") # p2pkh BIP44 # m / 44h / coin_typeh / accounth / change / address_index path = "m/44h/1h/0h" version = NETWORKS["testnet"]["bip32_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "tpubDChqWo2Xi2wNsxyJBE8ipcTJHLKWcqeeNUKBVTpUCNPZkHzHTm3qKAeHqgCou1t8PAY5ZnJ9QDa6zXSZxmjDnhiBpgZ7f6Yv88wEm5HXVbm" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external address = p2pkh(xpub_ext) exp_address = b"moutHSzeFWViMNEcvBxKzNCMj2kca8MvE1" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal address = p2pkh(xpub_int) exp_address = b"myWcXdNais9ExumnGKnNoJwoihQKfNPG9i" self.assertEqual(address, exp_address) # legacy segwit (p2wsh-p2sh) # m / 49h / coin_typeh / accounth / change / address_index path = "m/49h/1h/0h" version = NETWORKS["testnet"]["slip32_p2wsh_p2sh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "upub5Dj8j7YrwodV68mt58QmNpSzjqjso2WMXEpLGLSvskKccGuXhCh3dTedkzVLAePA617UyXAg2vdswJXTYjU4qjMJaHU79GJVVJCAiy9ezZ2" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external address = p2wpkh_p2sh(xpub_ext) exp_address = b"2Mw8tQ6uT6mHhybarVhjgomUhHQJTeV9A2c" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal address = p2wpkh_p2sh(xpub_int) exp_address = b"2N872CRJ3E1CzWjfixXr3aeC3hkF5Cz4kWb" self.assertEqual(address, exp_address) # legacy segwit (p2wsh-p2sh) # m / 49h / coin_typeh / accounth / change / address_index path = "m/49h/1h/0h" version = NETWORKS["testnet"]["slip32_p2wpkh_p2sh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "Upub5QdDrMHJWmBrWhwG1nskCtnoTdn91PBwqWU1BbiUFXA2ETUSTc5KiaWZZhSoj5c4KUBTr7Anv92P4U9Dqxd1zDTyQkaWYfmVP2U3Js1W5cG" self.assertEqual(xpub.decode(), exp) # native segwit (p2wpkh) # m / 84h / coin_typeh / accounth / change / address_index path = "m/84h/1h/0h" version = NETWORKS["testnet"]["slip32_p2wpkh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "vpub5ZhJmduYY7M5J2qCJgSW7hunX6zJrr5WuNg2kKt321HseZEYxqJc6Zso47aNXQw3Wf3sA8kppbfsxnLheUNXcL3xhzeBHLNp8fTVBN6DnJF" self.assertEqual(xpub.decode(), exp) # first addresses xpub_ext = derive(xpub, "./0/0") # external # explicit network is required to discriminate from testnet address = p2wpkh(xpub_ext, "regtest") exp_address = b"bcrt1qv8lcnmj09rpdqwgl025h2deygur64z4hqf7me5" self.assertEqual(address, exp_address) xpub_int = derive(xpub, "./1/0") # internal # explicit network is required to discriminate from testnet address = p2wpkh(xpub_int, "regtest") exp_address = b"bcrt1qqhxvky4y6qkwpvdzqjkdafmj20vs5trmt6y8w5" self.assertEqual(address, exp_address) # native segwit (p2wsh) # m / 84h / coin_typeh / accounth / change / address_index path = "m/84h/1h/0h" version = NETWORKS["testnet"]["slip32_p2wsh_prv"] rootprv = rootxprv_from_seed(seed, version) xprv = derive(rootprv, path) xpub = xpub_from_xprv(xprv) exp = "Vpub5kbPtsdz74uSibzaFLuUwnFbEu2a5Cm7DeKhfb9aPn8HGjoTjEgtBgjirpXr5r9wk87r2ikwhp4P5wxTwhXUkpAdYTkagjqp2PjMmGPBESU" self.assertEqual(xpub.decode(), exp)
def test_vector1(self): """BIP32 test vector 1 https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki """ seed = "000102030405060708090a0b0c0d0e0f" rootxprv = rootxprv_from_seed(seed) self.assertEqual( rootxprv, b"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" ) rootxpub = xpub_from_xprv(rootxprv) # neutering self.assertEqual( rootxpub, b"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" ) xprv = rootxprv xpub = rootxpub xprv = derive(xprv, ".") # private relative self.assertEqual( xprv, b"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" ) xprv = derive(rootxprv, "m") # private absolute self.assertEqual( xprv, b"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi" ) xpub = derive(xpub, ".") # public relative self.assertEqual( xpub, b"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" ) xpub = derive(rootxpub, "m") # public absolute self.assertEqual( xpub, b"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub661MyMwAqRbcFtXgS5sYJABqqG9YLmC4Q1Rdap9gSE8NqtwybGhePY2gZ29ESFjqJoCu1Rupje8YtGqsefD265TMg7usUDFdp6W1EGMcet8" ) xprv = derive(xprv, "./0'") # private relative self.assertEqual( xprv, b"xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7" ) xprv = derive(rootxprv, "m/0'") # private absolute self.assertEqual( xprv, b"xprv9uHRZZhk6KAJC1avXpDAp4MDc3sQKNxDiPvvkX8Br5ngLNv1TxvUxt4cV1rGL5hj6KCesnDYUhd7oWgT11eZG7XnxHrnYeSvkzY7d2bhkJ7" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub68Gmy5EdvgibQVfPdqkBBCHxA5htiqg55crXYuXoQRKfDBFA1WEjWgP6LHhwBZeNK1VTsfTFUHCdrfp1bgwQ9xv5ski8PX9rL2dZXvgGDnw" ) xprv = derive(xprv, "./1") # private relative self.assertEqual( xprv, b"xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs" ) xprv = derive(rootxprv, "m/0'/1") # private absolute self.assertEqual( xprv, b"xprv9wTYmMFdV23N2TdNG573QoEsfRrWKQgWeibmLntzniatZvR9BmLnvSxqu53Kw1UmYPxLgboyZQaXwTCg8MSY3H2EU4pWcQDnRnrVA1xe8fs" ) xpub = derive(xpub, "./1") # public relative self.assertEqual( xpub, b"xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub6ASuArnXKPbfEwhqN6e3mwBcDTgzisQN1wXN9BJcM47sSikHjJf3UFHKkNAWbWMiGj7Wf5uMash7SyYq527Hqck2AxYysAA7xmALppuCkwQ" ) xprv = derive(xprv, "./2H") # private relative self.assertEqual( xprv, b"xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM" ) xprv = derive(rootxprv, "m/0'/1/2'") # private absolute self.assertEqual( xprv, b"xprv9z4pot5VBttmtdRTWfWQmoH1taj2axGVzFqSb8C9xaxKymcFzXBDptWmT7FwuEzG3ryjH4ktypQSAewRiNMjANTtpgP4mLTj34bhnZX7UiM" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub6D4BDPcP2GT577Vvch3R8wDkScZWzQzMMUm3PWbmWvVJrZwQY4VUNgqFJPMM3No2dFDFGTsxxpG5uJh7n7epu4trkrX7x7DogT5Uv6fcLW5" ) xprv = derive(xprv, "./2") # private relative self.assertEqual( xprv, b"xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334" ) xprv = derive(rootxprv, "m/0'/1/2'/2") # private absolute self.assertEqual( xprv, b"xprvA2JDeKCSNNZky6uBCviVfJSKyQ1mDYahRjijr5idH2WwLsEd4Hsb2Tyh8RfQMuPh7f7RtyzTtdrbdqqsunu5Mm3wDvUAKRHSC34sJ7in334" ) xpub = derive(xpub, "./2") # public relative self.assertEqual( xpub, b"xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub6FHa3pjLCk84BayeJxFW2SP4XRrFd1JYnxeLeU8EqN3vDfZmbqBqaGJAyiLjTAwm6ZLRQUMv1ZACTj37sR62cfN7fe5JnJ7dh8zL4fiyLHV" ) xprv = derive(xprv, "./1000000000") # private relative self.assertEqual( xprv, b"xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76" ) # private absolute xprv = derive(rootxprv, "m/0'/1/2'/2/1000000000") self.assertEqual( xprv, b"xprvA41z7zogVVwxVSgdKUHDy1SKmdb533PjDz7J6N6mV6uS3ze1ai8FHa8kmHScGpWmj4WggLyQjgPie1rFSruoUihUZREPSL39UNdE3BBDu76" ) xpub = derive(xpub, "./1000000000") # public relative self.assertEqual( xpub, b"xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub6H1LXWLaKsWFhvm6RVpEL9P4KfRZSW7abD2ttkWP3SSQvnyA8FSVqNTEcYFgJS2UaFcxupHiYkro49S8yGasTvXEYBVPamhGW6cFJodrTHy" )
def test_vector2(self): """BIP32 test vector 2 https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki """ seed = "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542" rootxprv = rootxprv_from_seed(seed) self.assertEqual( rootxprv, b"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U" ) rootxpub = xpub_from_xprv(rootxprv) # neutering self.assertEqual( rootxpub, b"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB" ) xprv = rootxprv xpub = rootxpub xprv = derive(xprv, ".") # private relative self.assertEqual( xprv, b"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U" ) xprv = derive(rootxprv, "m") # private absolute self.assertEqual( xprv, b"xprv9s21ZrQH143K31xYSDQpPDxsXRTUcvj2iNHm5NUtrGiGG5e2DtALGdso3pGz6ssrdK4PFmM8NSpSBHNqPqm55Qn3LqFtT2emdEXVYsCzC2U" ) xpub = derive(xpub, ".") # public relative self.assertEqual( xpub, b"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB" ) xpub = derive(rootxpub, "m") # public absolute self.assertEqual( xpub, b"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub661MyMwAqRbcFW31YEwpkMuc5THy2PSt5bDMsktWQcFF8syAmRUapSCGu8ED9W6oDMSgv6Zz8idoc4a6mr8BDzTJY47LJhkJ8UB7WEGuduB" ) xprv = derive(xprv, "./0") # private relative self.assertEqual( xprv, b"xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt" ) xprv = derive(rootxprv, "m/0") # private absolute self.assertEqual( xprv, b"xprv9vHkqa6EV4sPZHYqZznhT2NPtPCjKuDKGY38FBWLvgaDx45zo9WQRUT3dKYnjwih2yJD9mkrocEZXo1ex8G81dwSM1fwqWpWkeS3v86pgKt" ) xpub = derive(xpub, "./0") # public relative self.assertEqual( xpub, b"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH" ) xpub = derive(rootxpub, "m/0") # public absolute self.assertEqual( xpub, b"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub69H7F5d8KSRgmmdJg2KhpAK8SR3DjMwAdkxj3ZuxV27CprR9LgpeyGmXUbC6wb7ERfvrnKZjXoUmmDznezpbZb7ap6r1D3tgFxHmwMkQTPH" ) xprv = derive(xprv, "./2147483647H") # private relative self.assertEqual( xprv, b"xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9" ) xprv = derive(rootxprv, "m/0/2147483647H") # private absolute self.assertEqual( xprv, b"xprv9wSp6B7kry3Vj9m1zSnLvN3xH8RdsPP1Mh7fAaR7aRLcQMKTR2vidYEeEg2mUCTAwCd6vnxVrcjfy2kRgVsFawNzmjuHc2YmYRmagcEPdU9" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub6ASAVgeehLbnwdqV6UKMHVzgqAG8Gr6riv3Fxxpj8ksbH9ebxaEyBLZ85ySDhKiLDBrQSARLq1uNRts8RuJiHjaDMBU4Zn9h8LZNnBC5y4a" ) xprv = derive(xprv, "./1") # private relative self.assertEqual( xprv, b"xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef" ) xprv = derive(rootxprv, "m/0/2147483647H/1") # private absolute self.assertEqual( xprv, b"xprv9zFnWC6h2cLgpmSA46vutJzBcfJ8yaJGg8cX1e5StJh45BBciYTRXSd25UEPVuesF9yog62tGAQtHjXajPPdbRCHuWS6T8XA2ECKADdw4Ef" ) xpub = derive(xpub, "./1") # public relative self.assertEqual( xpub, b"xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub6DF8uhdarytz3FWdA8TvFSvvAh8dP3283MY7p2V4SeE2wyWmG5mg5EwVvmdMVCQcoNJxGoWaU9DCWh89LojfZ537wTfunKau47EL2dhHKon" ) xprv = derive(xprv, "./2147483646H") # private relative self.assertEqual( xprv, b"xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc" ) # private absolute xprv = derive(rootxprv, "m/0/2147483647H/1/2147483646H") self.assertEqual( xprv, b"xprvA1RpRA33e1JQ7ifknakTFpgNXPmW2YvmhqLQYMmrj4xJXXWYpDPS3xz7iAxn8L39njGVyuoseXzU6rcxFLJ8HFsTjSyQbLYnMpCqE2VbFWc" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub6ERApfZwUNrhLCkDtcHTcxd75RbzS1ed54G1LkBUHQVHQKqhMkhgbmJbZRkrgZw4koxb5JaHWkY4ALHY2grBGRjaDMzQLcgJvLJuZZvRcEL" ) xprv = derive(xprv, "./2") # private relative self.assertEqual( xprv, b"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j" ) # private absolute xprv = derive(rootxprv, "m/0/2147483647H/1/2147483646H/2") self.assertEqual( xprv, b"xprvA2nrNbFZABcdryreWet9Ea4LvTJcGsqrMzxHx98MMrotbir7yrKCEXw7nadnHM8Dq38EGfSh6dqA9QWTyefMLEcBYJUuekgW4BYPJcr9E7j" ) xpub = derive(xpub, "./2") # public relative self.assertEqual( xpub, b"xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt" ) xpub = xpub_from_xprv(xprv) # neutering self.assertEqual( xpub, b"xpub6FnCn6nSzZAw5Tw7cgR9bi15UV96gLZhjDstkXXxvCLsUXBGXPdSnLFbdpq8p9HmGsApME5hQTZ3emM2rnY5agb9rXpVGyy3bdW6EEgAtqt" )
import secrets from hashlib import sha256 from btclib import base58wif, bip32, bip39, btcmsg, der, slip32 from btclib.secpoint import bytes_from_point, point_from_octets from btclib.utils import bytes_from_octets mnemonic = "token output grass below such awake census safe orphan device other meat" passphrase = "" seed = bip39.seed_from_mnemonic(mnemonic, passphrase) rxprv = bip32.rootxprv_from_seed(seed) rxpub = bip32.xpub_from_xprv(rxprv) assert rxpub == b"xpub661MyMwAqRbcFzL26X6G7bySxgU1oV6GviUrNnhbeAS3ULQq35KEV6uSf1aJXEHjFYy6LXUPrYnfR9bSKWdFZ5VnYaEb3AbHPmXFVAoKKYT", rxpub firmware_xprv = bip32.derive(rxprv, "m/0") firmware_xpub = bip32.derive(rxpub, "m/0") assert firmware_xpub == bip32.xpub_from_xprv(bip32.derive(rxprv, "m/0")) firmware_pubkey = bip32.deserialize(firmware_xpub)['key'] assert bytes_from_point(point_from_octets(firmware_pubkey), False).hex( ) == "042374b3b6b06b65a3b831f857634ea135bf10b014d5bba0f935cb9eb26a4b6547ed3b37f277427a0ab23bda0ca79c5785dc54d2387fa3f295f4d5674d5b637de2" assert bytes_from_point(point_from_octets(firmware_pubkey), True).hex( ) == "022374b3b6b06b65a3b831f857634ea135bf10b014d5bba0f935cb9eb26a4b6547" firmware_wif = base58wif.wif_from_xprv(firmware_xprv) firmware_address = slip32.address_from_xpub(firmware_xpub) app_xprv = bip32.derive(rxprv, "m/1") app_xpub = bip32.derive(rxpub, "m/1") assert app_xpub == bip32.xpub_from_xprv(bip32.derive(rxprv, "m/1")) app_pubkey = bip32.deserialize(app_xpub)['key'] assert bytes_from_point(point_from_octets(app_pubkey), False).hex( ) == "04ae3d0d5c669ed364636e79e72abc012a33be63e537babddf56bfd393256acf6dba0fac21da6386513674573a2d7baff4375c9b6d2498383853c52f0565f97f1a"
def test_testnet_versions(self): # data cross-checked with Electrum and https://jlopp.github.io/xpub-converter/ # 128 bits raw_entr = bytes.fromhex('6' * 32) # 12 words mnemonic = bip39.mnemonic_from_entropy(raw_entr, 'en') seed = bip39.seed_from_mnemonic(mnemonic, '') # p2pkh BIP44 m / 44' / coin_type' / account' / change / address_index path = "m/44h/1h/0h" version = bip32.TEST_tprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'tpubDChqWo2Xi2wNsxyJBE8ipcTJHLKWcqeeNUKBVTpUCNPZkHzHTm3qKAeHqgCou1t8PAY5ZnJ9QDa6zXSZxmjDnhiBpgZ7f6Yv88wEm5HXVbm' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'moutHSzeFWViMNEcvBxKzNCMj2kca8MvE1' self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'myWcXdNais9ExumnGKnNoJwoihQKfNPG9i' self.assertEqual(address, exp_address) # legacy segwit (p2wpkh-p2sh) m / 49'/ coin_type' / account' / change / address_index path = "m/49h/1h/0h" version = bip32.TEST_uprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'upub5Dj8j7YrwodV68mt58QmNpSzjqjso2WMXEpLGLSvskKccGuXhCh3dTedkzVLAePA617UyXAg2vdswJXTYjU4qjMJaHU79GJVVJCAiy9ezZ2' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external address = bip32.p2wpkh_p2sh_address_from_xpub(xpub_ext) exp_address = b'2Mw8tQ6uT6mHhybarVhjgomUhHQJTeV9A2c' self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal address = bip32.p2wpkh_p2sh_address_from_xpub(xpub_int) exp_address = b'2N872CRJ3E1CzWjfixXr3aeC3hkF5Cz4kWb' self.assertEqual(address, exp_address) # legacy segwit (p2wsh-p2sh) m / 49'/ coin_type' / account' / change / address_index path = "m/49h/1h/0h" version = bip32.TEST_Uprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Upub5QdDrMHJWmBrWhwG1nskCtnoTdn91PBwqWU1BbiUFXA2ETUSTc5KiaWZZhSoj5c4KUBTr7Anv92P4U9Dqxd1zDTyQkaWYfmVP2U3Js1W5cG' self.assertEqual(xpub, exp) # native segwit (p2wpkh) m / 84'/ coin_type' / account' / change / address_index path = "m/84h/1h/0h" version = bip32.TEST_vprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'vpub5ZhJmduYY7M5J2qCJgSW7hunX6zJrr5WuNg2kKt321HseZEYxqJc6Zso47aNXQw3Wf3sA8kppbfsxnLheUNXcL3xhzeBHLNp8fTVBN6DnJF' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external address = bip32.p2wpkh_address_from_xpub(xpub_ext) # this is regtest, not testnet!! exp_address = b'bcrt1qv8lcnmj09rpdqwgl025h2deygur64z4hqf7me5' # FIXME: self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal address = bip32.p2wpkh_address_from_xpub(xpub_int) # this is regtest, not testnet!! exp_address = b'bcrt1qqhxvky4y6qkwpvdzqjkdafmj20vs5trmt6y8w5' # FIXME: self.assertEqual(address, exp_address) # native segwit (p2wsh) m / 84'/ coin_type' / account' / change / address_index path = "m/84h/1h/0h" version = bip32.TEST_Vprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Vpub5kbPtsdz74uSibzaFLuUwnFbEu2a5Cm7DeKhfb9aPn8HGjoTjEgtBgjirpXr5r9wk87r2ikwhp4P5wxTwhXUkpAdYTkagjqp2PjMmGPBESU' self.assertEqual(xpub, exp)
def test_versions(self): # data cross-checked with Electrum and https://jlopp.github.io/xpub-converter/ # 128 bits raw_entr = bytes.fromhex('6'*32) # 12 words mnemonic = bip39.mnemonic_from_entropy(raw_entr, 'en') seed = bip39.seed_from_mnemonic(mnemonic, '') ##### TESTNET # p2pkh BIP44 m / 44' / coin_type' / account' / change / address_index path = "m/44h/1h/0h" version = bip32.TEST_tprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'tpubDChqWo2Xi2wNsxyJBE8ipcTJHLKWcqeeNUKBVTpUCNPZkHzHTm3qKAeHqgCou1t8PAY5ZnJ9QDa6zXSZxmjDnhiBpgZ7f6Yv88wEm5HXVbm' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'moutHSzeFWViMNEcvBxKzNCMj2kca8MvE1' self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'myWcXdNais9ExumnGKnNoJwoihQKfNPG9i' self.assertEqual(address, exp_address) # legacy segwit (p2wpkh-p2sh) m / 49'/ coin_type' / account' / change / address_index path = "m/49h/1h/0h" version = bip32.TEST_uprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'upub5Dj8j7YrwodV68mt58QmNpSzjqjso2WMXEpLGLSvskKccGuXhCh3dTedkzVLAePA617UyXAg2vdswJXTYjU4qjMJaHU79GJVVJCAiy9ezZ2' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external # TODO: address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'2Mw8tQ6uT6mHhybarVhjgomUhHQJTeV9A2c' # TODO: self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal # TODO: address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'2N872CRJ3E1CzWjfixXr3aeC3hkF5Cz4kWb' # TODO: self.assertEqual(address, exp_address) # multi-sig version version = bip32.TEST_Uprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Upub5QdDrMHJWmBrWhwG1nskCtnoTdn91PBwqWU1BbiUFXA2ETUSTc5KiaWZZhSoj5c4KUBTr7Anv92P4U9Dqxd1zDTyQkaWYfmVP2U3Js1W5cG' self.assertEqual(xpub, exp) # native segwit (p2wpkh) m / 84'/ coin_type' / account' / change / address_index path = "m/84h/1h/0h" version = bip32.TEST_vprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'vpub5ZhJmduYY7M5J2qCJgSW7hunX6zJrr5WuNg2kKt321HseZEYxqJc6Zso47aNXQw3Wf3sA8kppbfsxnLheUNXcL3xhzeBHLNp8fTVBN6DnJF' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'bcrt1qv8lcnmj09rpdqwgl025h2deygur64z4hqf7me5' # FIXME: self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'bcrt1qqhxvky4y6qkwpvdzqjkdafmj20vs5trmt6y8w5' # FIXME: self.assertEqual(address, exp_address) # multi-sig version version = bip32.TEST_Vprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Vpub5kbPtsdz74uSibzaFLuUwnFbEu2a5Cm7DeKhfb9aPn8HGjoTjEgtBgjirpXr5r9wk87r2ikwhp4P5wxTwhXUkpAdYTkagjqp2PjMmGPBESU' self.assertEqual(xpub, exp) ##### MAINNET # p2pkh BIP44 m / 44' / coin_type' / account' / change / address_index path = "m/44h/0h/0h" version = bip32.MAIN_xprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'xpub6C3uWu5Go5q62JzJpbjyCLYRGLYvexFeiepZTsYZ6SRexARkNfjG7GKtQVuGR3KHsyKsAwv7Hz3iNucPp6pfHiLvBczyK1j5CtBtpHB3NKx' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'1DDKKVHoFWGfctyEEJvrusqq6ipEaieGCq' self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'1FhKoffreKHzhtBMVW9NSsg3ZF148JPGoR' self.assertEqual(address, exp_address) # legacy segwit (p2wpkh-p2sh) m / 49'/ coin_type' / account' / change / address_index path = "m/49h/0h/0h" version = bip32.MAIN_yprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'ypub6YBGdYufCVeoPVmNXfdrWhaBCXsQoLKNetNmD9bPTrKmnKVmiyU8f1uJqwGdmBb8kbAZpHoYfXQTLbWpkXc4skQDAreeCUXdbX9k8vtiHsN' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'3FmNAiTCWe5kPMgc4dtSgEdY8VuaCiJEH8' # FIXME: self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'34FLgkoRYX5Q5fqiZCZDwsK5GpXxmFuLJN' # FIXME: self.assertEqual(address, exp_address) # multi-sig version version = bip32.MAIN_Yprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Ypub6j5Mkne6mTDAp4vkUL6qLmuyvKug1gzxyA2S8QrvqdABQW4gVNrQk8mEeeE7Kcp2z4EYgsofYjnxTm8b3km22EWt1Km3bszdVFRcipc6rXu' self.assertEqual(xpub, exp) # native segwit (p2wpkh) m / 84'/ coin_type' / account' / change / address_index path = "m/84h/0h/0h" version = bip32.MAIN_zprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'zpub6qg3Uc1BAQkQvcBUYMmZHSzbsshSon3FvJ8yvH3ZZMjFNvJkwSji8UUwghiF3wvpvSvcNWVP8kfUhc2V2RwGp6pTC3ouj6njj956f26TniN' self.assertEqual(xpub, exp) # first addresses xpub_ext = bip32.derive(xpub, "./0/0") # external # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_ext) exp_address = b'bc1q0hy024867ednvuhy9en4dggflt5w9unw4ztl5a' # FIXME: self.assertEqual(address, exp_address) xpub_int = bip32.derive(xpub, "./1/0") # internal # FIXME: address = bip32.p2pkh_address_from_xpub(xpub_int) exp_address = b'bc1qy4x03jyl88h2zeg7l287xhv2xrwk4c3ztfpjd2' # FIXME: self.assertEqual(address, exp_address) # multi-sig version version = bip32.MAIN_Zprv rootprv = bip32.rootxprv_from_seed(seed, version) xprv = bip32.derive(rootprv, path) xpub = bip32.xpub_from_xprv(xprv) exp = b'Zpub72a8bqjcjNJnMBLrV2EY7XLQbfji28irEZneqYK6w8Zf16sfhr7zDbLsVQficP9j9uzbF6VW1y3ypmeFKf6Dxaw82WvK8WFjcsLyEvMNZjF' self.assertEqual(xpub, exp)
def test_mainnet(self): # bitcoin core derivation style rootxprv = b'xprv9s21ZrQH143K2ZP8tyNiUtgoezZosUkw9hhir2JFzDhcUWKz8qFYk3cxdgSFoCMzt8E2Ubi1nXw71TLhwgCfzqFHfM5Snv4zboSebePRmLS' # m/0'/0'/463' addr1 = b'1DyfBWxhVLmrJ7keyiHeMbt7N3UdeGU4G5' indexes = [0x80000000, 0x80000000, 0x80000000 + 463] addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv(bip32.derive(rootxprv, indexes))) self.assertEqual(addr, addr1) path = "m/0'/0'/463'" addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv(bip32.derive(rootxprv, path))) self.assertEqual(addr, addr1) # m/0'/0'/267' addr2 = b'11x2mn59Qy43DjisZWQGRResjyQmgthki' indexes = [0x80000000, 0x80000000, 0x80000000 + 267] addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv(bip32.derive(rootxprv, indexes))) self.assertEqual(addr, addr2) path = "m/0'/0'/267'" addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv(bip32.derive(rootxprv, path))) self.assertEqual(addr, addr2) xkey_version = bip32.PRV_VERSION[0] seed = "bfc4cbaad0ff131aa97fa30a48d09ae7df914bcc083af1e07793cd0a7c61a03f65d622848209ad3366a419f4718a80ec9037df107d8d12c19b83202de00a40ad" seed = bytes.fromhex(seed) xprv = bip32.rootxprv_from_seed(seed, xkey_version) xpub = b'xpub661MyMwAqRbcFMYjmw8C6dJV97a4oLss6hb3v9wTQn2X48msQB61RCaLGtNhzgPCWPaJu7SvuB9EBSFCL43kTaFJC3owdaMka85uS154cEh' self.assertEqual(bip32.xpub_from_xprv(xprv), xpub) ind = [0, 0] addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv(bip32.derive(xprv, ind))) self.assertEqual(addr, b'1FcfDbWwGs1PmyhMVpCAhoTfMnmSuptH6g') ind = [0, 1] addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv(bip32.derive(xprv, ind))) self.assertEqual(addr, b'1K5GjYkZnPFvMDTGaQHTrVnd8wjmrtfR5x') ind = [0, 2] addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv(bip32.derive(xprv, ind))) self.assertEqual(addr, b'1PQYX2uN7NYFd7Hq22ECMzfDcKhtrHmkfi') ind = [1, 0] addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv(bip32.derive(xprv, ind))) self.assertEqual(addr, b'1BvSYpojWoWUeaMLnzbkK55v42DbizCoyq') ind = [1, 1] addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv(bip32.derive(xprv, ind))) self.assertEqual(addr, b'1NXB59hF4QzYpFrB7o6usLBjbk2D3ZqxAL') ind = [1, 2] addr = bip32.p2pkh_address_from_xpub(bip32.xpub_from_xprv(bip32.derive(xprv, ind))) self.assertEqual(addr, b'16NLYkKtvYhW1Jp86tbocku3gxWcvitY1w') # version/key mismatch in extended parent key temp = base58.decode_check(rootxprv) bad_xprv = base58.encode_check(temp[0:45] + b'\x01' + temp[46:]) self.assertRaises(ValueError, bip32.ckd, bad_xprv, 1) #bip32.ckd(bad_xprv, 1) # version/key mismatch in extended parent key xpub = bip32.xpub_from_xprv(rootxprv) temp = base58.decode_check(xpub) bad_xpub = base58.encode_check(temp[0:45] + b'\x00' + temp[46:]) self.assertRaises(ValueError, bip32.ckd, bad_xpub, 1) #bip32.ckd(bad_xpub, 1) # no private/hardened derivation from pubkey self.assertRaises(ValueError, bip32.ckd, xpub, 0x80000000)