4

I am trying to re-generate the receiving addresses (and change addresses, for that matter) my mycelium wallet has generated.

So far I've used trezor's implementation of BIP39 to generate the entropy from the 12 words, and a BIP32 implementation I have used previously (successfully, to generate the same addresses as bitcoin core, which uses a different subkeys scheme but from a tpub, not from entropy), to produce the keys from the entropy.

Here's the code:

from bip32utils import BIP32Key
from bip32utils import BIP32_HARDEN
import bip39

wallet_generator = bip39.Mnemonic('english')
entropy = wallet_generator.to_entropy('12 words here')
key = BIP32Key.fromEntropy(entropy)
account_number = 0
i = 0
print key.ChildKey(44 + BIP32_HARDEN) \
         .ChildKey(0 + BIP32_HARDEN) \
         .ChildKey(account_number + BIP32_HARDEN) \
         .ChildKey(0) \
         .ChildKey(i) \
         .Address()

I am trying to follow BIP44's scheme as described here.

I am getting a key, but not the one that appear in my first mycelium transaction. I've tried to search the first 100 i with account_number 0 to 9, to no avail. Using bip32gen from the command line does not produce the correct key either:

echo YOUR_ENTROPY_IN_HEX_HERE | \
    bip32gen -v \
    -i entropy -f - -x \
    -o addr -F - -X \
    m/44h/0h/0h/0/0

With entropy converted to hex with print ''.join('{:02X}'.format(x) for x in entropy)

What am I missing? Is the entropy with BIP39 part wrong? Is that BIP32 library yielding erroneous addresses? What alternatives are there?

UPDATE:

Thanks to this site, I've seen that the xprv generated from the 12 words is incorrect. So either the bip39 is faulty, or the way I'm using it is.

3
  • Try with the second to last part of the derivation path being hardened. Right now you have m/44'/0'/0'/0/i, try m/44'/0'/0'/0'/i.
    – Andrew Chow
    Nov 12, 2017 at 5:34
  • @AndrewChow still nothing.
    – Gabriel
    Nov 12, 2017 at 14:59
  • not sure what exactly shall be achieved, but I know that every wallet has different type of implementations, as outlined here in a post: bitcoin.stackexchange.com/questions/60690/… - maybe this helps... Nov 16, 2017 at 11:34

1 Answer 1

3
+50

The difficulty is with the poorly named BIP32Key.fromEntropy.

Typically to create a new wallet, you:

  1. Get some entropy from a cryptographically secure random source, at least 128 bits and must be a multiple of 32 bits.
  2. Convert the entropy to a mnemonic (this conversion is not a one-way function, it's bijective).
  3. Convert the mnemonic to a 512-bit seed (this conversion is one way).
  4. Convert the seed to an extended private key (also one way).
  5. Do the BIP-32 derivation and all the rest....

BIP32Key.fromEntropy really should have been named BIP32Key.fromSeed.

Here's an example:

from bip32utils import BIP32Key
from bip32utils import BIP32_HARDEN
import os, bip39

strength_bits = 128
entropy = os.urandom(strength_bits // 8)
wallet_generator = bip39.Mnemonic('english')
mnemonic = wallet_generator.to_mnemonic(entropy)
assert wallet_generator.to_entropy(mnemonic) == entropy  # see, bijective!

# Or specify the mnemonic directly if you prefer:
mnemonic = 'aware report movie exile buyer drum poverty supreme gym oppose float elegant'

print mnemonic
seed = bip39.Mnemonic.to_seed(mnemonic)
key = BIP32Key.fromEntropy(seed)
account_number = 0
i = 0
print key.ChildKey(44 + BIP32_HARDEN) \
         .ChildKey(0 + BIP32_HARDEN) \
         .ChildKey(account_number + BIP32_HARDEN) \
         .ChildKey(0) \
         .ChildKey(i) \
         .Address()

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.