use bip39::Mnemonic;
use clap::{Arg, Command};
use rand::RngCore;
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
fn main() {
let matches = Command::new("bip39-cli")
.version("1.0")
.author("Your Name")
.about("Generates BIP39 mnemonic phrases")
.arg(
Arg::new("generate")
.short('g')
.long("generate")
.help("Generate a new mnemonic phrase")
.action(clap::ArgAction::SetTrue),
)
.arg(
Arg::new("words")
.short('w')
.long("words")
.value_name("WORDS")
.help("Number of words in the mnemonic (12 or 24)")
.default_value("12")
.value_parser(clap::value_parser!(u8)),
)
.arg(
Arg::new("entropy")
.short('e')
.long("entropy")
.value_name("STRING")
.help("Custom entropy string (optional)")
.required(false),
)
.get_matches();
let should_generate = matches.get_flag("generate") || std::env::args().len() == 1;
if should_generate {
let word_count = *matches.get_one::<u8>("words").unwrap();
let entropy_len = match word_count {
12 => 16, 24 => 32, _ => {
eprintln!("Error: Word count must be 12 or 24");
std::process::exit(1);
}
};
let (entropy, custom_entropy_used) =
if let Some(custom_entropy) = matches.get_one::<String>("entropy") {
let mut hasher = DefaultHasher::new();
custom_entropy.hash(&mut hasher);
let hash = hasher.finish();
let mut entropy = vec![0u8; entropy_len];
for (i, byte) in entropy.iter_mut().enumerate() {
*byte = ((hash >> (i % 8)) ^ (hash >> ((i + 7) % 8))) as u8;
}
for i in 8..entropy_len {
entropy[i] = ((hash >> (i % 8)) ^ custom_entropy.len() as u64) as u8;
}
(entropy, Some(custom_entropy.clone()))
} else {
let mut entropy = vec![0u8; entropy_len];
rand::thread_rng().fill_bytes(&mut entropy);
(entropy, None)
};
match Mnemonic::from_entropy(&entropy) {
Ok(mnemonic) => {
let words: Vec<&str> = mnemonic.word_iter().collect();
println!("🔐 BIP39 Mnemonic Phrase ({} words):", word_count);
if let Some(custom_str) = custom_entropy_used {
println!("Randomness used: Custom string: \"{}\"", custom_str);
}
println!();
println!("Generated {} words:", word_count);
println!();
println!("{}", words.join(" "));
println!();
}
Err(e) => {
eprintln!("Error generating mnemonic: {}", e);
std::process::exit(1);
}
}
} else {
let mut cmd = Command::new("bip39-cli")
.version("1.0")
.author("Your Name")
.about("Generates BIP39 mnemonic phrases")
.arg(
Arg::new("generate")
.short('g')
.long("generate")
.help("Generate a new mnemonic phrase")
.action(clap::ArgAction::SetTrue),
)
.arg(
Arg::new("words")
.short('w')
.long("words")
.value_name("WORDS")
.help("Number of words in the mnemonic (12 or 24)")
.default_value("12")
.value_parser(clap::value_parser!(u8)),
)
.arg(
Arg::new("entropy")
.short('e')
.long("entropy")
.value_name("STRING")
.help("Custom entropy string (optional)")
.required(false),
);
cmd.print_help().unwrap();
println!();
}
}