use crate::errors::{Error, Result};
use ecdsa::RecoveryId as EcdsaRecoveryId;
use ethers_core::{k256::ecdsa::Signature as KSig, types::Signature as EthSig};
use k256::{
ecdsa::{RecoveryId, Signature, VerifyingKey},
FieldBytes,
};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use zerocopy::AsBytes;
pub const LEN: usize = 65;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Sig(pub (Signature, RecoveryId));
impl Sig {
pub fn from_bytes(b: &[u8]) -> Result<Self> {
if b.len() != LEN {
return Err(Error::Other {
message: "invalid signature length".to_string(),
retryable: false,
});
}
let sig = Signature::try_from(&b[..64]).map_err(|e| Error::Other {
message: format!("failed to load recoverable signature {}", e),
retryable: false,
})?;
let recid = RecoveryId::try_from(b[64]).map_err(|e| Error::Other {
message: format!("failed to create recovery Id {}", e),
retryable: false,
})?;
Ok(Self((sig, recid)))
}
pub fn to_bytes(&self) -> [u8; LEN] {
let bb = self.0 .0.to_bytes();
let mut b = [0u8; LEN];
b.copy_from_slice(&[&bb[..], &[u8::from(self.0 .1)]].concat());
b
}
pub fn recover_public_key(
&self,
digest: &[u8],
) -> Result<(crate::key::secp256k1::public_key::Key, VerifyingKey)> {
recover_pubkeys(&self.0 .0, self.0 .1, digest)
}
pub fn r(&self) -> primitive_types::U256 {
let b = self.0 .0.to_vec();
primitive_types::U256::from_big_endian(&b[0..32])
}
pub fn s(&self) -> primitive_types::U256 {
let b = self.0 .0.to_vec();
primitive_types::U256::from_big_endian(&b[32..64])
}
pub fn v(&self) -> u64 {
u8::from(self.0 .1) as u64
}
}
impl<'de> Deserialize<'de> for Sig {
fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
use serde::de::Error;
let val = String::deserialize(deserializer)
.and_then(|s| hex::decode(s).map_err(Error::custom))?;
Self::from_bytes(val.as_bytes()).map_err(Error::custom)
}
}
impl Serialize for Sig {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(&hex::encode(self.to_bytes()))
}
}
fn recover_pubkeys(
rsig: &Signature,
recid: RecoveryId,
digest: &[u8],
) -> Result<(crate::key::secp256k1::public_key::Key, VerifyingKey)> {
let vkey =
VerifyingKey::recover_from_prehash(digest, rsig, recid).map_err(|e| Error::Other {
message: format!("failed recover_verifying_key_from_digest_bytes {}", e),
retryable: false,
})?;
Ok((vkey.into(), vkey))
}
impl From<Sig> for Signature {
fn from(sig: Sig) -> Self {
sig.0 .0
}
}
impl From<Sig> for [u8; LEN] {
fn from(sig: Sig) -> Self {
sig.to_bytes()
}
}
#[test]
fn test_signature() {
let _ = env_logger::builder()
.filter_level(log::LevelFilter::Info)
.is_test(true)
.try_init();
let pk = crate::key::secp256k1::private_key::Key::generate().unwrap();
let pubkey = pk.to_public_key();
let msg: Vec<u8> = random_manager::secure_bytes(100).unwrap();
let hashed = crate::hash::sha256(msg);
let sig = pk.sign_digest(&hashed).unwrap();
assert_eq!(sig.to_bytes().len(), crate::key::secp256k1::signature::LEN);
let (recovered_pubkey, _) = sig.recover_public_key(&hashed).unwrap();
assert_eq!(pubkey.to_eth_address(), recovered_pubkey.to_eth_address());
assert_eq!(pubkey, recovered_pubkey);
}
pub fn decode_signature(b: &[u8]) -> Result<Signature> {
let sig = Signature::from_der(b).map_err(|e| Error::Other {
message: format!("failed Signature::from_der {}", e),
retryable: false,
})?;
Ok(sig.normalize_s().unwrap_or(sig))
}
pub fn sig_from_digest_bytes_trial_recovery(
sig: &KSig,
digest: &[u8; 32],
vk: &VerifyingKey,
) -> Result<EthSig> {
let recid =
EcdsaRecoveryId::trial_recovery_from_prehash(vk, digest.as_bytes(), sig).map_err(|e| {
Error::Other {
message: format!("failed EcdsaRecoveryId::trial_recovery_from_prehash {}", e),
retryable: false,
}
})?;
let r_bytes: FieldBytes = sig.r().into();
let s_bytes: FieldBytes = sig.s().into();
let r = primitive_types::U256::from_big_endian(r_bytes.as_slice());
let s = primitive_types::U256::from_big_endian(s_bytes.as_slice());
Ok(EthSig {
r,
s,
v: recid.to_byte() as u64,
})
}
pub fn apply_eip155(sig: &mut ethers_core::types::Signature, chain_id: u64) {
let v = (chain_id * 2 + 35) + sig.v;
sig.v = v;
}
#[test]
fn test_signature_serialization() {
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
struct Data {
sig: Sig,
}
let pk = crate::key::secp256k1::private_key::Key::generate().unwrap();
let pubkey = pk.to_public_key();
let msg: Vec<u8> = random_manager::secure_bytes(100).unwrap();
let hashed = crate::hash::sha256(msg);
let sig = pk.sign_digest(&hashed).unwrap();
let d = Data { sig: sig.clone() };
let json_encoded = serde_json::to_string(&d).unwrap();
println!("json_encoded:\n{}", json_encoded);
let json_decoded = serde_json::from_str::<Data>(&json_encoded).unwrap();
assert_eq!(sig, json_decoded.sig);
let (recovered_pubkey, _) = json_decoded.sig.recover_public_key(&hashed).unwrap();
assert_eq!(pubkey.to_eth_address(), recovered_pubkey.to_eth_address());
assert_eq!(pubkey, recovered_pubkey);
}