3 unstable releases
| 0.2.0 | Jan 4, 2026 |
|---|---|
| 0.1.2 | Jan 1, 2026 |
| 0.1.0 | Dec 31, 2025 |
#16 in #bip-39
Used in 3 crates
190KB
2K
SLoC
rustywallet-mnemonic
BIP39 mnemonic (seed phrase) generation and management for cryptocurrency wallets with secure memory handling and comprehensive validation.
Features
- Mnemonic Generation: Generate cryptographically secure 12, 15, 18, 21, or 24-word mnemonics
- Validation: Complete mnemonic validation including checksum verification and wordlist compliance
- Seed Derivation: PBKDF2-HMAC-SHA512 seed derivation with optional passphrase support
- Passphrase Support: BIP39 "25th word" passphrase functionality for enhanced security
- Memory Security: Automatic zeroization of sensitive data on drop
- Standard Compliance: Full BIP39 specification compliance with English wordlist
- Integration Ready: Seamless integration with rustywallet-keys for key derivation
Installation
Add this to your Cargo.toml:
[dependencies]
rustywallet-mnemonic = "0.1.0"
Quick Start
use rustywallet_mnemonic::prelude::*;
// Generate a new 12-word mnemonic
let mnemonic = Mnemonic::generate(WordCount::Words12);
println!("Mnemonic: {}", mnemonic.to_phrase());
// Derive seed with passphrase
let seed = mnemonic.to_seed("my-passphrase");
println!("Seed: {}", seed.to_hex());
Mnemonic Generation
Generate Different Word Counts
use rustywallet_mnemonic::prelude::*;
// 12-word mnemonic (128-bit entropy)
let mnemonic_12 = Mnemonic::generate(WordCount::Words12);
// 24-word mnemonic (256-bit entropy) - recommended for maximum security
let mnemonic_24 = Mnemonic::generate(WordCount::Words24);
// Other supported lengths
let mnemonic_15 = Mnemonic::generate(WordCount::Words15);
let mnemonic_18 = Mnemonic::generate(WordCount::Words18);
let mnemonic_21 = Mnemonic::generate(WordCount::Words21);
Parse Existing Mnemonic
let phrase = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
let mnemonic = Mnemonic::from_phrase(phrase)?;
Seed Derivation
With Passphrase (BIP39 "25th word")
let mnemonic = Mnemonic::generate(WordCount::Words12);
// Derive seed with passphrase for enhanced security
let seed_with_passphrase = mnemonic.to_seed("my-secret-passphrase");
// Different passphrases produce different seeds
let seed_different = mnemonic.to_seed("different-passphrase");
Without Passphrase
// Standard seed derivation without passphrase
let seed = mnemonic.to_seed("");
// or use the convenience method
let seed_normalized = mnemonic.to_seed_normalized();
Passphrase Support
Passphrases provide an additional layer of security by acting as a "25th word":
let mnemonic = Mnemonic::from_phrase("your twelve word mnemonic phrase here")?;
// Each passphrase creates a different wallet
let wallet_1 = mnemonic.to_seed("passphrase1");
let wallet_2 = mnemonic.to_seed("passphrase2");
let wallet_3 = mnemonic.to_seed(""); // No passphrase
// All three seeds will be completely different
assert_ne!(wallet_1.as_bytes(), wallet_2.as_bytes());
assert_ne!(wallet_1.as_bytes(), wallet_3.as_bytes());
Validation
Mnemonic Validation
// Validate mnemonic phrase
let valid_phrase = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
assert!(Mnemonic::from_phrase(valid_phrase).is_ok());
// Invalid checksum
let invalid_phrase = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon";
assert!(Mnemonic::from_phrase(invalid_phrase).is_err());
// Invalid word
let invalid_word = "invalid abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
assert!(Mnemonic::from_phrase(invalid_word).is_err());
Word Count Validation
// Check if phrase has correct word count
let phrase = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
let word_count = phrase.split_whitespace().count();
assert_eq!(word_count, 12);
API Reference
Core Types
Mnemonic
The main mnemonic type with secure memory handling.
impl Mnemonic {
// Generate new mnemonic
pub fn generate(word_count: WordCount) -> Self;
// Parse from phrase
pub fn from_phrase(phrase: &str) -> Result<Self, MnemonicError>;
// Convert to phrase string
pub fn to_phrase(&self) -> String;
// Derive seed with passphrase
pub fn to_seed(&self, passphrase: &str) -> Seed;
// Derive seed without passphrase
pub fn to_seed_normalized(&self) -> Seed;
// Derive private key directly
pub fn to_private_key(&self, passphrase: &str) -> Result<PrivateKey, KeyError>;
}
WordCount
Supported mnemonic lengths.
pub enum WordCount {
Words12, // 128-bit entropy
Words15, // 160-bit entropy
Words18, // 192-bit entropy
Words21, // 224-bit entropy
Words24, // 256-bit entropy
}
Seed
Derived seed with secure memory handling.
impl Seed {
pub fn as_bytes(&self) -> &[u8];
pub fn to_hex(&self) -> String;
}
BIP39 Specification Compliance
| Word Count | Entropy Bits | Checksum Bits | Total Bits | Security Level |
|---|---|---|---|---|
| 12 | 128 | 4 | 132 | Standard |
| 15 | 160 | 5 | 165 | Enhanced |
| 18 | 192 | 6 | 198 | High |
| 21 | 224 | 7 | 231 | Very High |
| 24 | 256 | 8 | 264 | Maximum |
Error Handling
use rustywallet_mnemonic::MnemonicError;
match Mnemonic::from_phrase("invalid phrase") {
Ok(mnemonic) => println!("Valid mnemonic"),
Err(MnemonicError::InvalidChecksum) => println!("Checksum validation failed"),
Err(MnemonicError::InvalidWordCount) => println!("Invalid number of words"),
Err(MnemonicError::InvalidWord(word)) => println!("Invalid word: {}", word),
}
Security Considerations
- Entropy Source: Uses
OsRngfor cryptographically secure random number generation - Memory Safety: All sensitive data (entropy, seeds) is automatically zeroized on drop
- Debug Protection: Debug output is masked to prevent accidental exposure in logs
- PBKDF2 Parameters: Uses 2048 iterations with HMAC-SHA512 as per BIP39 specification
- Constant-Time Operations: Checksum validation uses constant-time comparison
Integration with rustywallet-keys
use rustywallet_mnemonic::prelude::*;
use rustywallet_keys::prelude::*;
// Generate mnemonic and derive keys
let mnemonic = Mnemonic::generate(WordCount::Words12);
let private_key = mnemonic.to_private_key("my-passphrase")?;
// Derive public key and address
let public_key = private_key.public_key();
let address = public_key.to_address();
println!("Address: {}", address);
Examples
See the examples/ directory for complete usage examples:
generate.rs- Basic mnemonic generationvalidation.rs- Mnemonic validation examplespassphrase.rs- Passphrase usage patternsintegration.rs- Integration with other rustywallet crates
Contributing
Contributions are welcome! Please read our Contributing Guidelines and Code of Conduct.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Dependencies
~6MB
~81K SLoC