use crate::address::Address;
use crate::constants::secpk1n;
use crate::context::SECP256K1;
use crate::error::Error;
use crate::transaction::v_to_num;
use crate::utils::{
big_endian_uint256_deserialize, big_endian_uint256_serialize, bytes_to_hex_str,
hex_str_to_bytes,
};
use num256::Uint256;
use num_traits::{ToPrimitive, Zero};
use secp256k1::ecdsa::{RecoverableSignature, RecoveryId};
use secp256k1::Message;
use sha3::{Digest, Keccak256};
use std::fmt::{self, Display};
use std::str::FromStr;
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub enum Signature {
LegacySignature {
#[serde(
serialize_with = "big_endian_uint256_serialize",
deserialize_with = "big_endian_uint256_deserialize"
)]
v: Uint256,
#[serde(
serialize_with = "big_endian_uint256_serialize",
deserialize_with = "big_endian_uint256_deserialize"
)]
r: Uint256,
#[serde(
serialize_with = "big_endian_uint256_serialize",
deserialize_with = "big_endian_uint256_deserialize"
)]
s: Uint256,
},
ModernSignature {
v: bool,
#[serde(
serialize_with = "big_endian_uint256_serialize",
deserialize_with = "big_endian_uint256_deserialize"
)]
r: Uint256,
#[serde(
serialize_with = "big_endian_uint256_serialize",
deserialize_with = "big_endian_uint256_deserialize"
)]
s: Uint256,
},
}
impl Signature {
pub fn new(v: bool, r: Uint256, s: Uint256) -> Signature {
Signature::ModernSignature { r, s, v }
}
pub fn new_legacy(v: Uint256, r: Uint256, s: Uint256) -> Signature {
Signature::LegacySignature { v, r, s }
}
pub fn get_r(&self) -> Uint256 {
match self {
Signature::LegacySignature { r, .. } | Signature::ModernSignature { r, .. } => *r,
}
}
pub fn get_s(&self) -> Uint256 {
match self {
Signature::LegacySignature { s, .. } | Signature::ModernSignature { s, .. } => *s,
}
}
pub fn get_v(&self) -> Uint256 {
match self {
Signature::LegacySignature { v, .. } => *v,
Signature::ModernSignature { v, .. } => v_to_num(*v),
}
}
pub fn error_check(&self) -> Result<(), Error> {
if self.get_r() >= secpk1n() || self.get_r() == Uint256::zero() {
return Err(Error::InvalidR);
} else if self.get_s() > secpk1n() / 2u8.into() || self.get_s() == Uint256::zero() {
return Err(Error::InvalidS);
}
if self.get_v() >= 61480u32.into() {
return Err(Error::InvalidV);
}
match self.get_signature_v() {
Ok(_) => Ok(()),
Err(e) => Err(e),
}
}
pub fn is_valid(&self) -> bool {
self.error_check().is_ok()
}
pub fn legacy_network_id(&self) -> Option<Uint256> {
match self {
Signature::LegacySignature { v, .. } => {
if *v == 27u8.into() || *v == 28u8.into() {
None
} else {
let network_id = ((*v - 1u8.into()) / 2u8.into()) - 17u8.into();
if network_id == 3u8.into() || network_id == 2u8.into() {
None
} else {
Some(network_id)
}
}
}
Signature::ModernSignature { .. } => None,
}
}
pub fn get_signature_v(&self) -> Result<u8, Error> {
match self {
Signature::LegacySignature { v, .. } => {
if *v == 27u8.into() {
Ok(27)
} else if *v == 28u8.into() {
Ok(28)
} else if *v >= 37u8.into() {
let network_id = self.legacy_network_id().ok_or(Error::InvalidNetworkId)?;
let vee = *v - (network_id * 2u8.into()) - 8u8.into();
let vee = vee.to_be_bytes()[31];
assert!(vee == 27 || vee == 28);
Ok(vee)
} else {
Err(Error::InvalidV)
}
}
Signature::ModernSignature { v, .. } => {
if *v {
Ok(28)
} else {
Ok(27)
}
}
}
}
pub fn into_bytes(self) -> [u8; 65] {
self.to_bytes()
}
pub fn to_bytes(&self) -> [u8; 65] {
let r: [u8; 32] = self.get_r().into();
let s: [u8; 32] = self.get_s().into();
let mut result = [0x00u8; 65];
result[0..32].copy_from_slice(&r);
result[32..64].copy_from_slice(&s);
result[64] = self
.get_signature_v()
.expect("Into bytes on invalid signature");
result
}
pub fn from_bytes(bytes: &[u8]) -> Result<Self, Error> {
if bytes.len() != 65 {
return Err(Error::InvalidSignatureLength);
}
let r: Uint256 = {
let mut data: [u8; 32] = Default::default();
data.copy_from_slice(&bytes[0..32]);
data.into()
};
let s: Uint256 = {
let mut data: [u8; 32] = Default::default();
data.copy_from_slice(&bytes[32..64]);
data.into()
};
let v = bytes[64];
if v == 27 || v == 28 {
Ok(Signature::ModernSignature { v: v == 28, r, s })
} else {
Ok(Signature::LegacySignature { v: v.into(), r, s })
}
}
pub fn recover(&self, hash: &[u8]) -> Result<Address, Error> {
let v = RecoveryId::from_i32(self.get_signature_v()?.to_i32().ok_or(Error::InvalidV)? - 27)
.map_err(Error::DecodeRecoveryId)?;
let msg = Message::from_digest_slice(hash).map_err(Error::ParseMessage)?;
let compact = RecoverableSignature::from_compact(&self.to_bytes()[..64], v)
.map_err(Error::ParseRecoverableSignature)?;
let pkey = SECP256K1.with(move |object| -> Result<_, Error> {
let secp256k1 = object.borrow();
let pkey = secp256k1
.recover_ecdsa(&msg, &compact)
.map_err(Error::RecoverSignature)?;
Ok(pkey.serialize_uncompressed())
})?;
assert_eq!(pkey.len(), 65);
if pkey[1..].to_vec() == [0x00u8; 64].to_vec() {
return Err(Error::ZeroPrivKey);
}
let sender = Keccak256::digest(&pkey[1..]);
debug_assert_eq!(sender.len(), 32);
Address::from_slice(&sender[12..])
}
}
impl Display for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "0x{}", bytes_to_hex_str(&self.to_bytes()))
}
}
impl FromStr for Signature {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = match s.strip_prefix("0x") {
Some(s) => s,
None => s,
};
let bytes = hex_str_to_bytes(s)?;
Signature::from_bytes(&bytes)
}
}
impl fmt::LowerHex for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if f.alternate() {
write!(
f,
"0x{}",
bytes_to_hex_str(&self.clone().to_bytes()).to_lowercase()
)
} else {
write!(
f,
"{}",
bytes_to_hex_str(&self.clone().to_bytes()).to_lowercase()
)
}
}
}
impl fmt::UpperHex for Signature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if f.alternate() {
write!(f, "0x{}", bytes_to_hex_str(&self.to_bytes()).to_uppercase())
} else {
write!(f, "{}", bytes_to_hex_str(&self.to_bytes()).to_uppercase())
}
}
}
#[test]
fn new_signature() {
let sig = Signature::new(false, 2u32.into(), 3u32.into());
assert_eq!(sig.get_signature_v().unwrap(), 27);
assert_eq!(sig.get_r(), 2u32.into());
assert_eq!(sig.get_s(), 3u32.into());
}
#[test]
fn to_string() {
let sig = Signature::new(true, 2u32.into(), 3u32.into());
let sig_string = sig.to_string();
assert_eq!(
sig_string,
concat!(
"0x",
"0000000000000000000000000000000000000000000000000000000000000002",
"0000000000000000000000000000000000000000000000000000000000000003",
"1c"
)
);
let new_sig = Signature::from_str(&sig_string).expect("Unable to parse signature");
assert_eq!(sig, new_sig);
assert!(sig_string.starts_with("0x"));
let new_sig = Signature::from_str(&sig_string[2..]).expect("Unable to parse signature");
assert_eq!(sig, new_sig);
}
#[test]
fn to_upper_hex() {
let sig = Signature::new(true, 65450u32.into(), 32456u32.into());
let sig_string = format!("{sig:#X}");
assert_eq!(
sig_string,
concat!(
"0x",
"000000000000000000000000000000000000000000000000000000000000FFAA",
"0000000000000000000000000000000000000000000000000000000000007EC8",
"1C"
)
);
let sig_string = format!("{sig:X}");
assert_eq!(
sig_string,
concat!(
"000000000000000000000000000000000000000000000000000000000000FFAA",
"0000000000000000000000000000000000000000000000000000000000007EC8",
"1C"
)
);
}
#[test]
fn to_lower_hex() {
let sig = Signature::new(true, 65450u32.into(), 32456u32.into());
let sig_string = format!("{sig:#x}");
assert_eq!(
sig_string,
concat!(
"0x",
"000000000000000000000000000000000000000000000000000000000000ffaa",
"0000000000000000000000000000000000000000000000000000000000007ec8",
"1c"
)
);
let sig_string = format!("{sig:x}");
assert_eq!(
sig_string,
concat!(
"000000000000000000000000000000000000000000000000000000000000ffaa",
"0000000000000000000000000000000000000000000000000000000000007ec8",
"1c"
)
);
}
#[test]
fn into_bytes() {
let sig = Signature::new(true, 2u32.into(), 3u32.into());
let sig_bytes = sig.to_bytes();
assert_eq!(
sig_bytes.to_vec(),
vec![
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 28
],
);
let new_sig = Signature::from_bytes(&sig_bytes).expect("Unable to reconstruct signature");
assert_eq!(sig, new_sig);
}
#[test]
#[should_panic]
fn parse_invalid_signature() {
let _sig: Signature = "deadbeef".parse().unwrap();
let _sig: Signature = "0x".parse().unwrap();
}
#[test]
fn generate_ethereum_signature() {
use crate::PrivateKey;
let private_key: PrivateKey =
"0xc5e8f61d1ab959b397eecc0a37a6517b8e67a0e7cf1f4bce5591f3ed80199122"
.parse()
.unwrap();
let address: Address = "0xc783df8a850f42e7F7e57013759C285caa701eB6"
.parse()
.unwrap();
let checkpoint =
hex_str_to_bytes("0x666f6f0000000000000000000000000000000000000000000000000000000000636865636b706f696e7400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000003000000000000000000000000c783df8a850f42e7f7e57013759c285caa701eb6000000000000000000000000ead9c93b79ae7c1591b1fb5323bd777e86e150d4000000000000000000000000e5904695748fe4a84b40b3fc79de2277660bd1d300000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000000000000000000000000000d050000000000000000000000000000000000000000000000000000000000000d050000000000000000000000000000000000000000000000000000000000000d05")
.unwrap();
let sig: Signature = "0xe108a7776de6b87183b0690484a74daef44aa6daf907e91abaf7bbfa426ae7706b12e0bd44ef7b0634710d99c2d81087a2f39e075158212343a3b2948ecf33d01c".parse().unwrap();
assert_eq!(private_key.to_address(), address);
let generated_sig = private_key.sign_ethereum_msg(&checkpoint);
assert_eq!(sig, generated_sig)
}
#[test]
fn parse_hex_signature() {
let sig: Signature = "0xe108a7776de6b87183b0690484a74daef44aa6daf907e91abaf7bbfa426ae7706b12e0bd44ef7b0634710d99c2d81087a2f39e075158212343a3b2948ecf33d01c".parse().unwrap();
let correct_r =
hex_str_to_bytes("0xe108a7776de6b87183b0690484a74daef44aa6daf907e91abaf7bbfa426ae770")
.unwrap();
let correct_s =
hex_str_to_bytes("0x6b12e0bd44ef7b0634710d99c2d81087a2f39e075158212343a3b2948ecf33d0")
.unwrap();
assert_eq!(sig.get_r(), Uint256::from_be_bytes(&correct_r));
assert_eq!(sig.get_s(), Uint256::from_be_bytes(&correct_s));
assert_eq!(sig.get_signature_v().unwrap(), 28);
}