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.