Skip to content

Commit 689b212

Browse files
committed
Merge branch 'derive_master'
2 parents b3f6696 + 0e022cd commit 689b212

2 files changed

Lines changed: 23 additions & 6 deletions

File tree

bip32/bip32.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def get_extended_pubkey_from_path(self, path):
8484
if isinstance(path, str):
8585
path = _deriv_path_str_to_list(path)
8686
chaincode, key = self.master_chaincode, self.master_privkey
87+
pubkey = self.master_pubkey
8788
# We'll need the private key at some point anyway, so let's derive
8889
# everything from private keys.
8990
if _hardened_index_in_path(path):
@@ -98,15 +99,13 @@ def get_extended_pubkey_from_path(self, path):
9899
# We won't need private keys for the whole path, so let's only use
99100
# public key derivation.
100101
else:
101-
key = self.master_pubkey
102102
for index in path:
103-
key, chaincode = \
104-
_derive_public_child(key, chaincode, index)
105-
pubkey = key
103+
pubkey, chaincode = \
104+
_derive_public_child(pubkey, chaincode, index)
106105
return chaincode, pubkey
107106

108107
def get_pubkey_from_path(self, path):
109-
"""Get a privkey from a derivation path.
108+
"""Get a pubkey from a derivation path.
110109
111110
:param path: A list of integers (index of each depth) or a string with
112111
m/x/x'/x notation. (e.g. m/0'/1/2'/2 or m/0H/1/2H/2).

tests/test_bip32.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1+
import coincurve
12
import os
3+
import pytest
24

35
from bip32 import BIP32, HARDENED_INDEX
46

@@ -85,7 +87,7 @@ def test_vector_3():
8587
assert (bip32.get_xpriv_from_path("m/0H") == bip32.get_xpriv_from_path([HARDENED_INDEX]))
8688

8789

88-
def test_sanity_tests():
90+
def test_sanity_checks():
8991
seed = bytes.fromhex("1077a46dc8545d372f22d9e110ae6c5c2bf7620fe9c4c911f5404d112233e1aa270567dd3554092e051ba3ba86c303590b0309116ac89964ff284db2219d7511")
9092
first_bip32 = BIP32.from_seed(seed)
9193
sec_bip32 = BIP32.from_xpriv("xprv9s21ZrQH143K3o4KUs47P2x9afhH31ekMo2foNTYwrU9wwZ8g5EatR9bn6YmCacdvnHWMnPFUqieQrnunrzuF5UfgGbhbEW43zRnhpPDBUL")
@@ -105,6 +107,7 @@ def test_sanity_tests():
105107
assert first_bip32.get_xpub_from_path(h_path) == sec_bip32.get_xpub_from_path(h_path)
106108
assert first_bip32.get_xpriv_from_path(mixed_path) == sec_bip32.get_xpriv_from_path(mixed_path)
107109
assert first_bip32.get_xpub_from_path(mixed_path) == sec_bip32.get_xpub_from_path(mixed_path)
110+
108111
# Taken from iancoleman's website
109112
bip32 = BIP32.from_seed(bytes.fromhex("ac8c2377e5cde867d7e420fbe04d8906309b70d51b8fe58d6844930621a9bc223929155dcfebb4da9d62c86ec0d15adf936a663f4f0cf39cbb0352e7dac073d6"))
110113
assert bip32.get_master_xpriv() == bip32.get_xpriv_from_path([]) == "xprv9s21ZrQH143K2GzaKJsW7DQsxeDpY3zqgusaSx6owWGC19k4mhwnVAsm4qPsCw43NkY2h1BzVLyxWHt9NKF86QRyBj53vModdGcNxtpD6KX"
@@ -124,6 +127,7 @@ def test_sanity_tests():
124127
assert bip32.get_master_xpriv() == xpriv2
125128
assert bip32.get_xpriv_from_path([HARDENED_INDEX, 18]) == xpriv
126129
assert bip32.get_xpub_from_path([HARDENED_INDEX, 18]) == xpub
130+
127131
# We should recognize the networks..
128132
# .. for xprivs:
129133
bip32 = BIP32.from_xpriv("xprv9wHokC2KXdTSpEepFcu53hMDUHYfAtTaLEJEMyxBPAMf78hJg17WhL5FyeDUQH5KWmGjGgEb2j74gsZqgupWpPbZgP6uFmP8MYEy5BNbyET")
@@ -135,6 +139,7 @@ def test_sanity_tests():
135139
assert bip32.network == "main"
136140
bip32 = BIP32.from_xpub("tpubD6NzVbkrYhZ4WN3WiKRjeo2eGyYNiKNg8vcQ1UjLNJJaDvoFhmR1XwJsbo5S4vicSPoWQBThR3Rt8grXtP47c1AnoiXMrEmFdRZupxJzH1j")
137141
assert bip32.network == "test"
142+
138143
# We should create valid network encoding..
139144
assert BIP32.from_seed(os.urandom(32),
140145
"test").get_master_xpub().startswith("tpub")
@@ -144,3 +149,16 @@ def test_sanity_tests():
144149
"main").get_master_xpub().startswith("xpub")
145150
assert BIP32.from_seed(os.urandom(32),
146151
"main").get_master_xpriv().startswith("xprv")
152+
153+
# We can get the keys from "m" or []
154+
bip32 = BIP32.from_seed(os.urandom(32))
155+
assert (bip32.get_master_xpub() == bip32.get_xpub_from_path("m") ==
156+
bip32.get_xpub_from_path([]))
157+
assert (bip32.get_master_xpriv() == bip32.get_xpriv_from_path("m") ==
158+
bip32.get_xpriv_from_path([]))
159+
master_non_extended_pubkey = bip32.get_privkey_from_path("m")
160+
pubkey = coincurve.PublicKey.from_secret(master_non_extended_pubkey)
161+
assert pubkey.format() == bip32.get_pubkey_from_path("m")
162+
# But getting from "m'" does not make sense
163+
with pytest.raises(ValueError, match="invalid format"):
164+
bip32.get_pubkey_from_path("m'")

0 commit comments

Comments
 (0)