How to generate Bitcoin keys/addresses from a seed in Python?
Asked Answered
B

1

7

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?

Broadwater answered 15/1, 2019 at 16:6 Comment(0)
D
10

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 bip32utils

mnemon = 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: 487a440fb26cb376168b6b88a2e46699cb9967bdc4a107fab571f6fdeaab02ea95d149073b3319735c5eace5acafd362edd1ad4c3ac3f655aaa6468973999500

Root key:
    Address: 15Zpz6hJkSkAiw1A5Sm9UoemCVBCuW1SSP
    Public : 036830d1cbcecf9e01ce1ddb154ccb754a6a765d06b3b48dced926861e03bd9485
    Private: KzKjSsprRaWBfVy3oPNwPJBAzVxLXU5AAT5Xe9EJh5pJjpJAqP7q

Child key m/0/0:
    Address: 1AP5U7iDUrvH8B1m1qiarbkA31Ux7jX8YF
    Public : 03a78bb2b1fb86280b4091e5cdffc5d8c87430f5c0988e84a7c5d972bb3f1a1b93
    Private: 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.

Dickerson answered 2/6, 2021 at 16:9 Comment(11)
it looks like you generated the public key for a child key. Can I generate the public master key?Fieldpiece
@GuerlandoOCs - Sure. The master key is identical with root_key and is also a BIP32Key, i.e. it works completely analog, e.g. public_hex = root_key.PublicKey().hex(). With root_key.dump() you get a complete overview.Dickerson
@GuerlandoOCs - I've adapted the post and added the corresponding outputs.Dickerson
what is import bip32utils?Fieldpiece
Oh I see, this does not use only Mnemonic as you said, it also uses another library.Fieldpiece
The problem of using bip32_utils is because I need to install that into a rpi zero with no internet and no possibility for dongle. Since it depends on ecdsa an offline installaiton will not work. mnemonic can be installed but I guess this one notFieldpiece
@GuerlandoOCs - what is import bip32utils? This question is irritating. You mentioned this library yourself in your question: Does anyone have an example of how to use bip32utils to convert a seed... Which library are you referring to? Also, the restrictions mentioned in the comment regarding the use of other libraries should be mentioned in the question. mnemonic offers to my knowledge only few functionalities concerning the keys themselves, see the Edit section of my answer.Dickerson
@GuerlandoOCs - Sorry, I just saw that the original question was not yours at all. Perhaps a new question with a more detailed description of your requirements would make more sense, since your requirements seem to be quite different from those of the OP.Dickerson
No problem, I learned a lot with the answerFieldpiece
thank your for the excellent reply. I'm wondering whether it's possible to create a BIP32Key object from a private key (I have it as a hex value, ascii)? I seem to find no way to do itRegulable
@Regulable - see Can I create a BIP32Key object using a private key?Dickerson

© 2022 - 2024 — McMap. All rights reserved.