I am trying to create a set of public/private keys from a mnemonic based on BIP0039. I am working in Python.
Here is the code I have so far:
from mnemonic import Mnemonic
mnemon = Mnemonic('english')
words = mnemon.generate(256)
mnemon.check(words)
seed = mnemon.to_seed(words)
In BIP0039, it is stated that you should be able to get to the Keys with a seed, but I haven't been able to figure it out in Python using bip32utils. Does anyone have an example of how to use bip32utils to convert a seed into private/public keys and their respective addresses?
The generation of the seed from the mnemonic is already implemented in the posted code.
The root key is derived from the seed with:
root_key = bip32utils.BIP32Key.fromEntropy(seed)
For BIP32 the child keys are created with:
child_key = root_key.ChildKey(0).ChildKey(0)
and for BIP44:
child_key = root_key.ChildKey(44 + bip32utils.BIP32_HARDEN).ChildKey(0 + bip32utils.BIP32_HARDEN).ChildKey(0 + bip32utils.BIP32_HARDEN).ChildKey(0).ChildKey(0)
The BIP32Key
class encapsulates the key and provides different methods to retrieve the keys in different formats.
Example for BIP32:
from mnemonic import Mnemonic
import bip32utilsmnemon = Mnemonic('english')
#words = mnemon.generate(256)
#print(words)
#mnemon.check(words)
#seed = mnemon.to_seed(words)
seed = mnemon.to_seed(b'lucky labor rally law toss orange weasel try surge meadow type crumble proud slide century')
print(f'BIP39 Seed: {seed.hex()}\n')root_key = bip32utils.BIP32Key.fromEntropy(seed)
root_address = root_key.Address()
root_public_hex = root_key.PublicKey().hex()
root_private_wif = root_key.WalletImportFormat()
print('Root key:')
print(f'\tAddress: {root_address}')
print(f'\tPublic : {root_public_hex}')
print(f'\tPrivate: {root_private_wif}\n')child_key = root_key.ChildKey(0).ChildKey(0)
child_address = child_key.Address()
child_public_hex = child_key.PublicKey().hex()
child_private_wif = child_key.WalletImportFormat()
print('Child key m/0/0:')
print(f'\tAddress: {child_address}')
print(f'\tPublic : {child_public_hex}')
print(f'\tPrivate: {child_private_wif}\n')
produces the output:
BIP39 Seed: 487a440fb26cb376168b6b88a2e46699cb9967bdc4a107fab571f6fdeaab02ea95d149073b3319735c5eace5acafd362edd1ad4c3ac3f655aaa6468973999500Root key:Address: 15Zpz6hJkSkAiw1A5Sm9UoemCVBCuW1SSPPublic : 036830d1cbcecf9e01ce1ddb154ccb754a6a765d06b3b48dced926861e03bd9485Private: KzKjSsprRaWBfVy3oPNwPJBAzVxLXU5AAT5Xe9EJh5pJjpJAqP7qChild key m/0/0:Address: 1AP5U7iDUrvH8B1m1qiarbkA31Ux7jX8YFPublic : 03a78bb2b1fb86280b4091e5cdffc5d8c87430f5c0988e84a7c5d972bb3f1a1b93Private: L47DQmmwwc88oZLPmyZr7CQWn1RzayBmH6gSpnFoMRCCTsR5yRpN
This can be verified using the website https://iancoleman.io/bip39/#english by entering the mnemonic used in the example above into the BIP39 Mnemonic field and selecting BIP32 as the derivation path.
The keys can be dumped in different formats using the BIP32Key#dump()
method, e.g.:
root_key.dump()
provides the following output:
* Identifier* (hex): b'3215de8b72f8c407682a6e9334ccd11ae17b1f9c'* (fpr): b'3215de8b'* (main addr): 15Zpz6hJkSkAiw1A5Sm9UoemCVBCuW1SSP
* Secret key* (hex): 5c9c29e08d1ee9d3c8295ba2a931a9f0166e4282cc01702549664736a16b3a89* (wif): KzKjSsprRaWBfVy3oPNwPJBAzVxLXU5AAT5Xe9EJh5pJjpJAqP7q
* Public key* (hex): b'036830d1cbcecf9e01ce1ddb154ccb754a6a765d06b3b48dced926861e03bd9485'
* Chain code* (hex): b'43088cf562e569922e1c1d0d689144ca2b171cb3cc3b2fedaa198f63be7ec130'
* Serialized* (pub hex): b'0488b21e00000000000000000043088cf562e569922e1c1d0d689144ca2b171cb3cc3b2fedaa198f63be7ec130036830d1cbcecf9e01ce1ddb154ccb754a6a765d06b3b48dced926861e03bd9485'* (prv hex): b'0488ade400000000000000000043088cf562e569922e1c1d0d689144ca2b171cb3cc3b2fedaa198f63be7ec130005c9c29e08d1ee9d3c8295ba2a931a9f0166e4282cc01702549664736a16b3a89'* (pub b58): xpub661MyMwAqRbcFD9E5CavptgKf8JFbkynXnRui6zHDi7TveyV1vnebzqJ1UUDRbcWjBLNy29ABLUxgevE86Pmt3PNMDZFzLyRzQuebs5Kn1G* (prv b58): xprv9s21ZrQH143K2j4kyB3vTkjb76TmCJFwAZWJuiaffNaV3reLUPUQ4CWpABQbzZoo1SvSbuykaZfwj241YvtCs9FVpeKMAFd9eXvQTZwxSNU
Btw, the source code of BIP32Key#dump()
is also a nice description of which method returns which format.
Edit:
The mnemonic library provides the method Mnemonic#to_hd_master_key()
which returns the extended private key Base58 encoded as defined e.g. in bitcon/bips, xprv...
. If this is enough for you, then you do not need bip32utils.
However, as far as I can see, there is no support within mnemonic to derive the private key from this, the chain code, the public or extended public key. This is just implemented in the bip32utils class.
It is not clear to me which libraries you can use and which not. You may have to implement the missing functionalities yourself (with corresponding effort):
Chain code and private key can be determined from the extended private key. For this you need only knowledge about the format (see e.g. bitcon/bips). The public key can be derived from the private key if the curve is known (secp256k1 for Bitcoin) (ec arithmetic or an ec library is required for this) and thus the extended public key. bip32utils can serve as a blueprint for this.