bsv/primitives/
private_key.rs1use crate::primitives::base_point::BasePoint;
8use crate::primitives::big_number::{BigNumber, Endian};
9use crate::primitives::curve::Curve;
10use crate::primitives::ecdsa::ecdsa_sign;
11use crate::primitives::error::PrimitivesError;
12use crate::primitives::hash::{sha256, sha256_hmac};
13use crate::primitives::point::Point;
14use crate::primitives::public_key::PublicKey;
15use crate::primitives::random::random_bytes;
16use crate::primitives::signature::Signature;
17use crate::primitives::utils::{base58_check_decode, base58_check_encode};
18
19#[derive(Clone, Debug)]
24pub struct PrivateKey {
25 inner: BigNumber,
26}
27
28impl PrivateKey {
29 pub fn from_random() -> Result<Self, PrimitivesError> {
34 let curve = Curve::secp256k1();
35 loop {
36 let bytes = random_bytes(32);
37 let bn = BigNumber::from_bytes(&bytes, Endian::Big);
38 let key = bn
39 .umod(&curve.n)
40 .map_err(|e| PrimitivesError::InvalidPrivateKey(format!("mod n: {}", e)))?;
41 if !key.is_zero() {
42 return Ok(PrivateKey { inner: key });
43 }
44 }
46 }
47
48 pub fn from_bytes(bytes: &[u8]) -> Result<Self, PrimitivesError> {
52 let bn = BigNumber::from_bytes(bytes, Endian::Big);
53 Self::validate_range(&bn)?;
54 Ok(PrivateKey { inner: bn })
55 }
56
57 pub fn from_hex(hex: &str) -> Result<Self, PrimitivesError> {
62 let bn = BigNumber::from_hex(hex)?;
63 Self::validate_range(&bn)?;
64 Ok(PrivateKey { inner: bn })
65 }
66
67 pub fn from_string(s: &str) -> Result<Self, PrimitivesError> {
69 Self::from_hex(s)
70 }
71
72 pub fn from_wif(wif: &str) -> Result<Self, PrimitivesError> {
77 let (prefix, payload) = base58_check_decode(wif, 1)?;
78
79 if payload.len() != 33 {
80 return Err(PrimitivesError::InvalidWif(format!(
81 "invalid WIF data length: expected 33, got {}",
82 payload.len()
83 )));
84 }
85
86 if payload[32] != 0x01 {
87 return Err(PrimitivesError::InvalidWif(
88 "invalid WIF compression flag (expected 0x01)".to_string(),
89 ));
90 }
91
92 let _ = prefix; let bn = BigNumber::from_bytes(&payload[..32], Endian::Big);
94 Self::validate_range(&bn)?;
95 Ok(PrivateKey { inner: bn })
96 }
97
98 pub fn to_hex(&self) -> String {
100 let hex = self.inner.to_hex();
101 format!("{:0>64}", hex)
102 }
103
104 pub fn to_wif(&self, prefix: &[u8]) -> String {
109 let mut key_data = self.inner.to_array(Endian::Big, Some(32));
110 key_data.push(0x01); base58_check_encode(&key_data, prefix)
112 }
113
114 pub fn to_public_key(&self) -> PublicKey {
118 let base_point = BasePoint::instance();
119 let point = base_point.mul(&self.inner);
120 PublicKey::from_point(point)
121 }
122
123 pub fn sign(&self, message: &[u8], force_low_s: bool) -> Result<Signature, PrimitivesError> {
128 let msg_hash = sha256(message);
129 ecdsa_sign(&msg_hash, &self.inner, force_low_s)
130 }
131
132 pub fn to_bytes(&self) -> Vec<u8> {
134 self.inner.to_array(Endian::Big, Some(32))
135 }
136
137 pub fn bn(&self) -> &BigNumber {
139 &self.inner
140 }
141
142 pub fn derive_shared_secret(&self, public_key: &PublicKey) -> Result<Point, PrimitivesError> {
147 if !public_key.point().validate() {
148 return Err(PrimitivesError::InvalidPublicKey(
149 "public key is not on the curve".to_string(),
150 ));
151 }
152 let result = public_key.point().mul(&self.inner);
153 Ok(result)
154 }
155
156 pub fn derive_child(
161 &self,
162 counterparty: &PublicKey,
163 invoice_number: &str,
164 ) -> Result<PrivateKey, PrimitivesError> {
165 let curve = Curve::secp256k1();
166 let shared_secret = self.derive_shared_secret(counterparty)?;
167 let shared_secret_bytes = shared_secret.to_der(true); let hmac_result = sha256_hmac(&shared_secret_bytes, invoice_number.as_bytes());
169 let hmac_bn = BigNumber::from_bytes(&hmac_result, Endian::Big);
170 let child =
171 self.inner.add(&hmac_bn).umod(&curve.n).map_err(|e| {
172 PrimitivesError::ArithmeticError(format!("derive_child mod n: {}", e))
173 })?;
174 let child_bytes = child.to_array(Endian::Big, Some(32));
175 PrivateKey::from_bytes(&child_bytes)
176 }
177
178 fn validate_range(bn: &BigNumber) -> Result<(), PrimitivesError> {
180 let curve = Curve::secp256k1();
181 if bn.is_zero() {
182 return Err(PrimitivesError::InvalidPrivateKey(
183 "private key must not be zero".to_string(),
184 ));
185 }
186 if bn.cmp(&curve.n) >= 0 {
187 return Err(PrimitivesError::InvalidPrivateKey(
188 "private key must be less than curve order n".to_string(),
189 ));
190 }
191 if bn.is_negative() {
192 return Err(PrimitivesError::InvalidPrivateKey(
193 "private key must not be negative".to_string(),
194 ));
195 }
196 Ok(())
197 }
198}
199
200impl PartialEq for PrivateKey {
201 fn eq(&self, other: &Self) -> bool {
202 self.inner.cmp(&other.inner) == 0
203 }
204}
205
206#[cfg(test)]
207mod tests {
208 use super::*;
209 use crate::primitives::ecdsa::ecdsa_verify;
210
211 #[test]
216 fn test_private_key_from_random() {
217 let key = PrivateKey::from_random().unwrap();
218 let curve = Curve::secp256k1();
219
220 assert!(!key.bn().is_zero(), "Random key should not be zero");
222 assert!(
223 key.bn().cmp(&curve.n) < 0,
224 "Random key should be less than n"
225 );
226 }
227
228 #[test]
229 fn test_private_key_from_random_unique() {
230 let k1 = PrivateKey::from_random().unwrap();
231 let k2 = PrivateKey::from_random().unwrap();
232 assert_ne!(k1, k2, "Two random keys should differ");
233 }
234
235 #[test]
240 fn test_private_key_from_hex() {
241 let key = PrivateKey::from_hex("1").unwrap();
242 assert_eq!(
243 key.to_hex(),
244 "0000000000000000000000000000000000000000000000000000000000000001"
245 );
246 }
247
248 #[test]
249 fn test_private_key_hex_roundtrip() {
250 let hex = "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35";
251 let key = PrivateKey::from_hex(hex).unwrap();
252 assert_eq!(key.to_hex(), hex);
253 }
254
255 #[test]
256 fn test_private_key_from_hex_zero_rejected() {
257 let result = PrivateKey::from_hex("0");
258 assert!(result.is_err(), "Zero should be rejected");
259 }
260
261 #[test]
262 fn test_private_key_from_hex_too_large() {
263 let result = PrivateKey::from_hex(
266 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
267 );
268 assert!(result.is_err(), "n should be rejected");
269 }
270
271 #[test]
276 fn test_private_key_from_string() {
277 let key = PrivateKey::from_string("1").unwrap();
278 assert_eq!(
279 key.to_hex(),
280 "0000000000000000000000000000000000000000000000000000000000000001"
281 );
282 }
283
284 #[test]
289 fn test_private_key_wif_roundtrip() {
290 let key = PrivateKey::from_hex("1").unwrap();
291 let wif = key.to_wif(&[0x80]);
292 let recovered = PrivateKey::from_wif(&wif).unwrap();
293 assert_eq!(key, recovered, "WIF round-trip should recover same key");
294 }
295
296 #[test]
297 fn test_private_key_wif_known_vector() {
298 let wif = "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn";
300 let key = PrivateKey::from_wif(wif).unwrap();
301 assert_eq!(
302 key.to_hex(),
303 "0000000000000000000000000000000000000000000000000000000000000001"
304 );
305 }
306
307 #[test]
308 fn test_private_key_to_wif_known_vector() {
309 let key = PrivateKey::from_hex("1").unwrap();
310 let wif = key.to_wif(&[0x80]);
311 assert_eq!(wif, "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn");
312 }
313
314 #[test]
315 fn test_private_key_wif_test_vectors() {
316 use serde::Deserialize;
317
318 #[derive(Deserialize)]
319 struct WifVector {
320 private_key_hex: String,
321 wif_mainnet: String,
322 wif_prefix: String,
323 #[allow(dead_code)]
324 description: String,
325 }
326
327 let data = include_str!("../../test-vectors/private_key_wif.json");
328 let vectors: Vec<WifVector> = serde_json::from_str(data).unwrap();
329
330 for (i, v) in vectors.iter().enumerate() {
331 let key = PrivateKey::from_hex(&v.private_key_hex).unwrap();
332 let prefix_bytes = crate::primitives::utils::from_hex(&v.wif_prefix).unwrap();
333 let wif = key.to_wif(&prefix_bytes);
334 assert_eq!(wif, v.wif_mainnet, "Vector {}: WIF mismatch", i);
335
336 let recovered = PrivateKey::from_wif(&wif).unwrap();
338 assert_eq!(key, recovered, "Vector {}: WIF round-trip failed", i);
339 }
340 }
341
342 #[test]
347 fn test_private_key_to_public_key() {
348 let key = PrivateKey::from_hex("1").unwrap();
350 let pubkey = key.to_public_key();
351 let compressed = pubkey.to_der_hex();
352 assert_eq!(
353 compressed,
354 "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
355 );
356 }
357
358 #[test]
363 fn test_private_key_sign_verify() {
364 let key = PrivateKey::from_hex("1").unwrap();
365 let sig = key.sign(b"Hello, BSV!", true).unwrap();
366 let pubkey = key.to_public_key();
367
368 let msg_hash = sha256(b"Hello, BSV!");
369 assert!(
370 ecdsa_verify(&msg_hash, &sig, pubkey.point()),
371 "Signature should verify"
372 );
373 }
374
375 #[test]
376 fn test_private_key_sign_low_s() {
377 let curve = Curve::secp256k1();
378 let key = PrivateKey::from_hex("ff").unwrap();
379 let sig = key.sign(b"test low s", true).unwrap();
380 assert!(
381 sig.s().cmp(&curve.half_n) <= 0,
382 "s should be low when force_low_s is true"
383 );
384 }
385
386 #[test]
391 fn test_private_key_to_bytes() {
392 let key = PrivateKey::from_hex("1").unwrap();
393 let bytes = key.to_bytes();
394 assert_eq!(bytes.len(), 32);
395 assert_eq!(bytes[31], 1);
396 assert_eq!(bytes[0], 0);
397 }
398}