Skip to content

HD Keys

In Addresses we saw that an Address should be used for one payment only. That means a wallet needs a great many keys. Generating each one at random, and backing each one up separately, is not quite ideal: a backup taken yesterday doesn’t hold the key we created this morning.

The BIP32 specification solves this with Hierarchical Deterministic (HD) keys. From a single seed, a wallet derives a whole tree of key pairs, with the root of that tree being a master key. The same seed always gives the same tree, so one backup of the seed covers every key the wallet will ever derive from it.

Figure 1 shows how one gets from a seed to the master key. The example uses the seed from the first BIP32 test vector, and the values underneath are the real ones.

The seed is passed through HMAC-SHA512 with the key “Bitcoin seed”. The 64-byte result is split in two: the left 32 bytes become the master Private Key and the right 32 bytes become the master chain code. Together they form the master extended key.seed: 16 to 64 bytesHMAC-SHA512( “Bitcoin seed”, seed )left 32 bytesright 32 bytesmaster Private Keymaster chain codemaster extended key000102030405060708090a0b0c0d0e0fe8f32e72 … c8436b35873dff81 … ed37d50864 bytes
Figure 1: Deriving the master key from a seed

Referring to Figure 1, we notice a few interesting things:

  1. The seed is a random value of between 16 and 64 bytes. In practice it usually comes from a Mnemonic, the list of words a user writes down.
  2. The seed is passed through HMAC-SHA512, using the fixed string Bitcoin seed as the HMAC key. This gives us 64 bytes.
  3. The left 32 bytes become the master Private Key. The right 32 bytes become the master chain code.

The chain code is the new ingredient here. It is not a key, and it signs nothing. It is extra entropy that goes into the derivation of every child key, and it is what stops someone who knows only a Public Key from deriving that key’s children.

A key together with its chain code is called an extended key. With a Private Key it is an extended Private Key (xprv), and with the matching Public Key an extended Public Key (xpub). An extended key carries everything needed to derive the part of the tree below it.

To hand an extended key from one program to another, BIP32 serialises it into 78 bytes, and encodes those with Base58Check, the same encoding we use for Addresses. The 78 bytes hold:

  • a 4-byte version, which gives the string its familiar prefix: xprv and xpub on mainnet, tprv and tpub on testnet,
  • the depth of the key in the tree, 0 for the master key,
  • a 4-byte fingerprint of the parent key, taken from the parent’s Public Key Hash,
  • the 4-byte index of this key among its parent’s children,
  • the 32-byte chain code,
  • the 33-byte key: a compressed Public Key, or a Private Key with a 00 byte in front.

The master key of Figure 1, serialised as an xprv, looks like this:

xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi

An xprv is as good as a seed for everything below it in the tree. Treat it with the same care as the seed itself.

Every key in the tree can have up to 2³² children, numbered by a 4-byte index. The indexes are split into two halves:

  • normal children, with indexes from 0 to 2³¹ - 1,
  • hardened children, with indexes from 2³¹ upward. We write a hardened index with an apostrophe, so 0' is the index 2³¹.

Figure 2 shows how a child is derived from its parent.

The parent chain code is the HMAC-SHA512 key, and the parent key plus the 4-byte index is the data. The parent key is the parent Public Key for a normal child, or a zero byte plus the parent Private Key for a hardened child. The left 32 bytes of the result are added to the parent Private Key, modulo n, to give the child Private Key. The right 32 bytes become the child chain code.parent chain codeparent keyindex iHMAC-SHA512( chain code, parent key + i )left 32 bytesright 32 bytesleft + parent Private Key (mod n)child Private Keychild chain codenormal: parent Public Keyhardened: 00 + parent Private Key4 bytes, big-endianFrom a parent Public Key: child Public Key = left × G + parent Public Key
Figure 2: Deriving a child key from its parent

Referring to Figure 2:

  1. The parent’s chain code is used as the HMAC key.
  2. The data is the parent key followed by the 4-byte index. For a normal child, the parent key is the parent’s compressed Public Key. For a hardened child, it is the parent’s Private Key, with a 00 byte in front.
  3. The left 32 bytes of the result are added to the parent’s Private Key, modulo the order of the curve, to give the child’s Private Key.
  4. The right 32 bytes become the child’s chain code, ready for deriving the next level down.

To reach a key deeper in the tree we repeat the process, one level at a time.

It turns out that, for normal children, we don’t need the Private Key at all to derive the child’s Public Key. Adding a number to a Private Key and then computing its Public Key gives the same result as adding that number’s point on the curve to the Public Key. So, as the footnote to Figure 2 shows, anyone holding a parent’s xpub can derive the Public Keys, and therefore the Addresses, of all its normal children.

This is what makes a watch-only wallet possible. We can give a server the xpub of an account, and it can derive a fresh receiving Address for every payment, without ever holding a key that can spend the coins.

A hardened child can’t be derived this way, because its derivation needs the parent’s Private Key as input. An xpub can only follow normal steps.

We name a key by its path from the master key, written with an m for the master key and a / between levels, e.g. m/0'/1. Most wallets lay out their tree following the BIP44 convention, as in Figure 3.

The path m/44’/236’/0’ leads from the master key through purpose, coin type and account, all hardened. Below the account are the normal branches 0 for receiving and 1 for change, each with numbered Address keys. Everything below the account can be derived from the account xpub.m44’236’0’01…/0/0…/0/1…/0/2…/1/0masterpurposecoin typeaccountreceivingchangederivable from the account xpubhardenednormal
Figure 3: A BIP44 path, and the part of the tree an account xpub can see

The levels of a BIP44 path are:

  1. purpose, always 44' for this layout.
  2. coin type, 236' for Bitcoin SV in the SLIP-44 registry.
  3. account, so that one seed can hold several independent accounts.
  4. change, 0 for receiving Addresses that we give out, and 1 for the change Outputs our own Transactions pay back to us.
  5. index, counting up from 0, one for each new Address.

Do note that the first three levels are hardened, and the last two are not. This puts the boundary of Figure 3 exactly where we want it: an account’s xpub lets a server watch every receiving and change Address in that account, and nothing else.

Wallets do not all agree on the path. Some Bitcoin SV wallets use a coin type of 0' or 145', or a layout of their own. If you restore a seed into a different wallet and it shows no coins, the most likely reason is that the two wallets derive their keys along different paths.

HD keys were designed for a world in which a seed was a complete backup. Restore the seed, derive the keys along the usual path, ask an indexer which Addresses had been used, and the wallet is whole again.

That is no longer the whole story. Our wallets also derive keys with BRC-42, from both our own key and a counterparty’s, and they don’t ask an indexer about their history. A seed alone can’t bring those back, as we explain in Wallets that keep their own history. HD keys remain a good way to organise the keys a wallet derives on its own.

Both of our libraries implement BIP32. You can see how to derive keys, use an xpub for a watch-only wallet, and turn a derived key into a signing key in DartSV and Bitcoin4J.

For the technical details of the specification, read the original paper on Hierarchical Deterministic Wallets.