diff --git a/bipentropy/bipentropy.py b/bipentropy/bipentropy.py index 7a13fbf..727733a 100644 --- a/bipentropy/bipentropy.py +++ b/bipentropy/bipentropy.py @@ -24,6 +24,7 @@ import hashlib from mnemonic import Mnemonic as bip39 from pycoin.symbols.btc import network as BTC from pycoin.encoding.bytes32 import from_bytes_32, to_bytes_32 +import base58 class BIPEntropy(object): @@ -60,14 +61,21 @@ class BIPEntropy(object): def bip32_xprv_to_xprv(self, path, xprv_string): path = self.__decorate_path(path) - node = BTC.parse.bip32_prv(xprv_string).subkey_for_path(path) + ent = self.bip32_xprv_to_entropy(path, xprv_string) - # if API to pycoin hadn't been shitcoined: - # return BIP32Node(node.chain_code(), secret_exponent=node.secret_exponent()).hwif() - - node._depth = 0 - node._parent_fingerprint = bytes(4) - node._child_index = 0 + # From Peter Gray + # Taking 64 bytes of the HMAC digest, the first 32 bytes are the chain code, and second 32 bytes are the private + # key for BIP32 XPRV value. Child number, depth, and parent fingerprint are forced to zero. + prefix = b'\x04\x88\xad\xe4' + depth = b'\x00' + parent_fingerprint = b'\x00\x00\x00\x00' + child_num = b'\x00\x00\x00\x00' + chain_code = ent[:32] + private_key = b'\x00' + ent[32:] + extended_key = prefix + depth + parent_fingerprint + child_num + chain_code + private_key + checksum = hashlib.sha256(hashlib.sha256(extended_key).digest()).digest()[:4] + derived_xprv_string = base58.b58encode(extended_key + checksum).decode() + node = BTC.parse(derived_xprv_string) return node.hwif(as_private=True) diff --git a/test_entropy.py b/test_entropy.py index d9e7419..2b62bbb 100644 --- a/test_entropy.py +++ b/test_entropy.py @@ -25,6 +25,7 @@ import pytest XPRV = 'xprv9s21ZrQH143K2LBWUUQRFXhucrQqBpKdRRxNVq2zBqsx8HVqFk2uYo8kmbaLLHRdqtQpUm98uKfu3vca1LqdGhUtyoFnCNkfmXRyPXLjbKb' + def test_mnemonic(): e = bipentropy.BIPEntropy() mnemonic = 'install scatter logic circle pencil average fall shoe quantum disease suspect usage' @@ -58,10 +59,10 @@ def test_entropy_to_mnemonic(): assert e.entropy_to_bip39(entropy, 24) == words24 def test_wif_from_entropy(): - # PDG: not sure about this? e = bipentropy.BIPEntropy() - entropy = e.bip32_xprv_to_entropy("m/83696968'/0'/0'", XPRV) - assert e.entropy_to_wif(entropy) == 'L5G6UFMvJaFt1KPvupEtT8TUN2YrFnQJm1LA2nEczWrR7MuoxB1Z' + entropy = e.bip32_xprv_to_entropy("m/83696968'/2'/0'", XPRV) + entropy = entropy[:32] + assert e.entropy_to_wif(entropy) == 'Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp' def test_mnemonic(): e = bipentropy.BIPEntropy() @@ -83,7 +84,7 @@ def test_mnemonic(): def test_xprv(): e = bipentropy.BIPEntropy() result = e.bip32_xprv_to_xprv("83696968'/32'/0'", XPRV) - assert result == 'xprv9s21ZrQH143K3KJoGoKpsDsWdDNDBKs1wqFymBpCGJtrYXrfKzykGDBadZq5SrNde22F83X9qhFZr4uyV9TptTgLqCBc6XFN9tssphdxVeg' + assert result == 'xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UGXMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX' @pytest.mark.parametrize('path, width, expect', [ ("83696968'/128169'/32'/0'", 32, 'ea3ceb0b02ee8e587779c63f4b7b3a21e950a213f1ec53cab608d13e8796e6dc'), @@ -99,9 +100,9 @@ def test_bipentropy_applications(): 'near account window bike charge season chef number sketch tomorrow excuse sniff circle vital hockey outdoor supply token' assert app.xprv(XPRV, 0) == \ - 'xprv9s21ZrQH143K3KJoGoKpsDsWdDNDBKs1wqFymBpCGJtrYXrfKzykGDBadZq5SrNde22F83X9qhFZr4uyV9TptTgLqCBc6XFN9tssphdxVeg' + 'xprv9s21ZrQH143K2srSbCSg4m4kLvPMzcWydgmKEnMmoZUurYuBuYG46c6P71UGXMzmriLzCCBvKQWBUv3vPB3m1SATMhp3uEjXHJ42jFg7myX' - assert app.wif(XPRV, 0) == 'L5G6UFMvJaFt1KPvupEtT8TUN2YrFnQJm1LA2nEczWrR7MuoxB1Z' + assert app.wif(XPRV, 0) == 'Kzyv4uF39d4Jrw2W7UryTHwZr1zQVNk4dAFyqE6BuMrMh1Za7uhp' assert app.hex(XPRV, 0, 32) == 'ea3ceb0b02ee8e587779c63f4b7b3a21e950a213f1ec53cab608d13e8796e6dc'