Skip to content
Permalink
Browse files

Implement CanonicalSerialize/Deserialize improvements (#109)

* Implement CanonicalSerialize/Deserialize improvements

* Improve code readability by using cursor

* Add tests for uncompressed serialization

* Improve serialization size (do not require full u64 limbs to be serialised)

* Change Flags to enum types

* Split up serialization with and without flags.

* Implement simple derive macro

* Derive traits for Groth16 and GM17 keys and proofs
  • Loading branch information
paberr committed Mar 3, 2020
1 parent 1c5f789 commit 3094511574d5a9e7c3001f262bfdb06c7f8d889c
Showing with 1,082 additions and 435 deletions.
  1. +1 −0 Cargo.toml
  2. +32 −0 algebra-core/algebra-core-derive/Cargo.toml
  3. +1 −0 algebra-core/algebra-core-derive/LICENSE-APACHE
  4. +1 −0 algebra-core/algebra-core-derive/LICENSE-MIT
  5. +127 −0 algebra-core/algebra-core-derive/src/lib.rs
  6. +2 −0 algebra-core/src/biginteger/macros.rs
  7. +26 −2 algebra-core/src/biginteger/mod.rs
  8. +3 −1 algebra-core/src/curves/mod.rs
  9. +2 −1 algebra-core/src/curves/models/short_weierstrass_jacobian.rs
  10. +2 −1 algebra-core/src/curves/models/short_weierstrass_projective.rs
  11. +2 −1 algebra-core/src/curves/models/twisted_edwards_extended.rs
  12. +4 −1 algebra-core/src/fields/mod.rs
  13. +29 −28 algebra-core/src/fields/models/fp12_2over3over2.rs
  14. +30 −25 algebra-core/src/fields/models/fp2.rs
  15. +35 −33 algebra-core/src/fields/models/fp3.rs
  16. +31 −30 algebra-core/src/fields/models/fp6_2over3.rs
  17. +32 −36 algebra-core/src/fields/models/fp6_3over2.rs
  18. +18 −0 algebra-core/src/io.rs
  19. +4 −8 algebra-core/src/serialize/error.rs
  20. +169 −0 algebra-core/src/serialize/flags.rs
  21. +353 −118 algebra-core/src/serialize/mod.rs
  22. +2 −2 algebra/src/bls12_377/curves/tests.rs
  23. +8 −5 algebra/src/bls12_377/fields/tests.rs
  24. +2 −2 algebra/src/bls12_381/curves/tests.rs
  25. +2 −2 algebra/src/edwards_bls12/curves/tests.rs
  26. +2 −2 algebra/src/edwards_sw6/curves/tests.rs
  27. +1 −1 algebra/src/jubjub/curves/tests.rs
  28. +3 −3 algebra/src/mnt6/curves/tests.rs
  29. +3 −3 algebra/src/sw6/curves/tests.rs
  30. +9 −2 algebra/src/sw6/fields/tests.rs
  31. +72 −90 algebra/src/tests/curves.rs
  32. +58 −30 algebra/src/tests/fields.rs
  33. +1 −0 gm17/Cargo.toml
  34. +7 −4 gm17/src/lib.rs
  35. +1 −0 groth16/Cargo.toml
  36. +7 −4 groth16/src/lib.rs
@@ -13,6 +13,7 @@ members = [
"groth16",
"r1cs-core",
"r1cs-std",
"algebra-core/algebra-core-derive",
]

[profile.release]
@@ -0,0 +1,32 @@
[package]
name = "algebra-core-derive"
version = "0.1.0"
authors = [
"Sean Bowe",
"Alessandro Chiesa",
"Matthew Green",
"Ian Miers",
"Pratyush Mishra",
"Howard Wu"
]
description = "A library for deriving serialization traits"
homepage = "https://libzexe.org"
repository = "https://github.com/scipr/zexe"
documentation = "https://docs.rs/algebra/"
keywords = ["cryptography", "finite fields", "elliptic curves", "pairing", "serialization"]
categories = ["cryptography"]
include = ["Cargo.toml", "src", "README.md", "LICENSE-APACHE", "LICENSE-MIT"]
license = "MIT/Apache-2.0"
edition = "2018"

################################# Dependencies ################################

[lib]
proc-macro = true

[dependencies]
proc-macro2 = "1.0"
syn = "1.0"
quote = "1.0"

algebra-core = { path = "..", default-features = false }
@@ -0,0 +1,127 @@
extern crate proc_macro;

use proc_macro2::TokenStream;
use syn::{parse_macro_input, Data, DeriveInput, Index};

use quote::quote;

#[proc_macro_derive(CanonicalSerialize)]
pub fn derive_canonical_serialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
proc_macro::TokenStream::from(impl_canonical_serialize(&ast))
}

fn impl_canonical_serialize(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;

let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

let mut serialize_body = Vec::<TokenStream>::new();
let mut serialized_size_body = Vec::<TokenStream>::new();

match ast.data {
Data::Struct(ref data_struct) => {
for (i, field) in data_struct.fields.iter().enumerate() {
match field.ident {
None => {
let index = Index::from(i);
serialize_body
.push(quote! { CanonicalSerialize::serialize(&self.#index, writer)?; });
serialized_size_body.push(
quote! { size += CanonicalSerialize::serialized_size(&self.#index); },
);
},
Some(ref ident) => {
serialize_body
.push(quote! { CanonicalSerialize::serialize(&self.#ident, writer)?; });
serialized_size_body.push(
quote! { size += CanonicalSerialize::serialized_size(&self.#ident); },
);
},
}
}
},
_ => panic!(
"Serialize can only be derived for structs, {} is not a struct",
name
),
};

let gen = quote! {
impl #impl_generics CanonicalSerialize for #name #ty_generics #where_clause {
#[allow(unused_mut, unused_variables)]
fn serialize<W: ::algebra_core::io::Write>(&self, writer: &mut W) -> Result<(), ::algebra_core::SerializationError> {
#(#serialize_body)*
Ok(())
}
#[allow(unused_mut, unused_variables)]
fn serialized_size(&self) -> usize {
let mut size = 0;
#(#serialized_size_body)*
size
}
}
};
gen
}

#[proc_macro_derive(CanonicalDeserialize)]
pub fn derive_canonical_deserialize(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
proc_macro::TokenStream::from(impl_canonical_deserialize(&ast))
}

fn impl_canonical_deserialize(ast: &syn::DeriveInput) -> TokenStream {
let name = &ast.ident;

let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();

let deserialize_body;

match ast.data {
Data::Struct(ref data_struct) => {
let mut tuple = false;
let mut field_cases = Vec::<TokenStream>::new();
for field in data_struct.fields.iter() {
match &field.ident {
None => {
tuple = true;
field_cases.push(quote! { ::algebra_core::CanonicalDeserialize::deserialize(reader)?, })
},
// struct field without len_type
Some(ident) => {
field_cases.push(quote! { #ident: ::algebra_core::CanonicalDeserialize::deserialize(reader)?, })
},
}
}

if tuple {
deserialize_body = quote!({
Ok(#name (
#(#field_cases)*
))
});
} else {
deserialize_body = quote!({
Ok(#name {
#(#field_cases)*
})
});
}
},
_ => panic!(
"Deserialize can only be derived for structs, {} is not a Struct",
name
),
};

let gen = quote! {
impl #impl_generics CanonicalDeserialize for #name #ty_generics #where_clause {
#[allow(unused_mut,unused_variables)]
fn deserialize<R: ::algebra_core::io::Read>(reader: &mut R) -> Result<Self, ::algebra_core::SerializationError> {
#deserialize_body
}
}
};
gen
}
@@ -10,6 +10,8 @@ macro_rules! bigint_impl {
}

impl BigInteger for $name {
const NUM_LIMBS: usize = $num_limbs;

#[inline]
fn add_nocarry(&mut self, other: &Self) -> bool {
let mut carry = 0;
@@ -2,7 +2,8 @@ use crate::{
bytes::{FromBytes, ToBytes},
fields::BitIterator,
io::{Read, Result as IoResult, Write},
UniformRand, Vec,
serialize::{deserialize_num_limbs, serialize_num_limbs},
CanonicalDeserialize, CanonicalSerialize, EmptyFlags, SerializationError, UniformRand, Vec,
};
use core::fmt::{Debug, Display};
use rand::{
@@ -21,14 +22,34 @@ bigint_impl!(BigInteger384, 6);
bigint_impl!(BigInteger768, 12);
bigint_impl!(BigInteger832, 13);

impl<T: BigInteger> CanonicalSerialize for T {
fn serialize<W: Write>(&self, writer: &mut W) -> Result<(), SerializationError> {
serialize_num_limbs(writer, self.as_ref(), Self::NUM_LIMBS * 8, EmptyFlags)
}

fn serialized_size(&self) -> usize {
Self::NUM_LIMBS * 8
}
}

impl<T: BigInteger> CanonicalDeserialize for T {
fn deserialize<R: Read>(reader: &mut R) -> Result<Self, SerializationError> {
let mut value = T::default();
deserialize_num_limbs::<_, EmptyFlags>(reader, value.as_mut(), Self::NUM_LIMBS * 8, false)?;
Ok(value)
}
}

#[cfg(test)]
mod tests;

/// This defines a `BigInteger`, a smart wrapper around a
/// sequence of `u64` limbs, least-significant digit first.
/// sequence of `u64` limbs, least-significant limb first.
pub trait BigInteger:
ToBytes
+ FromBytes
+ CanonicalSerialize
+ CanonicalDeserialize
+ Copy
+ Clone
+ Debug
@@ -45,6 +66,9 @@ pub trait BigInteger:
+ AsRef<[u64]>
+ From<u64>
{
/// Number of limbs.
const NUM_LIMBS: usize;

/// Add another representation to this one, returning the carry bit.
fn add_nocarry(&mut self, other: &Self) -> bool;

@@ -2,7 +2,7 @@ use crate::{
bytes::{FromBytes, ToBytes},
fields::{Field, PrimeField, SquareRootField},
groups::Group,
UniformRand, Vec,
CanonicalDeserialize, CanonicalSerialize, UniformRand, Vec,
};
use core::{
fmt::{Debug, Display},
@@ -207,6 +207,8 @@ pub trait AffineCurve:
+ Sized
+ ToBytes
+ FromBytes
+ CanonicalSerialize
+ CanonicalDeserialize
+ Copy
+ Clone
+ Default
@@ -1,7 +1,8 @@
use crate::{
curves::models::SWModelParameters as Parameters,
io::{Read, Result as IoResult, Write},
CanonicalDeserialize, CanonicalSerialize, UniformRand, Vec,
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
CanonicalSerializeWithFlags, UniformRand, Vec,
};
use core::{
fmt::{Display, Formatter, Result as FmtResult},
@@ -1,7 +1,8 @@
use crate::{
curves::models::SWModelParameters as Parameters,
io::{Read, Result as IoResult, Write},
CanonicalDeserialize, CanonicalSerialize, UniformRand, Vec,
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
CanonicalSerializeWithFlags, UniformRand, Vec,
};
use core::{
fmt::{Display, Formatter, Result as FmtResult},
@@ -1,6 +1,7 @@
use crate::{
io::{Read, Result as IoResult, Write},
CanonicalDeserialize, CanonicalSerialize, UniformRand, Vec,
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
CanonicalSerializeWithFlags, UniformRand, Vec,
};
use core::{
fmt::{Display, Formatter, Result as FmtResult},
@@ -1,7 +1,8 @@
use crate::{
biginteger::BigInteger,
bytes::{FromBytes, ToBytes},
CanonicalDeserialize, CanonicalSerialize, UniformRand, Vec,
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
CanonicalSerializeWithFlags, UniformRand, Vec,
};
use core::{
fmt::{Debug, Display},
@@ -63,7 +64,9 @@ pub trait Field:
+ Sized
+ Hash
+ CanonicalSerialize
+ CanonicalSerializeWithFlags
+ CanonicalDeserialize
+ CanonicalDeserializeWithFlags
+ Add<Self, Output = Self>
+ Sub<Self, Output = Self>
+ Mul<Self, Output = Self>
@@ -1,6 +1,7 @@
use crate::{
io::{Read, Result as IoResult, Write},
CanonicalDeserialize, CanonicalSerialize, SerializationError, UniformRand,
CanonicalDeserialize, CanonicalDeserializeWithFlags, CanonicalSerialize,
CanonicalSerializeWithFlags, EmptyFlags, Flags, SerializationError, UniformRand,
};
use core::{
cmp::Ordering,
@@ -486,42 +487,42 @@ impl<P: Fp12Parameters> FromBytes for Fp12<P> {
}
}

impl<P: Fp12Parameters> CanonicalSerialize for Fp12<P> {
fn serialize(
impl<P: Fp12Parameters> CanonicalSerializeWithFlags for Fp12<P> {
fn serialize_with_flags<W: Write, F: Flags>(
&self,
extra_info: &[bool],
output_buf: &mut [u8],
writer: &mut W,
flags: F,
) -> Result<(), SerializationError> {
let fp_byte_size = <<<P::Fp6Params as Fp6Parameters>::Fp2Params as Fp2Parameters>::Fp as CanonicalSerialize>::buffer_size();
if output_buf.len() != 12 * fp_byte_size {
return Err(SerializationError::BufferWrongSize);
}
self.c0
.serialize(&[], &mut output_buf[..6 * fp_byte_size])?;
self.c1.serialize(
extra_info,
&mut output_buf[6 * fp_byte_size..12 * fp_byte_size],
)?;
self.c0.serialize(writer)?;
self.c1.serialize_with_flags(writer, flags)?;
Ok(())
}
}

impl<P: Fp12Parameters> CanonicalSerialize for Fp12<P> {
fn serialize<W: Write>(&self, writer: &mut W) -> Result<(), SerializationError> {
self.serialize_with_flags(writer, EmptyFlags)
}

fn buffer_size() -> usize {
12*<<<P::Fp6Params as Fp6Parameters>::Fp2Params as Fp2Parameters>::Fp as CanonicalSerialize>::buffer_size()
fn serialized_size(&self) -> usize {
self.c0.serialized_size() + self.c1.serialized_size()
}
}

impl<P: Fp12Parameters> CanonicalDeserializeWithFlags for Fp12<P> {
fn deserialize_with_flags<R: Read, F: Flags>(
reader: &mut R,
) -> Result<(Self, F), SerializationError> {
let c0 = Fp6::deserialize(reader)?;
let (c1, flags) = Fp6::deserialize_with_flags(reader)?;
Ok((Fp12::new(c0, c1), flags))
}
}

impl<P: Fp12Parameters> CanonicalDeserialize for Fp12<P> {
fn deserialize(bytes: &[u8], extra_info_buf: &mut [bool]) -> Result<Self, SerializationError>
where
Self: Sized,
{
let fp_byte_size = <<<P::Fp6Params as Fp6Parameters>::Fp2Params as Fp2Parameters>::Fp as CanonicalSerialize>::buffer_size();
if bytes.len() != 12 * fp_byte_size {
return Err(SerializationError::BufferWrongSize);
}
let mut dummy_mutable_slice = [false; 0];
let c0 = Fp6::deserialize(&bytes[..6 * fp_byte_size], &mut dummy_mutable_slice)?;
let c1 = Fp6::deserialize(&bytes[6 * fp_byte_size..12 * fp_byte_size], extra_info_buf)?;
fn deserialize<R: Read>(reader: &mut R) -> Result<Self, SerializationError> {
let c0 = Fp6::deserialize(reader)?;
let c1 = Fp6::deserialize(reader)?;
Ok(Fp12::new(c0, c1))
}
}

0 comments on commit 3094511

Please sign in to comment.
You can’t perform that action at this time.