Skip to content

Commit

Permalink
Serde support
Browse files Browse the repository at this point in the history
  • Loading branch information
afck committed Apr 28, 2019
1 parent 183a64b commit c5390da
Show file tree
Hide file tree
Showing 7 changed files with 215 additions and 1 deletion.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ repository = "https://github.com/ebfull/pairing"
rand = "0.4"
byteorder = "1"
ff = { version = "0.4", features = ["derive"] }
serde = { version = "1.0", optional = true, features = ["derive"] }

[features]
unstable-features = ["expose-arith"]
expose-arith = []
default = []

[dev-dependencies]
serde_json = "1.0"
1 change: 1 addition & 0 deletions src/bls12_381/fq12.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use rand::{Rand, Rng};

/// An element of Fq12, represented by c0 + c1 * w.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Fq12 {
pub c0: Fq6,
pub c1: Fq6,
Expand Down
1 change: 1 addition & 0 deletions src/bls12_381/fq2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ use std::cmp::Ordering;

/// An element of Fq2, represented by c0 + c1 * u.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Fq2 {
pub c0: Fq,
pub c1: Fq,
Expand Down
1 change: 1 addition & 0 deletions src/bls12_381/fq6.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use rand::{Rand, Rng};

/// An element of Fq6, represented by c0 + c1 * v + c2 * v^(2).
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct Fq6 {
pub c0: Fq2,
pub c1: Fq2,
Expand Down
2 changes: 2 additions & 0 deletions src/bls12_381/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ mod fq2;
mod fq6;
mod fr;

#[cfg(feature = "serde")]
mod serde_impl;
#[cfg(test)]
mod tests;

Expand Down
203 changes: 203 additions & 0 deletions src/bls12_381/serde_impl.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
use std::fmt;
use std::marker::PhantomData;

use super::{Fq, FqRepr, Fr, FrRepr, G1Affine, G2Affine, G1, G2};
use {CurveAffine, CurveProjective, EncodedPoint, PrimeField};

use serde::de::{Error as DeserializeError, SeqAccess, Visitor};
use serde::ser::SerializeTuple;
use serde::{Deserialize, Deserializer, Serialize, Serializer};

const ERR_CODE: &str = "deserialized bytes don't encode a group element";

impl Serialize for G1 {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.into_affine().serialize(s)
}
}

impl<'de> Deserialize<'de> for G1 {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Ok(G1Affine::deserialize(d)?.into_projective())
}
}

impl Serialize for G1Affine {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize_affine(self, s)
}
}

impl<'de> Deserialize<'de> for G1Affine {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Ok(deserialize_affine(d)?)
}
}

impl Serialize for G2 {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.into_affine().serialize(s)
}
}

impl<'de> Deserialize<'de> for G2 {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Ok(G2Affine::deserialize(d)?.into_projective())
}
}

impl Serialize for G2Affine {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize_affine(self, s)
}
}

impl<'de> Deserialize<'de> for G2Affine {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Ok(deserialize_affine(d)?)
}
}

/// Serializes a group element using its compressed representation.
fn serialize_affine<S: Serializer, C: CurveAffine>(c: &C, s: S) -> Result<S::Ok, S::Error> {
let len = C::Compressed::size();
let mut tup = s.serialize_tuple(len)?;
for byte in c.into_compressed().as_ref() {
tup.serialize_element(byte)?;
}
tup.end()
}

/// Deserializes the compressed representation of a group element.
fn deserialize_affine<'de, D: Deserializer<'de>, C: CurveAffine>(d: D) -> Result<C, D::Error> {
struct TupleVisitor<C> {
_ph: PhantomData<C>,
}

impl<'de, C: CurveAffine> Visitor<'de> for TupleVisitor<C> {
type Value = C;

fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
let len = C::Compressed::size();
write!(f, "a tuple of size {}", len)
}

#[inline]
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<C, A::Error> {
let mut compressed = C::Compressed::empty();
for (i, byte) in compressed.as_mut().iter_mut().enumerate() {
let len_err = || DeserializeError::invalid_length(i, &self);
*byte = seq.next_element()?.ok_or_else(len_err)?;
}
let to_err = |_| DeserializeError::custom(ERR_CODE);
compressed.into_affine().map_err(to_err)
}
}

let len = C::Compressed::size();
d.deserialize_tuple(len, TupleVisitor { _ph: PhantomData })
}

impl Serialize for Fr {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.into_repr().serialize(s)
}
}

impl<'de> Deserialize<'de> for Fr {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Fr::from_repr(FrRepr::deserialize(d)?).map_err(|_| D::Error::custom(ERR_CODE))
}
}

impl Serialize for FrRepr {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.0.serialize(s)
}
}

impl<'de> Deserialize<'de> for FrRepr {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Ok(FrRepr(<_>::deserialize(d)?))
}
}

impl Serialize for Fq {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.into_repr().serialize(s)
}
}

impl<'de> Deserialize<'de> for Fq {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Fq::from_repr(FqRepr::deserialize(d)?).map_err(|_| D::Error::custom(ERR_CODE))
}
}

impl Serialize for FqRepr {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
self.0.serialize(s)
}
}

impl<'de> Deserialize<'de> for FqRepr {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Ok(FqRepr(<_>::deserialize(d)?))
}
}

#[cfg(test)]
mod tests {
extern crate serde_json;

use super::*;
use bls12_381::Fq12;

use std::fmt::Debug;

use rand::{Rng, SeedableRng, XorShiftRng};

fn test_roundtrip<T: Serialize + for<'a> Deserialize<'a> + Debug + PartialEq>(t: &T) {
let ser = serde_json::to_vec(t).unwrap();
assert_eq!(*t, serde_json::from_slice(&ser).unwrap());
}

#[test]
fn serde_g1() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let g: G1 = rng.gen();
test_roundtrip(&g);
test_roundtrip(&g.into_affine());
}

#[test]
fn serde_g2() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let g: G2 = rng.gen();
test_roundtrip(&g);
test_roundtrip(&g.into_affine());
}

#[test]
fn serde_fr() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let f: Fr = rng.gen();
test_roundtrip(&f);
test_roundtrip(&f.into_repr());
}

#[test]
fn serde_fq() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let f: Fq = rng.gen();
test_roundtrip(&f);
test_roundtrip(&f.into_repr());
}

#[test]
fn serde_fq12() {
let mut rng = XorShiftRng::from_seed([0x5dbe6259, 0x8d313d76, 0x3237db17, 0xe5bc0654]);
let f: Fq12 = rng.gen();
test_roundtrip(&f);
}
}
4 changes: 3 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,11 @@
#![deny(missing_debug_implementations)]

extern crate byteorder;
#[macro_use]
extern crate ff;
extern crate rand;
#[cfg(feature = "serde")]
#[macro_use(Serialize, Deserialize)]
extern crate serde;

#[cfg(test)]
pub mod tests;
Expand Down

0 comments on commit c5390da

Please sign in to comment.