2 releases
Uses new Rust 2024
new 0.1.1 | Apr 18, 2025 |
---|---|
0.1.0 | Apr 18, 2025 |
#442 in Magic Beans
48KB
628 lines
bitcoin-address-generator
A Rust library for Bitcoin key derivation and address generation.
Features
- 🔐 Secure Memory Handling: Sensitive data like private keys and seeds are automatically zeroized when no longer needed
- 🔑 BIP39 Mnemonic Generation: Create new mnemonic phrases with various word counts (12, 15, 18, 21, 24 words)
- 💼 Multiple Address Types:
- Legacy addresses (P2PKH) via BIP44
- Nested SegWit addresses (P2SH-WPKH) via BIP49
- Native SegWit addresses (P2WPKH) via BIP84
- Taproot addresses (P2TR) via BIP86
- 🌐 Network Support: Works with Bitcoin mainnet, testnet, regtest, and signet
- 🛠️ Script Hash Calculation: Calculate script hashes for Bitcoin addresses (compatible with Electrum servers)
- 📋 Private Key Export: Derive private keys in WIF format
- 🧩 BIP32 HD Wallet: Supports custom derivation paths
- 📚 Multi-language Support: Generate mnemonics in different languages
Installation
Add this to your Cargo.toml
:
[dependencies]
bitcoin-address-generator = "0.1.0"
Usage Examples
Generate a New Mnemonic Phrase
use bitcoin_address_generator::{generate_mnemonic, WordCount};
use bip39::Language;
fn main() {
// Generate a default 12-word mnemonic in English
let mnemonic = generate_mnemonic(None, None).unwrap();
println!("Generated mnemonic: {}", mnemonic);
// Generate a 24-word mnemonic in English
let mnemonic = generate_mnemonic(Some(WordCount::Words24), None).unwrap();
println!("24-word mnemonic: {}", mnemonic);
// Generate a 12-word mnemonic in Japanese
let mnemonic = generate_mnemonic(None, Some(Language::Japanese)).unwrap();
println!("Japanese mnemonic: {}", mnemonic);
}
Derive Different Address Types from a Mnemonic
use bitcoin_address_generator::derive_bitcoin_address;
use bitcoin::Network;
fn main() {
let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
// Derive a Legacy (P2PKH) address
let p2pkh_addr = derive_bitcoin_address(
mnemonic,
Some("m/44'/0'/0'/0/0"),
Some(Network::Bitcoin),
None
).unwrap();
println!("Legacy address: {}", p2pkh_addr.address);
// Derive a Nested SegWit (P2SH-WPKH) address
let p2sh_wpkh_addr = derive_bitcoin_address(
mnemonic,
Some("m/49'/0'/0'/0/0"),
Some(Network::Bitcoin),
None
).unwrap();
println!("Nested SegWit address: {}", p2sh_wpkh_addr.address);
// Derive a Native SegWit (P2WPKH) address
let p2wpkh_addr = derive_bitcoin_address(
mnemonic,
Some("m/84'/0'/0'/0/0"),
Some(Network::Bitcoin),
None
).unwrap();
println!("Native SegWit address: {}", p2wpkh_addr.address);
// Derive a Taproot (P2TR) address
let p2tr_addr = derive_bitcoin_address(
mnemonic,
Some("m/86'/0'/0'/0/0"),
Some(Network::Bitcoin),
None
).unwrap();
println!("Taproot address: {}", p2tr_addr.address);
// Derive a testnet address
let testnet_addr = derive_bitcoin_address(
mnemonic,
Some("m/84'/1'/0'/0/0"),
Some(Network::Testnet),
None
).unwrap();
println!("Testnet address: {}", testnet_addr.address);
}
Derive Multiple Addresses at Once
use bitcoin_address_generator::derive_bitcoin_addresses;
use bitcoin::Network;
fn main() {
let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
// Derive 5 consecutive receiving addresses (m/84'/0'/0'/0/0 through m/84'/0'/0'/0/4)
let receive_addresses = derive_bitcoin_addresses(
mnemonic,
Some("m/84'/0'/0'"), // Base path up to account level
Some(Network::Bitcoin),
None, // No BIP39 passphrase
Some(false), // Receiving addresses (false = receiving, true = change)
Some(0), // Start index
Some(5) // Number of addresses to generate
).unwrap();
println!("Generated {} receiving addresses:", receive_addresses.addresses.len());
for (i, addr) in receive_addresses.addresses.iter().enumerate() {
println!("Address {}: {} (path: {})", i, addr.address, addr.path);
}
// Derive 3 change addresses (m/84'/0'/0'/1/0 through m/84'/0'/0'/1/2)
let change_addresses = derive_bitcoin_addresses(
mnemonic,
Some("m/84'/0'/0'"), // Base path up to account level
Some(Network::Bitcoin),
None, // No BIP39 passphrase
Some(true), // Change addresses (false = receiving, true = change)
Some(0), // Start index
Some(3) // Number of addresses to generate
).unwrap();
println!("\nGenerated {} change addresses:", change_addresses.addresses.len());
for (i, addr) in change_addresses.addresses.iter().enumerate() {
println!("Change Address {}: {} (path: {})", i, addr.address, addr.path);
}
// You can also start from a specific index
let custom_range = derive_bitcoin_addresses(
mnemonic,
Some("m/84'/0'/0'"),
Some(Network::Bitcoin),
None,
Some(false),
Some(10), // Start from index 10
Some(2) // Generate 2 addresses
).unwrap();
println!("\nCustom range addresses:");
for addr in custom_range.addresses.iter() {
println!("{} (path: {})", addr.address, addr.path);
}
}
Calculate a Script Hash for an Address
use bitcoin_address_generator::calculate_script_hash;
use bitcoin::Network;
fn main() {
// Calculate script hash for a P2PKH address
let script_hash = calculate_script_hash(
"1LqBGSKuX5yYUonjxT5qGfpUsXKYYWeabA",
Some(Network::Bitcoin)
).unwrap();
println!("Script hash: {}", script_hash);
// This can be used with Electrum servers for transaction history
}
Derive a Private Key in WIF Format
use bitcoin_address_generator::derive_private_key;
use bitcoin::Network;
fn main() {
let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
// Derive private key for a specific derivation path
let private_key = derive_private_key(
mnemonic,
Some("m/84'/0'/0'/0/0"),
Some(Network::Bitcoin),
None
).unwrap();
println!("Private key (WIF): {}", private_key);
}
Using a BIP39 Passphrase (Optional Extra Security)
use bitcoin_address_generator::derive_bitcoin_address;
use bitcoin::Network;
fn main() {
let mnemonic = "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about";
let passphrase = "my secret passphrase";
// Derive address with a BIP39 passphrase
let addr = derive_bitcoin_address(
mnemonic,
Some("m/84'/0'/0'/0/0"),
Some(Network::Bitcoin),
Some(passphrase)
).unwrap();
println!("Address with passphrase: {}", addr.address);
println!("Public key: {}", addr.public_key);
}
API Documentation
Main Functions
generate_mnemonic(word_count: Option<WordCount>, language: Option<Language>) -> Result<String, DerivationError>
Generates a new BIP39 mnemonic phrase.
word_count
: Optional. Number of words (12, 15, 18, 21, or 24). Defaults to 12.language
: Optional. Mnemonic language. Defaults to English.- Returns: The mnemonic phrase as a string, or an error.
derive_bitcoin_address(mnemonic_phrase: &str, derivation_path_str: Option<&str>, network: Option<Network>, bip39_passphrase: Option<&str>) -> Result<GetAddressResponse, DerivationError>
Derives a Bitcoin address from a mnemonic phrase.
mnemonic_phrase
: The BIP39 mnemonic phrase.derivation_path_str
: Optional. BIP32 derivation path. Defaults to "m/84'/0'/0'/0/0".network
: Optional. Bitcoin network. Defaults to Bitcoin mainnet.bip39_passphrase
: Optional. BIP39 passphrase. Defaults to empty string.- Returns: A
GetAddressResponse
containing address, derivation path, and public key, or an error.
derive_bitcoin_addresses(mnemonic_phrase: &str, derivation_path_str: Option<&str>, network: Option<Network>, bip39_passphrase: Option<&str>, is_change: Option<bool>, start_index: Option<u32>, count: Option<u32>) -> Result<GetAddressesResponse, DerivationError>
Derives multiple Bitcoin addresses from a single mnemonic by iterating through a range of indices.
mnemonic_phrase
: The BIP39 mnemonic phrase.derivation_path_str
: Optional. Base path up to the account level (e.g., "m/84'/0'/0'"). Defaults to "m/84'/0'/0'".network
: Optional. Bitcoin network. Defaults to Bitcoin mainnet.bip39_passphrase
: Optional. BIP39 passphrase. Defaults to empty string.is_change
: Optional. Whether to derive change addresses (true) or receiving addresses (false). Defaults to false.start_index
: Optional. Starting index for address derivation. Defaults to 0.count
: Optional. Number of addresses to generate. Defaults to 1. Returns: AGetAddressesResponse
containing a collection of addresses, or an error.
calculate_script_hash(address: &str, network: Option<Network>) -> Result<String, DerivationError>
Calculates a script hash for a Bitcoin address.
address
: The Bitcoin address.network
: Optional. Bitcoin network. Defaults to Bitcoin mainnet.- Returns: The script hash as a hex string, or an error.
derive_private_key(mnemonic_phrase: &str, derivation_path_str: Option<&str>, network: Option<Network>, bip39_passphrase: Option<&str>) -> Result<String, DerivationError>
Derives a private key in WIF format.
mnemonic_phrase
: The BIP39 mnemonic phrase.derivation_path_str
: Optional. BIP32 derivation path. Defaults to "m/84'/0'/0'/0/0".network
: Optional. Bitcoin network. Defaults to Bitcoin mainnet.bip39_passphrase
: Optional. BIP39 passphrase. Defaults to empty string.- Returns: The private key in WIF format, or an error.
Data Structures
GetAddressResponse
Holds the result of address derivation.
pub struct GetAddressResponse {
pub address: String,
pub path: String,
pub public_key: String,
}
GetAddressesResponse
Holds the result of multiple address derivation.
pub struct GetAddressesResponse {
pub addresses: Vec<GetAddressResponse>,
}
WordCount
Enum representing the possible number of words in a mnemonic phrase.
pub enum WordCount {
Words12 = 12,
Words15 = 15,
Words18 = 18,
Words21 = 21,
Words24 = 24,
}
DerivationError
Error type for key derivation operations.
Security Considerations
-
Protecting Private Keys: This library uses the
zeroize
crate to automatically clear sensitive data from memory when it's no longer needed. -
Mnemonic Phrases: Treat mnemonic phrases with the same level of security as private keys. They should never be stored unencrypted or shared.
-
BIP39 Passphrases: Using a BIP39 passphrase adds an extra layer of security, but also means you must remember both the mnemonic and the passphrase to recover your wallet.
-
Network Validation: The library validates that the derivation path's coin type matches the requested network to prevent address derivation on the wrong network.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature
) - Commit your changes (
git commit -m 'Add some amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Run tests and show logs
cargo test -- --nocapture
Run a specific test
cargo test <test_name> -- --nocapture
cargo test test_generate_mnemonic -- --nocapture
Dependencies
~11MB
~173K SLoC