Skip to content

Commit

Permalink
refactor: (De)Serialization of points using GroupEncoding (#88)
Browse files Browse the repository at this point in the history
* refactor: implement (De)Serialization of points using the `GroupEncoding` trait

- Updated curve point (de)serialization logic from the internal representation to the
  representation offered by the implementation of the `GroupEncoding` trait.

* fix: add explicit json serde tests
  • Loading branch information
huitseeker authored Sep 18, 2023
1 parent 8e3a33a commit 2f3e388
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 3 deletions.
70 changes: 67 additions & 3 deletions src/derive/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -288,22 +288,86 @@ 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<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
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<D: ::serde::Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
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<S: ::serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
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<D: ::serde::Deserializer<'de>>(
deserializer: D,
) -> Result<Self, D::Error> {
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,
pub z: $base,
}

#[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!();
Expand Down
12 changes: 12 additions & 0 deletions src/tests/curve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}
}

Expand Down

0 comments on commit 2f3e388

Please sign in to comment.