Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Customizable serialization for SWCurveConfig and TECurveConfig #467

Merged
merged 4 commits into from
Sep 6, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@
- [\#430](https://github.com/arkworks-rs/algebra/pull/430) (`ark-ec`) Add functionality for mapping a field element to a curve element for hash-to-curve.
- [\#440](https://github.com/arkworks-rs/algebra/pull/440) (`ark-ff`) Add a method to construct a field element from an element of the underlying base prime field.
- [\#446](https://github.com/arkworks-rs/algebra/pull/446) (`ark-ff`) Add `CyclotomicMultSubgroup` trait and impl for extension fields
- [\#467](https://github.com/arkworks-rs/algebra/pull/467) (`ark-ec`)
- Move implementation of `serialize_with_mode()`, `deserialize_with_mode()`, and `serialized_size()` into `{SW,TE}CurveConfig` to allow customization.

### Improvements

Expand Down
71 changes: 8 additions & 63 deletions ec/src/models/short_weierstrass/affine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use ark_serialize::{
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
CanonicalSerializeWithFlags, Compress, SerializationError, Valid, Validate,
CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError, Valid, Validate,
};
use ark_std::{
borrow::Borrow,
Expand Down Expand Up @@ -125,7 +124,7 @@ impl<P: SWCurveConfig> Affine<P> {
///
/// The results are sorted by lexicographical order.
/// This means that, if `P::BaseField: PrimeField`, the results are sorted as integers.
fn get_ys_from_x_unchecked(x: P::BaseField) -> Option<(P::BaseField, P::BaseField)> {
pub fn get_ys_from_x_unchecked(x: P::BaseField) -> Option<(P::BaseField, P::BaseField)> {
alexander-zw marked this conversation as resolved.
Show resolved Hide resolved
// Compute the curve equation x^3 + Ax + B.
// Since Rust does not optimise away additions with zero, we explicitly check
// for that case here, and avoid multiplication by `a` if possible.
Expand Down Expand Up @@ -186,6 +185,7 @@ impl<P: SWCurveConfig> Zeroize for Affine<P> {
}

impl<P: SWCurveConfig> Distribution<Affine<P>> for Standard {
/// Generates a uniformly random instance of the curve.
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Affine<P> {
loop {
Expand Down Expand Up @@ -344,38 +344,18 @@ impl<P: SWCurveConfig> From<Projective<P>> for Affine<P> {
}

impl<P: SWCurveConfig> CanonicalSerialize for Affine<P> {
#[allow(unused_qualifications)]
alexander-zw marked this conversation as resolved.
Show resolved Hide resolved
#[inline]
fn serialize_with_mode<W: Write>(
&self,
mut writer: W,
alexander-zw marked this conversation as resolved.
Show resolved Hide resolved
writer: W,
compress: ark_serialize::Compress,
) -> Result<(), SerializationError> {
let (x, y, flags) = match self.infinity {
true => (
P::BaseField::zero(),
P::BaseField::zero(),
SWFlags::infinity(),
),
false => (self.x, self.y, self.to_flags()),
};

match compress {
Compress::Yes => x.serialize_with_flags(writer, flags),
Compress::No => {
x.serialize_with_mode(&mut writer, compress)?;
y.serialize_with_flags(&mut writer, flags)
},
}
P::serialize_with_mode(self, writer, compress)
}

#[inline]
fn serialized_size(&self, compress: Compress) -> usize {
let zero = P::BaseField::zero();
match compress {
Compress::Yes => zero.serialized_size_with_flags::<SWFlags>(),
Compress::No => zero.compressed_size() + zero.serialized_size_with_flags::<SWFlags>(),
}
P::serialized_size(compress)
}
}

Expand All @@ -390,47 +370,12 @@ impl<P: SWCurveConfig> Valid for Affine<P> {
}
alexander-zw marked this conversation as resolved.
Show resolved Hide resolved

impl<P: SWCurveConfig> CanonicalDeserialize for Affine<P> {
#[allow(unused_qualifications)]
fn deserialize_with_mode<R: Read>(
mut reader: R,
reader: R,
compress: Compress,
validate: Validate,
) -> Result<Self, SerializationError> {
let (x, y, flags) = match compress {
Compress::Yes => {
let (x, flags): (_, SWFlags) =
CanonicalDeserializeWithFlags::deserialize_with_flags(reader)?;
match flags {
SWFlags::PointAtInfinity => (Self::identity().x, Self::identity().y, flags),
_ => {
let is_positive = flags.is_positive().unwrap();
let (y, neg_y) = Self::get_ys_from_x_unchecked(x)
.ok_or(SerializationError::InvalidData)?;
if is_positive {
(x, y, flags)
} else {
(x, neg_y, flags)
}
},
}
},
Compress::No => {
let x: P::BaseField =
CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
let (y, flags): (_, SWFlags) =
CanonicalDeserializeWithFlags::deserialize_with_flags(&mut reader)?;
(x, y, flags)
},
};
if flags.is_infinity() {
Ok(Self::identity())
} else {
let point = Self::new_unchecked(x, y);
if let Validate::Yes = validate {
point.check()?;
}
Ok(point)
}
P::deserialize_with_mode(reader, compress, validate)
}
}

Expand Down
10 changes: 4 additions & 6 deletions ec/src/models/short_weierstrass/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ impl<P: SWCurveConfig> Hash for Projective<P> {
}

impl<P: SWCurveConfig> Distribution<Projective<P>> for Standard {
/// Generates a uniformly random instance of the curve.
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Projective<P> {
loop {
Expand Down Expand Up @@ -504,21 +505,19 @@ impl<P: SWCurveConfig> From<Affine<P>> for Projective<P> {
}

impl<P: SWCurveConfig> CanonicalSerialize for Projective<P> {
#[allow(unused_qualifications)]
#[inline]
fn serialize_with_mode<W: Write>(
&self,
writer: W,
compress: Compress,
) -> Result<(), SerializationError> {
let aff = Affine::<P>::from(*self);
aff.serialize_with_mode(writer, compress)
P::serialize_with_mode(&aff, writer, compress)
}

#[inline]
fn serialized_size(&self, compress: Compress) -> usize {
let aff = Affine::<P>::from(*self);
aff.serialized_size(compress)
P::serialized_size(compress)
}
}

Expand All @@ -540,13 +539,12 @@ impl<P: SWCurveConfig> Valid for Projective<P> {
}

impl<P: SWCurveConfig> CanonicalDeserialize for Projective<P> {
#[allow(unused_qualifications)]
fn deserialize_with_mode<R: Read>(
reader: R,
compress: Compress,
validate: Validate,
) -> Result<Self, SerializationError> {
let aff = Affine::<P>::deserialize_with_mode(reader, compress, validate)?;
let aff = P::deserialize_with_mode(reader, compress, validate)?;
Ok(aff.into())
}
}
Expand Down
89 changes: 89 additions & 0 deletions ec/src/models/short_weierstrass/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
use ark_serialize::{
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
CanonicalSerializeWithFlags, Compress, SerializationError, Valid, Validate,
};
use ark_std::io::{Read, Write};

use ark_ff::fields::Field;

use crate::{AffineRepr, Group};
Expand Down Expand Up @@ -98,4 +104,87 @@ pub trait SWCurveConfig: super::CurveConfig {

res
}

/// If uncompressed, serializes both x and y coordinates as well as a bit for whether it is
/// infinity. If compressed, serializes x coordinate with two bits to encode whether y is
/// positive, negative, or infinity.
#[inline]
fn serialize_with_mode<W: Write>(
item: &Affine<Self>,
mut writer: W,
compress: ark_serialize::Compress,
) -> Result<(), SerializationError> {
let (x, y, flags) = match item.infinity {
true => (
Self::BaseField::zero(),
Self::BaseField::zero(),
SWFlags::infinity(),
),
false => (item.x, item.y, item.to_flags()),
};

match compress {
Compress::Yes => x.serialize_with_flags(writer, flags),
Compress::No => {
x.serialize_with_mode(&mut writer, compress)?;
y.serialize_with_flags(&mut writer, flags)
},
}
}

/// If `validate` is `Yes`, calls `check()` to make sure the element is valid.
fn deserialize_with_mode<R: Read>(
mut reader: R,
compress: Compress,
validate: Validate,
) -> Result<Affine<Self>, SerializationError> {
let (x, y, flags) = match compress {
Compress::Yes => {
let (x, flags): (_, SWFlags) =
CanonicalDeserializeWithFlags::deserialize_with_flags(reader)?;
match flags {
SWFlags::PointAtInfinity => (
Affine::<Self>::identity().x,
Affine::<Self>::identity().y,
flags,
),
_ => {
let is_positive = flags.is_positive().unwrap();
let (y, neg_y) = Affine::<Self>::get_ys_from_x_unchecked(x)
.ok_or(SerializationError::InvalidData)?;
if is_positive {
(x, y, flags)
} else {
(x, neg_y, flags)
}
},
}
},
Compress::No => {
let x: Self::BaseField =
CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
let (y, flags): (_, SWFlags) =
CanonicalDeserializeWithFlags::deserialize_with_flags(&mut reader)?;
(x, y, flags)
},
};
if flags.is_infinity() {
Ok(Affine::<Self>::identity())
} else {
let point = Affine::<Self>::new_unchecked(x, y);
if let Validate::Yes = validate {
point.check()?;
}
Ok(point)
}
}

#[inline]
fn serialized_size(compress: Compress) -> usize {
let zero = Self::BaseField::zero();
match compress {
Compress::Yes => zero.serialized_size_with_flags::<SWFlags>(),
Compress::No => zero.compressed_size() + zero.serialized_size_with_flags::<SWFlags>(),
}
}
}
49 changes: 7 additions & 42 deletions ec/src/models/twisted_edwards/affine.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use ark_serialize::{
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
CanonicalSerializeWithFlags, Compress, SerializationError, Valid, Validate,
CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError, Valid, Validate,
};
use ark_std::{
borrow::Borrow,
Expand Down Expand Up @@ -260,6 +259,7 @@ impl<P: TECurveConfig> Default for Affine<P> {
}

impl<P: TECurveConfig> Distribution<Affine<P>> for Standard {
/// Generates a uniformly random instance of the curve.
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Affine<P> {
loop {
Expand Down Expand Up @@ -301,30 +301,18 @@ impl<P: TECurveConfig> From<Projective<P>> for Affine<P> {
}
}
impl<P: TECurveConfig> CanonicalSerialize for Affine<P> {
#[allow(unused_qualifications)]
#[inline]
fn serialize_with_mode<W: Write>(
&self,
mut writer: W,
writer: W,
compress: ark_serialize::Compress,
) -> Result<(), SerializationError> {
let flags = TEFlags::from_x_coordinate(self.x);
match compress {
Compress::Yes => self.y.serialize_with_flags(writer, flags),
Compress::No => {
self.x.serialize_uncompressed(&mut writer)?;
self.y.serialize_uncompressed(&mut writer)
},
}
P::serialize_with_mode(self, writer, compress)
}

#[inline]
fn serialized_size(&self, compress: Compress) -> usize {
let zero = P::BaseField::zero();
match compress {
Compress::Yes => zero.serialized_size_with_flags::<TEFlags>(),
Compress::No => self.x.uncompressed_size() + self.y.uncompressed_size(),
}
P::serialized_size(compress)
}
}

Expand All @@ -339,35 +327,12 @@ impl<P: TECurveConfig> Valid for Affine<P> {
}

impl<P: TECurveConfig> CanonicalDeserialize for Affine<P> {
#[allow(unused_qualifications)]
fn deserialize_with_mode<R: Read>(
mut reader: R,
reader: R,
compress: Compress,
validate: Validate,
) -> Result<Self, SerializationError> {
let (x, y) = match compress {
Compress::Yes => {
let (y, flags): (_, TEFlags) =
CanonicalDeserializeWithFlags::deserialize_with_flags(reader)?;
let (x, neg_x) =
Self::get_xs_from_y_unchecked(y).ok_or(SerializationError::InvalidData)?;
if flags.is_negative() {
(neg_x, y)
} else {
(x, y)
}
},
Compress::No => {
let x: P::BaseField = CanonicalDeserialize::deserialize_uncompressed(&mut reader)?;
let y: P::BaseField = CanonicalDeserialize::deserialize_uncompressed(&mut reader)?;
(x, y)
},
};
let point = Self::new_unchecked(x, y);
if let Validate::Yes = validate {
point.check()?;
}
Ok(point)
P::deserialize_with_mode(reader, compress, validate)
}
}

Expand Down
8 changes: 4 additions & 4 deletions ec/src/models/twisted_edwards/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ impl<P: TECurveConfig> Hash for Projective<P> {
}

impl<P: TECurveConfig> Distribution<Projective<P>> for Standard {
/// Generates a uniformly random instance of the curve.
#[inline]
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Projective<P> {
loop {
Expand Down Expand Up @@ -430,13 +431,12 @@ impl<P: TECurveConfig> CanonicalSerialize for Projective<P> {
compress: Compress,
) -> Result<(), SerializationError> {
let aff = Affine::<P>::from(*self);
aff.serialize_with_mode(writer, compress)
P::serialize_with_mode(&aff, writer, compress)
}

#[inline]
fn serialized_size(&self, compress: Compress) -> usize {
let aff = Affine::<P>::from(*self);
aff.serialized_size(compress)
P::serialized_size(compress)
}
}

Expand Down Expand Up @@ -464,7 +464,7 @@ impl<P: TECurveConfig> CanonicalDeserialize for Projective<P> {
compress: Compress,
validate: Validate,
) -> Result<Self, SerializationError> {
let aff = Affine::<P>::deserialize_with_mode(reader, compress, validate)?;
let aff = P::deserialize_with_mode(reader, compress, validate)?;
Ok(aff.into())
}
}
Expand Down
Loading