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