Skip to content

Commit

Permalink
Merge pull request #28 from dfns/prefer-compact
Browse files Browse the repository at this point in the history
Add `generic_ec::serde::PreferCompact`
  • Loading branch information
survived authored Mar 27, 2024
2 parents d1316f1 + 98b179e commit 0d5de2b
Show file tree
Hide file tree
Showing 4 changed files with 466 additions and 66 deletions.
6 changes: 6 additions & 0 deletions generic-ec/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## v0.2.3
* Add `generic_ec::serde::PreferCompact` that serializes points/scalars in compact form,
but deserialization recognizes both compact and non-compact formats [#28]

[#28]: https://github.com/dfns/generic-ec/pull/28

## v0.2.2
* Implement `serde_with::SerializeAs<&T>` for `generic_ec::serde::Compact` when `T` is
serializable via `Compact` [#27]
Expand Down
2 changes: 1 addition & 1 deletion generic-ec/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "generic-ec"
version = "0.2.2"
version = "0.2.3"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/dfns/generic-ec"
Expand Down
216 changes: 189 additions & 27 deletions generic-ec/src/serde.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,11 @@ impl<'de, E: Curve> serde::Deserialize<'de> for CurveName<E> {
pub use optional::*;
#[cfg(feature = "serde")]
mod optional {
use crate::core::Curve;
use crate::{core::Curve, Point, Scalar, SecretScalar};

use super::CurveName;

impl<E: Curve> serde::Serialize for crate::Point<E> {
impl<E: Curve> serde::Serialize for Point<E> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
Expand All @@ -179,7 +179,7 @@ mod optional {
}
}

impl<'de, E: Curve> serde::Deserialize<'de> for crate::Point<E> {
impl<'de, E: Curve> serde::Deserialize<'de> for Point<E> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
Expand All @@ -190,7 +190,7 @@ mod optional {
}
}

impl<E: Curve> serde::Serialize for crate::Scalar<E> {
impl<E: Curve> serde::Serialize for Scalar<E> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
Expand All @@ -199,7 +199,7 @@ mod optional {
}
}

impl<'de, E: Curve> serde::Deserialize<'de> for crate::Scalar<E> {
impl<'de, E: Curve> serde::Deserialize<'de> for Scalar<E> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
Expand All @@ -210,7 +210,7 @@ mod optional {
}
}

impl<E: Curve> serde::Serialize for crate::SecretScalar<E> {
impl<E: Curve> serde::Serialize for SecretScalar<E> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
Expand All @@ -219,22 +219,20 @@ mod optional {
}
}

impl<'de, E: Curve> serde::Deserialize<'de> for crate::SecretScalar<E> {
impl<'de, E: Curve> serde::Deserialize<'de> for SecretScalar<E> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
Ok(crate::SecretScalar::new(&mut crate::Scalar::deserialize(
deserializer,
)?))
Ok(SecretScalar::new(&mut Scalar::deserialize(deserializer)?))
}
}

/// Compact serialization format
pub struct Compact;

impl<E: Curve> serde_with::SerializeAs<crate::Point<E>> for Compact {
fn serialize_as<S>(source: &crate::Point<E>, serializer: S) -> Result<S::Ok, S::Error>
impl<E: Curve> serde_with::SerializeAs<Point<E>> for Compact {
fn serialize_as<S>(source: &Point<E>, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Expand All @@ -243,8 +241,8 @@ mod optional {
}
}

impl<'de, E: Curve> serde_with::DeserializeAs<'de, crate::Point<E>> for Compact {
fn deserialize_as<D>(deserializer: D) -> Result<crate::Point<E>, D::Error>
impl<'de, E: Curve> serde_with::DeserializeAs<'de, Point<E>> for Compact {
fn deserialize_as<D>(deserializer: D) -> Result<Point<E>, D::Error>
where
D: serde::Deserializer<'de>,
{
Expand All @@ -255,8 +253,8 @@ mod optional {
}
}

impl<E: Curve> serde_with::SerializeAs<crate::Scalar<E>> for Compact {
fn serialize_as<S>(source: &crate::Scalar<E>, serializer: S) -> Result<S::Ok, S::Error>
impl<E: Curve> serde_with::SerializeAs<Scalar<E>> for Compact {
fn serialize_as<S>(source: &Scalar<E>, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Expand All @@ -265,8 +263,8 @@ mod optional {
}
}

impl<'de, E: Curve> serde_with::DeserializeAs<'de, crate::Scalar<E>> for Compact {
fn deserialize_as<D>(deserializer: D) -> Result<crate::Scalar<E>, D::Error>
impl<'de, E: Curve> serde_with::DeserializeAs<'de, Scalar<E>> for Compact {
fn deserialize_as<D>(deserializer: D) -> Result<Scalar<E>, D::Error>
where
D: serde::Deserializer<'de>,
{
Expand All @@ -277,11 +275,8 @@ mod optional {
}
}

impl<E: Curve> serde_with::SerializeAs<crate::SecretScalar<E>> for Compact {
fn serialize_as<S>(
source: &crate::SecretScalar<E>,
serializer: S,
) -> Result<S::Ok, S::Error>
impl<E: Curve> serde_with::SerializeAs<SecretScalar<E>> for Compact {
fn serialize_as<S>(source: &SecretScalar<E>, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
Expand All @@ -290,16 +285,16 @@ mod optional {
}
}

impl<'de, E: Curve> serde_with::DeserializeAs<'de, crate::SecretScalar<E>> for Compact {
fn deserialize_as<D>(deserializer: D) -> Result<crate::SecretScalar<E>, D::Error>
impl<'de, E: Curve> serde_with::DeserializeAs<'de, SecretScalar<E>> for Compact {
fn deserialize_as<D>(deserializer: D) -> Result<SecretScalar<E>, D::Error>
where
D: serde::Deserializer<'de>,
{
let mut scalar =
<Compact as serde_with::DeserializeAs<'de, crate::Scalar<E>>>::deserialize_as(
<Compact as serde_with::DeserializeAs<'de, Scalar<E>>>::deserialize_as(
deserializer,
)?;
Ok(crate::SecretScalar::new(&mut scalar))
Ok(SecretScalar::new(&mut scalar))
}
}

Expand Down Expand Up @@ -342,6 +337,173 @@ mod optional {
}
}

/// Serializes point/scalar compactly. Deserializes both compact
/// and non-compact points/scalars.
///
/// It can be used when some data used to be serialized in default serialization
/// format, and at some point you decided to use a compact serialization format.
/// `PreferCompact` serializes points/scalar in compact format, but at deserialization
/// it accepts both compact and non-compact forms.
///
/// `PreferCompact` does not work on `serde` backends which serialize structs as
/// lists, such as `bincode`. Notably, (de)serialization of points/scalars in compact
/// format will still work, but deserialization from non-compact form will produce
/// an error.
pub struct PreferCompact;

impl<T> serde_with::SerializeAs<T> for PreferCompact
where
Compact: serde_with::SerializeAs<T>,
{
fn serialize_as<S>(source: &T, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
<Compact as serde_with::SerializeAs<T>>::serialize_as(source, serializer)
}
}

impl<'de, T> serde_with::DeserializeAs<'de, T> for PreferCompact
where
T: serde::Deserialize<'de>,
Compact: serde_with::DeserializeAs<'de, T>,
{
fn deserialize_as<D>(deserializer: D) -> Result<T, D::Error>
where
D: serde::Deserializer<'de>,
{
use serde_with::DeserializeAs;

struct Visitor<T> {
is_human_readable: bool,
_out: core::marker::PhantomData<T>,
}
impl<'de, T> serde::de::Visitor<'de> for Visitor<T>
where
T: serde::Deserialize<'de>,
Compact: serde_with::DeserializeAs<'de, T>,
{
type Value = T;
fn expecting(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
f.write_str("preferably compact point/scalar")
}

fn visit_bytes<Err>(self, v: &[u8]) -> Result<Self::Value, Err>
where
Err: serde::de::Error,
{
Compact::deserialize_as(NewTypeDeserializer::new(OverrideHumanReadable {
deserializer: serde::de::value::BytesDeserializer::<Err>::new(v),
is_human_readable: self.is_human_readable,
}))
}
fn visit_str<Err>(self, v: &str) -> Result<Self::Value, Err>
where
Err: serde::de::Error,
{
Compact::deserialize_as(NewTypeDeserializer::new(OverrideHumanReadable {
deserializer: serde::de::value::StrDeserializer::<Err>::new(v),
is_human_readable: self.is_human_readable,
}))
}

fn visit_seq<A>(self, _seq: A) -> Result<Self::Value, A::Error>
where
A: serde::de::SeqAccess<'de>,
{
Err(<A::Error as serde::de::Error>::custom(
"cannot deserialize in `PreferCompact` mode \
from sequence: it's ambiguous",
))
}
fn visit_map<A>(self, map: A) -> Result<Self::Value, A::Error>
where
A: serde::de::MapAccess<'de>,
{
T::deserialize(OverrideHumanReadable {
deserializer: serde::de::value::MapAccessDeserializer::new(map),
is_human_readable: self.is_human_readable,
})
}

fn visit_newtype_struct<D>(self, deserializer: D) -> Result<Self::Value, D::Error>
where
D: serde::Deserializer<'de>,
{
Compact::deserialize_as(NewTypeDeserializer::new(OverrideHumanReadable {
deserializer,
is_human_readable: self.is_human_readable,
}))
}
}

let is_human_readable = deserializer.is_human_readable();
deserializer.deserialize_any(Visitor {
is_human_readable,
_out: core::marker::PhantomData::<T>,
})
}
}

/// Wraps a [`serde::Deserializer`] and overrides `fn is_human_readable()`
struct OverrideHumanReadable<D> {
is_human_readable: bool,
deserializer: D,
}
impl<'de, D> serde::Deserializer<'de> for OverrideHumanReadable<D>
where
D: serde::Deserializer<'de>,
{
type Error = <D as serde::Deserializer<'de>>::Error;

fn is_human_readable(&self) -> bool {
self.is_human_readable
}

fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
self.deserializer.deserialize_any(visitor)
}

serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}

/// See [`serde::de::value`]. New type deserializer is missing in the `serde` crate.
struct NewTypeDeserializer<D> {
deserializer: D,
}
impl<D> NewTypeDeserializer<D> {
pub fn new(deserializer: D) -> Self {
Self { deserializer }
}
}
impl<'de, D> serde::Deserializer<'de> for NewTypeDeserializer<D>
where
D: serde::Deserializer<'de>,
{
type Error = D::Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
visitor.visit_newtype_struct(self.deserializer)
}
fn is_human_readable(&self) -> bool {
self.deserializer.is_human_readable()
}
serde::forward_to_deserialize_any! {
bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
bytes byte_buf option unit unit_struct newtype_struct seq tuple
tuple_struct map struct enum identifier ignored_any
}
}

mod models {
use core::convert::TryFrom;

Expand Down
Loading

0 comments on commit 0d5de2b

Please sign in to comment.