1use 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 shared_secret = self.derive_shared_secret(counterparty)?;
166 self.derive_child_with_secret(&shared_secret, invoice_number)
167 }
168
169 pub fn derive_child_with_secret(
181 &self,
182 shared_secret: &Point,
183 invoice_number: &str,
184 ) -> Result<PrivateKey, PrimitivesError> {
185 let curve = Curve::secp256k1();
186 let shared_secret_bytes = shared_secret.to_der(true); let hmac_result = sha256_hmac(&shared_secret_bytes, invoice_number.as_bytes());
188 let hmac_bn = BigNumber::from_bytes(&hmac_result, Endian::Big);
189 let child =
190 self.inner.add(&hmac_bn).umod(&curve.n).map_err(|e| {
191 PrimitivesError::ArithmeticError(format!("derive_child mod n: {}", e))
192 })?;
193 let child_bytes = child.to_array(Endian::Big, Some(32));
194 PrivateKey::from_bytes(&child_bytes)
195 }
196
197 fn validate_range(bn: &BigNumber) -> Result<(), PrimitivesError> {
199 let curve = Curve::secp256k1();
200 if bn.is_zero() {
201 return Err(PrimitivesError::InvalidPrivateKey(
202 "private key must not be zero".to_string(),
203 ));
204 }
205 if bn.cmp(&curve.n) >= 0 {
206 return Err(PrimitivesError::InvalidPrivateKey(
207 "private key must be less than curve order n".to_string(),
208 ));
209 }
210 if bn.is_negative() {
211 return Err(PrimitivesError::InvalidPrivateKey(
212 "private key must not be negative".to_string(),
213 ));
214 }
215 Ok(())
216 }
217}
218
219impl PartialEq for PrivateKey {
220 fn eq(&self, other: &Self) -> bool {
221 self.inner.cmp(&other.inner) == 0
222 }
223}
224
225#[cfg(test)]
226mod tests {
227 use super::*;
228 use crate::primitives::ecdsa::ecdsa_verify;
229
230 #[test]
235 fn test_private_key_from_random() {
236 let key = PrivateKey::from_random().unwrap();
237 let curve = Curve::secp256k1();
238
239 assert!(!key.bn().is_zero(), "Random key should not be zero");
241 assert!(
242 key.bn().cmp(&curve.n) < 0,
243 "Random key should be less than n"
244 );
245 }
246
247 #[test]
248 fn test_private_key_from_random_unique() {
249 let k1 = PrivateKey::from_random().unwrap();
250 let k2 = PrivateKey::from_random().unwrap();
251 assert_ne!(k1, k2, "Two random keys should differ");
252 }
253
254 #[test]
259 fn test_private_key_from_hex() {
260 let key = PrivateKey::from_hex("1").unwrap();
261 assert_eq!(
262 key.to_hex(),
263 "0000000000000000000000000000000000000000000000000000000000000001"
264 );
265 }
266
267 #[test]
268 fn test_private_key_hex_roundtrip() {
269 let hex = "e8f32e723decf4051aefac8e2c93c9c5b214313817cdb01a1494b917c8436b35";
270 let key = PrivateKey::from_hex(hex).unwrap();
271 assert_eq!(key.to_hex(), hex);
272 }
273
274 #[test]
275 fn test_private_key_from_hex_zero_rejected() {
276 let result = PrivateKey::from_hex("0");
277 assert!(result.is_err(), "Zero should be rejected");
278 }
279
280 #[test]
281 fn test_private_key_from_hex_too_large() {
282 let result = PrivateKey::from_hex(
285 "fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141",
286 );
287 assert!(result.is_err(), "n should be rejected");
288 }
289
290 #[test]
295 fn test_private_key_from_string() {
296 let key = PrivateKey::from_string("1").unwrap();
297 assert_eq!(
298 key.to_hex(),
299 "0000000000000000000000000000000000000000000000000000000000000001"
300 );
301 }
302
303 #[test]
308 fn test_private_key_wif_roundtrip() {
309 let key = PrivateKey::from_hex("1").unwrap();
310 let wif = key.to_wif(&[0x80]);
311 let recovered = PrivateKey::from_wif(&wif).unwrap();
312 assert_eq!(key, recovered, "WIF round-trip should recover same key");
313 }
314
315 #[test]
316 fn test_private_key_wif_known_vector() {
317 let wif = "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn";
319 let key = PrivateKey::from_wif(wif).unwrap();
320 assert_eq!(
321 key.to_hex(),
322 "0000000000000000000000000000000000000000000000000000000000000001"
323 );
324 }
325
326 #[test]
327 fn test_private_key_to_wif_known_vector() {
328 let key = PrivateKey::from_hex("1").unwrap();
329 let wif = key.to_wif(&[0x80]);
330 assert_eq!(wif, "KwDiBf89QgGbjEhKnhXJuH7LrciVrZi3qYjgd9M7rFU73sVHnoWn");
331 }
332
333 #[test]
334 fn test_private_key_wif_test_vectors() {
335 use serde::Deserialize;
336
337 #[derive(Deserialize)]
338 struct WifVector {
339 private_key_hex: String,
340 wif_mainnet: String,
341 wif_prefix: String,
342 #[allow(dead_code)]
343 description: String,
344 }
345
346 let data = include_str!("../../test-vectors/private_key_wif.json");
347 let vectors: Vec<WifVector> = serde_json::from_str(data).unwrap();
348
349 for (i, v) in vectors.iter().enumerate() {
350 let key = PrivateKey::from_hex(&v.private_key_hex).unwrap();
351 let prefix_bytes = crate::primitives::utils::from_hex(&v.wif_prefix).unwrap();
352 let wif = key.to_wif(&prefix_bytes);
353 assert_eq!(wif, v.wif_mainnet, "Vector {}: WIF mismatch", i);
354
355 let recovered = PrivateKey::from_wif(&wif).unwrap();
357 assert_eq!(key, recovered, "Vector {}: WIF round-trip failed", i);
358 }
359 }
360
361 #[test]
366 fn test_private_key_to_public_key() {
367 let key = PrivateKey::from_hex("1").unwrap();
369 let pubkey = key.to_public_key();
370 let compressed = pubkey.to_der_hex();
371 assert_eq!(
372 compressed,
373 "0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798"
374 );
375 }
376
377 #[test]
382 fn test_private_key_sign_verify() {
383 let key = PrivateKey::from_hex("1").unwrap();
384 let sig = key.sign(b"Hello, BSV!", true).unwrap();
385 let pubkey = key.to_public_key();
386
387 let msg_hash = sha256(b"Hello, BSV!");
388 assert!(
389 ecdsa_verify(&msg_hash, &sig, pubkey.point()),
390 "Signature should verify"
391 );
392 }
393
394 #[test]
395 fn test_private_key_sign_low_s() {
396 let curve = Curve::secp256k1();
397 let key = PrivateKey::from_hex("ff").unwrap();
398 let sig = key.sign(b"test low s", true).unwrap();
399 assert!(
400 sig.s().cmp(&curve.half_n) <= 0,
401 "s should be low when force_low_s is true"
402 );
403 }
404
405 #[test]
410 fn test_private_key_to_bytes() {
411 let key = PrivateKey::from_hex("1").unwrap();
412 let bytes = key.to_bytes();
413 assert_eq!(bytes.len(), 32);
414 assert_eq!(bytes[31], 1);
415 assert_eq!(bytes[0], 0);
416 }
417}