BIP39 Mnemonic Security-Focused API Documentation

Algorithm: BIP39 (Bitcoin Improvement Proposal 39)
Type: Mnemonic Seed Phrase Generation
Security Level: 128-256 bits of entropy
Word Lists: 2048 words per language
Supported Languages: English, Japanese, French, Spanish, Chinese (Simplified/Traditional), Korean, Czech, Portuguese
Standard: BIP39 Specification

Table of Contents

  1. Security Contract
  2. Attack Resistance Matrix
  3. Secure Usage Examples
  4. Common Mistakes
  5. Performance vs Security
  6. Platform-Specific Notes
  7. Compliance Information

Security Contract

generateMnemonic(strength?: number, language?: string): string

Preconditions:

Postconditions:

Side Effects:

mnemonicToSeed(mnemonic: string, passphrase?: string): Uint8Array

Preconditions:

Postconditions:

Side Effects:

validateMnemonic(mnemonic: string, language?: string): boolean

Preconditions:

Postconditions:

Side Effects:

entropyToMnemonic(entropy: Uint8Array, language?: string): string

Preconditions:

Postconditions:

Side Effects:

Attack Resistance Matrix

✅ Attacks Prevented

Attack Type Protection Mechanism Security Level
Brute Force (128-bit) Large keyspace 2^128 operations
Brute Force (256-bit) Maximum keyspace 2^256 operations
Dictionary Attack PBKDF2 with 2048 iterations Slows attacks
Checksum Forgery SHA256 checksum validation 2^-8 to 2^-4 probability
Word Substitution Checksum detects changes Invalid mnemonic
Timing Attacks Constant-time validation No information leakage
Weak Randomness Uses secure random source Full entropy

❌ Attacks NOT Prevented

Attack Type Reason Mitigation Required
Physical Observation Words visible when entered Use hardware wallets
Memory Disclosure Mnemonic in plaintext memory Secure memory handling
Weak Passphrase User-chosen passphrase Enforce strong passphrases
Social Engineering Users may share mnemonics User education
Clipboard Attacks Copy/paste exposes mnemonic Avoid clipboard usage
Screen Recording Display of mnemonic Secure display methods
Acoustic Analysis Keyboard sounds during entry Use virtual keyboards

⚠️ Security Limitations

  1. Word List Dependency: Security depends on standardized word lists
  2. Human Memory: 12-24 words challenging to memorize accurately
  3. No Forward Secrecy: Compromised mnemonic reveals all derived keys
  4. Passphrase Weakness: Most users don’t use additional passphrase
  5. Error Correction: No built-in error correction beyond checksum

Secure Usage Examples

Secure Wallet Generation

import { BIP39 } from '@metamui/bip39';
import { secureErase } from '@metamui/secure-memory';

class SecureWallet {
  static async generateWallet(): Promise<{
    mnemonic: string;
    seed: Uint8Array;
  }> {
    // Generate maximum entropy mnemonic (24 words)
    const mnemonic = BIP39.generateMnemonic(256);
    
    // Derive seed with optional passphrase
    const passphrase = await this.getSecurePassphrase();
    const seed = BIP39.mnemonicToSeed(mnemonic, passphrase);
    
    // Clear passphrase from memory
    secureErase(passphrase);
    
    return { mnemonic, seed };
  }
  
  private static async getSecurePassphrase(): Promise<string> {
    // In production, get from secure input
    // This is just an example
    return 'optional-secure-passphrase';
  }
}

// Usage with secure display
async function displayMnemonicSecurely(mnemonic: string) {
  const words = mnemonic.split(' ');
  
  console.log('Write down these words in order:');
  console.log('NEVER share them with anyone!');
  console.log('NEVER enter them on a website!');
  
  // Display words in groups to aid memorization
  for (let i = 0; i < words.length; i += 4) {
    const group = words.slice(i, i + 4).join(' ');
    console.log(`Words ${i + 1}-${i + 4}: ${group}`);
    
    // In real app, wait for user confirmation
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
  
  console.log('\nHave you written down all words? [yes/no]');
}

Secure Mnemonic Recovery

class MnemonicRecovery {
  static async recoverWallet(
    mnemonicWords: string[],
    passphrase?: string
  ): Promise<Uint8Array | null> {
    // Reconstruct mnemonic from array
    const mnemonic = mnemonicWords.join(' ').toLowerCase().trim();
    
    // Validate before processing
    if (!BIP39.validateMnemonic(mnemonic)) {
      // Don't reveal which word is wrong
      console.error('Invalid recovery phrase');
      return null;
    }
    
    // Derive seed
    const seed = BIP39.mnemonicToSeed(
      mnemonic,
      passphrase || ''
    );
    
    // Clear sensitive data
    mnemonicWords.forEach(word => secureErase(word));
    secureErase(mnemonic);
    
    return seed;
  }
  
  // Secure word-by-word entry
  static async enterMnemonicSecurely(): Promise<string[]> {
    const words: string[] = [];
    const wordCount = await this.getWordCount(); // 12, 15, 18, 21, or 24
    
    for (let i = 0; i < wordCount; i++) {
      // In production, use secure input method
      const word = await this.getWordSecurely(i + 1);
      
      // Validate word exists in wordlist
      if (!BIP39.wordlists.english.includes(word)) {
        throw new Error(`Word ${i + 1} not in wordlist`);
      }
      
      words.push(word);
    }
    
    return words;
  }
}

Multi-Language Support

// Generate mnemonic in different languages
const mnemonics = {
  english: BIP39.generateMnemonic(128, 'english'),
  japanese: BIP39.generateMnemonic(128, 'japanese'),
  french: BIP39.generateMnemonic(128, 'french'),
  spanish: BIP39.generateMnemonic(128, 'spanish')
};

// All generate different words but same entropy can produce same seed
const entropy = crypto.getRandomValues(new Uint8Array(16));

const sameSeedMnemonics = {
  english: BIP39.entropyToMnemonic(entropy, 'english'),
  japanese: BIP39.entropyToMnemonic(entropy, 'japanese')
};

// Both produce identical seeds despite different words
const seed1 = BIP39.mnemonicToSeed(sameSeedMnemonics.english);
const seed2 = BIP39.mnemonicToSeed(sameSeedMnemonics.japanese);
// seed1 equals seed2

Hierarchical Deterministic (HD) Wallet

import { Ed25519 } from '@metamui/ed25519';
import { HKDF } from '@metamui/hkdf';

class HDWallet {
  private constructor(private seed: Uint8Array) {}
  
  static fromMnemonic(mnemonic: string, passphrase?: string): HDWallet {
    if (!BIP39.validateMnemonic(mnemonic)) {
      throw new Error('Invalid mnemonic');
    }
    
    const seed = BIP39.mnemonicToSeed(mnemonic, passphrase);
    return new HDWallet(seed);
  }
  
  async deriveKey(path: string): Promise<{
    privateKey: Uint8Array;
    publicKey: Uint8Array;
  }> {
    // BIP32/BIP44 path derivation
    const pathSegments = path.split('/');
    let key = this.seed;
    
    for (const segment of pathSegments) {
      const index = parseInt(segment.replace("'", ""));
      const hardened = segment.includes("'");
      
      // Derive child key
      key = await HKDF.expand(
        key,
        new TextEncoder().encode(`${index}${hardened ? 'H' : 'S'}`),
        32
      );
    }
    
    // Generate Ed25519 keypair from derived seed
    return Ed25519.generateKeyPair(key);
  }
}

Common Mistakes

❌ Weak Entropy Sources

// NEVER DO THIS - Predictable entropy!
function insecureEntropy(): Uint8Array {
  const entropy = new Uint8Array(16);
  const timestamp = Date.now();
  
  // Timestamp is predictable!
  for (let i = 0; i < 8; i++) {
    entropy[i] = (timestamp >> (i * 8)) & 0xFF;
  }
  
  // Math.random() is not cryptographically secure!
  for (let i = 8; i < 16; i++) {
    entropy[i] = Math.floor(Math.random() * 256);
  }
  
  return entropy;
}

// CORRECT: Use cryptographically secure random
function secureEntropy(): Uint8Array {
  return crypto.getRandomValues(new Uint8Array(16));
}

❌ Storing Mnemonics Insecurely

// NEVER DO THIS - Plaintext storage!
function insecureStorage(mnemonic: string) {
  // Browser localStorage is not secure!
  localStorage.setItem('wallet_mnemonic', mnemonic);
  
  // Plain files are not secure!
  fs.writeFileSync('wallet.txt', mnemonic);
  
  // Logging exposes secrets!
  console.log('Generated mnemonic:', mnemonic);
}

// BETTER: Encrypt before storage (still risky)
async function betterStorage(mnemonic: string, password: string) {
  const key = await deriveKey(password);
  const encrypted = await encrypt(key, mnemonic);
  
  // Store encrypted version only
  localStorage.setItem('wallet_encrypted', encrypted);
  
  // Clear plaintext immediately
  secureErase(mnemonic);
}

❌ Poor Passphrase Practices

// BAD: Weak or no passphrase
const seed1 = BIP39.mnemonicToSeed(mnemonic); // No passphrase
const seed2 = BIP39.mnemonicToSeed(mnemonic, '123456'); // Weak
const seed3 = BIP39.mnemonicToSeed(mnemonic, 'password'); // Common

// GOOD: Strong passphrase
const strongPassphrase = generateStrongPassphrase();
const seed = BIP39.mnemonicToSeed(mnemonic, strongPassphrase);

// BEST: Separate passphrase from mnemonic storage
// Store mnemonic in one secure location
// Store passphrase in different secure location

❌ Validation Errors

// WRONG: Accepting invalid mnemonics
function acceptAnyWords(words: string) {
  // This skips validation!
  const seed = BIP39.mnemonicToSeed(words);
  return seed;
}

// CORRECT: Always validate first
function validateBeforeUse(words: string) {
  if (!BIP39.validateMnemonic(words)) {
    throw new Error('Invalid mnemonic phrase');
  }
  
  const seed = BIP39.mnemonicToSeed(words);
  return seed;
}

Performance vs Security

Entropy vs Word Count Trade-offs

Entropy Bits Word Count Security Level Use Case
128 12 Standard Most wallets
160 15 Enhanced Higher security
192 18 High Important accounts
224 21 Very High Rarely used
256 24 Maximum Cold storage

PBKDF2 Iteration Count

// BIP39 specifies 2048 iterations
// This is relatively low by modern standards
// But changing it breaks compatibility

// For additional security, use strong passphrase
// Or additional key stretching:
async function enhancedSeedDerivation(
  mnemonic: string,
  passphrase: string
): Promise<Uint8Array> {
  // Standard BIP39 seed
  const basicSeed = BIP39.mnemonicToSeed(mnemonic, passphrase);
  
  // Additional stretching with Argon2
  const enhancedSeed = await Argon2.hash(
    basicSeed,
    new TextEncoder().encode('enhanced-derivation'),
    {
      timeCost: 10,
      memoryCost: 65536,
      outputLength: 64
    }
  );
  
  return enhancedSeed;
}

Platform-Specific Notes

Browser/JavaScript

Node.js

Python

Rust

Mobile (iOS/Android)

Compliance Information

Standards Compliance

Security Considerations

Best Practices

DO:

DON’T:

Regulatory Notes


Security Notice: BIP39 mnemonics are the keys to your digital assets. Treat them with extreme care. Never share them. Never enter them online. Always verify you can recover your wallet before storing significant value.

Last Updated: 2025-07-06
**Version
: 3.0.0
License: BSL-1.1

Security Analysis

Threat Model: BIP39 Threat Model

The comprehensive threat analysis covers:

For complete security analysis and risk assessment, see the dedicated threat model documentation.