From 9c506a7819be28fd3b7078690e4216ec5e53744f Mon Sep 17 00:00:00 2001 From: Wolfgang Welz Date: Sun, 4 Feb 2024 13:07:08 +0100 Subject: [PATCH 1/3] add parity to u64 conversion --- crates/primitives/src/signature/parity.rs | 25 +++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/crates/primitives/src/signature/parity.rs b/crates/primitives/src/signature/parity.rs index f2b43dc98..20d9a08d9 100644 --- a/crates/primitives/src/signature/parity.rs +++ b/crates/primitives/src/signature/parity.rs @@ -92,6 +92,15 @@ impl Parity { } } + /// Return the corresponding u64 V value. + pub const fn to_u64(&self) -> u64 { + match self { + Self::Eip155(v) => *v, + Self::NonEip155(b) => *b as u64 + 27, + Self::Parity(b) => *b as u64, + } + } + /// Inverts the parity. pub const fn inverted(&self) -> Self { match *self { @@ -205,6 +214,22 @@ mod test { } } + #[test] + fn u64_round_trip() { + let parity = Parity::Eip155(37); + assert_eq!(parity, Parity::try_from(parity.to_u64()).unwrap()); + let parity = Parity::Eip155(38); + assert_eq!(parity, Parity::try_from(parity.to_u64()).unwrap()); + let parity = Parity::NonEip155(false); + assert_eq!(parity, Parity::try_from(parity.to_u64()).unwrap()); + let parity = Parity::NonEip155(true); + assert_eq!(parity, Parity::try_from(parity.to_u64()).unwrap()); + let parity = Parity::Parity(false); + assert_eq!(parity, Parity::try_from(parity.to_u64()).unwrap()); + let parity = Parity::Parity(true); + assert_eq!(parity, Parity::try_from(parity.to_u64()).unwrap()); + } + #[test] fn round_trip() { // with chain ID 1 From bea435e34c2a0b7bbfbbf9d8eea6fc78233333ad Mon Sep 17 00:00:00 2001 From: Wolfgang Welz Date: Sun, 4 Feb 2024 13:07:49 +0100 Subject: [PATCH 2/3] fix bincode serialization --- crates/primitives/src/signature/sig.rs | 84 ++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 13 deletions(-) diff --git a/crates/primitives/src/signature/sig.rs b/crates/primitives/src/signature/sig.rs index 05e173311..86565d672 100644 --- a/crates/primitives/src/signature/sig.rs +++ b/crates/primitives/src/signature/sig.rs @@ -405,20 +405,31 @@ impl serde::Serialize for crate::Signature { where S: serde::Serializer, { - use serde::ser::SerializeMap; + // if the serializer is human readable, serialize as a map, otherwise as a tuple + if serializer.is_human_readable() { + use serde::ser::SerializeMap; - let mut map = serializer.serialize_map(Some(3))?; + let mut map = serializer.serialize_map(Some(3))?; - map.serialize_entry("r", &self.r)?; - map.serialize_entry("s", &self.s)?; + map.serialize_entry("r", &self.r)?; + map.serialize_entry("s", &self.s)?; - match self.v { - Parity::Eip155(v) => map.serialize_entry("v", &crate::U64::from(v))?, - Parity::NonEip155(b) => map.serialize_entry("v", &(b as u8 + 27))?, - Parity::Parity(true) => map.serialize_entry("yParity", "0x1")?, - Parity::Parity(false) => map.serialize_entry("yParity", "0x0")?, + match self.v { + Parity::Eip155(v) => map.serialize_entry("v", &crate::U64::from(v))?, + Parity::NonEip155(b) => map.serialize_entry("v", &(b as u8 + 27))?, + Parity::Parity(true) => map.serialize_entry("yParity", "0x1")?, + Parity::Parity(false) => map.serialize_entry("yParity", "0x0")?, + } + map.end() + } else { + use serde::ser::SerializeTuple; + + let mut tuple = serializer.serialize_tuple(3)?; + tuple.serialize_element(&self.r)?; + tuple.serialize_element(&self.s)?; + tuple.serialize_element(&self.v.to_u64())?; + tuple.end() } - map.end() } } @@ -472,8 +483,8 @@ impl<'de> serde::Deserialize<'de> for crate::Signature { } } - struct SignatureVisitor; - impl<'de> serde::de::Visitor<'de> for SignatureVisitor { + struct MapVisitor; + impl<'de> serde::de::Visitor<'de> for MapVisitor { type Value = crate::Signature; fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { @@ -526,7 +537,37 @@ impl<'de> serde::Deserialize<'de> for crate::Signature { } } - deserializer.deserialize_map(SignatureVisitor) + struct TupleVisitor; + impl<'de> serde::de::Visitor<'de> for TupleVisitor { + type Value = crate::Signature; + + fn expecting(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + formatter.write_str("a tuple containing r, s, and v") + } + + fn visit_seq(self, mut seq: A) -> Result + where + A: serde::de::SeqAccess<'de>, + { + let r = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + let s = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?; + let v: u64 = seq + .next_element()? + .ok_or_else(|| serde::de::Error::invalid_length(2, &self))?; + + crate::Signature::from_rs_and_parity(r, s, v).map_err(serde::de::Error::custom) + } + } + + if deserializer.is_human_readable() { + deserializer.deserialize_map(MapVisitor) + } else { + deserializer.deserialize_tuple(3, TupleVisitor) + } } } @@ -664,6 +705,23 @@ mod tests { assert_eq!(serialized, expected); } + #[cfg(feature = "serde")] + #[test] + fn test_bincode_roundtrip() { + let raw_signature_without_y_parity = serde_json::json!( + { + "r":"0xc569c92f176a3be1a6352dd5005bfc751dcb32f57623dd2a23693e64bf4447b0", + "s":"0x1a891b566d369e79b7a66eecab1e008831e22daa15f91a0a0cf4f9f28f47ee05", + "v":"0x37" + }); + + let signature: crate::Signature = + serde_json::from_value(raw_signature_without_y_parity).unwrap(); + + let bin = bincode::serialize(&signature).unwrap(); + assert_eq!(bincode::deserialize::(&bin).unwrap(), signature); + } + #[cfg(feature = "rlp")] #[test] fn signature_rlp_decode() { From 580ab730c375b7f3ffe38b9f673c72964fbd080d Mon Sep 17 00:00:00 2001 From: Wolfgang Welz Date: Sun, 4 Feb 2024 14:12:18 +0100 Subject: [PATCH 3/3] don't use json in bincode test --- crates/primitives/src/signature/sig.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/crates/primitives/src/signature/sig.rs b/crates/primitives/src/signature/sig.rs index 86565d672..0d78cae75 100644 --- a/crates/primitives/src/signature/sig.rs +++ b/crates/primitives/src/signature/sig.rs @@ -708,15 +708,14 @@ mod tests { #[cfg(feature = "serde")] #[test] fn test_bincode_roundtrip() { - let raw_signature_without_y_parity = serde_json::json!( - { - "r":"0xc569c92f176a3be1a6352dd5005bfc751dcb32f57623dd2a23693e64bf4447b0", - "s":"0x1a891b566d369e79b7a66eecab1e008831e22daa15f91a0a0cf4f9f28f47ee05", - "v":"0x37" - }); - - let signature: crate::Signature = - serde_json::from_value(raw_signature_without_y_parity).unwrap(); + let signature = crate::Signature::from_rs_and_parity( + U256::from_str("0xc569c92f176a3be1a6352dd5005bfc751dcb32f57623dd2a23693e64bf4447b0") + .unwrap(), + U256::from_str("0x1a891b566d369e79b7a66eecab1e008831e22daa15f91a0a0cf4f9f28f47ee05") + .unwrap(), + 1, + ) + .unwrap(); let bin = bincode::serialize(&signature).unwrap(); assert_eq!(bincode::deserialize::(&bin).unwrap(), signature);