ebellocchia / bip_utils

Generation of mnemonics, seeds, private/public keys and addresses for different types of cryptocurrencies
MIT License
324 stars 86 forks source link

Derivation data explanation? #88

Closed AFlowOfCode closed 1 year ago

AFlowOfCode commented 1 year ago

Hi, I have been playing around with this and it is an excellent tool that is easy to use. I am still learning about HD key generation and I hope you can help me clear up a couple things that look confusing when I print the derivation data for nist256p1 keys. I apologize in advance if the explanations are obvious! I would be very happy with a link to somewhere the answers to my questions are explained.

Below is the code I'm using, which I modified only slightly from this example.

"""Example of keys derivation using BIP32 (nist256p1 curve)."""
from bip_utils import (
    Bip32Slip10Nist256p1, Bip39MnemonicGenerator, Bip39SeedGenerator, 
    Bip39WordsNum)

# Generate random mnemonic
mnemonic = Bip39MnemonicGenerator().FromWordsNumber(Bip39WordsNum.WORDS_NUM_24)

# Generate seed from mnemonic
seed_bytes = Bip39SeedGenerator(mnemonic).Generate()

# Construct from seed, using nist256p1 curve for key derivation
bip32_mst_ctx = Bip32Slip10Nist256p1.FromSeed(seed_bytes)

# master derivation data
print('Master derivation data')
print('depth:', bip32_mst_ctx.Depth().ToInt())
print('is master:', bip32_mst_ctx.FingerPrint().IsMasterKey())
print('fingerprint:', str(bip32_mst_ctx.FingerPrint()))
print('parent is master:', bip32_mst_ctx.ParentFingerPrint().IsMasterKey())
print('parent fingerprint:', str(bip32_mst_ctx.ParentFingerPrint()))
print('\n')

# Derive a path
bip32_der_ctx = bip32_mst_ctx.DerivePath("m/44'/888'/0'/0/0")

# child derivation data
print('Child derivation data')
print('depth:', bip32_der_ctx.Depth().ToInt())
print('is master:', bip32_der_ctx.FingerPrint().IsMasterKey())
print('fingerprint:', str(bip32_der_ctx.FingerPrint()))
print('parent is master:', bip32_der_ctx.ParentFingerPrint().IsMasterKey())
print('parent fingerprint:', str(bip32_der_ctx.ParentFingerPrint()))

Here is example output:

Master derivation data
depth: 0
is master: False
fingerprint: f414e809
parent is master: True
parent fingerprint: 00000000

Child derivation data
depth: 5
is master: False
fingerprint: a8557683
parent is master: False
parent fingerprint: b48c04f1

Questions about the output:

Thank you for your help!

ebellocchia commented 1 year ago

Hi,

  1. When you directly derive a path using DerivePath, you are deriving a new child at each /, so m/44'/888'/0'/0/0 means you derived 5 children keys and that's why the depth is 5 (for more information, see here). That's also the reason why the fingerprint of the child doesn't match the master one (b48c04f1 is the fingerprint of the parent key, i.e. m/44'/888'/0'/0).
  2. I understand your confusion here, maybe I should move the IsMasterKey method to the Bip32Base class. However, conceptually, the fingerprint is the hash160 of the current public key, so it's always different from zero and therefore FingerPrint().IsMasterKey() cannot return true. The parent fingerprint, instead, is the fingerprint of the parent key and it's set to zero for the master key by default, that's why bip32_mst_ctx.ParentFingerPrint().IsMasterKey() returns true.

I hope it helps.

Regards, Emanuele

AFlowOfCode commented 1 year ago

Thanks, very helpful!