Derivation Paths

Locating keys and addresses in HD wallets

BIP 44, BIP 49, BIP 84

A derivation path provides the location of keys (and addresses) in an HD wallet.

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 in Bitcoin are:

Bitcoin wallets use common derivation paths for deriving new addresses. This helps with compatibility and the recovery of keys between different wallets.

tool-66496fb4d75d6
Tool Icon

Derivation Paths

Derive multiple private keys and addresses from a mnemonic sentence or seed using a specified derivation path.

Mnemonic Sentence + Passphrase
0 words extra word
0 bytes

Starting with m/, enter a full derivation path to a specific child key. For example, derivation paths are often shortened to m/44'/0'/0', but that assumes you want to see the first key in the receiving section, which is m/44'/0'/0'/0/0. In other words, you may want to add an /0/0 to the base path you get from a wallet to retrieve the addresses you expect.

m / purpose' / coin type' / account' / receiving or change / index
Settings

Never enter your seed in to a website, or use a seed generated by a website. Websites can easily save the seed and use it to steal all your bitcoins.

0 secs

Notation

What does a derivation path mean?

Firstly, we have a basic notation for describing the derivation path for a specific extended private key in an HD wallet.

For example:

m/0/1/3'
Diagram explaining the notation of a derivation path.

You can derive up to 4,294,967,296 (just over 4 billion) children from a single extended key. The first half are for normal children, and the second half are for hardened children.

The ' syntax saves on having to write the full index numbers for hardened children. For example, 3' means index 2147483651 (or 2147483648 + 3).

Wallet Structure

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

m / purpose' / coin_type' / account' / change / index
Diagram showing the meaning of the different levels in a derivation path.

m: Master

This is the master extended key, which is the first extended private key at the top of the HD wallet tree.

All derivation paths start with an m.

This master extended key is created from the seed.

m/44': Purpose (hardened)

The first level specifies the upcoming wallet structure.

There are three schemes currently being used by wallets:

This number reflects the number of the BIP.

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

The second level indicates the specific cryptocurrency the keys will be used for.

Different cryptocurrencies can use the same private keys and public keys. 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 (e.g. Trezor), where you can have a single seed and use it for holding a variety of different coins.

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

The third level allows you to create separate accounts for funds.

For example, you can create separate "pots" from the same seed, and the coins in these separate accounts will not be mixed.

The default account index is 0'.

You could obviously create many different accounts at random 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 fourth level separates the keys and addresses in to "Receiving" and "Change":

This allows you to differentiate the coins that have arrived from external payments from the coins that you have sent back to yourself as change.

These are normal children. This means they have corresponding extended public keys, which can be used to derive the public keys independently for the children below.

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

The fifth level contains the keys that you actually use for sending and receiving payments in the wallet.

So every time you generate a new address to receive a payment, you're incrementing the index for the child key at this level (starting from 0).

So the actual keys used for addresses are in the lowest level of the key tree; the first few levels in the path are just used to structure the hierarchical deterministic wallet in a functional way.

You don't actually this level for extended keys (i.e. for deriving further children). You only use the child keys at this level for their private keys and public keys.

Derivation Paths

What derivation paths do bitcoin wallets use?

Here are the most common derivation paths used by bitcoin wallets.

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

Diagram showing the derivation path for a BIP 32 wallet.

This is the original derivation path specification from BIP 32.

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

This is a 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

Diagram showing the derivation path for a BIP 44 wallet.

BIP 44 builds upon the original BIP 32 scheme to include a purpose (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 first level of 44' indicates that the wallet uses 1addresses (P2PKH).

BIP 44 Extended Key Addresses

The address for an extended key in the BIP 44 derivation path scheme starts with a xprv or xpub.

For example:

xprv9s21ZrQH143K2EP9nDiaJau1McCzYYhL7xsfZn7QJJ2yRS6b1M8L519xr2PkBZnc7Rupi3juCj1FDzCsM1xtwNXfNqJVcdSUca9iGZmoZSa

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

Diagram showing the derivation path for a BIP 49 wallet.

BIP 49 uses the same structure as BIP 44.

The first level of 49' indicates that the wallet uses 3addresses (P2WPKH wrapped in P2SH).

BIP 49 Extended Key Addresses

The address for an extended key in the BIP 49 derivation path scheme starts with a yprv or ypub.

For example:

yprvABrGsX5C9jansXaGcaWCWfzWXaMSVAgq35PtMB1HgJQrUXupG1Hth4p6sEMLBUSXX52dTXLTfPMo7GpS4iNujcDGFAzvCYFxtJDMfAjMP7X

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

Diagram showing the derivation path for a BIP 84 wallet.

BIP 84 uses the same structure as BIP 44.

The first level of 84' indicates that the wallet uses bc1addresses (P2WPKH).

BIP 84 Extended Key Addresses

The address for an extended key in the BIP 84 derivation path scheme starts with a zprv or zpub.

For example:

zprvAWgYBBk7JR8GipmPSwHpim61hYVtRngKxBv78ZuB4JnjXdj3WfTTK8UEtSJvBP6Svi9SCzw283iLzZRznQnvXqts7WhLnT5TA2H13pohcMV

Gap Limit

Diagram showing the gap limit for addresses in an HD wallet.

The gap limit refers to how many unused addresses a wallet will scan through before it stops looking for a balance at further addresses.

The standard gap limit is 20.

Address gap limit is currently set to 20. If the software hits 20 unused addresses in a row, it expects there are no used addresses beyond this point and stops searching the address chain.
BIP 44

So when recovering an HD wallet from a seed, the wallet will start by checking for a balance on the first 20 addresses. If no balance is found at any of these addresses, the wallet will stop checking further addresses and assume that the wallet has not received any payments.

For example, if you generated your own mnemonic seed and decided to receive your first payment at an address sitting at the index m/44'/0'/0'/0/20, if you import this seed in to a different wallet it will likely display a balance of zero.

This gap limit applies to all addresses in the wallet too. So if you receive a payment to the address at m/44'/0'/0'/0/5 (which is fine), but then decide to receive your next payment to an address at m/44'/0'/0'/0/26 (a gap of 21), that second payment will not get picked up if you decide to import your seed in to a different wallet later on.

So basically, you should avoid leaving a gap of 20 addresses between payments.

Tips

Some general tips for working with derivation paths:

Code

Here are some code snippets to show you how you can create different derivation paths from a seed.

I've used existing libraries to help keep the code simple.

This code requires the bitcoin-ruby library.

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

This code requires the hdkeychain library.

package main

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

	"github.com/btcsuite/btcd/btcutil/hdkeychain" // go get -u github.com/btcsuite/btcd/btcutil/hdkeychain
	"github.com/btcsuite/btcd/chaincfg"           // chaincfg.MainNetParams
)

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)
	}
}

Resources