alloy_primitives/signature/
primitive_sig.rs

1#![allow(clippy::missing_const_for_fn)] // On purpose for forward compatibility.
2
3use crate::{hex, normalize_v, signature::SignatureError, uint, B256, U256};
4use alloc::vec::Vec;
5use core::{fmt::Display, str::FromStr};
6
7#[cfg(feature = "k256")]
8use crate::Address;
9
10/// The order of the [Secp256k1](https://en.bitcoin.it/wiki/Secp256k1) curve.
11const SECP256K1N_ORDER: U256 =
12    uint!(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141_U256);
13
14/// An Ethereum ECDSA signature.
15#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
16pub struct PrimitiveSignature {
17    y_parity: bool,
18    r: U256,
19    s: U256,
20}
21
22impl Display for PrimitiveSignature {
23    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
24        write!(f, "0x{}", hex::encode(self.as_bytes()))
25    }
26}
27
28impl TryFrom<&[u8]> for PrimitiveSignature {
29    type Error = SignatureError;
30
31    /// Parses a 65-byte long raw signature.
32    ///
33    /// See [`from_raw`](Self::from_raw).
34    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
35        Self::from_raw(bytes)
36    }
37}
38
39impl FromStr for PrimitiveSignature {
40    type Err = SignatureError;
41
42    fn from_str(s: &str) -> Result<Self, Self::Err> {
43        Self::from_raw_array(&hex::decode_to_array(s)?)
44    }
45}
46
47impl From<&PrimitiveSignature> for [u8; 65] {
48    #[inline]
49    fn from(value: &PrimitiveSignature) -> [u8; 65] {
50        value.as_bytes()
51    }
52}
53
54impl From<PrimitiveSignature> for [u8; 65] {
55    #[inline]
56    fn from(value: PrimitiveSignature) -> [u8; 65] {
57        value.as_bytes()
58    }
59}
60
61impl From<&PrimitiveSignature> for Vec<u8> {
62    #[inline]
63    fn from(value: &PrimitiveSignature) -> Self {
64        value.as_bytes().to_vec()
65    }
66}
67
68impl From<PrimitiveSignature> for Vec<u8> {
69    #[inline]
70    fn from(value: PrimitiveSignature) -> Self {
71        value.as_bytes().to_vec()
72    }
73}
74
75#[cfg(feature = "k256")]
76impl From<(k256::ecdsa::Signature, k256::ecdsa::RecoveryId)> for PrimitiveSignature {
77    fn from(value: (k256::ecdsa::Signature, k256::ecdsa::RecoveryId)) -> Self {
78        Self::from_signature_and_parity(value.0, value.1.is_y_odd())
79    }
80}
81
82#[cfg(feature = "k256")]
83impl TryFrom<PrimitiveSignature> for k256::ecdsa::Signature {
84    type Error = k256::ecdsa::Error;
85
86    fn try_from(value: PrimitiveSignature) -> Result<Self, Self::Error> {
87        value.to_k256()
88    }
89}
90
91#[cfg(feature = "rlp")]
92impl PrimitiveSignature {
93    /// Decode an RLP-encoded VRS signature. Accepts `decode_parity` closure which allows to
94    /// customize parity decoding and possibly extract additional data from it (e.g chain_id for
95    /// legacy signature).
96    pub fn decode_rlp_vrs(
97        buf: &mut &[u8],
98        decode_parity: impl FnOnce(&mut &[u8]) -> alloy_rlp::Result<bool>,
99    ) -> Result<Self, alloy_rlp::Error> {
100        use alloy_rlp::Decodable;
101
102        let parity = decode_parity(buf)?;
103        let r = Decodable::decode(buf)?;
104        let s = Decodable::decode(buf)?;
105
106        Ok(Self::new(r, s, parity))
107    }
108}
109
110impl PrimitiveSignature {
111    /// Instantiate a new signature from `r`, `s`, and `v` values.
112    #[inline]
113    pub const fn new(r: U256, s: U256, y_parity: bool) -> Self {
114        Self { r, s, y_parity }
115    }
116
117    /// Parses a 65-byte long raw signature.
118    ///
119    /// The first 32 bytes is the `r` value, the second 32 bytes the `s` value, and the final byte
120    /// is the `v` value in 'Electrum' notation.
121    #[inline]
122    pub fn from_raw(bytes: &[u8]) -> Result<Self, SignatureError> {
123        Self::from_raw_array(
124            bytes.try_into().map_err(|_| SignatureError::FromBytes("expected exactly 65 bytes"))?,
125        )
126    }
127
128    /// Parses a 65-byte long raw signature.
129    ///
130    /// See [`from_raw`](Self::from_raw).
131    #[inline]
132    pub fn from_raw_array(bytes: &[u8; 65]) -> Result<Self, SignatureError> {
133        let [bytes @ .., v] = bytes;
134        let v = *v as u64;
135        let Some(parity) = normalize_v(v) else { return Err(SignatureError::InvalidParity(v)) };
136        Ok(Self::from_bytes_and_parity(bytes, parity))
137    }
138
139    /// Parses a signature from a byte slice, with a v value
140    ///
141    /// # Panics
142    ///
143    /// If the slice is not at least 64 bytes long.
144    #[inline]
145    #[track_caller]
146    pub fn from_bytes_and_parity(bytes: &[u8], parity: bool) -> Self {
147        let (r_bytes, s_bytes) = bytes[..64].split_at(32);
148        let r = U256::from_be_slice(r_bytes);
149        let s = U256::from_be_slice(s_bytes);
150        Self::new(r, s, parity)
151    }
152
153    /// Returns the byte-array representation of this signature.
154    ///
155    /// The first 32 bytes are the `r` value, the second 32 bytes the `s` value
156    /// and the final byte is the `v` value in 'Electrum' notation.
157    #[inline]
158    pub fn as_bytes(&self) -> [u8; 65] {
159        let mut sig = [0u8; 65];
160        sig[..32].copy_from_slice(&self.r.to_be_bytes::<32>());
161        sig[32..64].copy_from_slice(&self.s.to_be_bytes::<32>());
162        sig[64] = 27 + self.y_parity as u8;
163        sig
164    }
165
166    /// Decode the signature from the ERC-2098 compact representation.
167    ///
168    /// The first 32 bytes are the `r` value, and the next 32 bytes are the `s` value with `yParity`
169    /// in the top bit of the `s` value, as described in ERC-2098.
170    ///
171    /// See <https://eips.ethereum.org/EIPS/eip-2098>
172    ///
173    /// # Panics
174    ///
175    /// If the slice is not at least 64 bytes long.
176    pub fn from_erc2098(bytes: &[u8]) -> Self {
177        let (r_bytes, y_and_s_bytes) = bytes[..64].split_at(32);
178        let r = U256::from_be_slice(r_bytes);
179        let y_and_s = U256::from_be_slice(y_and_s_bytes);
180        let y_parity = y_and_s.bit(255);
181        let mut s = y_and_s;
182        s.set_bit(255, false);
183        Self { y_parity, r, s }
184    }
185
186    /// Returns the ERC-2098 compact representation of this signature.
187    ///
188    /// The first 32 bytes are the `r` value, and the next 32 bytes are the `s` value with `yParity`
189    /// in the top bit of the `s` value, as described in ERC-2098.
190    ///
191    /// See <https://eips.ethereum.org/EIPS/eip-2098>
192    pub fn as_erc2098(&self) -> [u8; 64] {
193        let normalized = self.normalized_s();
194        // The top bit of the `s` parameters is always 0, due to the use of canonical
195        // signatures which flip the solution parity to prevent negative values, which was
196        // introduced as a constraint in Homestead.
197        let mut sig = [0u8; 64];
198        sig[..32].copy_from_slice(&normalized.r().to_be_bytes::<32>());
199        sig[32..64].copy_from_slice(&normalized.s().to_be_bytes::<32>());
200        debug_assert_eq!(sig[32] >> 7, 0, "top bit of s should be 0");
201        sig[32] |= (normalized.y_parity as u8) << 7;
202        sig
203    }
204
205    /// Sets the recovery ID by normalizing a `v` value.
206    #[inline]
207    pub fn with_parity(mut self, v: bool) -> Self {
208        self.y_parity = v;
209        self
210    }
211
212    /// Returns the inner ECDSA signature.
213    #[cfg(feature = "k256")]
214    #[deprecated(note = "use `Signature::to_k256` instead")]
215    #[inline]
216    pub fn into_inner(self) -> k256::ecdsa::Signature {
217        self.try_into().expect("signature conversion failed")
218    }
219
220    /// Returns the inner ECDSA signature.
221    #[cfg(feature = "k256")]
222    #[inline]
223    pub fn to_k256(self) -> Result<k256::ecdsa::Signature, k256::ecdsa::Error> {
224        k256::ecdsa::Signature::from_scalars(self.r.to_be_bytes(), self.s.to_be_bytes())
225    }
226
227    /// Instantiate from a signature and recovery id
228    #[cfg(feature = "k256")]
229    pub fn from_signature_and_parity(sig: k256::ecdsa::Signature, v: bool) -> Self {
230        let r = U256::from_be_slice(sig.r().to_bytes().as_ref());
231        let s = U256::from_be_slice(sig.s().to_bytes().as_ref());
232        Self { y_parity: v, r, s }
233    }
234
235    /// Creates a [`PrimitiveSignature`] from the serialized `r` and `s` scalar values, which
236    /// comprise the ECDSA signature, alongside a `v` value, used to determine the recovery ID.
237    #[inline]
238    pub fn from_scalars_and_parity(r: B256, s: B256, parity: bool) -> Self {
239        Self::new(U256::from_be_bytes(r.0), U256::from_be_bytes(s.0), parity)
240    }
241
242    /// Normalizes the signature into "low S" form as described in
243    /// [BIP 0062: Dealing with Malleability][1].
244    ///
245    /// If `s` is already normalized, returns `None`.
246    ///
247    /// [1]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki
248    #[inline]
249    pub fn normalize_s(&self) -> Option<Self> {
250        let s = self.s();
251        if s > SECP256K1N_ORDER >> 1 {
252            Some(Self { y_parity: !self.y_parity, r: self.r, s: SECP256K1N_ORDER - s })
253        } else {
254            None
255        }
256    }
257
258    /// Normalizes the signature into "low S" form as described in
259    /// [BIP 0062: Dealing with Malleability][1].
260    ///
261    /// If `s` is already normalized, returns `self`.
262    ///
263    /// [1]: https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki
264    #[inline]
265    pub fn normalized_s(self) -> Self {
266        self.normalize_s().unwrap_or(self)
267    }
268
269    /// Returns the recovery ID.
270    #[cfg(feature = "k256")]
271    #[inline]
272    pub fn recid(&self) -> k256::ecdsa::RecoveryId {
273        k256::ecdsa::RecoveryId::new(self.y_parity, false)
274    }
275
276    #[cfg(feature = "k256")]
277    #[doc(hidden)]
278    #[deprecated(note = "use `Signature::recid` instead")]
279    pub fn recovery_id(&self) -> k256::ecdsa::RecoveryId {
280        self.recid()
281    }
282
283    /// Recovers an [`Address`] from this signature and the given message by first prefixing and
284    /// hashing the message according to [EIP-191](crate::eip191_hash_message).
285    #[cfg(feature = "k256")]
286    #[inline]
287    pub fn recover_address_from_msg<T: AsRef<[u8]>>(
288        &self,
289        msg: T,
290    ) -> Result<Address, SignatureError> {
291        self.recover_from_msg(msg).map(|vk| Address::from_public_key(&vk))
292    }
293
294    /// Recovers an [`Address`] from this signature and the given prehashed message.
295    #[cfg(feature = "k256")]
296    #[inline]
297    pub fn recover_address_from_prehash(&self, prehash: &B256) -> Result<Address, SignatureError> {
298        self.recover_from_prehash(prehash).map(|vk| Address::from_public_key(&vk))
299    }
300
301    /// Recovers a [`VerifyingKey`] from this signature and the given message by first prefixing and
302    /// hashing the message according to [EIP-191](crate::eip191_hash_message).
303    ///
304    /// [`VerifyingKey`]: k256::ecdsa::VerifyingKey
305    #[cfg(feature = "k256")]
306    #[inline]
307    pub fn recover_from_msg<T: AsRef<[u8]>>(
308        &self,
309        msg: T,
310    ) -> Result<k256::ecdsa::VerifyingKey, SignatureError> {
311        self.recover_from_prehash(&crate::eip191_hash_message(msg))
312    }
313
314    /// Recovers a [`VerifyingKey`] from this signature and the given prehashed message.
315    ///
316    /// [`VerifyingKey`]: k256::ecdsa::VerifyingKey
317    #[cfg(feature = "k256")]
318    #[inline]
319    pub fn recover_from_prehash(
320        &self,
321        prehash: &B256,
322    ) -> Result<k256::ecdsa::VerifyingKey, SignatureError> {
323        let this = self.normalized_s();
324        k256::ecdsa::VerifyingKey::recover_from_prehash(
325            prehash.as_slice(),
326            &this.to_k256()?,
327            this.recid(),
328        )
329        .map_err(Into::into)
330    }
331
332    /// Returns the `r` component of this signature.
333    #[inline]
334    pub fn r(&self) -> U256 {
335        self.r
336    }
337
338    /// Returns the `s` component of this signature.
339    #[inline]
340    pub fn s(&self) -> U256 {
341        self.s
342    }
343
344    /// Returns the recovery ID as a `bool`.
345    #[inline]
346    pub fn v(&self) -> bool {
347        self.y_parity
348    }
349
350    /// Length of RLP RS field encoding
351    #[cfg(feature = "rlp")]
352    pub fn rlp_rs_len(&self) -> usize {
353        alloy_rlp::Encodable::length(&self.r) + alloy_rlp::Encodable::length(&self.s)
354    }
355
356    /// Write R and S to an RLP buffer in progress.
357    #[cfg(feature = "rlp")]
358    pub fn write_rlp_rs(&self, out: &mut dyn alloy_rlp::BufMut) {
359        alloy_rlp::Encodable::encode(&self.r, out);
360        alloy_rlp::Encodable::encode(&self.s, out);
361    }
362
363    /// Write the VRS to the output.
364    #[cfg(feature = "rlp")]
365    pub fn write_rlp_vrs(&self, out: &mut dyn alloy_rlp::BufMut, v: impl alloy_rlp::Encodable) {
366        v.encode(out);
367        self.write_rlp_rs(out);
368    }
369
370    #[doc(hidden)]
371    #[inline(always)]
372    pub fn test_signature() -> Self {
373        Self::from_scalars_and_parity(
374            b256!("0x840cfc572845f5786e702984c2a582528cad4b49b2a10b9db1be7fca90058565"),
375            b256!("0x25e7109ceb98168d95b09b18bbf6b685130e0562f233877d492b94eee0c5b6d1"),
376            false,
377        )
378    }
379}
380
381#[cfg(feature = "arbitrary")]
382impl<'a> arbitrary::Arbitrary<'a> for PrimitiveSignature {
383    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
384        Ok(Self::new(u.arbitrary()?, u.arbitrary()?, u.arbitrary()?))
385    }
386}
387
388#[cfg(feature = "arbitrary")]
389impl proptest::arbitrary::Arbitrary for PrimitiveSignature {
390    type Parameters = ();
391    type Strategy = proptest::strategy::Map<
392        <(U256, U256, bool) as proptest::arbitrary::Arbitrary>::Strategy,
393        fn((U256, U256, bool)) -> Self,
394    >;
395
396    fn arbitrary_with((): Self::Parameters) -> Self::Strategy {
397        use proptest::strategy::Strategy;
398        proptest::arbitrary::any::<(U256, U256, bool)>()
399            .prop_map(|(r, s, y_parity)| Self::new(r, s, y_parity))
400    }
401}
402
403#[cfg(feature = "serde")]
404mod signature_serde {
405    use super::PrimitiveSignature;
406    use crate::{normalize_v, U256, U64};
407    use serde::{Deserialize, Deserializer, Serialize};
408
409    #[derive(Serialize, Deserialize)]
410    struct HumanReadableRepr {
411        r: U256,
412        s: U256,
413        #[serde(rename = "yParity")]
414        y_parity: Option<U64>,
415        #[serde(default, skip_serializing_if = "Option::is_none")]
416        v: Option<U64>,
417    }
418
419    type NonHumanReadableRepr = (U256, U256, U64);
420
421    impl Serialize for PrimitiveSignature {
422        fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
423        where
424            S: serde::Serializer,
425        {
426            // if the serializer is human readable, serialize as a map, otherwise as a tuple
427            if serializer.is_human_readable() {
428                HumanReadableRepr {
429                    y_parity: Some(U64::from(self.y_parity as u64)),
430                    v: Some(U64::from(self.y_parity as u64)),
431                    r: self.r,
432                    s: self.s,
433                }
434                .serialize(serializer)
435            } else {
436                let repr: NonHumanReadableRepr = (self.r, self.s, U64::from(self.y_parity as u64));
437                repr.serialize(serializer)
438            }
439        }
440    }
441
442    impl<'de> Deserialize<'de> for PrimitiveSignature {
443        fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
444        where
445            D: Deserializer<'de>,
446        {
447            let (y_parity, v, r, s) = if deserializer.is_human_readable() {
448                let HumanReadableRepr { y_parity, v, r, s } = <_>::deserialize(deserializer)?;
449                (y_parity, v, r, s)
450            } else {
451                let (r, s, y_parity) = NonHumanReadableRepr::deserialize(deserializer)?;
452                (Some(y_parity), None, r, s)
453            };
454
455            // Attempt to extract `y_parity` bit from either `yParity` key or `v` value.
456            let y_parity = if let Some(y_parity) = y_parity {
457                match y_parity.to::<u64>() {
458                    0 => false,
459                    1 => true,
460                    _ => return Err(serde::de::Error::custom("invalid yParity")),
461                }
462            } else if let Some(v) = v {
463                normalize_v(v.to()).ok_or(serde::de::Error::custom("invalid v"))?
464            } else {
465                return Err(serde::de::Error::custom("missing `yParity` or `v`"));
466            };
467
468            Ok(Self::new(r, s, y_parity))
469        }
470    }
471}
472
473#[cfg(test)]
474mod tests {
475    use super::*;
476    use core::str::FromStr;
477
478    #[cfg(feature = "rlp")]
479    use alloy_rlp::{Decodable, Encodable};
480
481    #[test]
482    #[cfg(feature = "k256")]
483    fn can_recover_tx_sender_not_normalized() {
484        let sig = PrimitiveSignature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap();
485        let hash = b256!("0x5eb4f5a33c621f32a8622d5f943b6b102994dfe4e5aebbefe69bb1b2aa0fc93e");
486        let expected = address!("0x0f65fe9276bc9a24ae7083ae28e2660ef72df99e");
487        assert_eq!(sig.recover_address_from_prehash(&hash).unwrap(), expected);
488    }
489
490    #[test]
491    #[cfg(feature = "k256")]
492    fn recover_web3_signature() {
493        // test vector taken from:
494        // https://web3js.readthedocs.io/en/v1.2.2/web3-eth-accounts.html#sign
495        let sig = PrimitiveSignature::from_str(
496            "b91467e570a6466aa9e9876cbcd013baba02900b8979d43fe208a4a4f339f5fd6007e74cd82e037b800186422fc2da167c747ef045e5d18a5f5d4300f8e1a0291c"
497        ).expect("could not parse signature");
498        let expected = address!("0x2c7536E3605D9C16a7a3D7b1898e529396a65c23");
499        assert_eq!(sig.recover_address_from_msg("Some data").unwrap(), expected);
500    }
501
502    #[test]
503    fn signature_from_str() {
504        let s1 = PrimitiveSignature::from_str(
505            "0xaa231fbe0ed2b5418e6ba7c19bee2522852955ec50996c02a2fe3e71d30ddaf1645baf4823fea7cb4fcc7150842493847cfb6a6d63ab93e8ee928ee3f61f503500"
506        ).expect("could not parse 0x-prefixed signature");
507
508        let s2 = PrimitiveSignature::from_str(
509            "aa231fbe0ed2b5418e6ba7c19bee2522852955ec50996c02a2fe3e71d30ddaf1645baf4823fea7cb4fcc7150842493847cfb6a6d63ab93e8ee928ee3f61f503500"
510        ).expect("could not parse non-prefixed signature");
511
512        assert_eq!(s1, s2);
513    }
514
515    #[cfg(feature = "serde")]
516    #[test]
517    fn deserialize_with_parity() {
518        let raw_signature_with_y_parity = serde_json::json!({
519            "r": "0xc569c92f176a3be1a6352dd5005bfc751dcb32f57623dd2a23693e64bf4447b0",
520            "s": "0x1a891b566d369e79b7a66eecab1e008831e22daa15f91a0a0cf4f9f28f47ee05",
521            "v": "0x1",
522            "yParity": "0x1"
523        });
524
525        let signature: PrimitiveSignature =
526            serde_json::from_value(raw_signature_with_y_parity).unwrap();
527
528        let expected = PrimitiveSignature::new(
529            U256::from_str("0xc569c92f176a3be1a6352dd5005bfc751dcb32f57623dd2a23693e64bf4447b0")
530                .unwrap(),
531            U256::from_str("0x1a891b566d369e79b7a66eecab1e008831e22daa15f91a0a0cf4f9f28f47ee05")
532                .unwrap(),
533            true,
534        );
535
536        assert_eq!(signature, expected);
537    }
538
539    #[cfg(feature = "serde")]
540    #[test]
541    fn serialize_both_parity() {
542        // this test should be removed if the struct moves to an enum based on tx type
543        let signature = PrimitiveSignature::new(
544            U256::from_str("0xc569c92f176a3be1a6352dd5005bfc751dcb32f57623dd2a23693e64bf4447b0")
545                .unwrap(),
546            U256::from_str("0x1a891b566d369e79b7a66eecab1e008831e22daa15f91a0a0cf4f9f28f47ee05")
547                .unwrap(),
548            true,
549        );
550
551        let serialized = serde_json::to_string(&signature).unwrap();
552        assert_eq!(
553            serialized,
554            r#"{"r":"0xc569c92f176a3be1a6352dd5005bfc751dcb32f57623dd2a23693e64bf4447b0","s":"0x1a891b566d369e79b7a66eecab1e008831e22daa15f91a0a0cf4f9f28f47ee05","yParity":"0x1","v":"0x1"}"#
555        );
556    }
557
558    #[cfg(feature = "serde")]
559    #[test]
560    fn serialize_v_only() {
561        // this test should be removed if the struct moves to an enum based on tx type
562        let signature = PrimitiveSignature::new(
563            U256::from_str("0xc569c92f176a3be1a6352dd5005bfc751dcb32f57623dd2a23693e64bf4447b0")
564                .unwrap(),
565            U256::from_str("0x1a891b566d369e79b7a66eecab1e008831e22daa15f91a0a0cf4f9f28f47ee05")
566                .unwrap(),
567            true,
568        );
569
570        let expected = r#"{"r":"0xc569c92f176a3be1a6352dd5005bfc751dcb32f57623dd2a23693e64bf4447b0","s":"0x1a891b566d369e79b7a66eecab1e008831e22daa15f91a0a0cf4f9f28f47ee05","yParity":"0x1","v":"0x1"}"#;
571
572        let serialized = serde_json::to_string(&signature).unwrap();
573        assert_eq!(serialized, expected);
574    }
575
576    #[cfg(feature = "serde")]
577    #[test]
578    fn bincode_roundtrip() {
579        let signature = PrimitiveSignature::new(
580            U256::from_str("0xc569c92f176a3be1a6352dd5005bfc751dcb32f57623dd2a23693e64bf4447b0")
581                .unwrap(),
582            U256::from_str("0x1a891b566d369e79b7a66eecab1e008831e22daa15f91a0a0cf4f9f28f47ee05")
583                .unwrap(),
584            true,
585        );
586
587        let bin = bincode::serialize(&signature).unwrap();
588        assert_eq!(bincode::deserialize::<PrimitiveSignature>(&bin).unwrap(), signature);
589    }
590
591    #[cfg(feature = "rlp")]
592    #[test]
593    fn signature_rlp_encode() {
594        // Given a Signature instance
595        let sig = PrimitiveSignature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap();
596
597        // Initialize an empty buffer
598        let mut buf = vec![];
599
600        // Encode the Signature into the buffer
601        sig.write_rlp_vrs(&mut buf, sig.v());
602
603        // Define the expected hex-encoded string
604        let expected = "80a048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804";
605
606        // Assert that the encoded buffer matches the expected hex-encoded string
607        assert_eq!(hex::encode(&buf), expected);
608    }
609
610    #[cfg(feature = "rlp")]
611    #[test]
612    fn signature_rlp_length() {
613        // Given a Signature instance
614        let sig = PrimitiveSignature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap();
615
616        // Assert that the length of the Signature matches the expected length
617        assert_eq!(sig.rlp_rs_len() + sig.v().length(), 67);
618    }
619
620    #[cfg(feature = "rlp")]
621    #[test]
622    fn rlp_vrs_len() {
623        let signature = PrimitiveSignature::test_signature();
624        assert_eq!(67, signature.rlp_rs_len() + 1);
625    }
626
627    #[cfg(feature = "rlp")]
628    #[test]
629    fn encode_and_decode() {
630        let signature = PrimitiveSignature::test_signature();
631
632        let mut encoded = Vec::new();
633        signature.write_rlp_vrs(&mut encoded, signature.v());
634        assert_eq!(encoded.len(), signature.rlp_rs_len() + signature.v().length());
635        let decoded = PrimitiveSignature::decode_rlp_vrs(&mut &*encoded, bool::decode).unwrap();
636        assert_eq!(signature, decoded);
637    }
638
639    #[test]
640    fn as_bytes() {
641        let signature = PrimitiveSignature::new(
642            U256::from_str(
643                "18515461264373351373200002665853028612451056578545711640558177340181847433846",
644            )
645            .unwrap(),
646            U256::from_str(
647                "46948507304638947509940763649030358759909902576025900602547168820602576006531",
648            )
649            .unwrap(),
650            false,
651        );
652
653        let expected = hex!("0x28ef61340bd939bc2195fe537567866003e1a15d3c71ff63e1590620aa63627667cbe9d8997f761aecb703304b3800ccf555c9f3dc64214b297fb1966a3b6d831b");
654        assert_eq!(signature.as_bytes(), expected);
655    }
656
657    #[test]
658    fn as_erc2098_y_false() {
659        let signature = PrimitiveSignature::new(
660            U256::from_str(
661                "47323457007453657207889730243826965761922296599680473886588287015755652701072",
662            )
663            .unwrap(),
664            U256::from_str(
665                "57228803202727131502949358313456071280488184270258293674242124340113824882788",
666            )
667            .unwrap(),
668            false,
669        );
670
671        let expected = hex!("0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b907e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064");
672        assert_eq!(signature.as_erc2098(), expected);
673    }
674
675    #[test]
676    fn as_erc2098_y_true() {
677        let signature = PrimitiveSignature::new(
678            U256::from_str("0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76")
679                .unwrap(),
680            U256::from_str("0x139c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793")
681                .unwrap(),
682            true,
683        );
684
685        let expected = hex!("0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76939c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793");
686        assert_eq!(signature.as_erc2098(), expected);
687    }
688
689    #[test]
690    fn from_erc2098_y_false() {
691        let expected = PrimitiveSignature::new(
692            U256::from_str(
693                "47323457007453657207889730243826965761922296599680473886588287015755652701072",
694            )
695            .unwrap(),
696            U256::from_str(
697                "57228803202727131502949358313456071280488184270258293674242124340113824882788",
698            )
699            .unwrap(),
700            false,
701        );
702
703        assert_eq!(
704            PrimitiveSignature::from_erc2098(
705                &hex!("0x68a020a209d3d56c46f38cc50a33f704f4a9a10a59377f8dd762ac66910e9b907e865ad05c4035ab5792787d4a0297a43617ae897930a6fe4d822b8faea52064")
706            ),
707            expected
708        );
709    }
710
711    #[test]
712    fn from_erc2098_y_true() {
713        let expected = PrimitiveSignature::new(
714            U256::from_str("0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76")
715                .unwrap(),
716            U256::from_str("0x139c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793")
717                .unwrap(),
718            true,
719        );
720
721        assert_eq!(
722            PrimitiveSignature::from_erc2098(
723                &hex!("0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76939c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793")
724            ),
725            expected
726        );
727    }
728
729    #[test]
730    fn display_impl() {
731        let sig = PrimitiveSignature::new(
732            U256::from_str("0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76")
733                .unwrap(),
734            U256::from_str("0x139c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f550793")
735                .unwrap(),
736            true,
737        );
738
739        assert_eq!(
740            format!("{sig}"),
741            "0x9328da16089fcba9bececa81663203989f2df5fe1faa6291a45381c81bd17f76139c6d6b623b42da56557e5e734a43dc83345ddfadec52cbe24d0cc64f5507931c"
742        );
743    }
744}