diff --git a/src/derive/curve.rs b/src/derive/curve.rs index 098d1a2f..660e85d8 100644 --- a/src/derive/curve.rs +++ b/src/derive/curve.rs @@ -288,8 +288,72 @@ macro_rules! new_curve_impl { } + /// A macro to help define point serialization using the [`group::GroupEncoding`] trait + /// This assumes both point types ($name, $nameaffine) implement [`group::GroupEncoding`]. + #[cfg(feature = "derive_serde")] + macro_rules! serialize_deserialize_to_from_bytes { + () => { + impl ::serde::Serialize for $name { + fn serialize(&self, serializer: S) -> Result { + let bytes = &self.to_bytes(); + if serializer.is_human_readable() { + ::hex::serde::serialize(&bytes.0, serializer) + } else { + ::serde_arrays::serialize(&bytes.0, serializer) + } + } + } + + paste::paste! { + use ::serde::de::Error as _; + impl<'de> ::serde::Deserialize<'de> for $name { + fn deserialize>( + deserializer: D, + ) -> Result { + let bytes = if deserializer.is_human_readable() { + ::hex::serde::deserialize(deserializer)? + } else { + ::serde_arrays::deserialize::<_, u8, [< $name _COMPRESSED_SIZE >]>(deserializer)? + }; + Option::from(Self::from_bytes(&[< $name Compressed >](bytes))).ok_or_else(|| { + D::Error::custom("deserialized bytes don't encode a valid field element") + }) + } + } + } + + impl ::serde::Serialize for $name_affine { + fn serialize(&self, serializer: S) -> Result { + let bytes = &self.to_bytes(); + if serializer.is_human_readable() { + ::hex::serde::serialize(&bytes.0, serializer) + } else { + ::serde_arrays::serialize(&bytes.0, serializer) + } + } + } + + paste::paste! { + use ::serde::de::Error as _; + impl<'de> ::serde::Deserialize<'de> for $name_affine { + fn deserialize>( + deserializer: D, + ) -> Result { + let bytes = if deserializer.is_human_readable() { + ::hex::serde::deserialize(deserializer)? + } else { + ::serde_arrays::deserialize::<_, u8, [< $name _COMPRESSED_SIZE >]>(deserializer)? + }; + Option::from(Self::from_bytes(&[< $name Compressed >](bytes))).ok_or_else(|| { + D::Error::custom("deserialized bytes don't encode a valid field element") + }) + } + } + } + }; + } + #[derive(Copy, Clone, Debug)] - #[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] $($privacy)* struct $name { pub x: $base, pub y: $base, @@ -297,13 +361,13 @@ macro_rules! new_curve_impl { } #[derive(Copy, Clone, PartialEq)] - #[cfg_attr(feature = "derive_serde", derive(Serialize, Deserialize))] $($privacy)* struct $name_affine { pub x: $base, pub y: $base, } - + #[cfg(feature = "derive_serde")] + serialize_deserialize_to_from_bytes!(); impl_compressed!(); impl_uncompressed!(); diff --git a/src/tests/curve.rs b/src/tests/curve.rs index 54d23791..2f93bbb4 100644 --- a/src/tests/curve.rs +++ b/src/tests/curve.rs @@ -74,12 +74,24 @@ where assert_eq!(projective_point.to_affine(), affine_point_rec); assert_eq!(affine_point, affine_point_rec); } + { + let affine_json = serde_json::to_string(&affine_point).unwrap(); + let reader = std::io::Cursor::new(affine_json); + let affine_point_rec: G::AffineExt = serde_json::from_reader(reader).unwrap(); + assert_eq!(affine_point, affine_point_rec); + } { let projective_bytes = bincode::serialize(&projective_point).unwrap(); let reader = std::io::Cursor::new(projective_bytes); let projective_point_rec: G = bincode::deserialize_from(reader).unwrap(); assert_eq!(projective_point, projective_point_rec); } + { + let projective_json = serde_json::to_string(&projective_point).unwrap(); + let reader = std::io::Cursor::new(projective_json); + let projective_point_rec: G = serde_json::from_reader(reader).unwrap(); + assert_eq!(projective_point, projective_point_rec); + } } }