Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 19 additions & 11 deletions pycardano/crypto/bip32.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -322,28 +322,36 @@ 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 self._xprivate_key is None:
raise ValueError("Missing private key. Can't do private derivation.")

private_node = (
self._xprivate_key[:32],
self._xprivate_key[32:],
self._public_key,
self._chain_code,
self._path,
)
return self._derive_private_child_key_by_index(private_node, index)

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
Expand Down
48 changes: 48 additions & 0 deletions test/pycardano/crypto/test_bip32.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Loading