Skip to content

Commit 0e7d401

Browse files
Customizable serialization for SWCurveConfig and TECurveConfig (#467)
Co-authored-by: Pratyush Mishra <pratyushmishra@berkeley.edu>
1 parent 602664b commit 0e7d401

8 files changed

Lines changed: 188 additions & 115 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@
144144
- [\#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.
145145
- [\#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.
146146
- [\#446](https://github.com/arkworks-rs/algebra/pull/446) (`ark-ff`) Add `CyclotomicMultSubgroup` trait and impl for extension fields
147+
- [\#467](https://github.com/arkworks-rs/algebra/pull/467) (`ark-ec`)
148+
- Move implementation of `serialize_with_mode()`, `deserialize_with_mode()`, and `serialized_size()` into `{SW,TE}CurveConfig` to allow customization.
147149

148150
### Improvements
149151

ec/src/models/short_weierstrass/affine.rs

Lines changed: 8 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use ark_serialize::{
2-
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
3-
CanonicalSerializeWithFlags, Compress, SerializationError, Valid, Validate,
2+
CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError, Valid, Validate,
43
};
54
use ark_std::{
65
borrow::Borrow,
@@ -125,7 +124,7 @@ impl<P: SWCurveConfig> Affine<P> {
125124
///
126125
/// The results are sorted by lexicographical order.
127126
/// This means that, if `P::BaseField: PrimeField`, the results are sorted as integers.
128-
fn get_ys_from_x_unchecked(x: P::BaseField) -> Option<(P::BaseField, P::BaseField)> {
127+
pub fn get_ys_from_x_unchecked(x: P::BaseField) -> Option<(P::BaseField, P::BaseField)> {
129128
// Compute the curve equation x^3 + Ax + B.
130129
// Since Rust does not optimise away additions with zero, we explicitly check
131130
// for that case here, and avoid multiplication by `a` if possible.
@@ -186,6 +185,7 @@ impl<P: SWCurveConfig> Zeroize for Affine<P> {
186185
}
187186

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

346346
impl<P: SWCurveConfig> CanonicalSerialize for Affine<P> {
347-
#[allow(unused_qualifications)]
348347
#[inline]
349348
fn serialize_with_mode<W: Write>(
350349
&self,
351-
mut writer: W,
350+
writer: W,
352351
compress: ark_serialize::Compress,
353352
) -> Result<(), SerializationError> {
354-
let (x, y, flags) = match self.infinity {
355-
true => (
356-
P::BaseField::zero(),
357-
P::BaseField::zero(),
358-
SWFlags::infinity(),
359-
),
360-
false => (self.x, self.y, self.to_flags()),
361-
};
362-
363-
match compress {
364-
Compress::Yes => x.serialize_with_flags(writer, flags),
365-
Compress::No => {
366-
x.serialize_with_mode(&mut writer, compress)?;
367-
y.serialize_with_flags(&mut writer, flags)
368-
},
369-
}
353+
P::serialize_with_mode(self, writer, compress)
370354
}
371355

372356
#[inline]
373357
fn serialized_size(&self, compress: Compress) -> usize {
374-
let zero = P::BaseField::zero();
375-
match compress {
376-
Compress::Yes => zero.serialized_size_with_flags::<SWFlags>(),
377-
Compress::No => zero.compressed_size() + zero.serialized_size_with_flags::<SWFlags>(),
378-
}
358+
P::serialized_size(compress)
379359
}
380360
}
381361

@@ -390,47 +370,12 @@ impl<P: SWCurveConfig> Valid for Affine<P> {
390370
}
391371

392372
impl<P: SWCurveConfig> CanonicalDeserialize for Affine<P> {
393-
#[allow(unused_qualifications)]
394373
fn deserialize_with_mode<R: Read>(
395-
mut reader: R,
374+
reader: R,
396375
compress: Compress,
397376
validate: Validate,
398377
) -> Result<Self, SerializationError> {
399-
let (x, y, flags) = match compress {
400-
Compress::Yes => {
401-
let (x, flags): (_, SWFlags) =
402-
CanonicalDeserializeWithFlags::deserialize_with_flags(reader)?;
403-
match flags {
404-
SWFlags::PointAtInfinity => (Self::identity().x, Self::identity().y, flags),
405-
_ => {
406-
let is_positive = flags.is_positive().unwrap();
407-
let (y, neg_y) = Self::get_ys_from_x_unchecked(x)
408-
.ok_or(SerializationError::InvalidData)?;
409-
if is_positive {
410-
(x, y, flags)
411-
} else {
412-
(x, neg_y, flags)
413-
}
414-
},
415-
}
416-
},
417-
Compress::No => {
418-
let x: P::BaseField =
419-
CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
420-
let (y, flags): (_, SWFlags) =
421-
CanonicalDeserializeWithFlags::deserialize_with_flags(&mut reader)?;
422-
(x, y, flags)
423-
},
424-
};
425-
if flags.is_infinity() {
426-
Ok(Self::identity())
427-
} else {
428-
let point = Self::new_unchecked(x, y);
429-
if let Validate::Yes = validate {
430-
point.check()?;
431-
}
432-
Ok(point)
433-
}
378+
P::deserialize_with_mode(reader, compress, validate)
434379
}
435380
}
436381

ec/src/models/short_weierstrass/group.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ impl<P: SWCurveConfig> Hash for Projective<P> {
9696
}
9797

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

506507
impl<P: SWCurveConfig> CanonicalSerialize for Projective<P> {
507-
#[allow(unused_qualifications)]
508508
#[inline]
509509
fn serialize_with_mode<W: Write>(
510510
&self,
511511
writer: W,
512512
compress: Compress,
513513
) -> Result<(), SerializationError> {
514514
let aff = Affine::<P>::from(*self);
515-
aff.serialize_with_mode(writer, compress)
515+
P::serialize_with_mode(&aff, writer, compress)
516516
}
517517

518518
#[inline]
519519
fn serialized_size(&self, compress: Compress) -> usize {
520-
let aff = Affine::<P>::from(*self);
521-
aff.serialized_size(compress)
520+
P::serialized_size(compress)
522521
}
523522
}
524523

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

542541
impl<P: SWCurveConfig> CanonicalDeserialize for Projective<P> {
543-
#[allow(unused_qualifications)]
544542
fn deserialize_with_mode<R: Read>(
545543
reader: R,
546544
compress: Compress,
547545
validate: Validate,
548546
) -> Result<Self, SerializationError> {
549-
let aff = Affine::<P>::deserialize_with_mode(reader, compress, validate)?;
547+
let aff = P::deserialize_with_mode(reader, compress, validate)?;
550548
Ok(aff.into())
551549
}
552550
}

ec/src/models/short_weierstrass/mod.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
use ark_serialize::{
2+
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
3+
CanonicalSerializeWithFlags, Compress, SerializationError, Valid, Validate,
4+
};
5+
use ark_std::io::{Read, Write};
6+
17
use ark_ff::fields::Field;
28

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

99105
res
100106
}
107+
108+
/// If uncompressed, serializes both x and y coordinates as well as a bit for whether it is
109+
/// infinity. If compressed, serializes x coordinate with two bits to encode whether y is
110+
/// positive, negative, or infinity.
111+
#[inline]
112+
fn serialize_with_mode<W: Write>(
113+
item: &Affine<Self>,
114+
mut writer: W,
115+
compress: ark_serialize::Compress,
116+
) -> Result<(), SerializationError> {
117+
let (x, y, flags) = match item.infinity {
118+
true => (
119+
Self::BaseField::zero(),
120+
Self::BaseField::zero(),
121+
SWFlags::infinity(),
122+
),
123+
false => (item.x, item.y, item.to_flags()),
124+
};
125+
126+
match compress {
127+
Compress::Yes => x.serialize_with_flags(writer, flags),
128+
Compress::No => {
129+
x.serialize_with_mode(&mut writer, compress)?;
130+
y.serialize_with_flags(&mut writer, flags)
131+
},
132+
}
133+
}
134+
135+
/// If `validate` is `Yes`, calls `check()` to make sure the element is valid.
136+
fn deserialize_with_mode<R: Read>(
137+
mut reader: R,
138+
compress: Compress,
139+
validate: Validate,
140+
) -> Result<Affine<Self>, SerializationError> {
141+
let (x, y, flags) = match compress {
142+
Compress::Yes => {
143+
let (x, flags): (_, SWFlags) =
144+
CanonicalDeserializeWithFlags::deserialize_with_flags(reader)?;
145+
match flags {
146+
SWFlags::PointAtInfinity => (
147+
Affine::<Self>::identity().x,
148+
Affine::<Self>::identity().y,
149+
flags,
150+
),
151+
_ => {
152+
let is_positive = flags.is_positive().unwrap();
153+
let (y, neg_y) = Affine::<Self>::get_ys_from_x_unchecked(x)
154+
.ok_or(SerializationError::InvalidData)?;
155+
if is_positive {
156+
(x, y, flags)
157+
} else {
158+
(x, neg_y, flags)
159+
}
160+
},
161+
}
162+
},
163+
Compress::No => {
164+
let x: Self::BaseField =
165+
CanonicalDeserialize::deserialize_with_mode(&mut reader, compress, validate)?;
166+
let (y, flags): (_, SWFlags) =
167+
CanonicalDeserializeWithFlags::deserialize_with_flags(&mut reader)?;
168+
(x, y, flags)
169+
},
170+
};
171+
if flags.is_infinity() {
172+
Ok(Affine::<Self>::identity())
173+
} else {
174+
let point = Affine::<Self>::new_unchecked(x, y);
175+
if let Validate::Yes = validate {
176+
point.check()?;
177+
}
178+
Ok(point)
179+
}
180+
}
181+
182+
#[inline]
183+
fn serialized_size(compress: Compress) -> usize {
184+
let zero = Self::BaseField::zero();
185+
match compress {
186+
Compress::Yes => zero.serialized_size_with_flags::<SWFlags>(),
187+
Compress::No => zero.compressed_size() + zero.serialized_size_with_flags::<SWFlags>(),
188+
}
189+
}
101190
}

ec/src/models/twisted_edwards/affine.rs

Lines changed: 7 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use ark_serialize::{
2-
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
3-
CanonicalSerializeWithFlags, Compress, SerializationError, Valid, Validate,
2+
CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError, Valid, Validate,
43
};
54
use ark_std::{
65
borrow::Borrow,
@@ -260,6 +259,7 @@ impl<P: TECurveConfig> Default for Affine<P> {
260259
}
261260

262261
impl<P: TECurveConfig> Distribution<Affine<P>> for Standard {
262+
/// Generates a uniformly random instance of the curve.
263263
#[inline]
264264
fn sample<R: Rng + ?Sized>(&self, rng: &mut R) -> Affine<P> {
265265
loop {
@@ -301,30 +301,18 @@ impl<P: TECurveConfig> From<Projective<P>> for Affine<P> {
301301
}
302302
}
303303
impl<P: TECurveConfig> CanonicalSerialize for Affine<P> {
304-
#[allow(unused_qualifications)]
305304
#[inline]
306305
fn serialize_with_mode<W: Write>(
307306
&self,
308-
mut writer: W,
307+
writer: W,
309308
compress: ark_serialize::Compress,
310309
) -> Result<(), SerializationError> {
311-
let flags = TEFlags::from_x_coordinate(self.x);
312-
match compress {
313-
Compress::Yes => self.y.serialize_with_flags(writer, flags),
314-
Compress::No => {
315-
self.x.serialize_uncompressed(&mut writer)?;
316-
self.y.serialize_uncompressed(&mut writer)
317-
},
318-
}
310+
P::serialize_with_mode(self, writer, compress)
319311
}
320312

321313
#[inline]
322314
fn serialized_size(&self, compress: Compress) -> usize {
323-
let zero = P::BaseField::zero();
324-
match compress {
325-
Compress::Yes => zero.serialized_size_with_flags::<TEFlags>(),
326-
Compress::No => self.x.uncompressed_size() + self.y.uncompressed_size(),
327-
}
315+
P::serialized_size(compress)
328316
}
329317
}
330318

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

341329
impl<P: TECurveConfig> CanonicalDeserialize for Affine<P> {
342-
#[allow(unused_qualifications)]
343330
fn deserialize_with_mode<R: Read>(
344-
mut reader: R,
331+
reader: R,
345332
compress: Compress,
346333
validate: Validate,
347334
) -> Result<Self, SerializationError> {
348-
let (x, y) = match compress {
349-
Compress::Yes => {
350-
let (y, flags): (_, TEFlags) =
351-
CanonicalDeserializeWithFlags::deserialize_with_flags(reader)?;
352-
let (x, neg_x) =
353-
Self::get_xs_from_y_unchecked(y).ok_or(SerializationError::InvalidData)?;
354-
if flags.is_negative() {
355-
(neg_x, y)
356-
} else {
357-
(x, y)
358-
}
359-
},
360-
Compress::No => {
361-
let x: P::BaseField = CanonicalDeserialize::deserialize_uncompressed(&mut reader)?;
362-
let y: P::BaseField = CanonicalDeserialize::deserialize_uncompressed(&mut reader)?;
363-
(x, y)
364-
},
365-
};
366-
let point = Self::new_unchecked(x, y);
367-
if let Validate::Yes = validate {
368-
point.check()?;
369-
}
370-
Ok(point)
335+
P::deserialize_with_mode(reader, compress, validate)
371336
}
372337
}
373338

ec/src/models/twisted_edwards/group.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ impl<P: TECurveConfig> Hash for Projective<P> {
8282
}
8383

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

436437
#[inline]
437438
fn serialized_size(&self, compress: Compress) -> usize {
438-
let aff = Affine::<P>::from(*self);
439-
aff.serialized_size(compress)
439+
P::serialized_size(compress)
440440
}
441441
}
442442

@@ -464,7 +464,7 @@ impl<P: TECurveConfig> CanonicalDeserialize for Projective<P> {
464464
compress: Compress,
465465
validate: Validate,
466466
) -> Result<Self, SerializationError> {
467-
let aff = Affine::<P>::deserialize_with_mode(reader, compress, validate)?;
467+
let aff = P::deserialize_with_mode(reader, compress, validate)?;
468468
Ok(aff.into())
469469
}
470470
}

0 commit comments

Comments
 (0)