← All writing

October 22, 2026

HD Wallets: One Seed, Many Keys

A wallet needs a new address for every deposit, but backing up a new private key each time doesn't scale. A hierarchical deterministic (HD) wallet, defined in BIP32, derives every key from one seed, so one backup covers all of them.

From mnemonic to seed

The 12 or 24 words of BIP39 are an encoding of entropy. The seed comes from stretching them:

seed=PBKDF2-HMAC-SHA512(mnemonic, "mnemonic"∥passphrase, 2048)\text{seed} = \text{PBKDF2-HMAC-SHA512}(\text{mnemonic},\ \text{"mnemonic"} \parallel \text{passphrase},\ 2048)

The optional passphrase gives a different wallet for each value, and a wrong one is not an error, it just opens a different, empty wallet.

The master key

The seed goes through one HMAC to produce a private key and a chain code:

I=HMAC-SHA512("Bitcoin seed", seed),km=IL,cm=IRI = \text{HMAC-SHA512}(\text{"Bitcoin seed"},\ \text{seed}), \qquad k_{m} = I_L, \quad c_{m} = I_R

Here ILI_L and IRI_R are the left and right 32 bytes of II, giving the private key and the chain code.

The chain code is extra entropy that every child derivation mixes in. It keeps a child key from being computed from its public key alone.

Deriving a child

Child number ii of a parent (k,K,c)(k, K, c) is computed with the parent's chain code as the HMAC key:

I={HMAC-SHA512(c, K∥i)i<231 (normal)HMAC-SHA512(c, 0x00∥k∥i)i≥231 (hardened)I = \begin{cases} \text{HMAC-SHA512}(c,\ K \parallel i) & i < 2^{31} \ \text{(normal)} \\ \text{HMAC-SHA512}(c,\ 0\text{x}00 \parallel k \parallel i) & i \ge 2^{31} \ \text{(hardened)} \end{cases} ki=IL+k(modn),ci=IRk_i = I_L + k \pmod n, \qquad c_i = I_R

Each child has its own chain code, so the process repeats down a tree. A path such as m/44'/60'/0'/0/5 is just a list of child indices, and the apostrophe marks a hardened one.

Public derivation

For normal children, the public key can be derived without the private key. Since ki=IL+kk_i = I_L + k, adding IL⋅GI_L \cdot G to the parent public key gives:

Ki=IL⋅G+KK_i = I_L \cdot G + K

This is why an extended public key (xpub, the public key plus chain code) is useful. A server holding only an xpub can generate unlimited deposit addresses and watch them, while the private keys stay somewhere else.

Why hardened derivation exists

Public derivation has a sharp edge. If someone has the xpub and any one normal child private key, they can recover the parent:

k=ki−IL(modn)k = k_i - I_L \pmod n

ILI_L is computable from the public data, so the leak walks up the tree, and every sibling falls with it. Hardened derivation puts the parent private key into the HMAC input, so ILI_L can't be computed from public data and the link is cut. The cost is that hardened children can't be derived from an xpub.

Paths in practice

BIP44 fixes a convention so wallets can restore each other:

m / purpose' / coin_type' / account' / change / address_index

The upper levels are hardened, so one account's xpub can be shared without exposing the others. Only the last two levels are normal, which is what lets a server derive addresses.

Where it stops working

  • Ed25519. BIP32's public derivation relies on elliptic-curve point addition in the way secp256k1 allows. SLIP-0010 defines Ed25519 derivation with hardened children only, so chains like Solana can't use xpub-style address generation.
  • MPC wallets. There is no seed to derive from, because the key never exists in one place. Threshold schemes derive child keys by applying the same additive tweak to the shared key, so the same tree structure works without ever assembling the parent. I'll cover that in a separate note.

The idea is small: one HMAC per level, and addition on the curve. The security comes from keeping the chain code and the parent private key out of the wrong hands.