use arrayref::array_mut_ref;
use sha2::Digest;
use sha2::Sha256;
use crate::ecc::PublicKey;
use crate::ecc::PublicKeyAddress;
use crate::error::Error;
use crate::error::Result;
pub fn recover(msg: &[u8], sig: impl AsRef<[u8]>) -> Result<PublicKey<33>> {
let mut sig = sig.as_ref().to_vec();
sig.rotate_left(1);
let sig = sig.as_mut_slice();
let sig_byte = array_mut_ref![sig, 0, 65];
let hash = self::magic_hash(msg);
if sig_byte[64] >= 27 && sig_byte[64] <= 30 {
sig_byte[64] -= 27;
} else if sig_byte[64] >= 31 && sig_byte[64] <= 34 {
sig_byte[64] -= 31;
} else {
return Err(Error::InvalidRecoverId(sig_byte[64]));
}
crate::ecc::recover_hash(&hash, sig_byte)
}
pub fn verify(msg: &[u8], address: &PublicKeyAddress, sig: impl AsRef<[u8]>) -> bool {
match recover(msg, sig.as_ref()) {
Ok(recover_pk) => {
if recover_pk.address() == *address {
return true;
}
tracing::debug!(
"failed to recover pubkey address, got: {}, expect: {}",
address,
recover_pk.address()
);
false
}
Err(e) => {
tracing::debug!(
"failed to recover pubkey: {:?}\nmsg: {:?}\nsig:{:?}",
e,
msg,
sig.as_ref(),
);
false
}
}
}
fn varint_buf_num(n: u64) -> Vec<u8> {
if n < 253 {
vec![n as u8]
} else if n < 0x10000 {
let mut buf = Vec::new();
buf.extend_from_slice(&[253u8]);
buf.extend_from_slice(&(n as u16).to_le_bytes());
buf
} else if n < 0x100000000 {
let mut buf = Vec::new();
buf.extend_from_slice(&[254u8]);
buf.extend_from_slice(&(n as u32).to_le_bytes());
buf
} else {
let mut buf = Vec::with_capacity(9);
buf.push(255u8);
buf.extend_from_slice(&n.to_le_bytes());
buf
}
}
pub fn magic_hash(msg: &[u8]) -> [u8; 32] {
let magic_bytes = "Bitcoin Signed Message:\n".as_bytes();
let mut buf = Vec::new();
buf.extend_from_slice(varint_buf_num(magic_bytes.len() as u64).as_slice());
buf.extend_from_slice(magic_bytes);
buf.extend_from_slice(varint_buf_num(msg.len() as u64).as_slice());
buf.extend_from_slice(msg);
let hash = Sha256::digest(Sha256::digest(&buf));
hash.into()
}
#[cfg(test)]
mod test_bip137;