Caloogy Article
中文

How Mnemonic Phrases Become Private Keys: BIP-39 and HD Wallets

Date
Mar 27, 2025
Series
Wallet
Reading
5 min
Topics
WalletBip 39Bip 32Bip 44

The one-sentence version

12 English words are actually a "human-readable encoding" consisting of a 128-bit random number plus a 4-bit checksum. It is stretched into a 512-bit seed via PBKDF2, which then derives countless private keys like a tree layer by layer according to BIP-32 rules. Therefore, a single set of recovery phrase can manage all chains and all addresses. Consequently, the recovery phrase is everything: if lost, all addresses are lost; if leaked, all addresses are leaked.

This article has three layers:

  1. Layer 1: The Intuition: A key tree
  2. Layer 2: Real-World Use: Why "balance is 0 after import," the role of a passphrase, and the risks of xpub leakage
  3. Layer 3: Principles and Engineering Key points: BIP-39 encoding and checksum, PBKDF2, BIP-32 derivation, derivation paths, including a standard test vector

Layer 1: The Intuition

1.1 A Key Tree

Early Bitcoin wallets had to back up a new private key every time a new address was generated, which was very cumbersome. HD (Hierarchical Deterministic) wallets introduced a different approach:

  1. Generate only one root secret (the recovery phrase);
  2. Use fixed mathematical rules to "grow" branches and leaves from the root, where each leaf is a private key;
  3. With the same root and the same rules, the same tree is always grown.

Thus, by backing up the recovery phrase just once, the entire tree can be fully recovered in any wallet software.

1.2 Why Words

A 128-bit random number written in hexadecimal is 32 characters long; miscopying a single character ruins everything. BIP-39 splits it into 11-bit segments, where each segment corresponds to a word (a wordlist of 211=20482^{11} = 2048 words), and includes a checksum so the wallet can detect if a word is miscopied (similar to how the last digit of an ID card works in the Luhn algorithm and checksums).


Layer 2: Real-World Use


Layer 3: Principles and Engineering

3.1 BIP-39: Entropy → Words

Entropy Checksum Total Bits Number of Words
128 bits 4 bits 132 12
256 bits 8 bits 264 24

The checksum takes the first entropy bits/32\text{entropy bits}/32 bits of SHA256(entropy)\mathrm{SHA256}(\text{entropy}) and is appended to the entropy, then every 11 bits, a word is looked up in the wordlist.

Standard Test Vector: All-zero Entropy

Entropy is 16 zero bytes (128 zeros).

  • The beginning of SHA256(00×16)\mathrm{SHA256}(\texttt{00}\times 16) is 374708ff..., the first hex digit 3 = 0011, so the checksum is 0011;
  • 132 bits = the first 121 bits are all 0, and the last 11 bits are 0000000 0011;
  • The first 11 segments are all 0, corresponding to the 0th word in the wordlist: abandon; the last segment is 3, corresponding to the 3rd word: about (the wordlist starts with abandon, ability, able, about).

Recovery phrase: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about. This is the first one in the BIP-39 official test vectors; never use it to store money: everyone knows it. (Checksum verified via Python.)

In a 12-word phrase, only part of the bits in the last word are entropy, while the rest is the checksum. Therefore, if you write 12 words at random, there is only about a 1/161/16 probability of passing the checksum.

3.2 Words → Seed: PBKDF2

seed=PBKDF2-HMAC-SHA512(mnemonic, salt="mnemonic"+passphrase, 2048 iterations)\text{seed} = \mathrm{PBKDF2\text{-}HMAC\text{-}SHA512}\big(\text{mnemonic},\ \text{salt} = \texttt{"mnemonic"} + \text{passphrase},\ 2048 \text{ iterations}\big)

2048 iterations represent key stretching: making each passphrase guess take a little more time. However, for 128-bit random entropy, stretching is actually not strictly necessary; it primarily protects the user-defined passphrase.

3.3 Seed → Tree: BIP-32

Root node: HMAC-SHA512("Bitcoin seed", seed)\mathrm{HMAC\text{-}SHA512}(\texttt{"Bitcoin seed"},\ \text{seed}), where the left 256 bits are the master private key and the right 256 bits are the "chain code."

Each child node is calculated via HMAC-SHA512 using the parent's key, chain code, and child index ii:

Type Input Feature
Normal Derivation (i<231i < 2^{31}) Parent public key + chain code + ii Can derive all child public keys using only the xpub (convenient for read-only monitoring)
Hardened Derivation (i≥231i \ge 2^{31}, written as i′i') Parent private key + chain code + ii Requires the private key to derive; leakage of a child private key does not compromise the parent private key

In normal derivation, child private key == parent private key +tweak+ \text{tweak} (modulo curve order nn), while the tweak only depends on the public xpub. Therefore, "xpub + one child private key" can subtract out the parent private key. This is why the upper layers of the path must use hardened derivation.

3.4 Derivation Paths

BIP-44 specifies: m / purpose' / coin_type' / account' / change / address_index

Chain Common Path
Bitcoin (Legacy addresses) m/44'/0'/0'/0/0
Bitcoin (Native SegWit) m/84'/0'/0'/0/0
Ethereum m/44'/60'/0'/0/0

3.5 Engineering details


Summary

Layer Key points
Intuition One root secret, growing a whole key tree according to fixed rules
BIP-39 Entropy + SHA-256 checksum, one word every 11 bits; PBKDF2 stretching into a seed
BIP-32 Layer-by-layer derivation via HMAC-SHA512; hardened derivation protects the parent private key
Risk The recovery phrase is everything; different paths result in 0 balance; xpub leaks privacy and carries collateral risk