1010)
1111
1212
13+ class PrivateDerivationError (ValueError ):
14+ """
15+ Tried to use a derivation requiring private keys, without private keys.
16+ """
17+ pass
18+
19+
1320class BIP32 :
1421 def __init__ (self , chaincode , privkey = None , pubkey = None , fingerprint = None ,
1522 depth = 0 , index = 0 , network = "main" ):
@@ -53,8 +60,12 @@ def get_extended_privkey_from_path(self, path):
5360 m/x/x'/x notation. (e.g. m/0'/1/2'/2 or m/0H/1/2H/2).
5461 :return: chaincode (bytes), privkey (bytes)
5562 """
63+ if self .master_privkey is None :
64+ raise PrivateDerivationError
65+
5666 if isinstance (path , str ):
5767 path = _deriv_path_str_to_list (path )
68+
5869 chaincode , privkey = self .master_chaincode , self .master_privkey
5970 for index in path :
6071 if index & HARDENED_INDEX :
@@ -63,6 +74,7 @@ def get_extended_privkey_from_path(self, path):
6374 else :
6475 privkey , chaincode = \
6576 _derive_unhardened_private_child (privkey , chaincode , index )
77+
6678 return chaincode , privkey
6779
6880 def get_privkey_from_path (self , path ):
@@ -72,6 +84,9 @@ def get_privkey_from_path(self, path):
7284 m/x/x'/x notation. (e.g. m/0'/1/2'/2 or m/0H/1/2H/2).
7385 :return: privkey (bytes)
7486 """
87+ if self .master_privkey is None :
88+ raise PrivateDerivationError
89+
7590 return self .get_extended_privkey_from_path (path )[1 ]
7691
7792 def get_extended_pubkey_from_path (self , path ):
@@ -83,6 +98,10 @@ def get_extended_pubkey_from_path(self, path):
8398 """
8499 if isinstance (path , str ):
85100 path = _deriv_path_str_to_list (path )
101+
102+ if _hardened_index_in_path (path ) and self .master_privkey is None :
103+ raise PrivateDerivationError
104+
86105 chaincode , key = self .master_chaincode , self .master_privkey
87106 pubkey = self .master_pubkey
88107 # We'll need the private key at some point anyway, so let's derive
@@ -102,6 +121,7 @@ def get_extended_pubkey_from_path(self, path):
102121 for index in path :
103122 pubkey , chaincode = \
104123 _derive_public_child (pubkey , chaincode , index )
124+
105125 return chaincode , pubkey
106126
107127 def get_pubkey_from_path (self , path ):
@@ -120,8 +140,12 @@ def get_xpriv_from_path(self, path):
120140 m/x/x'/x notation. (e.g. m/0'/1/2'/2 or m/0H/1/2H/2).
121141 :return: The encoded extended pubkey as str.
122142 """
143+ if self .master_privkey is None :
144+ raise PrivateDerivationError
145+
123146 if isinstance (path , str ):
124147 path = _deriv_path_str_to_list (path )
148+
125149 if len (path ) == 0 :
126150 return self .get_master_xpriv ()
127151 elif len (path ) == 1 :
@@ -133,6 +157,7 @@ def get_xpriv_from_path(self, path):
133157 parent_pubkey ,
134158 path [- 1 ], chaincode ,
135159 self .network )
160+
136161 return base58 .b58encode_check (extended_key ).decode ()
137162
138163 def get_xpub_from_path (self , path ):
@@ -144,6 +169,10 @@ def get_xpub_from_path(self, path):
144169 """
145170 if isinstance (path , str ):
146171 path = _deriv_path_str_to_list (path )
172+
173+ if _hardened_index_in_path (path ) and self .master_privkey is None :
174+ raise PrivateDerivationError
175+
147176 if len (path ) == 0 :
148177 return self .get_master_xpub ()
149178 elif len (path ) == 1 :
@@ -155,10 +184,13 @@ def get_xpub_from_path(self, path):
155184 parent_pubkey ,
156185 path [- 1 ], chaincode ,
157186 self .network )
187+
158188 return base58 .b58encode_check (extended_key ).decode ()
159189
160190 def get_master_xpriv (self ):
161191 """Get the encoded extended private key of the master private key"""
192+ if self .master_privkey is None :
193+ raise PrivateDerivationError
162194 extended_key = _serialize_extended_key (self .master_privkey , self .depth ,
163195 self .parent_fingerprint ,
164196 self .index ,
0 commit comments