1#![allow(clippy::missing_const_for_fn)] use 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
10const SECP256K1N_ORDER: U256 =
12 uint!(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141_U256);
13
14#[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 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 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 #[inline]
115 pub const fn new(r: U256, s: U256, y_parity: bool) -> Self {
116 Self { r, s, y_parity }
117 }
118
119 #[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 #[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 #[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 #[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 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 pub fn as_erc2098(&self) -> [u8; 64] {
195 let normalized = self.normalized_s();
196 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 #[inline]
209 pub fn with_parity(mut self, v: bool) -> Self {
210 self.y_parity = v;
211 self
212 }
213
214 #[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 #[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 #[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 #[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 #[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 #[inline]
267 pub fn normalized_s(self) -> Self {
268 self.normalize_s().unwrap_or(self)
269 }
270
271 #[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 #[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 #[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 #[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 #[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 #[inline]
336 pub fn r(&self) -> U256 {
337 self.r
338 }
339
340 #[inline]
342 pub fn s(&self) -> U256 {
343 self.s
344 }
345
346 #[inline]
348 pub fn v(&self) -> bool {
349 self.y_parity
350 }
351
352 #[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 #[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 #[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 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 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 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 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 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 let sig = Signature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap();
597
598 let mut buf = vec![];
600
601 sig.write_rlp_vrs(&mut buf, sig.v());
603
604 let expected = "80a048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804";
606
607 assert_eq!(hex::encode(&buf), expected);
609 }
610
611 #[cfg(feature = "rlp")]
612 #[test]
613 fn signature_rlp_length() {
614 let sig = Signature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap();
616
617 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}