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

Add serde feature. #87

Closed
wants to merge 1 commit into from
Closed
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
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