| Crates.io | rustywallet-address |
| lib.rs | rustywallet-address |
| version | 0.3.0 |
| created_at | 2025-12-31 13:57:46.165226+00 |
| updated_at | 2026-01-04 07:18:13.78702+00 |
| description | Cryptocurrency address generation and validation for Bitcoin and Ethereum |
| homepage | |
| repository | https://github.com/nirvagold/rustywallet |
| max_upload_size | |
| id | 2014754 |
| size | 89,106 |
Comprehensive cryptocurrency address generation and validation library for Bitcoin and Ethereum networks.
1... mainnet, m/n testnet)bc1q... mainnet, tb1q... testnet)bc1p... mainnet, tb1p... testnet)sp1... mainnet, tsp1... testnet)0x...)Add this to your Cargo.toml:
[dependencies]
rustywallet-address = "0.3"
rustywallet-keys = "0.1"
use rustywallet_keys::prelude::PrivateKey;
use rustywallet_address::prelude::*;
// Generate a random private key
let private_key = PrivateKey::random();
let public_key = private_key.public_key();
// Bitcoin Legacy (P2PKH)
let p2pkh = P2PKHAddress::from_public_key(&public_key, Network::BitcoinMainnet)?;
println!("P2PKH: {}", p2pkh); // 1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2
// Bitcoin SegWit (P2WPKH)
let p2wpkh = P2WPKHAddress::from_public_key(&public_key, Network::BitcoinMainnet)?;
println!("P2WPKH: {}", p2wpkh); // bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4
// Bitcoin Taproot (P2TR)
let p2tr = P2TRAddress::from_public_key(&public_key, Network::BitcoinMainnet)?;
println!("P2TR: {}", p2tr); // bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297
// Ethereum
let eth = EthereumAddress::from_public_key(&public_key)?;
println!("Ethereum: {}", eth); // 0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed
Derive addresses from output descriptors (BIP380-386):
use rustywallet_address::prelude::*;
// Derive from wpkh descriptor
let addr = Address::from_descriptor(
"wpkh(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)",
0,
Network::BitcoinMainnet,
)?;
assert!(addr.to_string().starts_with("bc1q"));
// Derive from Taproot descriptor
let addr = Address::from_descriptor(
"tr(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5)",
0,
Network::BitcoinMainnet,
)?;
assert!(addr.to_string().starts_with("bc1p"));
// Derive from nested SegWit descriptor
let addr = Address::from_descriptor(
"sh(wpkh(02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5))",
0,
Network::BitcoinMainnet,
)?;
assert!(addr.to_string().starts_with("3"));
// Derive multiple addresses from ranged descriptor
let addrs = Address::from_descriptor_range(
"wpkh(xpub.../0/*)",
0, // start index
10, // count
Network::BitcoinMainnet,
)?;
| Type | Description | Address Format |
|---|---|---|
pkh() |
Pay to pubkey hash | P2PKH (1...) |
wpkh() |
Pay to witness pubkey hash | P2WPKH (bc1q...) |
sh(wpkh()) |
Nested SegWit | P2SH-P2WPKH (3...) |
tr() |
Pay to Taproot | P2TR (bc1p...) |
wsh() |
Pay to witness script hash | P2WSH (bc1q...) |
multi() |
k-of-n multisig | Depends on wrapper |
sortedmulti() |
Sorted k-of-n multisig | Depends on wrapper |
use rustywallet_address::descriptor::*;
// Get descriptor type
let desc_type = get_descriptor_type("wpkh(KEY)")?;
assert_eq!(desc_type, DescriptorType::Wpkh);
assert!(desc_type.is_segwit());
// Check for wildcard
let has_wildcard = descriptor_has_wildcard("wpkh(xpub.../0/*)")?;
assert!(has_wildcard);
// Direct address derivation
let addr = derive_address_from_descriptor(
"tr(KEY)",
0,
Network::BitcoinMainnet,
)?;
Legacy Bitcoin addresses using Base58Check encoding:
use rustywallet_address::prelude::*;
// From public key
let address = P2PKHAddress::from_public_key(&public_key, Network::BitcoinMainnet)?;
// From string
let address = P2PKHAddress::from_str("1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2")?;
// Validate
P2PKHAddress::validate("1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2")?;
SegWit v0 addresses using Bech32 encoding:
use rustywallet_address::prelude::*;
// From public key
let address = P2WPKHAddress::from_public_key(&public_key, Network::BitcoinMainnet)?;
// From string
let address = P2WPKHAddress::from_str("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")?;
// Validate
P2WPKHAddress::validate("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4")?;
Taproot addresses using Bech32m encoding:
use rustywallet_address::prelude::*;
// From public key
let address = P2TRAddress::from_public_key(&public_key, Network::BitcoinMainnet)?;
// From string
let address = P2TRAddress::from_str("bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297")?;
// Validate
P2TRAddress::validate("bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297")?;
Privacy-preserving addresses using Bech32m encoding:
use rustywallet_address::prelude::*;
use rustywallet_address::silent_payments::{SilentPaymentAddress, SilentPaymentLabel};
// Create from scan and spend keys
let scan_key = PrivateKey::random();
let spend_key = PrivateKey::random();
let address = SilentPaymentAddress::new(
&scan_key.public_key(),
&spend_key.public_key(),
Network::BitcoinMainnet,
)?;
println!("SP Address: {}", address); // sp1q...
// Single-key mode (scan = spend)
let key = PrivateKey::random();
let address = SilentPaymentAddress::from_single_key(&key.public_key(), Network::BitcoinMainnet)?;
// Parse from string
let address = SilentPaymentAddress::parse("sp1q...")?;
// Labels for multiple addresses
let label = SilentPaymentLabel::new(1);
Ethereum addresses with EIP-55 checksum support:
use rustywallet_address::prelude::*;
// From public key
let address = EthereumAddress::from_public_key(&public_key)?;
// From string
let address = EthereumAddress::from_str("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")?;
// Validate with checksum
EthereumAddress::validate_checksum("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed")?;
// Convert to checksummed format
let checksummed = address.to_checksum();
use rustywallet_address::prelude::*;
// Generic address validation with auto-detection
let result = Address::validate("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4");
assert!(result.is_ok());
// Specific type validation
assert!(P2PKHAddress::validate("1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2").is_ok());
assert!(P2WPKHAddress::validate("bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4").is_ok());
assert!(P2TRAddress::validate("bc1p5d7rjq7g6rdk2yhzks9smlaqtedr4dekq08ge8ztwac72sfr9rusxg3297").is_ok());
assert!(EthereumAddress::validate("0x5aAeb6053F3E94C9b9A09f33669435E7Ef1BeAed").is_ok());
// Network-specific validation
let mainnet_addr = "1BvBMSEYstWetqTFn5Au4m4GFg7xJaNVN2";
let testnet_addr = "mipcBbFg9gMiCh81Kj8tqqdgoZub1ZJRfn";
assert!(P2PKHAddress::validate_network(mainnet_addr, Network::BitcoinMainnet).is_ok());
assert!(P2PKHAddress::validate_network(testnet_addr, Network::BitcoinTestnet).is_ok());
// Invalid addresses return detailed errors
match Address::validate("invalid_address") {
Err(AddressError::InvalidFormat(_)) => println!("Invalid format"),
Err(AddressError::ChecksumMismatch) => println!("Invalid checksum"),
_ => {}
}
| Network | P2PKH Prefix | P2WPKH Prefix | P2TR Prefix | Description |
|---|---|---|---|---|
| Bitcoin Mainnet | 1 |
bc1q |
bc1p |
Production Bitcoin network |
| Bitcoin Testnet | m, n |
tb1q |
tb1p |
Bitcoin test network |
| Bitcoin Regtest | m, n |
bcrt1q |
bcrt1p |
Local regression test network |
| Bitcoin Signet | m, n |
tb1q |
tb1p |
Bitcoin signet test network |
| Ethereum | N/A | N/A | N/A | All Ethereum networks use 0x |
Address - Generic address enum supporting all typesP2PKHAddress - Bitcoin Legacy addressesP2WPKHAddress - Bitcoin SegWit v0 addressesP2TRAddress - Bitcoin Taproot addressesEthereumAddress - Ethereum addressesNetwork - Supported network typesAddressError - Comprehensive error typesDescriptorType - Supported descriptor typesAddressFromDescriptor - Trait for descriptor-based derivation// Address creation
Address::from_str(s: &str) -> Result<Address, AddressError>
Address::from_public_key(pk: &PublicKey, network: Network) -> Result<Address, AddressError>
Address::from_descriptor(desc: &str, index: u32, network: Network) -> Result<Address, AddressError>
Address::from_descriptor_range(desc: &str, start: u32, count: u32, network: Network) -> Result<Vec<Address>, AddressError>
// Validation
Address::validate(s: &str) -> Result<(), AddressError>
Address::validate_network(s: &str, network: Network) -> Result<(), AddressError>
// Type checking
address.is_bitcoin() -> bool
address.is_ethereum() -> bool
address.address_type() -> AddressType
address.network() -> Option<Network>
// Conversion
address.to_string() -> String
address.as_bytes() -> &[u8]
use rustywallet_address::AddressError;
match Address::validate("invalid") {
Err(AddressError::InvalidFormat(_)) => "Invalid address format",
Err(AddressError::ChecksumMismatch) => "Checksum validation failed",
Err(AddressError::UnsupportedAddressType(_)) => "Address type not supported",
Ok(_) => "Valid address",
};
Licensed under the MIT License. See LICENSE for details.