1use crate::secp256k1::{Message, Signature};
2use crate::sha256;
3use crate::verify::MessageVerify;
4
5use std::io;
6use std::io::Write;
7
8pub struct BtcMessageVerify;
9
10impl MessageVerify for BtcMessageVerify {
11 fn verify<M, S, P>(message: M, signature: S, pub_key: Option<P>) -> crate::Result<Vec<u8>>
12 where
13 M: AsRef<[u8]>,
14 S: AsRef<[u8]>,
15 P: AsRef<[u8]>,
16 {
17 assert!(pub_key.is_none(), "btc message verify not need pub_key");
18
19 let message = message.as_ref();
20 let signature = signature.as_ref();
21
22 let signature = Signature::from_btc_signature(signature.into())?;
23 let msg_hash = signed_msg_hash(message);
24 let rec_id = signature.v() % 0x3;
25 let pub_key = signature.recover(&msg_hash, Some(rec_id))?;
26 pub_key.verify(&msg_hash, &signature)?;
27 Ok(pub_key.serialize(true))
28 }
29}
30
31fn signed_msg_hash(msg: &[u8]) -> Message {
32 let prefix = b"\x18Bitcoin Signed Message:\n";
33 let msg_len = VarInt(msg.len() as u64);
34 let mut prefixed_message = Vec::with_capacity(prefix.len() + msg_len.len() + msg.len());
35 prefixed_message.extend_from_slice(prefix);
36 msg_len
37 .consensus_encode(&mut prefixed_message)
38 .expect("encode message len don't error");
39 prefixed_message.extend_from_slice(msg);
40 let sha2_1: [u8; 32] = sha256(&prefixed_message);
41 let sha2_2: [u8; 32] = sha256(&sha2_1);
42 sha2_2
43}
44
45#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)]
46struct VarInt(pub u64);
47
48impl VarInt {
49 fn len(&self) -> usize {
50 match self.0 {
51 0..=0xFC => 1,
52 0xFD..=0xFFFF => 3,
53 0x10000..=0xFFFFFFFF => 5,
54 _ => 9,
55 }
56 }
57 fn consensus_encode<W: Write>(&self, w: &mut W) -> io::Result<()> {
58 match self.0 {
59 0..=0xFC => {
60 let len = self.0 as u8;
61 w.write_all(&[len])?;
62 }
63 0xFD..=0xFFFF => {
64 w.write_all(&[0xFD])?;
65 let len = self.0 as u16;
66 w.write_all(&len.to_le_bytes())?;
67 }
68 0x10000..=0xFFFFFFFF => {
69 w.write_all(&[0xFE])?;
70 let len = self.0 as u32;
71 w.write_all(&len.to_le_bytes())?;
72 }
73 _ => {
74 w.write_all(&[0xFF])?;
75 w.write_all(&self.0.to_le_bytes())?;
76 }
77 }
78 Ok(())
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
85 use crate::secp256k1::tests::get_pub_key_from_wif;
86 use base64::Engine;
87
88 #[test]
89 fn should_match_pub_key_unisat() {
90 let signature_base64 = "G59hY32s8BK8OWvFr05+cm2zBCuoNml7PqACluyT5VjgR9BGuljW+HTPFg1I1DMZOQDX0BA4Z69OT8r9mgHcQ3E=";
91 let message_bytes = b"HelloWorld";
92 let private_wif = "L4DWptSwVurT18jMFvbbMQ2jMpf9uweHNefgzwe6tnzK5fkm1V5S";
93 let pub_key = get_pub_key_from_wif(private_wif);
94 let signature = base64::prelude::BASE64_STANDARD
95 .decode(signature_base64)
96 .unwrap();
97 let res = BtcMessageVerify::verify(message_bytes, &signature, None::<Vec<u8>>);
98 assert!(res.is_ok());
99 assert_eq!(res.unwrap(), pub_key.serialize(true));
100 }
101
102 #[test]
103 fn should_match_pub_key() {
104 let signature_base64 = "G2UXxeWn35RGEtcv8IEqSY6iNTc0m+LmLRfJLhzdxK6nM/5GkFMUoGEvgSLQ95HanQpAI0jA8IVAZs9oa6kaqEE=";
105 let message_bytes = b"HelloWorld";
106 let private_wif = "5KYZdUEo39z3FPrtuX2QbbwGnNP5zTd7yyr2SC1j299sBCnWjss";
107 let pub_key = get_pub_key_from_wif(private_wif);
108 let signature = base64::prelude::BASE64_STANDARD
109 .decode(signature_base64)
110 .unwrap();
111 let res = BtcMessageVerify::verify(message_bytes, &signature, None::<Vec<u8>>);
112 assert!(res.is_ok());
113 assert_eq!(res.unwrap(), pub_key.serialize(true));
114 }
115 #[test]
116 fn should_not_match_pub_key() {
117 let signature_base64 = "G4dtJhhw1PF7gEvdp7tKFN0kvg5mc9C9CgVYS7bnwzrF8cAwAju2aKnIF5r7st8DipS/1lTq/fdK7wb/AGs/MhI=";
118 let message_bytes = b"1";
119 let private_wif = "L4DWptSwVurT18jMFvbbMQ2jMpf9uweHNefgzwe6tnzK5fkm1V5S";
120 let pub_key = get_pub_key_from_wif(private_wif);
121 let signature = base64::prelude::BASE64_STANDARD
122 .decode(signature_base64)
123 .unwrap();
124 let res = BtcMessageVerify::verify(message_bytes, &signature, None::<Vec<u8>>);
125 assert!(res.is_err());
126 }
127}