
Whitepaper. Bitcoin Improvement Proposal 39 (BIP-39), 2013. Specification authors: Marek Palatinus, Pavol Rusnak, Aaron Voisine, Sean Bowe.
Keywords: BIP-39, HD wallet, entropy, checksum, PBKDF2, HMAC-SHA512, seed phrase, cryptanalysis, BIP-32, Unicode NFKD.
BIP-39 defines a standard representation of computer-generated entropy as a mnemonic phrase and the deterministic derivation of a 512-bit binary seed from it. The pipeline consists of encoding 128–256 bits of the initial entropy into indices of a 2048-word dictionary with a short checksum, followed by computing PBKDF2-HMAC-SHA512 with 2048 iterations. The resulting seed is intended for subsequent use in BIP-32 and related hierarchical deterministic key systems.
From a cryptanalytic perspective, BIP-39 should be viewed not as encryption or a secret storage mechanism, but as a human-transferable secret format. The strength of the base case is determined by the unpredictability of the initial entropy, while practical risks typically arise from passphrase compromise, a weak random number generator, Unicode/dictionary errors, a backup leak, or offline brute-force attacks on an additional passphrase.
Status and purpose
BIP-39 is part of the Bitcoin Improvement Proposals application layer, has a Deployed status , and was dated September 10, 2013. Its focus is not on direct private key generation, but on a user-reversible representation of entropy in words and one-way seed derivation.
The rationale for the format is ergonomic: a paper record or controlled transmission of words is more convenient and less error-prone than writing a long hexadecimal string. However, the specification is not directly intended for converting a human-created phrase—a brainwallet—into a wallet: predictable phrases have low min-entropy and have historically been the target of mass brute-force attacks.
Security model
Let ENT be the initial uniform entropy. For a correct CSPRNG, brute-forcing it requires about 100 2^ENT attempts in the worst case, and the average work of a complete search is about 100 attempts 2^(ENT−1). For 12 words, BIP-39 encodes 128 bits of useful entropy; words don’t “add” it to 132 bits, since the 4 extra bits are a checksum.
LaTeX-compatible model:
\[ H_\infty(\mathrm{mnemonic}) \le H_\infty(\mathrm{ENT}) = \mathrm{ENT}. \]
With uniform generation: \[ \Pr[\text{success in }q\text{ independent attempts}] \approx q/2^{\mathrm{ENT}}. \]
An important auditing implication: PBKDF2 does not correct for weak initial entropy. If a device, library, or user has narrowed the candidate space, the attacker brute-forces this narrowed space, checking candidates against known derived addresses, xpub, or transaction history.
Entropy encoding
The specification allows ENT ∈ {128, 160, 192, 224, 256}for multiples of 32 values from 128 to 256 bits. SHA-256 is calculated from the binary entropy; the first ENT/32 bits of its result form the checksum CS. The concatenation is then ENT || CS divided into 11-bit blocks, each of which specifies an index from 0 to 2047 in a fixed dictionary.
LaTeX-compatible formulas:
\[ CS = \mathrm{first}_{ENT/32}\!\left(\mathrm{SHA256}(ENT)\right). \]
\[ B = ENT \parallel CS. \]
\[ MS = \frac{ENT + CS}{11} = \frac{33\,ENT}{352}. \]
| ENT, bit | CS, bit | ENT + CS, bit | Words, MS | Practical interpretation |
|---|---|---|---|---|
| 128 | 4 | 132 | 12 | Minimal standard format; cryptographically sufficient only with a high-quality CSPRNG. |
| 160 | 5 | 165 | 15 | An intermediate option with greater entropy and backup record length. |
| 192 | 6 | 198 | 18 | Increases the strength against brute force attacks, but does not protect against theft of the phrase itself. |
| 224 | 7 | 231 | 21 | A rarely used intermediate format. |
| 256 | 8 | 264 | 24 | Maximum BIP-39 format; 256 bits of useful entropy. |
Example from control vectors
The canonical compatibility vector uses 16 zero-byte entropy. It is encoded by the phrase abandon, repeated 11 times, followed by the final word about. This is not a secure phrase, but rather a deliberately public test example; importing such a phrase into a production wallet means that the corresponding seed and all derived keys are known in advance to any verifier.
ENT (hex): 00000000000000000000000000000000
Mnemonic: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
Passphrase: TREZOR
Seed (hex): c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e5349553
1f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04
Cryptanalytic fact
A checksum is not a MAC, digital signature, or error-correcting code. For example, for a 24-word phrase, it is only 8 bits: a randomly corrupted combination of indices passes the check with probability 1/256; the specification emphasizes that a checksum does not help correct errors. Therefore, the validity of BIP-39 does not prove that the user has restored the original wallet.
Vocabulary and Unicode
Each BIP-39 dictionary contains 2048 entries, as 11 bits encode exactly 100 2^11 = 2048 values. The English dictionary is sorted; the first four Latin letters of each word are sufficient for unambiguous identification, and visually and phonetically similar pairs are intentionally excluded. These properties reduce the likelihood of human error and allow the use of binary search or trie, but do not provide cryptographic security.
All strings involved in the transformation must be normalized as UTF-8 NFKD. This is crucial for non-ASCII dictionaries and passphrases: identical-looking characters may have different byte representations before normalization, and any difference in bytes changes the PBKDF2 result and, consequently, the entire wallet.
Example of compatibility error
The Japanese test vectors intentionally use a passphrase with intensive Unicode normalization. This demonstrates a typical audit scenario: an application that normalizes a string using anything other than NFKD, or that does so only for the mnemonic but not the salt, will calculate a different seed for a seemingly identical backup entry.
Derivation of binary seed
After receiving the mnemonic, BIP-39 generates a 64-byte seed using PBKDF2. The password is an NFKD-normalized UTF-8 mnemonic; the salt is an NFKD-normalized string "mnemonic" + passphrase. If there is no passphrase, an empty string is used, so the salt is "mnemonic".
LaTeX-compatible formula:
\[ \mathrm{seed}_{512}=\mathrm{PBKDF2}\text{-}\mathrm{HMAC}\text{-}\mathrm{SHA512}(P=\mathrm{NFKD}(M),\ S=\mathrm{NFKD}(\texttt{mnemonic}\parallel \pi),\ c=2048,\dkLen=64). \]
PBKDF2 computes a single 64-byte block: U_1 = HMAC-SHA512(P, S || INT_32_BE(1)), then U_j = HMAC-SHA512(P, U_(j−1)) for j=2…2048, and the output is the XOR of all U_j. This is a deterministic, not reversible, process: recovering the mnemonic from the seed is not computationally feasible.
def bip39_seed(mnemonic: str, passphrase: str = "") -> bytes:
P = unicodedata.normalize("NFKD", mnemonic).encode("utf-8")
S = unicodedata.normalize("NFKD", "mnemonic" + passphrase).encode("utf-8")
return hashlib.pbkdf2_hmac("sha512", P, S, 2048, dklen=64)
Practical historical context
PBKDF2-HMAC-SHA512 with 2048 iterations was a 2013 compromise between the delay in legitimate recovery and the cost of offline candidate verification. In the modern threat model, this is a relatively small work factor: if the mnemonic is leaked, an attacker can efficiently brute-force potential passphrases locally, without network limitations. Therefore, an additional passphrase is only useful if it has high entropy and is not stored alongside the passphrase.
Passphrase and negation
Any passphrase—even an erroneous one—produces a syntactically correct 512-bit seed and a deterministic set of keys. This property creates plausible deniability: one passphrase can open a decoy wallet, while another can open the main wallet. At the same time, it makes recovery fragile: a forgotten, incorrectly expanded, or otherwise normalized passphrase will not produce an obvious error, but will instead reveal a different, often empty, wallet.
Operational conclusion: you can’t verify recovery success solely by the application accepting 12/24 words. Verification should be performed using the pre-known fingerprint master key, descriptor, xpub, control address, and required derivation path.
Communication with BIP-32
The BIP-39 seed is typically passed to BIP-32, where it is used to construct an extended master key, followed by a hierarchy of child keys and addresses. BIP-39 itself does not define the network, address type, derivation path, script policy, or account structure; therefore, identical words may, with different interface settings, display the “wrong” set of addresses without changing the cryptographic seed.
This manifested itself as an architectural limitation: the original format lacked a versioning scheme specifying the address format. The modern approach with wallet descriptors reduces ambiguity, as the descriptor specifies the rules for deriving and interpreting addresses along with the key material.
Cryptanalytic scenarios
| Scenario | What is being attacked? | Why BIP-39 doesn’t save | Countermeasure |
|---|---|---|---|
| Brainwallet / hand-crafted phrase | A small, linguistically predictable phrase space | PBKDF2 only slows down candidate verification; it does not create missing entropy. | Generate ENT only from a wallet’s CSPRNG or a trusted OS |
| Weak RNG or generation pattern | Abbreviated set of ENT | 12 words appear to be a full 128-bit secret, although the actual entropy may be significantly lower. | Randomness source audit, implementation testing, vulnerable software update |
| Mnemonic leak | Complete original secret | Checksum and PBKDF2 do not prevent the passphrase from being imported; an empty passphrase means immediate access. | Offline backup, photo/cloud/messenger exclusion, hardware isolation |
| Weak BIP-39 passphrase | Dictionary or templates of additional secret | The check is performed offline by address or xpub; 2048 iterations are not a memory-hard barrier. | Unique random passphrase, independent storage, controlled recovery procedure |
| Substitution of vocabulary or Unicode | Semantics of strings and indexes | A different dictionary/encoding produces a different seed without breaking the basic PBKDF2 function | Fix the vocabulary language, use NFKD, test with vectors |
A fact from the practice of analysis
For recovery, investigation, and red-team audit purposes, derived public data is converted into oracle checks: the candidate phrase and passphrase are run through BIP-39, then BIP-32, and then the expected path; the resulting address, xpub, or fingerprint is compared with the known one. Therefore, the public nature of the addresses does not reveal the seed per se, but it does allow for the validation of each candidate in the presence of a weak candidate source.
Specification shortcomings
- Vocabulary dependency: the seed is derived from the mnemonic text, not from the original ENT; translating words to a different vocabulary produces a different seed.
- One-sidedness: an arbitrary BIP-32 seed cannot be represented by a BIP-39 mnemonic, since the mapping goes from phrase to seed via a hashing KDF.
- Short checksum: It provides only limited detection of random errors and does not correct them.
- No wallet versioning: the mnemonic does not communicate addressing and derivation rules.
The authors of BIP-39 proposed SLIP-0039 as a proposed successor aimed at addressing some of these shortcomings, primarily the structured sharing of the backup secret. However, ecosystem compatibility and widespread support for BIP-39 mean that audits should primarily focus on its precise semantics.
Validation and testing
A reliable implementation must verify that the number of words is acceptable, that each word is present in the chosen vocabulary, and that the extracted checksum matches the first ENT/32 bits SHA256(ENT). It is prohibited to arbitrarily “correct” a word based on a similar spelling: this could lead to a different, but checksum-valid, secret.
# Псевдокод проверки мнемоники
indices = [wordlist.index(word) for word in words]
B = concat_11_bit(indices)
ENT = B[:len(B) - len(B)//33]
CS = B[len(ENT):]
valid = CS == SHA256(ENT).bits[:len(ENT)//32]
The project’s test vectors python-mnemonic compare the initial entropy, mnemonic, and seed; passphrase is used for base vectors TREZOR. For the developer, this is a minimal regression set: it should detect errors in bit order, dictionary selection, NFKD normalization, UTF-8 serialization, and PBKDF2 parameters.
Recommendations
- Generate mnemonics exclusively from cryptographically strong randomness, and not from a phrase, date, hash of personal data, or “your own algorithm.”
- For inter-wallet compatibility, the official English vocabulary is preferred, as recommended by BIP-39; the language should be documented in the recovery documentation.
- Consider 12/24 words equivalent to a master secret: do not send them to websites, support forms, cloud notes, screenshots, or instant messengers.
- If a passphrase is used, create it as an independent high-entropy secret and test the full recovery process in advance with a controlled small amount.
- Archive not only mnemonics, but also metadata: network, wallet type, derivation paths, descriptor/xpub or fingerprint, software version, and information about the presence of a passphrase.
- During development, compare the result with published test vectors, including Unicode vectors; during auditing, separately examine the RNG, UI, backup export, and derivation paths.
Final Provision
BIP-39 remains a fundamental interface between random binary entropy and humans, not a standalone key management system. Its mathematical simplicity ENT → checksum → 11-битные индексы → mnemonic → PBKDF2 seed ensures portability; its practical limits are determined by the quality of ENT generation, the security of backup storage, strict adherence to normalization, and the parameters of subsequent HD derivation.
Sources
BIP-0039: mnemonic encoding for deterministic keys: https://moneysecrets.ru/bip-0039-mnemonic-encoding-for-deterministic-keys/
- Palatinus, M.; Rusnak, P.; Voisine, A.; Bowe, S. BIP-0039: Mnemonic code for generating deterministic keys . Bitcoin BIPs repository, status Deployed, originally intended 2013-09-10. github.com/bitcoin/bips .
- Bitcoin BIPs. BIP-0032: Hierarchical Deterministic Wallets . github.com/bitcoin/bips .
- Trezor. python-mnemonic: BIP-39 reference implementation and test vectors . github.com/trezor/python-mnemonic .
- Bitcoin BIPs. BIP-0380: Output Script Descriptors General Operation . github.com/bitcoin/bips .
- SatoshiLabs. SLIP-0039: Shamir’s Secret-Sharing for Mnemonic Codes . github.com/satoshilabs/slips .
