use std::fmt;
pub(crate) mod address;
pub(crate) mod entropy;
pub(crate) mod keygen;
pub(crate) mod pubkey;
pub(crate) mod secret;
pub(crate) mod wif;
pub use address::derive_address;
pub use keygen::PrivateKey;
pub use keygen::generate;
pub use pubkey::derive_pubkey;
pub use secret::{SecretAscii, SecretKeyHex, SecretWif};
pub use wif::encode_wif;
#[derive(Debug)]
pub struct Error(pub(crate) String);
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::error::Error for Error {}
impl From<entropy::EntropyError> for Error {
fn from(e: entropy::EntropyError) -> Self {
Error(e.0)
}
}
#[cfg(test)]
mod pipeline_tests {
use crate::address;
use crate::entropy::FixedEntropy;
use crate::keygen;
use crate::pubkey;
use crate::wif;
#[test]
fn test_full_pipeline_deterministic() {
let mut key_bytes = [0u8; 32];
key_bytes[31] = 0x01;
let entropy = FixedEntropy::new(key_bytes.to_vec());
let private_key = keygen::generate_with_entropy(&entropy).expect("generation must succeed");
assert_eq!(private_key.as_bytes(), &key_bytes);
let wif = wif::encode_wif(&private_key);
assert_eq!(
wif.expose_str(),
"KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
);
assert_eq!(
private_key.to_hex().expose_str(),
"0000000000000000000000000000000000000000000000000000000000000001"
);
let compressed_pubkey = pubkey::derive_pubkey(&private_key);
let pubkey_hex: String = compressed_pubkey
.iter()
.map(|b| format!("{:02x}", b))
.collect();
assert_eq!(
pubkey_hex,
"0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
);
let addr = address::derive_address(&compressed_pubkey);
assert_eq!(addr, "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4");
}
#[test]
fn test_full_pipeline_known_vector_two() {
let mut key_bytes = [0u8; 32];
key_bytes[31] = 0x02;
let entropy = FixedEntropy::new(key_bytes.to_vec());
let private_key = keygen::generate_with_entropy(&entropy).expect("generation must succeed");
let wif = wif::encode_wif(&private_key);
assert_eq!(
wif.expose_str(),
"KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU74NMTptX4"
);
let compressed_pubkey = pubkey::derive_pubkey(&private_key);
let pubkey_hex: String = compressed_pubkey
.iter()
.map(|b| format!("{:02x}", b))
.collect();
assert_eq!(
pubkey_hex,
"02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5"
);
let addr = address::derive_address(&compressed_pubkey);
assert_eq!(addr, "bc1qq6hag67dl53wl99vzg42z8eyzfz2xlkvxechjp");
}
#[test]
fn test_pipeline_different_entropy_different_outputs() {
let mut bytes_a = [0u8; 32];
bytes_a[31] = 0x01;
let mut bytes_b = [0u8; 32];
bytes_b[31] = 0x02;
let key_a = keygen::generate_with_entropy(&FixedEntropy::new(bytes_a.to_vec())).unwrap();
let key_b = keygen::generate_with_entropy(&FixedEntropy::new(bytes_b.to_vec())).unwrap();
let pubkey_a = pubkey::derive_pubkey(&key_a);
let pubkey_b = pubkey::derive_pubkey(&key_b);
let addr_a = address::derive_address(&pubkey_a);
let addr_b = address::derive_address(&pubkey_b);
assert_ne!(key_a.as_bytes(), key_b.as_bytes());
assert_ne!(pubkey_a, pubkey_b);
assert_ne!(addr_a, addr_b);
assert_ne!(
wif::encode_wif(&key_a).expose_str(),
wif::encode_wif(&key_b).expose_str()
);
}
}