A seed phrase is a human-readable encoding of a random number. Your wallet stretches that number into a 512-bit seed (BIP-39), builds a tree of keys from the seed (BIP-32), and picks keys from the tree using standard paths (BIP-44 and related). Anyone who has the words, plus the passphrase if you set one, can rebuild every key in that tree on any compatible wallet. That makes storage the part that matters most.
BIP-39: from randomness to words
- The wallet generates entropy: 128 bits for 12 words, up to 256 bits for 24 words.
- It appends a checksum, the first
entropy_bits / 32bits ofSHA-256(entropy). That's 4 bits for 12 words and 8 for 24. - It splits the result into 11-bit chunks. Each chunk is an index into a fixed list of 2048 words.
| Words | Entropy | Checksum | Total bits |
|---|---|---|---|
| 12 | 128 | 4 | 132 |
| 24 | 256 | 8 | 264 |
The words are only an encoding, so the security comes from the entropy. 128 random bits is already far beyond brute force. The checksum means most typos are caught, but not every one. And because the last word partly encodes the checksum, you can't pick all 12 words yourself.
The words then become a seed through a deliberately slow hash:
seed = PBKDF2-HMAC-SHA512(
password = mnemonic (NFKD-normalized),
salt = "mnemonic" + passphrase,
iterations = 2048,
length = 64 bytes
)
The optional passphrase (sometimes called the 25th word) goes into the salt. Every passphrase produces a valid, different wallet, and there is no "wrong passphrase" error. Lose the passphrase and the funds are gone even if you still have the words.
BIP-32: one seed, a tree of keys
The master key comes from HMAC-SHA512(key = "Bitcoin seed", data = seed). The left 32 bytes are the master private key and the right 32 bytes are the chain code. Each child key is derived from its parent key, its chain code, and an index.
- Hardened children (index written with
') need the parent private key to derive. - Non-hardened children can be derived from the parent public key. That's how an extended public key (xpub) lets a watch-only server generate receive addresses without holding secrets.
The catch is that if someone has an xpub and any non-hardened child private key under it, they can compute the parent private key. Treat xpubs as sensitive: they reveal your whole address history, and they are one leaked child key away from a full compromise.
BIP-44: standard paths
m / purpose' / coin_type' / account' / change / address_index
| Path | Used for |
|---|---|
m/44'/0'/0'/0/0 | Bitcoin legacy (P2PKH) |
m/84'/0'/0'/0/0 | Bitcoin native SegWit (BIP-84) |
m/86'/0'/0'/0/0 | Bitcoin Taproot (BIP-86) |
m/44'/60'/0'/0/0 | Ethereum and most EVM wallets |
m/44'/501'/0'/0' | Common Solana wallets (ed25519, all hardened, SLIP-0010) |
When a restored wallet "shows zero balance", the cause is almost always a different derivation path or a missing passphrase. The words themselves are rarely the problem.
Seeing it in code
This uses the public Hardhat/Anvil test mnemonic. Never generate or type a real seed phrase into a script on an internet-connected machine.
import { HDNodeWallet, Mnemonic, randomBytes } from "ethers";
// PUBLIC test mnemonic used by Hardhat and Anvil. Never send real funds to it.
const phrase = "test test test test test test test test test test test junk";
for (let i = 0; i < 3; i++) {
const w = HDNodeWallet.fromPhrase(phrase, undefined, `m/44'/60'/0'/0/${i}`);
console.log(w.path, w.address);
}
// m/44'/60'/0'/0/0 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266 ...
// Same words + a passphrase = a completely different wallet
const withPass = HDNodeWallet.fromPhrase(phrase, "correct horse", "m/44'/60'/0'/0/0");
console.log(withPass.address);
// The checksum catches most typos
console.log(Mnemonic.isValidMnemonic(phrase)); // true
console.log(Mnemonic.isValidMnemonic(phrase.replace("junk", "test"))); // false
const fresh = Mnemonic.fromEntropy(randomBytes(16)); // 128 bits -> 12 words
How to store a seed phrase
Never put it anywhere digital. That means no photos, no cloud notes, no password-manager notes synced to the cloud, no email to yourself, no chat messages, no screenshots, and never into a website, browser extension prompt, support form or AI chat. Legitimate support will never ask for it. Any page that asks for your seed phrase is a phishing attempt.
What works:
- Generate it on a hardware wallet so the words never touch a networked computer.
- Write it down by hand, with the word numbers, and check every word against the device.
- Use a durable medium for long-term storage: stamped or engraved metal survives fire and water far better than paper.
- Keep at least two copies in separate secure places, so one fire, flood or burglary doesn't take all of them.
- Test recovery before you fund the wallet properly. Wipe the device or use a second one, restore from the backup, and confirm you get the same first address.
- Consider a passphrase, stored separately from the words, so a found backup alone isn't enough. Only do this if you'll reliably keep both.
Avoid splitting a 24-word phrase into thirds. Each piece gives away part of the secret, and losing one piece can make recovery impossible. If you need to spread trust across people or places, use a scheme designed for it: a multisig wallet, or SLIP-39 Shamir backups on hardware that supports them.
For developers
- Keep development mnemonics (like the one above) completely separate from anything holding real value. Bots sweep funds sent to known test mnemonics almost immediately.
- Never log, print or commit a mnemonic or private key. Add
.envto.gitignore, and assume any key that has sat in a.envon a laptop is a hot key. - For production deployers and signers, use a hardware wallet, a multisig, or a KMS/HSM-backed signer instead of a raw mnemonic.
- Treat xpubs as private data in your backend.
Checklist
- BIP-39 turns 128–256 bits of entropy plus a checksum into 12–24 words, then PBKDF2 turns words plus passphrase into a seed.
- BIP-32 derives a key tree from the seed. BIP-44/84/86 paths pick the keys.
- Restore problems are usually a path or passphrase mismatch.
- Store the words offline, on durable media, in more than one place, and test recovery.
- Never type a real seed phrase into anything online.
Get the weekly commit
New blockchain deep dives every week.