• Hash256
  • Hash160
  • Reverse Bytes
  • Hexadecimal
  • Satoshis

Derivation Paths

How HD wallets derive keys.

BIP 44, BIP 49, BIP 84

The cool thing about extended keys is that they can derive children, and these child keys can derive more children, and so on. This allows you to create a tree of extended keys, with each key having its own unique derivation path from the master key.

You can derive keys in any way you want. But to help with compatibility between wallets, we have a set structure for how we derive keys for use in a hierarchical deterministic wallet.

The most common derivation paths used are:

  • BIP 44: m/44'/0'/0' (for 1addresses)
  • BIP 49: m/49'/0'/0' (for 3addresses)
  • BIP 84: m/84'/0'/0' (for bc1addresses)

1. Notation

First of all, we have a basic notation for describing the derivation path for a specific extended key. For example:

m/0/1/3'

The slashes / indicate a new level in the tree (a new child). The numbers (e.g. 0) indicate the child number from the parent.

The only other thing you need to know about the notation is that a ' or h indicates a hardened child extended private key (which means that the public keys it creates cannot be derived by the extended public key):

  • 0 - Normal Child (index 0)
  • 0' - Hardened Child (index 2147483648)

This ' just saves us having to write the full index numbers for hardened children. For example, 3' means index 2147483651.

Tip: You can derive up to 4294967296 children from a single extended key. The first half are for normal children, and the second half are for hardened children.

Note: Deriving hardened children is the default. Normal children are only derived when it would be useful to have a corresponding extended public key for deriving the same public keys.

2. Wallet Structure

To help with consistency between wallets, BIP 44 introduced the following structure:

m / purpose' / coin_type' / account' / change / index
The levels in the tree have a meaning.
m: Master

The master key (created from a seed).

m/44': Purpose (hardened)

This specifies the upcoming wallet structure.

There are three schemes currently being used by wallets:

Tip: The number reflects the number of the BIP. New schemes can use different BIP numbers.

m/44'/0': Coin Type (hardened)

The cryptocurrency the keys will be used for.

Different cryptocurrencies can use the same private keys and public keys derived from a seed. So instead of having separate seeds for different currencies (or using the same public keys on different chains), we can use the same seed with different derivation paths instead.

0' = Bitcoin
1' = Bitcoin (Testnet)
2' = Litecoin
3' = Dogecoin
...

Full list: https://github.com/satoshilabs/slips/blob/master/slip-0044.md

This is useful in hardware wallets, where you can have a single seed and use it for holding a variety of different coins.

m/44'/0'/0': Account (hardened)

This allows you to create separate accounts for funds. The default account is 0'.

For example, you can use the same seed yet still create separate “pots” for receiving payments. The coins in these separate accounts will never be mixed.

Tip: You could obviously create many different accounts at various indexes at this level. But to keep recovery simple, a wallet should create accounts in sequential order, and not create a new account if a previous one has not been used.

m/44'/0'/0'/0: Change

The keys and addresses we use are separated in to “Receiving” and “Change”.

  • Receiving = 0 - Addresses that we will give out to people for receiving payments.
  • Change = 1 - Addresses we use for sending change back to ourselves when we make transactions.

This means you will always be able to identify the coins that arrived from external payments.

m/44'/0'/0'/0/0: Index

These are the extended keys that you use for their private keys and public keys for actual usage in the wallet.

So as you can see, the first few levels in the path are just used to structure the hierarchical deterministic wallet in a practical way.

The actual keys used for addresses are in lowest level of the tree.

3. Derivation Paths

Here are some actual derivation paths used by wallets.

BIP 32: m/0'/0/0 (deprecated)

This is the original derivation path specification in BIP 32.

It just used the first child for accounts, and the next two children below for separating external and internal addresses. The children of these are used for their actual private keys and public keys to create addresses.

m / account' / external / index

This is a nice and simple derivation path, but it doesn’t allow for the option of creating alternative derivation path schemes.

This is where BIP 44, BIP 49, and BIP 84 come in.

BIP 44: m/44'/0'/0'/0/0

BIP 44 builds upon the original BIP 32 scheme to include a purpose1 (which is like a version number to identify the upcoming scheme), as well as a coin type so that the same seed can be used to generate keys for different cryptocurrencies.

The public keys are encoded to 1addresses (P2PKH).

BIP 49: m/49'/0'/0'/0/0

BIP 49 uses the same structure as BIP 44, but is used to indicate that the public keys should be encoded in to 3addresses (P2WPKH-P2SH).

BIP 49 Serialization

The extended keys in the BIP 49 derivation path use the version bytes 049d7878 “yprv” or 049d7cb2 “ypub” during serialization. This allows you to identify an extended key when it is part of the BIP 49 scheme.

For example:

yprvABrGsX5C9jant45o1Au7iHH54A8GXQH9SGhK5vkYKPUBDYsFy6KNUWX24moUE6KxoCh2qtZ8UpLaDWQiqt4aPdvvgjszQ4VrbLpfp5patGg

BIP 84: m/84'/0'/0'/0/0

BIP 84 uses the same structure as BIP 44, but is used to indicate that the public keys should be encoded in to bc1addresses (P2WPKH).

BIP 84 Serialization

The extended keys in the BIP 84 derivation path use the version bytes 04b2430c “zprv” or 04b24746 “zpub” during serialization. This allows you to identify an extended key when it is part of the BIP 84 scheme.

For example:

zprvAWgYBBk7JR8GjMGuqXgjvNNaE8GiU2GeMPDXsKeRhPr4GegVDkUw6aBA5ym4DzytCqoqbN9gwUh86o2HZaUbBscXZ5aQyyKLs4tKCeThpsa

4. Example

The following takes a seed (mnemonic sentence or hex) and derivation path, and shows you the address for the private extended key in that path (along with the next few children too).

Try it! - Derivation Paths

BIP 44: m / purpose’ / coin type’ / account’ / receving / index

Addresses:

m/44h/0h/0h/0/0: 1AZnveys2k5taGCCF743RtrWGwc58UMeq
m/44h/0h/0h/0/1: 1AMYJTJyV4o1hwNACJtfdXBW6BiD1f5FXb
m/44h/0h/0h/0/2: 1NPFFtSiFRatoeUf35rwYb8j8C1u7sVhGa
m/44h/0h/0h/0/3: 1L44VTYEzWesp8cxnXcPGbUzuwTYoSW9at
m/44h/0h/0h/0/4: 1FK85vpZavzZu6oBCvBcmD4FWXQT5fVYRu
m/44h/0h/0h/0/5: 12QaHfWLtyuMwNXuap3FscMY434bw4TS6n
m/44h/0h/0h/0/6: 1NeFG5BYAR9bnjAG72SDYKvNZBH4kPa8r1
m/44h/0h/0h/0/7: 1yF3BiHqbQKL4aRfNYHQt4ZpgNagC4nQe
m/44h/0h/0h/0/8: 144vmUhuAZJsV3m2GsP5Kqp55Pmzwx2gna
m/44h/0h/0h/0/9: 1DQM5w6C7gNaCKBxQV3rXKftcamRKDPQ2M
m/44h/0h/0h/0/10: 17XRvBac5xpgMVr6LbsDA56fgsaAed4oEV
m/44h/0h/0h/0/11: 1BSQC3Qn38UT2WVfcM6LdybkfE7tTGW5M2
m/44h/0h/0h/0/12: 1KUG4EDePnG97xQNXtuU9Xmp4sThqFvSoS
m/44h/0h/0h/0/13: 18sXnPcBnXBRFBYbqr85aKPPNpwT4f52a8
m/44h/0h/0h/0/14: 15S2gpAVvprN1GPE44oXCdtkA4L7yQtBkX
m/44h/0h/0h/0/15: 1FvC2STfbj7dcr2ApAPhagnSCP5Dmy79nH
m/44h/0h/0h/0/16: 15VZHWTEjnQuJSvUHzS7K6gmYjNv4A5cVJ
m/44h/0h/0h/0/17: 1N4S7Z43gb22PDCcpjHhX25cgDSLxegdWm
m/44h/0h/0h/0/18: 1MzS2BktGqokVM4kDuB6VavjLuib72W2je
m/44h/0h/0h/0/19: 1GDLeWJ4FcK2uiTFvLshtVcBArA7M9ECxq

Gap Limit: When recovering a wallet from a seed, you should only check the first 20 receiving addresses for a balance. If none have been used in the past, you can consider the account as unused.

Never enter your actual seed in to a website. Websites can save what you enter and use it to steal your coins.

5. Code

To save on code, these snippets use handy libraries (bitcoin-ruby, hdkeychain) for deriving extended keys.

Ruby

require 'bitcoin' # sum gem install bitcoin-ruby

seed = "67f93560761e20617de26e0cb84f7234aaf373ed2e66295c3d7397e6d7ebe882ea396d5d293808b0defd7edd2babd4c091ad942e6a9351e6d075a29d4df872af"

# ------
# BIP 44
# ------
# Note: Hardened keys start at 2**31 (the second half of the 2**32 possible children).

m = Bitcoin::ExtKey.generate_master(seed.htb) # convert hex to binary
purpose   = m.derive(2**31+44) # m/44'
coin_type = m.derive(2**31+44).derive(2**31+0) # m/44'/0'
account   = m.derive(2**31+44).derive(2**31+0).derive(2**31+0) # m/44'/0'/0'
receiving = m.derive(2**31+44).derive(2**31+0).derive(2**31+0).derive(0) # m/44'/0'/0'/0

20.times do |i| 
    puts receiving.derive(i).addr # m/44'/0'/0'/0/*
end

Go

package main

import (
    "encoding/hex" // byte array to hex string
    "fmt"

    "github.com/btcsuite/btcd/chaincfg" // chaincfg.MainNetParams
    "github.com/btcsuite/btcutil/hdkeychain" // https://godoc.org/github.com/btcsuite/btcutil/hdkeychain
)

func main() {

    // From Seed
    seedhex := "67f93560761e20617de26e0cb84f7234aaf373ed2e66295c3d7397e6d7ebe882ea396d5d293808b0defd7edd2babd4c091ad942e6a9351e6d075a29d4df872af"
    seed, _ := hex.DecodeString(seedhex) // hex to bytes
    // fmt.Println("seed: ", seedhex)

    // Generate Seed
    // seed, _ := hdkeychain.GenerateSeed(uint8(16))
    // fmt.Println(hex.EncodeToString(seed)) // bytes to hex

    // ------
    // BIP 44
    // ------
    // m
    m, _ := hdkeychain.NewMaster(seed, &chaincfg.MainNetParams)

    // m/44h
    purpose, _ := m.Child(hdkeychain.HardenedKeyStart + 44)

    // m/44h/0h
    coin, _ := purpose.Child(hdkeychain.HardenedKeyStart + 0)

    // m/44h/0h/0h
    account, _ := coin.Child(hdkeychain.HardenedKeyStart + 0)

    // m/44h/0h/0h/0
    receiving, _ := account.Child(0) // 0 = receiving, 1 = change

    // m/44h/0h/0h/0/*
    for i := 0; i < 20; i++ {
        index, _ := receiving.Child(uint32(i)) // takes an unsigned integer
        address, _ := index.Address(&chaincfg.MainNetParams)
        fmt.Println(address)
    }
}

  1. BIP 43 (Purpose Field)↩︎

By Greg Walker,

Last Updated: 04 Feb 2021
  • 04 Feb 2021: spelling fixes
  • 21 Jul 2020: redirected and renamed files from /guide/ to /technical/
  • 21 Jul 2020: renamed /guide/ to /technical/
Back to Top

Hey there, it's Greg.

I'll let you know about cool website updates, or if something seriously interesting happens in bitcoin.


Don't worry, it doesn't happen very often.