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)]
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 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 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 #[inline]
113 pub const fn new(r: U256, s: U256, y_parity: bool) -> Self {
114 Self { r, s, y_parity }
115 }
116
117 #[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 #[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 #[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 #[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 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 pub fn as_erc2098(&self) -> [u8; 64] {
193 let normalized = self.normalized_s();
194 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 #[inline]
207 pub fn with_parity(mut self, v: bool) -> Self {
208 self.y_parity = v;
209 self
210 }
211
212 #[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 #[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 #[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 #[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 #[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 #[inline]
265 pub fn normalized_s(self) -> Self {
266 self.normalize_s().unwrap_or(self)
267 }
268
269 #[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 #[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 #[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 #[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 #[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 #[inline]
334 pub fn r(&self) -> U256 {
335 self.r
336 }
337
338 #[inline]
340 pub fn s(&self) -> U256 {
341 self.s
342 }
343
344 #[inline]
346 pub fn v(&self) -> bool {
347 self.y_parity
348 }
349
350 #[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 #[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 #[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 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 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 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 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 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 let sig = PrimitiveSignature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap();
596
597 let mut buf = vec![];
599
600 sig.write_rlp_vrs(&mut buf, sig.v());
602
603 let expected = "80a048b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353a0efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c804";
605
606 assert_eq!(hex::encode(&buf), expected);
608 }
609
610 #[cfg(feature = "rlp")]
611 #[test]
612 fn signature_rlp_length() {
613 let sig = PrimitiveSignature::from_str("48b55bfa915ac795c431978d8a6a992b628d557da5ff759b307d495a36649353efffd310ac743f371de3b9f7f9cb56c0b28ad43601b4ab949f53faa07bd2c8041b").unwrap();
615
616 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}