1use std::fmt;
45
46pub(crate) mod address;
47pub(crate) mod entropy;
48pub(crate) mod keygen;
49pub(crate) mod pubkey;
50pub(crate) mod wif;
51
52pub use address::derive_address;
53pub use keygen::PrivateKey;
54pub use keygen::generate;
55pub use pubkey::derive_pubkey;
56pub use wif::encode_wif;
57
58#[derive(Debug)]
63pub struct Error(pub(crate) String);
64
65impl fmt::Display for Error {
66 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
67 write!(f, "{}", self.0)
68 }
69}
70
71impl std::error::Error for Error {}
72
73impl From<entropy::EntropyError> for Error {
74 fn from(e: entropy::EntropyError) -> Self {
75 Error(e.0)
76 }
77}
78
79#[cfg(test)]
80mod pipeline_tests {
81 use crate::address;
82 use crate::entropy::FixedEntropy;
83 use crate::keygen;
84 use crate::pubkey;
85 use crate::wif;
86
87 #[test]
95 fn test_full_pipeline_deterministic() {
96 let mut key_bytes = [0u8; 32];
97 key_bytes[31] = 0x01;
98
99 let entropy = FixedEntropy::new(key_bytes.to_vec());
100 let private_key = keygen::generate_with_entropy(&entropy).expect("generation must succeed");
101
102 assert_eq!(private_key.as_bytes(), &key_bytes);
103
104 let wif_str = wif::encode_wif(&private_key);
105 assert_eq!(
106 wif_str,
107 "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn"
108 );
109
110 let compressed_pubkey = pubkey::derive_pubkey(&private_key);
111 let pubkey_hex: String = compressed_pubkey
112 .iter()
113 .map(|b| format!("{:02x}", b))
114 .collect();
115 assert_eq!(
116 pubkey_hex,
117 "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
118 );
119
120 let addr = address::derive_address(&compressed_pubkey);
121 assert_eq!(addr, "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4");
122 }
123
124 #[test]
126 fn test_full_pipeline_known_vector_two() {
127 let mut key_bytes = [0u8; 32];
128 key_bytes[31] = 0x02;
129
130 let entropy = FixedEntropy::new(key_bytes.to_vec());
131 let private_key = keygen::generate_with_entropy(&entropy).expect("generation must succeed");
132
133 let wif_str = wif::encode_wif(&private_key);
134 assert_eq!(
136 wif_str,
137 "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU74NMTptX4"
138 );
139
140 let compressed_pubkey = pubkey::derive_pubkey(&private_key);
141 let pubkey_hex: String = compressed_pubkey
142 .iter()
143 .map(|b| format!("{:02x}", b))
144 .collect();
145 assert_eq!(
146 pubkey_hex,
147 "02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5"
148 );
149
150 let addr = address::derive_address(&compressed_pubkey);
151 assert_eq!(addr, "bc1qq6hag67dl53wl99vzg42z8eyzfz2xlkvxechjp");
152 }
153
154 #[test]
156 fn test_pipeline_different_entropy_different_outputs() {
157 let mut bytes_a = [0u8; 32];
158 bytes_a[31] = 0x01;
159 let mut bytes_b = [0u8; 32];
160 bytes_b[31] = 0x02;
161
162 let key_a = keygen::generate_with_entropy(&FixedEntropy::new(bytes_a.to_vec())).unwrap();
163 let key_b = keygen::generate_with_entropy(&FixedEntropy::new(bytes_b.to_vec())).unwrap();
164
165 let pubkey_a = pubkey::derive_pubkey(&key_a);
166 let pubkey_b = pubkey::derive_pubkey(&key_b);
167
168 let addr_a = address::derive_address(&pubkey_a);
169 let addr_b = address::derive_address(&pubkey_b);
170
171 assert_ne!(key_a.as_bytes(), key_b.as_bytes());
172 assert_ne!(pubkey_a, pubkey_b);
173 assert_ne!(addr_a, addr_b);
174 assert_ne!(wif::encode_wif(&key_a), wif::encode_wif(&key_b));
175 }
176}