From e9d3a60a7f01fcb5c23a96b2e0d6582a1d0cf204 Mon Sep 17 00:00:00 2001 From: Dmytro Medynskyi Date: Mon, 28 Oct 2024 18:52:08 +0100 Subject: [PATCH] extract Signature into conditional traits --- crates/primitives/src/signature/ecdsa_sig.rs | 73 ++++++++++--------- crates/primitives/src/signature/mod.rs | 2 + crates/primitives/src/signature/sig.rs | 27 +++++-- .../src/signature/super_signature.rs | 30 ++++++++ 4 files changed, 92 insertions(+), 40 deletions(-) create mode 100644 crates/primitives/src/signature/super_signature.rs diff --git a/crates/primitives/src/signature/ecdsa_sig.rs b/crates/primitives/src/signature/ecdsa_sig.rs index ff81ef530d..3076b0a385 100644 --- a/crates/primitives/src/signature/ecdsa_sig.rs +++ b/crates/primitives/src/signature/ecdsa_sig.rs @@ -7,6 +7,7 @@ use crate::{ }; use alloc::vec::Vec; use core::str::FromStr; +use crate::signature::super_signature::{ArbitrarySuperSig, K256SuperSig, RlpSuperSig, SerdeSuperSig}; /// The order of the secp256k1 curve const SECP256K1N_ORDER: U256 = @@ -21,46 +22,62 @@ pub struct EcdsaSignature { } impl EcdsaSignature { + /// Returns the recovery ID. + #[cfg(feature = "k256")] + #[inline] + const fn recid(&self) -> k256::ecdsa::RecoveryId { + self.v.recid() + } + + #[cfg(feature = "k256")] + #[doc(hidden)] + #[deprecated(note = "use `Signature::recid` instead")] + pub const fn recovery_id(&self) -> k256::ecdsa::RecoveryId { + self.recid() + } + + #[doc(hidden)] + fn test_signature() -> Self { + Self::from_scalars_and_parity( + b256!("840cfc572845f5786e702984c2a582528cad4b49b2a10b9db1be7fca90058565"), + b256!("25e7109ceb98168d95b09b18bbf6b685130e0562f233877d492b94eee0c5b6d1"), + false, + ) + .unwrap() + } +} + +impl RlpSuperSig for EcdsaSignature {} + +impl K256SuperSig for EcdsaSignature {} + +impl SerdeSuperSig for EcdsaSignature {} + +impl ArbitrarySuperSig for EcdsaSignature {} + +impl Signature for EcdsaSignature { /// Instantiate a new signature from `r`, `s`, and `v` values. - #[allow(clippy::missing_const_for_fn)] - pub fn new(r: U256, s: U256, v: Parity) -> Self { + fn new(r: U256, s: U256, v: Parity) -> Self { Self { r, s, v } } /// Returns the `r` component of this signature. #[inline] - pub const fn r(&self) -> U256 { + fn r(&self) -> U256 { self.r } /// Returns the `s` component of this signature. #[inline] - pub const fn s(&self) -> U256 { + fn s(&self) -> U256 { self.s } /// Returns the recovery ID as a `u8`. #[inline] - pub const fn v(&self) -> Parity { + fn v(&self) -> Parity { self.v } - - /// Returns the recovery ID. - #[cfg(feature = "k256")] - #[inline] - const fn recid(&self) -> k256::ecdsa::RecoveryId { - self.v.recid() - } - - #[cfg(feature = "k256")] - #[doc(hidden)] - #[deprecated(note = "use `Signature::recid` instead")] - pub const fn recovery_id(&self) -> k256::ecdsa::RecoveryId { - self.recid() - } -} - -impl Signature<'_> for EcdsaSignature { #[cfg(feature = "rlp")] fn decode_rlp_vrs(buf: &mut &[u8]) -> Result { use alloy_rlp::Decodable; @@ -73,16 +90,6 @@ impl Signature<'_> for EcdsaSignature { .map_err(|_| alloy_rlp::Error::Custom("attempted to decode invalid field element")) } - #[doc(hidden)] - fn test_signature() -> Self { - Self::from_scalars_and_parity( - b256!("840cfc572845f5786e702984c2a582528cad4b49b2a10b9db1be7fca90058565"), - b256!("25e7109ceb98168d95b09b18bbf6b685130e0562f233877d492b94eee0c5b6d1"), - false, - ) - .unwrap() - } - /// Returns the byte-array representation of this signature. /// /// The first 32 bytes are the `r` value, the second 32 bytes the `s` value @@ -385,7 +392,7 @@ impl serde::Serialize for EcdsaSignature { where S: serde::Serializer, { - // if the serializer is human readable, serialize as a map, otherwise as a tuple + // if the serializer is human-readable, serialize as a map, otherwise as a tuple if serializer.is_human_readable() { use serde::ser::SerializeMap; diff --git a/crates/primitives/src/signature/mod.rs b/crates/primitives/src/signature/mod.rs index 2e50ebf2ce..88aedf54ed 100644 --- a/crates/primitives/src/signature/mod.rs +++ b/crates/primitives/src/signature/mod.rs @@ -10,6 +10,8 @@ pub use ecdsa_sig::EcdsaSignature; mod utils; mod sig; +mod super_signature; + pub use sig::Signature; pub use utils::to_eip155_v; diff --git a/crates/primitives/src/signature/sig.rs b/crates/primitives/src/signature/sig.rs index 77409a32a5..a974561790 100644 --- a/crates/primitives/src/signature/sig.rs +++ b/crates/primitives/src/signature/sig.rs @@ -1,21 +1,34 @@ use crate::{Parity, SignatureError, U256}; use core::str::FromStr; +use crate::signature::super_signature::{ArbitrarySuperSig, K256SuperSig, RlpSuperSig, SerdeSuperSig}; /// An Ethereum Generic signature. -pub trait Signature<'a>: - TryFrom<&'a [u8], Error = SignatureError> + FromStr +pub trait Signature: + for<'a> TryFrom<&'a [u8], Error = SignatureError> ++ FromStr ++ RlpSuperSig ++ K256SuperSig ++ SerdeSuperSig ++ ArbitrarySuperSig { + /// Instantiate a new signature from `r`, `s`, and `v` values. + fn new(r: U256, s: U256, v: Parity) -> Self; + + /// Returns the `r` component of this signature. + fn r(&self) -> U256; + + /// Returns the `s` component of this signature. + fn s(&self) -> U256; + + /// Returns the recovery ID as a `u8`. + fn v(&self) -> Parity; + /// Decode an RLP-encoded VRS signature. #[cfg(feature = "rlp")] fn decode_rlp_vrs(buf: &mut &[u8]) -> Result where Self: Sized; - #[doc(hidden)] - fn test_signature() -> Self - where - Self: Sized; - /// Returns the byte-array representation of this signature. fn as_bytes(&self) -> [u8; 65]; diff --git a/crates/primitives/src/signature/super_signature.rs b/crates/primitives/src/signature/super_signature.rs new file mode 100644 index 0000000000..4eafed1f4f --- /dev/null +++ b/crates/primitives/src/signature/super_signature.rs @@ -0,0 +1,30 @@ +use crate::{Parity, U256}; + +#[cfg(not(feature = "rlp"))] +pub trait RlpSuperSig {} + +#[cfg(feature = "rlp")] +pub trait RlpSuperSig: alloy_rlp::Encodable + alloy_rlp::Decodable {} + +#[cfg(not(feature = "k256"))] +pub trait K256SuperSig {} + +#[cfg(feature = "k256")] +pub trait K256SuperSig: From<(k256::ecdsa::Signature, k256::ecdsa::RecoveryId)> {} + +#[cfg(not(feature = "serde"))] +pub trait SerdeSuperSig {} + +#[cfg(feature = "serde")] +pub trait SerdeSuperSig: serde::Serialize + serde::Deserialize {} + +#[cfg(not(feature = "arbitrary"))] +pub trait ArbitrarySuperSig {} + +#[cfg(feature = "arbitrary")] +pub trait ArbitrarySuperSig: +arbitrary::Arbitrary ++ proptest::arbitrary::Arbitrary::Strategy, + fn((U256, U256, Parity)) -> Option, +>> {} \ No newline at end of file