1pub mod descriptor;
7pub mod helpers;
8pub mod message;
9pub mod psbt;
10pub mod schnorr;
11pub mod scripts;
12pub mod sighash;
13pub mod taproot;
14pub mod tapscript;
15pub mod transaction;
16
17use crate::crypto;
18use crate::encoding;
19use crate::error::SignerError;
20use crate::traits;
21use k256::ecdsa::signature::hazmat::PrehashSigner;
22use k256::ecdsa::signature::hazmat::PrehashVerifier;
23use k256::ecdsa::{Signature as K256Signature, SigningKey, VerifyingKey};
24use zeroize::Zeroizing;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
28#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
29#[must_use]
30pub struct BitcoinSignature {
31 der_bytes: Vec<u8>,
33}
34
35impl BitcoinSignature {
36 #[must_use]
38 pub fn to_bytes(&self) -> Vec<u8> {
39 self.der_bytes.clone()
40 }
41
42 #[must_use]
44 pub fn der_bytes(&self) -> &[u8] {
45 &self.der_bytes
46 }
47
48 pub fn from_bytes(der: &[u8]) -> Result<Self, SignerError> {
50 K256Signature::from_der(der).map_err(|e| SignerError::InvalidSignature(e.to_string()))?;
52 Ok(Self {
53 der_bytes: der.to_vec(),
54 })
55 }
56}
57
58impl core::fmt::Display for BitcoinSignature {
59 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60 for byte in &self.der_bytes {
61 write!(f, "{byte:02x}")?;
62 }
63 Ok(())
64 }
65}
66
67pub fn double_sha256(data: &[u8]) -> [u8; 32] {
69 crypto::double_sha256(data)
70}
71
72pub struct BitcoinSigner {
77 signing_key: SigningKey,
78}
79
80impl BitcoinSigner {
83 fn sign_digest(&self, digest: &[u8; 32]) -> Result<BitcoinSignature, SignerError> {
85 let sig: K256Signature = self
86 .signing_key
87 .sign_prehash(digest)
88 .map_err(|e| SignerError::SigningFailed(e.to_string()))?;
89
90 let der = sig.to_der();
92 Ok(BitcoinSignature {
93 der_bytes: der.as_bytes().to_vec(),
94 })
95 }
96
97 #[must_use]
105 pub fn to_wif(&self) -> Zeroizing<String> {
106 let mut payload = Zeroizing::new(Vec::with_capacity(38));
107 payload.push(0x80); payload.extend_from_slice(&self.signing_key.to_bytes());
109 payload.push(0x01); let checksum = double_sha256(&payload);
111 payload.extend_from_slice(&checksum[..4]);
112 Zeroizing::new(bs58::encode(&*payload).into_string())
113 }
114
115 #[must_use]
122 pub fn to_wif_testnet(&self) -> Zeroizing<String> {
123 let mut payload = Zeroizing::new(Vec::with_capacity(38));
124 payload.push(0xEF); payload.extend_from_slice(&self.signing_key.to_bytes());
126 payload.push(0x01); let checksum = double_sha256(&payload);
128 payload.extend_from_slice(&checksum[..4]);
129 Zeroizing::new(bs58::encode(&*payload).into_string())
130 }
131
132 pub fn from_wif(wif: &str) -> Result<Self, SignerError> {
136 use crate::traits::KeyPair;
137 let decoded = Zeroizing::new(
138 bs58::decode(wif)
139 .into_vec()
140 .map_err(|e| SignerError::InvalidPrivateKey(format!("invalid WIF base58: {e}")))?,
141 );
142
143 if decoded.len() != 37 && decoded.len() != 38 {
145 return Err(SignerError::InvalidPrivateKey(format!(
146 "WIF must be 37 or 38 bytes, got {}",
147 decoded.len()
148 )));
149 }
150
151 let version = decoded[0];
153 if version != 0x80 && version != 0xEF {
154 return Err(SignerError::InvalidPrivateKey(format!(
155 "invalid WIF version: 0x{version:02x}"
156 )));
157 }
158
159 let payload_len = decoded.len() - 4;
161 let checksum = double_sha256(&decoded[..payload_len]);
162 use subtle::ConstantTimeEq;
163 if decoded[payload_len..].ct_eq(&checksum[..4]).unwrap_u8() != 1 {
164 return Err(SignerError::InvalidPrivateKey(
165 "invalid WIF checksum".into(),
166 ));
167 }
168
169 let key_bytes = &decoded[1..33];
171
172 Self::from_bytes(key_bytes)
173 }
174
175 #[must_use]
179 pub fn p2pkh_address(&self) -> String {
180 let pubkey = self.signing_key.verifying_key().to_sec1_bytes();
181 let h160 = hash160(&pubkey);
182 base58check_encode(0x00, &h160)
183 }
184
185 pub fn p2wpkh_address(&self) -> Result<String, SignerError> {
189 let pubkey = self.signing_key.verifying_key().to_sec1_bytes();
190 let h160 = hash160(&pubkey);
191 bech32_encode("bc", 0, &h160)
192 }
193
194 pub fn p2pkh_testnet_address(&self) -> String {
196 let pubkey = self.signing_key.verifying_key().to_sec1_bytes();
197 let h160 = hash160(&pubkey);
198 base58check_encode(0x6F, &h160) }
200
201 pub fn p2wpkh_testnet_address(&self) -> Result<String, SignerError> {
203 let pubkey = self.signing_key.verifying_key().to_sec1_bytes();
204 let h160 = hash160(&pubkey);
205 bech32_encode("tb", 0, &h160)
206 }
207
208 pub fn sign_message(&self, message: &[u8]) -> Result<BitcoinSignature, SignerError> {
213 let digest = bitcoin_message_hash(message);
214 self.sign_digest(&digest)
215 }
216}
217
218pub fn hash160(data: &[u8]) -> [u8; 20] {
220 crypto::hash160(data)
221}
222
223fn base58check_encode(version: u8, payload: &[u8]) -> String {
225 encoding::base58check_encode(version, payload)
226}
227
228pub(crate) fn bech32_encode(
230 hrp: &str,
231 witness_version: u8,
232 program: &[u8],
233) -> Result<String, SignerError> {
234 encoding::bech32_encode(hrp, witness_version, program)
235}
236
237pub fn bitcoin_message_hash(message: &[u8]) -> [u8; 32] {
241 let mut data = Vec::new();
242 data.extend_from_slice(b"\x18Bitcoin Signed Message:\n");
244 data.extend_from_slice(&varint_encode(message.len()));
246 data.extend_from_slice(message);
247 double_sha256(&data)
248}
249
250fn varint_encode(n: usize) -> Vec<u8> {
252 let mut buf = Vec::new();
253 encoding::encode_compact_size(&mut buf, n as u64);
254 buf
255}
256
257pub fn validate_address(address: &str) -> bool {
262 validate_mainnet_address(address) || validate_testnet_address(address)
263}
264
265pub fn validate_mainnet_address(address: &str) -> bool {
267 if address.starts_with("bc1") {
268 bech32::segwit::decode(address).is_ok()
270 } else if address.starts_with('1') || address.starts_with('3') {
271 validate_base58check(address, &[0x00, 0x05])
273 } else {
274 false
275 }
276}
277
278pub fn validate_testnet_address(address: &str) -> bool {
280 if address.starts_with("tb1") {
281 bech32::segwit::decode(address).is_ok()
282 } else if address.starts_with('m') || address.starts_with('n') || address.starts_with('2') {
283 validate_base58check(address, &[0x6F, 0xC4])
284 } else {
285 false
286 }
287}
288
289fn validate_base58check(address: &str, valid_versions: &[u8]) -> bool {
291 let decoded = match bs58::decode(address).into_vec() {
292 Ok(d) => d,
293 Err(_) => return false,
294 };
295 if decoded.len() != 25 {
296 return false;
297 }
298 if !valid_versions.contains(&decoded[0]) {
300 return false;
301 }
302 let checksum = double_sha256(&decoded[..21]);
304 decoded[21..25] == checksum[..4]
305}
306
307impl traits::Signer for BitcoinSigner {
308 type Signature = BitcoinSignature;
309 type Error = SignerError;
310
311 fn sign(&self, message: &[u8]) -> Result<BitcoinSignature, SignerError> {
312 let digest = double_sha256(message);
313 self.sign_digest(&digest)
314 }
315
316 fn sign_prehashed(&self, digest: &[u8]) -> Result<BitcoinSignature, SignerError> {
317 if digest.len() != 32 {
318 return Err(SignerError::InvalidHashLength {
319 expected: 32,
320 got: digest.len(),
321 });
322 }
323 let mut hash = [0u8; 32];
324 hash.copy_from_slice(digest);
325 self.sign_digest(&hash)
326 }
327
328 fn public_key_bytes(&self) -> Vec<u8> {
329 self.signing_key.verifying_key().to_sec1_bytes().to_vec()
330 }
331
332 fn public_key_bytes_uncompressed(&self) -> Vec<u8> {
333 self.signing_key
334 .verifying_key()
335 .to_encoded_point(false)
336 .as_bytes()
337 .to_vec()
338 }
339}
340
341impl traits::KeyPair for BitcoinSigner {
342 fn generate() -> Result<Self, SignerError> {
343 let mut key_bytes = zeroize::Zeroizing::new([0u8; 32]);
344 crate::security::secure_random(&mut *key_bytes)?;
345 let signing_key = SigningKey::from_bytes((&*key_bytes).into())
346 .map_err(|e| SignerError::InvalidPrivateKey(e.to_string()))?;
347 Ok(Self { signing_key })
348 }
349
350 fn from_bytes(private_key: &[u8]) -> Result<Self, SignerError> {
351 if private_key.len() != 32 {
352 return Err(SignerError::InvalidPrivateKey(format!(
353 "expected 32 bytes, got {}",
354 private_key.len()
355 )));
356 }
357 let signing_key = SigningKey::from_bytes(private_key.into())
358 .map_err(|e| SignerError::InvalidPrivateKey(e.to_string()))?;
359 Ok(Self { signing_key })
360 }
361
362 fn private_key_bytes(&self) -> Zeroizing<Vec<u8>> {
363 Zeroizing::new(self.signing_key.to_bytes().to_vec())
364 }
365}
366
367pub struct BitcoinVerifier {
374 verifying_key: VerifyingKey,
375}
376
377impl BitcoinVerifier {
378 pub fn from_public_key_bytes(bytes: &[u8]) -> Result<Self, SignerError> {
380 let verifying_key = VerifyingKey::from_sec1_bytes(bytes)
381 .map_err(|e| SignerError::InvalidPublicKey(e.to_string()))?;
382 Ok(Self { verifying_key })
383 }
384
385 fn verify_digest(
386 &self,
387 digest: &[u8; 32],
388 signature: &BitcoinSignature,
389 ) -> Result<bool, SignerError> {
390 let sig = K256Signature::from_der(&signature.der_bytes)
391 .map_err(|e| SignerError::InvalidSignature(e.to_string()))?;
392 match self.verifying_key.verify_prehash(digest, &sig) {
393 Ok(()) => Ok(true),
394 Err(_) => Ok(false),
395 }
396 }
397}
398
399impl traits::Verifier for BitcoinVerifier {
400 type Signature = BitcoinSignature;
401 type Error = SignerError;
402
403 fn verify(&self, message: &[u8], signature: &BitcoinSignature) -> Result<bool, SignerError> {
404 let digest = double_sha256(message);
405 self.verify_digest(&digest, signature)
406 }
407
408 fn verify_prehashed(
409 &self,
410 digest: &[u8],
411 signature: &BitcoinSignature,
412 ) -> Result<bool, SignerError> {
413 if digest.len() != 32 {
414 return Err(SignerError::InvalidHashLength {
415 expected: 32,
416 got: digest.len(),
417 });
418 }
419 let mut hash = [0u8; 32];
420 hash.copy_from_slice(digest);
421 self.verify_digest(&hash, signature)
422 }
423}
424
425#[cfg(test)]
426#[allow(clippy::unwrap_used, clippy::expect_used)]
427mod tests {
428 use super::*;
429 use crate::traits::{KeyPair, Signer, Verifier};
430
431 #[test]
432 fn test_generate_keypair() {
433 let signer = BitcoinSigner::generate().unwrap();
434 let pubkey = signer.public_key_bytes();
435 assert_eq!(pubkey.len(), 33); }
437
438 #[test]
439 fn test_from_bytes_roundtrip() {
440 let signer = BitcoinSigner::generate().unwrap();
441 let key_bytes = signer.private_key_bytes();
442 let restored = BitcoinSigner::from_bytes(&key_bytes).unwrap();
443 assert_eq!(signer.public_key_bytes(), restored.public_key_bytes());
444 }
445
446 #[test]
447 fn test_sign_verify_roundtrip() {
448 let signer = BitcoinSigner::generate().unwrap();
449 let msg = b"hello bitcoin";
450 let sig = signer.sign(msg).unwrap();
451 let verifier = BitcoinVerifier::from_public_key_bytes(&signer.public_key_bytes()).unwrap();
452 assert!(verifier.verify(msg, &sig).unwrap());
453 }
454
455 #[test]
456 fn test_double_sha256() {
457 let result = double_sha256(b"hello");
460 assert_eq!(
461 hex::encode(result),
462 "9595c9df90075148eb06860365df33584b75bff782a510c6cd4883a419833d50"
463 );
464 }
465
466 #[test]
467 fn test_rfc6979_deterministic() {
468 let privkey =
470 hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
471 .unwrap();
472 let signer = BitcoinSigner::from_bytes(&privkey).unwrap();
473 let sig1 = signer.sign(b"Satoshi Nakamoto").unwrap();
474 let sig2 = signer.sign(b"Satoshi Nakamoto").unwrap();
475 assert_eq!(sig1.der_bytes(), sig2.der_bytes());
476 }
477
478 #[test]
479 fn test_rfc6979_known_vector_privkey_1() {
480 let privkey =
483 hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
484 .unwrap();
485 let signer = BitcoinSigner::from_bytes(&privkey).unwrap();
486
487 let pubkey = signer.public_key_bytes();
489 assert_eq!(
490 hex::encode(&pubkey).to_uppercase(),
491 "0279BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
492 );
493
494 let sig = signer.sign(b"Satoshi Nakamoto").unwrap();
496 assert!(!sig.der_bytes().is_empty());
498 let verifier = BitcoinVerifier::from_public_key_bytes(&pubkey).unwrap();
500 assert!(verifier.verify(b"Satoshi Nakamoto", &sig).unwrap());
501 }
502
503 #[test]
504 fn test_rfc6979_known_vector_privkey_2() {
505 let privkey =
507 hex::decode("0000000000000000000000000000000000000000000000000000000000000002")
508 .unwrap();
509 let signer = BitcoinSigner::from_bytes(&privkey).unwrap();
510 let sig = signer.sign(b"Satoshi Nakamoto").unwrap();
511 let verifier = BitcoinVerifier::from_public_key_bytes(&signer.public_key_bytes()).unwrap();
512 assert!(verifier.verify(b"Satoshi Nakamoto", &sig).unwrap());
513 let sig2 = signer.sign(b"Satoshi Nakamoto").unwrap();
515 assert_eq!(sig.der_bytes(), sig2.der_bytes());
516 }
517
518 #[test]
519 fn test_der_encoding() {
520 let signer = BitcoinSigner::generate().unwrap();
521 let sig = signer.sign(b"DER test").unwrap();
522 assert_eq!(sig.der_bytes()[0], 0x30);
524 assert!(sig.der_bytes().len() >= 68 && sig.der_bytes().len() <= 72);
526 }
527
528 #[test]
529 fn test_invalid_privkey_rejected() {
530 assert!(BitcoinSigner::from_bytes(&[0u8; 32]).is_err());
531 assert!(BitcoinSigner::from_bytes(&[1u8; 31]).is_err());
532 assert!(BitcoinSigner::from_bytes(&[1u8; 33]).is_err());
533 }
534
535 #[test]
536 fn test_tampered_sig_fails() {
537 let signer = BitcoinSigner::generate().unwrap();
538 let sig = signer.sign(b"tamper test").unwrap();
539 let verifier = BitcoinVerifier::from_public_key_bytes(&signer.public_key_bytes()).unwrap();
540
541 let tampered_bytes: Vec<u8> = {
542 let mut b = sig.to_bytes();
543 if let Some(byte) = b.last_mut() {
544 *byte ^= 0xff;
545 }
546 b
547 };
548 let tampered = BitcoinSignature::from_bytes(&tampered_bytes);
549 if let Ok(t) = tampered {
551 let result = verifier.verify(b"tamper test", &t);
552 assert!(result.is_err() || !result.unwrap());
553 }
554 }
555
556 #[test]
557 fn test_wrong_pubkey_fails() {
558 let signer1 = BitcoinSigner::generate().unwrap();
559 let signer2 = BitcoinSigner::generate().unwrap();
560 let sig = signer1.sign(b"wrong key test").unwrap();
561 let verifier = BitcoinVerifier::from_public_key_bytes(&signer2.public_key_bytes()).unwrap();
562 assert!(!verifier.verify(b"wrong key test", &sig).unwrap());
563 }
564
565 #[test]
566 fn test_empty_message() {
567 let signer = BitcoinSigner::generate().unwrap();
568 let sig = signer.sign(b"").unwrap();
569 let verifier = BitcoinVerifier::from_public_key_bytes(&signer.public_key_bytes()).unwrap();
570 assert!(verifier.verify(b"", &sig).unwrap());
571 }
572
573 #[test]
574 fn test_sign_prehashed_roundtrip() {
575 let signer = BitcoinSigner::generate().unwrap();
576 let msg = b"prehash btc";
577 let digest = double_sha256(msg);
578 let sig = signer.sign_prehashed(&digest).unwrap();
579 let verifier = BitcoinVerifier::from_public_key_bytes(&signer.public_key_bytes()).unwrap();
580 assert!(verifier.verify_prehashed(&digest, &sig).unwrap());
581 }
582
583 #[test]
584 fn test_zeroize_on_drop() {
585 let signer = BitcoinSigner::generate().unwrap();
586 let key_bytes = signer.private_key_bytes();
587 let _: Zeroizing<Vec<u8>> = key_bytes;
588 drop(signer);
589 }
590
591 #[test]
594 fn test_p2pkh_known_address_privkey_1() {
595 let sk = hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
598 .unwrap();
599 let signer = BitcoinSigner::from_bytes(&sk).unwrap();
600 assert_eq!(signer.p2pkh_address(), "1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH");
601 }
602
603 #[test]
604 fn test_p2wpkh_known_address_privkey_1() {
605 let sk = hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
607 .unwrap();
608 let signer = BitcoinSigner::from_bytes(&sk).unwrap();
609 assert_eq!(
610 signer.p2wpkh_address().unwrap(),
611 "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"
612 );
613 }
614
615 #[test]
618 fn test_wif_encode_known() {
619 let sk = hex::decode("0000000000000000000000000000000000000000000000000000000000000001")
621 .unwrap();
622 let signer = BitcoinSigner::from_bytes(&sk).unwrap();
623 let wif = signer.to_wif();
624 assert!(wif.starts_with('K') || wif.starts_with('L'));
625 assert_eq!(wif.len(), 52); }
627
628 #[test]
629 fn test_wif_roundtrip() {
630 let signer = BitcoinSigner::generate().unwrap();
631 let wif = signer.to_wif();
632 let restored = BitcoinSigner::from_wif(&wif).unwrap();
633 assert_eq!(&*signer.private_key_bytes(), &*restored.private_key_bytes());
634 assert_eq!(signer.p2pkh_address(), restored.p2pkh_address());
635 }
636
637 #[test]
640 fn test_validate_known_addresses() {
641 assert!(validate_address("1BgGZ9tcN4rm9KBzDn7KprQz87SZ26SAMH")); assert!(validate_address(
643 "bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4"
644 )); assert!(!validate_address(""));
646 assert!(!validate_address("1invalid"));
647 assert!(!validate_address("bc1qinvalid"));
648 }
649
650 #[test]
653 fn test_bip137_sign_verify_roundtrip() {
654 let signer = BitcoinSigner::generate().unwrap();
655 let sig = signer.sign_message(b"Hello Bitcoin").unwrap();
656 assert_eq!(sig.der_bytes()[0], 0x30); let verifier = BitcoinVerifier::from_public_key_bytes(&signer.public_key_bytes()).unwrap();
660 let digest = bitcoin_message_hash(b"Hello Bitcoin");
661 assert!(verifier.verify_prehashed(&digest, &sig).unwrap());
662 }
663}