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