Skip to content

Key derivation

shigeyuki azuchi edited this page Mar 18, 2022 · 6 revisions

bitcoinrb supports key derivation using BIP32 and BIP39, BIP49, BIP84.

Mnemonic code for generating deterministic keys

bitcoinrb supports BIP39.The list of supported languages is under the wordlist directory.

Create word list from the entropy

mnemonic = Bitcoin::Mnemonic.new('english')

entropy = SecureRandom.hex(32)

word_list = mnemonic.to_mnemonic(entropy)
=> ["poet", "nephew", "hero", "bachelor", "valid", "actor", "despair", "hat", "crop", "clip", "success", "comic", "wife", "park", "fit", "artwork", "siege", "dismiss", "subject", "buffalo", "nerve", "pencil", "six", "picnic"]

Recover entropy from word list

mnemonic = Bitcoin::Mnemonic.new('english')

word_list = %w(scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump)

entropy = mnemonic.to_entropy(word_list)
=> c10ec20dc3cd9f652c7fac2f1230f7a3c828389a14392f05

Create seed

mnemonic = Bitcoin::Mnemonic.new('english')

word_list = %w(scissors invite lock maple supreme raw rapid void congress muscle digital elegant little brisk hair mango congress clump)

seed = mnemonic.to_seed(word_list)
=> a555426999448df9022c3afc2ed0e4aebff3a0ac37d8a395f81412e14994efc960ed168d39a80478e0467a3d5cfc134fef2767c1d3a27f18e3afeb11bfc8e6ad

# if there is a passphrase
seed = mnemonic.to_seed(word_list, passphrase: 'TREZOR')
=> 7b4a10be9d98e6cba265566db7f136718e1398c71cb581e1b2f464cac1ceedf4f3e274dc270003c670ad8d02c4558b2f8e39edea2775c9e232c7cb798b069e88

Key derivation

BIP32 based key derivation is possible as follows.

# create new master key.
master_key = Bitcoin::ExtKey.generate_master(seed)

# derive path 'm/0H'
key = @master_key.derive(0, true)

# derive path 'm/0H/1'
child_key = key.derive(1)

# serialize private key
child_key.to_base58
=> xprv9xAaazaeccMiuHCTmFX3Wy13VKqH5i1f2GtWaKLCPjAuiRDnSYgTeXkftzvwM3iw81DHj3pBbrqeqXzaxk9pK9NsZ3NnoGByvwVh2DqptmF

# convert to ext pubkey
ext_pubkey = child_key.ext_pubkey
ext_pubkey.to_base58
=> xpub6B9vzW7YSyv27mGvsH43t6wn3MfmVAjWPVp7Nhjox4htbDYvz5ziCL59kFGzpowJG9PusKfGuBC5M4VtAyign9k8JdkeK6uqeCcGKzorvuV

# recover extended private key from serialized one
ext_privkey = Bitcoin::ExtKey.from_base58('xprv9xAaazaeccMiuHCTmFX3Wy13VKqH5i1f2GtWaKLCPjAuiRDnSYgTeXkftzvwM3iw81DHj3pBbrqeqXzaxk9pK9NsZ3NnoGByvwVh2DqptmF')

# recover extended public key from serialized one
ext_pubkey = Bitcoin::ExtPubkey.from_base58('xpub6B9vzW7YSyv27mGvsH43t6wn3MfmVAjWPVp7Nhjox4htbDYvz5ziCL59kFGzpowJG9PusKfGuBC5M4VtAyign9k8JdkeK6uqeCcGKzorvuV')

Key derivation for BIP49

BIP49 defines the key derivation specification for P2WPKH-nested-in-P2SH account.The key derivation method is the same as above, but the generated address will change. If depth 1 is 49', the address generated in the lower hierarchy will be the address of P2WPKH nested in P2SH.

# m/49'/1'/0'/0/0
key = master_key.derive(49, true).derive(1, true).derive(0, true).derive(0).derive(0)
key.addr
=> 36NvZTcMsMowbt78wPzJaHHWaNiyR73Y4g # P2WPKH-nested-in-P2SH address

Key derivation for BIP84

BIP49 defines the key derivation specification for P2WPKH account.The key derivation method is the same as above, but the generated address will change. If depth 1 is 84', the address generated in the lower hierarchy will be the address of P2WPKH.

# m/84'/0'/0'/0/0
key = master_key.derive(84, true).derive(0, true).derive(0, true).derive(0).derive(0)
key.addr
=> bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu # P2WPKH address