Menu
BIP-bip-39 Final

BIP-39: Mnemonic Seeds

Mnemonic code specification for generating deterministic wallets. Human-readable backup for Bitcoin agents.

Type Bitcoin Improvement Proposal
Number bip-39
Status Final
Authors Marek Palatinus, Pavol Rusnak, Aaron Voisine, Sean Bowe
Original https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki

BIP-39: Mnemonic Code for Generating Deterministic Keys

BIP-39 defines a method for encoding random entropy as human-readable words, enabling easy backup and recovery of wallet seeds.

Why Mnemonics?

Raw entropy comparison:

Hex:     e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35
Binary:  11101000111100110010111001110010...
Mnemonic: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about

Benefits:

  • Human readable and memorable
  • Easy to write down
  • Error detection via checksum
  • Standardized across wallets

Generation Process

Entropy (ENT bits)

SHA256 → Checksum (CS bits = ENT/32)

ENT + CS → Binary string

Split into 11-bit groups

Map to wordlist

Mnemonic (MS words)

Entropy Sizes

ENT (bits)CS (bits)ENT+CSMS (words)
128413212
160516515
192619818
224723121
256826424

Recommendation: 24 words (256 bits) for maximum security.

Wordlist

  • Exactly 2048 words (2¹¹ = 2048)
  • Each word uniquely identified by first 4 characters
  • Similar words avoided (woman/women)
  • Available in multiple languages

English Wordlist Sample

0000: abandon
0001: ability
0002: able
...
2046: zero
2047: zone

Mnemonic to Seed

The mnemonic is converted to a 512-bit seed using PBKDF2:

seed = PBKDF2(
    password = mnemonic,
    salt = "mnemonic" + passphrase,
    iterations = 2048,
    dklen = 64,
    prf = HMAC-SHA512
)

The optional passphrase:

  • Adds plausible deniability (different passphrase = different wallet)
  • No way to verify if passphrase is correct
  • Empty string by default

Implementation

JavaScript (bip39)

const bip39 = require('bip39');

// Generate mnemonic
const mnemonic = bip39.generateMnemonic(256); // 24 words
console.log('Mnemonic:', mnemonic);

// Validate
const valid = bip39.validateMnemonic(mnemonic);
console.log('Valid:', valid);

// To seed (async)
const seed = await bip39.mnemonicToSeed(mnemonic, 'optional_passphrase');
console.log('Seed:', seed.toString('hex'));

// To seed (sync)
const seedSync = bip39.mnemonicToSeedSync(mnemonic);

Python (mnemonic)

from mnemonic import Mnemonic

mnemo = Mnemonic("english")

# Generate
mnemonic = mnemo.generate(256)  # 24 words
print("Mnemonic:", mnemonic)

# Validate
valid = mnemo.check(mnemonic)
print("Valid:", valid)

# To seed
seed = Mnemonic.to_seed(mnemonic, passphrase="")
print("Seed:", seed.hex())

From Entropy

const bip39 = require('bip39');
const crypto = require('crypto');

// Generate secure random entropy
const entropy = crypto.randomBytes(32); // 256 bits

// Convert to mnemonic
const mnemonic = bip39.entropyToMnemonic(entropy);

// Reverse: mnemonic to entropy
const recoveredEntropy = bip39.mnemonicToEntropy(mnemonic);

Checksum Verification

The last word contains checksum bits:

def verify_checksum(mnemonic_words):
    # Convert words to indices
    wordlist = load_wordlist()
    indices = [wordlist.index(word) for word in mnemonic_words]

    # Convert to binary
    binary = ''.join(format(i, '011b') for i in indices)

    # Split entropy and checksum
    ent_bits = len(mnemonic_words) * 11 * 32 // 33
    entropy = binary[:ent_bits]
    checksum = binary[ent_bits:]

    # Calculate expected checksum
    entropy_bytes = int(entropy, 2).to_bytes(ent_bits // 8, 'big')
    hash_bytes = hashlib.sha256(entropy_bytes).digest()
    expected = bin(hash_bytes[0])[2:].zfill(8)[:len(checksum)]

    return checksum == expected

Security Considerations

Entropy Quality

import secrets

# CORRECT: Use cryptographic randomness
entropy = secrets.token_bytes(32)

# WRONG: Never use weak randomness
import random
entropy = bytes([random.randint(0,255) for _ in range(32)])  # INSECURE!

Passphrase Usage

ScenarioPassphraseNotes
Standard backupEmptySimple, one wallet
Plausible deniabilitySecretDifferent wallets per passphrase
Duress walletDecoySmall funds to satisfy attacker

Warning: Forgetting passphrase = permanent fund loss

Storage

MethodSecurityUsability
Metal plateFire/water resistantMedium
Paper (multiple copies)Fire riskHigh
Encrypted digitalNeeds decryptionMedium
Memory onlyNo physical attack surfaceRisky

Never:

  • Store in cloud (Google Drive, iCloud, Dropbox)
  • Take photos
  • Email to yourself
  • Store on internet-connected device unencrypted

Test Vectors

Vector 1 (128-bit entropy)

Entropy: 00000000000000000000000000000000
Mnemonic: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
Seed (no passphrase): 5eb00bbddcf069084889a8ab9155568165f5c453ccb85e70811aaed6f6da5fc19a5ac40b389cd370d086206dec8aa6c43daea6690f20ad3d8d48b2d2ce9e38e4

Vector 2 (256-bit entropy)

Entropy: 7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f7f
Mnemonic: legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth useful legal winner thank year wave sausage worth title

With Passphrase

Mnemonic: abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about
Passphrase: TREZOR
Seed: c55257c360c07c72029aebc1b53c05ed0362ada38ead3e3e9efa3708e53495531f09a6987599d18264c1e1c92f2cf141630c7a3c4ab7c81b2f001698e7463b04

Language Support

LanguageFileFirst Word
Englishenglish.txtabandon
Japanesejapanese.txtあいこくしん
Spanishspanish.txtábaco
Chinese (Simplified)chinese_simplified.txt
Chinese (Traditional)chinese_traditional.txt
Frenchfrench.txtabaisser
Italianitalian.txtabaco
Koreankorean.txt가격
Czechczech.txtabdikace
Portugueseportuguese.txtabacate

Note: Different languages produce different seeds from same entropy.

Agent Best Practices

  1. Always use 24 words (256-bit entropy)
  2. Generate with CSPRNG only
  3. Validate before use (checksum verification)
  4. Store securely (never in code, logs, or cloud)
  5. Test recovery before funding
  6. Consider passphrase for additional security

Common Mistakes

MistakeConsequence
Weak entropy sourcePredictable keys, theft
Storing in cloudRemote theft
Screenshot/photoDevice compromise = theft
Wrong word orderDifferent wallet
Typo in wordChecksum fails OR different wallet
Forgotten passphrasePermanent fund loss

Machine-Readable Summary

{
  "bip": 39,
  "title": "Mnemonic Code for Generating Deterministic Keys",
  "status": "final",
  "word_counts": [12, 15, 18, 21, 24],
  "wordlist_size": 2048,
  "seed_derivation": {
    "function": "PBKDF2",
    "hash": "HMAC-SHA512",
    "iterations": 2048,
    "salt_prefix": "mnemonic"
  },
  "libraries": {
    "javascript": ["bip39"],
    "python": ["mnemonic", "bip_utils"],
    "rust": ["bip39"]
  }
}