From 0fba07f695297a249f87d98b31bd6d4750e7078f Mon Sep 17 00:00:00 2001 From: Jerry Date: Fri, 26 Sep 2025 19:29:54 -0700 Subject: [PATCH 1/2] Remove unncessary requirements for HDWallet derivation --- pycardano/crypto/bip32.py | 21 +++++++------ test/pycardano/crypto/test_bip32.py | 48 +++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 9 deletions(-) diff --git a/pycardano/crypto/bip32.py b/pycardano/crypto/bip32.py index 3095666b..2bf90490 100644 --- a/pycardano/crypto/bip32.py +++ b/pycardano/crypto/bip32.py @@ -82,12 +82,12 @@ class HDWallet: def __init__( self, - root_xprivate_key: bytes, - root_public_key: bytes, - root_chain_code: bytes, - xprivate_key: bytes, - public_key: bytes, - chain_code: bytes, + root_xprivate_key: Optional[bytes] = None, + root_public_key: Optional[bytes] = None, + root_chain_code: Optional[bytes] = None, + xprivate_key: Optional[bytes] = None, + public_key: Optional[bytes] = None, + chain_code: Optional[bytes] = None, path: str = "m", seed: Optional[bytes] = None, mnemonic: Optional[str] = None, @@ -322,13 +322,13 @@ def derive( if not isinstance(index, int): raise ValueError("Bad index, Please import only integer number!") - if not self._root_xprivate_key and not self._root_public_key: - raise ValueError("Missing root keys. Can't do derivation.") - if hardened: index += 2**31 if private: + if not self._xprivate_key: + raise ValueError("Missing private key. Can't do private derivation.") + private_node = ( self._xprivate_key[:32], self._xprivate_key[32:], @@ -338,6 +338,9 @@ def derive( ) return self._derive_private_child_key_by_index(private_node, index) + if not self._public_key: + raise ValueError("Missing public key. Can't do public derivation.") + public_node = ( self._public_key, self._chain_code, diff --git a/test/pycardano/crypto/test_bip32.py b/test/pycardano/crypto/test_bip32.py index 0559bedf..48eece73 100644 --- a/test/pycardano/crypto/test_bip32.py +++ b/test/pycardano/crypto/test_bip32.py @@ -387,3 +387,51 @@ def test_is_entropy_wrong_input(): def test_is_entropy_value_error(): is_entropy = HDWallet.is_entropy("*(#_") assert is_entropy is False + + +def test_non_harden_public_derivation(): + public_key = bytes.fromhex( + "601c86a2310f438079fff07454f4df4ce416bd181d972cd4c4615f15a733ba15" + ) + chain_code = bytes.fromhex( + "8a34b66a32c9d2d61d1d7a0e8fcf167efae3fb556af74808cd1ba8a22251c031" + ) + hdwallet = HDWallet(chain_code=chain_code, public_key=public_key) + hdwallet = hdwallet.derive(0, private=False, hardened=False) + child1 = hdwallet.derive(0, private=False, hardened=False) + child2 = hdwallet.derive(1, private=False, hardened=False) + child3 = hdwallet.derive(2, private=False, hardened=False) + + assert ( + child1.public_key.hex() + == "b3f354cbdc2837f823c5e0585995d3bd2d6edf1dc9fc8a1a90d01840c519408d" + ) + assert ( + child2.public_key.hex() + == "363aa29a3c93085859310ccddb182abcca18db6f6897a4f936ae82ba0a15af90" + ) + assert ( + child3.public_key.hex() + == "db58a4102f555ccb64a0db45259799cbd42fac14f7f6fd1059557fef3961e2c0" + ) + + +def test_non_harden_public_derivation_without_pubkey(): + chain_code = bytes.fromhex( + "8a34b66a32c9d2d61d1d7a0e8fcf167efae3fb556af74808cd1ba8a22251c031" + ) + hdwallet = HDWallet(chain_code=chain_code) + with pytest.raises(ValueError): + hdwallet.derive(0, private=False, hardened=False) + + +def test_non_harden_private_derivation_without_privkey(): + public_key = bytes.fromhex( + "601c86a2310f438079fff07454f4df4ce416bd181d972cd4c4615f15a733ba15" + ) + chain_code = bytes.fromhex( + "8a34b66a32c9d2d61d1d7a0e8fcf167efae3fb556af74808cd1ba8a22251c031" + ) + hdwallet = HDWallet(chain_code=chain_code, public_key=public_key) + with pytest.raises(ValueError): + hdwallet.derive(0, private=True, hardened=False) From f6d9a20a04c4fbc793290007afc15f6ed0a3c883 Mon Sep 17 00:00:00 2001 From: Jerry Date: Fri, 26 Sep 2025 19:42:41 -0700 Subject: [PATCH 2/2] Fix type check --- pycardano/crypto/bip32.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/pycardano/crypto/bip32.py b/pycardano/crypto/bip32.py index 2bf90490..e6454228 100644 --- a/pycardano/crypto/bip32.py +++ b/pycardano/crypto/bip32.py @@ -326,7 +326,7 @@ def derive( index += 2**31 if private: - if not self._xprivate_key: + if self._xprivate_key is None: raise ValueError("Missing private key. Can't do private derivation.") private_node = ( @@ -336,17 +336,22 @@ def derive( self._chain_code, self._path, ) - return self._derive_private_child_key_by_index(private_node, index) - if not self._public_key: - raise ValueError("Missing public key. Can't do public derivation.") + if any(x is None for x in private_node): + raise ValueError(f"None values in private node: {private_node}") + + return self._derive_private_child_key_by_index(private_node, index) # type: ignore public_node = ( self._public_key, self._chain_code, self._path, ) - return self._derive_public_child_key_by_index(public_node, index) + + if any(x is None for x in public_node): + raise ValueError(f"None values in public node: {public_node}") + + return self._derive_public_child_key_by_index(public_node, index) # type: ignore def _derive_private_child_key_by_index( self, private_pnode: Tuple[bytes, bytes, bytes, bytes, str], index: int