Make serialization less wasteful.

This removes the unneeded length from key and signature representation,
removing 8 bytes from each. Also adds `from_bytes` and `to_bytes`
methods to convert keys and signatures.
master
Andreas Fackler 7 years ago committed by Andreas Fackler
parent 4fec9da3d6
commit c7eda7a14a
  1. 10
      src/error.rs
  2. 87
      src/lib.rs
  3. 13
      src/mock/mod.rs
  4. 117
      src/serde_impl.rs

@ -28,3 +28,13 @@ mod tests {
is_send_and_sync(Error::NotEnoughShares); is_send_and_sync(Error::NotEnoughShares);
} }
} }
/// An error reading a structure from an array of bytes.
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
pub enum FromBytesError {
#[fail(display = "Invalid representation.")]
Invalid,
}
/// The result of attempting to read a structure from an array of bytes.
pub type FromBytesResult<T> = ::std::result::Result<T, FromBytesError>;

@ -44,29 +44,37 @@ use byteorder::{BigEndian, ByteOrder};
use hex_fmt::HexFmt; use hex_fmt::HexFmt;
use init_with::InitWith; use init_with::InitWith;
use log::debug; use log::debug;
use pairing::{CurveAffine, CurveProjective, Engine, Field}; use pairing::{CurveAffine, CurveProjective, EncodedPoint, Engine, Field};
use rand::{ChaChaRng, OsRng, Rand, Rng, SeedableRng}; use rand::{ChaChaRng, OsRng, Rand, Rng, SeedableRng};
use rand_derive::Rand; use rand_derive::Rand;
use tiny_keccak::sha3_256; use tiny_keccak::sha3_256;
use error::{Error, Result}; use error::{Error, FromBytesError, FromBytesResult, Result};
use into_fr::IntoFr; use into_fr::IntoFr;
use poly::{Commitment, Poly}; use poly::{Commitment, Poly};
use secret::{clear_fr, ContainsSecret, MemRange, FR_SIZE}; use secret::{clear_fr, ContainsSecret, MemRange, FR_SIZE};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
#[cfg(not(feature = "use-insecure-test-only-mock-crypto"))] #[cfg(not(feature = "use-insecure-test-only-mock-crypto"))]
pub use pairing::bls12_381::{Bls12 as PEngine, Fr, G1Affine, G2Affine, G1, G2}; pub use pairing::bls12_381::{Bls12 as PEngine, Fr, FrRepr, G1Affine, G2Affine, G1, G2};
#[cfg(feature = "use-insecure-test-only-mock-crypto")] #[cfg(feature = "use-insecure-test-only-mock-crypto")]
mod mock; mod mock;
#[cfg(feature = "use-insecure-test-only-mock-crypto")] #[cfg(feature = "use-insecure-test-only-mock-crypto")]
pub use mock::{ pub use mock::{
Mersenne8 as Fr, Mocktography as PEngine, Ms8Affine as G1Affine, Ms8Affine as G2Affine, Mersenne8 as Fr, Mersenne8 as FrRepr, Mocktography as PEngine, Ms8Affine as G1Affine,
Ms8Projective as G1, Ms8Projective as G2, Ms8Affine as G2Affine, Ms8Projective as G1, Ms8Projective as G2, PK_SIZE, SIG_SIZE,
}; };
/// The size of a key's representation in bytes.
#[cfg(not(feature = "use-insecure-test-only-mock-crypto"))]
pub const PK_SIZE: usize = 48;
/// The size of a signature's representation in bytes.
#[cfg(not(feature = "use-insecure-test-only-mock-crypto"))]
pub const SIG_SIZE: usize = 96;
/// The number of words (`u32`) in a ChaCha RNG seed. /// The number of words (`u32`) in a ChaCha RNG seed.
const CHACHA_RNG_SEED_SIZE: usize = 8; const CHACHA_RNG_SEED_SIZE: usize = 8;
@ -122,9 +130,20 @@ impl PublicKey {
Ciphertext(u, v, w) Ciphertext(u, v, w)
} }
/// Returns the key with the given representation, if valid.
pub fn from_bytes<B: Borrow<[u8; PK_SIZE]>>(bytes: B) -> FromBytesResult<Self> {
let mut compressed: <G1Affine as CurveAffine>::Compressed = EncodedPoint::empty();
compressed.as_mut().copy_from_slice(bytes.borrow());
let opt_affine = compressed.into_affine().ok();
let projective = opt_affine.ok_or(FromBytesError::Invalid)?.into_projective();
Ok(PublicKey(projective))
}
/// Returns a byte string representation of the public key. /// Returns a byte string representation of the public key.
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> [u8; PK_SIZE] {
self.0.into_affine().into_compressed().as_ref().to_vec() let mut bytes = [0u8; PK_SIZE];
bytes.copy_from_slice(self.0.into_affine().into_compressed().as_ref());
bytes
} }
} }
@ -159,8 +178,13 @@ impl PublicKeyShare {
PEngine::pairing(share.0, hash) == PEngine::pairing((self.0).0, *w) PEngine::pairing(share.0, hash) == PEngine::pairing((self.0).0, *w)
} }
/// Returns the key share with the given representation, if valid.
pub fn from_bytes<B: Borrow<[u8; PK_SIZE]>>(bytes: B) -> FromBytesResult<Self> {
Ok(PublicKeyShare(PublicKey::from_bytes(bytes)?))
}
/// Returns a byte string representation of the public key share. /// Returns a byte string representation of the public key share.
pub fn to_bytes(&self) -> Vec<u8> { pub fn to_bytes(&self) -> [u8; PK_SIZE] {
self.0.to_bytes() self.0.to_bytes()
} }
} }
@ -191,6 +215,22 @@ impl Signature {
debug!("Signature: {:0.10}, parity: {}", HexFmt(uncomp), parity); debug!("Signature: {:0.10}, parity: {}", HexFmt(uncomp), parity);
parity parity
} }
/// Returns the signature with the given representation, if valid.
pub fn from_bytes<B: Borrow<[u8; SIG_SIZE]>>(bytes: B) -> FromBytesResult<Self> {
let mut compressed: <G2Affine as CurveAffine>::Compressed = EncodedPoint::empty();
compressed.as_mut().copy_from_slice(bytes.borrow());
let opt_affine = compressed.into_affine().ok();
let projective = opt_affine.ok_or(FromBytesError::Invalid)?.into_projective();
Ok(Signature(projective))
}
/// Returns a byte string representation of the signature.
pub fn to_bytes(&self) -> [u8; SIG_SIZE] {
let mut bytes = [0u8; SIG_SIZE];
bytes.copy_from_slice(self.0.into_affine().into_compressed().as_ref());
bytes
}
} }
/// A signature share. /// A signature share.
@ -205,6 +245,18 @@ impl fmt::Debug for SignatureShare {
} }
} }
impl SignatureShare {
/// Returns the signature share with the given representation, if valid.
pub fn from_bytes<B: Borrow<[u8; SIG_SIZE]>>(bytes: B) -> FromBytesResult<Self> {
Ok(SignatureShare(Signature::from_bytes(bytes)?))
}
/// Returns a byte string representation of the signature share.
pub fn to_bytes(&self) -> [u8; SIG_SIZE] {
self.0.to_bytes()
}
}
/// A secret key; wraps a single prime field element. The field element is /// A secret key; wraps a single prime field element. The field element is
/// heap allocated to avoid any stack copying that result when passing /// heap allocated to avoid any stack copying that result when passing
/// `SecretKey`s between stack frames. /// `SecretKey`s between stack frames.
@ -827,6 +879,17 @@ mod tests {
assert_eq!(20, xwh(g0, &[0; 20]).len()); assert_eq!(20, xwh(g0, &[0; 20]).len());
} }
#[test]
fn test_from_to_bytes() {
let sk: SecretKey = random();
let sig = sk.sign("Please sign here: ______");
let pk = sk.public_key();
let pk2 = PublicKey::from_bytes(pk.to_bytes()).expect("invalid pk representation");
assert_eq!(pk, pk2);
let sig2 = Signature::from_bytes(sig.to_bytes()).expect("invalid sig representation");
assert_eq!(sig, sig2);
}
#[test] #[test]
fn test_serde() { fn test_serde() {
use bincode; use bincode;
@ -836,9 +899,17 @@ mod tests {
let pk = sk.public_key(); let pk = sk.public_key();
let ser_pk = bincode::serialize(&pk).expect("serialize public key"); let ser_pk = bincode::serialize(&pk).expect("serialize public key");
let deser_pk = bincode::deserialize(&ser_pk).expect("deserialize public key"); let deser_pk = bincode::deserialize(&ser_pk).expect("deserialize public key");
assert_eq!(ser_pk.len(), PK_SIZE);
assert_eq!(pk, deser_pk); assert_eq!(pk, deser_pk);
let ser_sig = bincode::serialize(&sig).expect("serialize signature"); let ser_sig = bincode::serialize(&sig).expect("serialize signature");
let deser_sig = bincode::deserialize(&ser_sig).expect("deserialize signature"); let deser_sig = bincode::deserialize(&ser_sig).expect("deserialize signature");
assert_eq!(ser_sig.len(), SIG_SIZE);
assert_eq!(sig, deser_sig); assert_eq!(sig, deser_sig);
} }
#[test]
fn test_size() {
assert_eq!(<G1Affine as CurveAffine>::Compressed::size(), PK_SIZE);
assert_eq!(<G2Affine as CurveAffine>::Compressed::size(), SIG_SIZE);
}
} }

@ -21,6 +21,11 @@ use super::{CurveAffine, CurveProjective, Engine};
pub use self::ms8::Mersenne8; pub use self::ms8::Mersenne8;
/// The size of a key's representation in bytes.
pub const PK_SIZE: usize = 4;
/// The size of a signature's representation in bytes.
pub const SIG_SIZE: usize = 4;
/// A `pairing` Engine based on `Mersenne8` prime fields. /// A `pairing` Engine based on `Mersenne8` prime fields.
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Mocktography; pub struct Mocktography;
@ -292,7 +297,7 @@ mod test {
// There are copy & pasted results of calculations from external programs in these tests. // There are copy & pasted results of calculations from external programs in these tests.
#![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))] #![cfg_attr(feature = "cargo-clippy", allow(unreadable_literal))]
use super::{Mersenne8, Mocktography, Ms8Affine}; use super::{EncodedPoint, Mersenne8, Mocktography, Ms8Affine, PK_SIZE, SIG_SIZE};
use Engine; use Engine;
#[test] #[test]
@ -319,4 +324,10 @@ mod test {
assert_eq!(Mocktography::pairing(q, p), Mersenne8::new(res)); assert_eq!(Mocktography::pairing(q, p), Mersenne8::new(res));
} }
} }
#[test]
fn size() {
assert_eq!(<Ms8Affine as EncodedPoint>::size(), PK_SIZE);
assert_eq!(<Ms8Affine as EncodedPoint>::size(), SIG_SIZE);
}
} }

@ -1,9 +1,9 @@
use std::borrow::Cow; use std::borrow::Cow;
use super::G1;
use serde::de::Error as DeserializeError; use serde::de::Error as DeserializeError;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use G1;
use poly::{coeff_pos, BivarCommitment}; use poly::{coeff_pos, BivarCommitment};
@ -43,11 +43,13 @@ impl<'de> Deserialize<'de> for BivarCommitment {
/// Serialization and deserialization of a group element's compressed representation. /// Serialization and deserialization of a group element's compressed representation.
pub mod projective { pub mod projective {
use std::fmt;
use std::marker::PhantomData;
use pairing::{CurveAffine, CurveProjective, EncodedPoint}; use pairing::{CurveAffine, CurveProjective, EncodedPoint};
use serde::de::Error as DeserializeError; use serde::de::{Error as DeserializeError, SeqAccess, Visitor};
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{ser::SerializeTuple, Deserializer, Serializer};
const ERR_LEN: &str = "wrong length of deserialized group element";
const ERR_CODE: &str = "deserialized bytes don't encode a group element"; const ERR_CODE: &str = "deserialized bytes don't encode a group element";
pub fn serialize<S, C>(c: &C, s: S) -> Result<S::Ok, S::Error> pub fn serialize<S, C>(c: &C, s: S) -> Result<S::Ok, S::Error>
@ -55,7 +57,12 @@ pub mod projective {
S: Serializer, S: Serializer,
C: CurveProjective, C: CurveProjective,
{ {
c.into_affine().into_compressed().as_ref().serialize(s) let len = <C::Affine as CurveAffine>::Compressed::size();
let mut tup = s.serialize_tuple(len)?;
for byte in c.into_affine().into_compressed().as_ref() {
tup.serialize_element(byte)?;
}
tup.end()
} }
pub fn deserialize<'de, D, C>(d: D) -> Result<C, D::Error> pub fn deserialize<'de, D, C>(d: D) -> Result<C, D::Error>
@ -63,14 +70,32 @@ pub mod projective {
D: Deserializer<'de>, D: Deserializer<'de>,
C: CurveProjective, C: CurveProjective,
{ {
let bytes = <Vec<u8>>::deserialize(d)?; struct TupleVisitor<C> {
if bytes.len() != <C::Affine as CurveAffine>::Compressed::size() { _ph: PhantomData<C>,
return Err(D::Error::custom(ERR_LEN));
} }
let mut compressed = <C::Affine as CurveAffine>::Compressed::empty();
compressed.as_mut().copy_from_slice(&bytes); impl<'de, C: CurveProjective> Visitor<'de> for TupleVisitor<C> {
let to_err = |_| D::Error::custom(ERR_CODE); type Value = C;
Ok(compressed.into_affine().map_err(to_err)?.into_projective())
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
let len = <C::Affine as CurveAffine>::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::Affine as CurveAffine>::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);
Ok(compressed.into_affine().map_err(to_err)?.into_projective())
}
}
let len = <C::Affine as CurveAffine>::Compressed::size();
d.deserialize_tuple(len, TupleVisitor { _ph: PhantomData })
} }
} }
@ -130,90 +155,66 @@ pub mod projective_vec {
/// Serialization and deserialization of vectors of field elements. /// Serialization and deserialization of vectors of field elements.
pub mod field_vec { pub mod field_vec {
use std::borrow::Borrow; use std::borrow::Borrow;
use std::marker::PhantomData;
use pairing::{PrimeField, PrimeFieldRepr}; use pairing::PrimeField;
use serde::de::Error as DeserializeError; use serde::de::Error as DeserializeError;
use serde::ser::Error as SerializeError;
use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::{Deserialize, Deserializer, Serialize, Serializer};
/// A wrapper type to facilitate serialization and deserialization of field elements. use {Fr, FrRepr};
pub struct FieldWrap<F, B>(B, PhantomData<F>);
impl<F, B> FieldWrap<F, B> { /// A wrapper type to facilitate serialization and deserialization of field elements.
pub fn new(f: B) -> Self { pub struct FieldWrap<B>(B);
FieldWrap(f, PhantomData)
}
}
impl<F> FieldWrap<F, F> { impl FieldWrap<Fr> {
pub fn into_inner(self) -> F { pub fn into_inner(self) -> Fr {
self.0 self.0
} }
} }
impl<F: PrimeField, B: Borrow<F>> Serialize for FieldWrap<F, B> { impl<B: Borrow<Fr>> Serialize for FieldWrap<B> {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> { fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
let mut bytes = Vec::new(); self.0.borrow().into_repr().0.serialize(s)
self.0
.borrow()
.into_repr()
.write_be(&mut bytes)
.map_err(|_| S::Error::custom("failed to write bytes"))?;
bytes.serialize(s)
} }
} }
impl<'de, F: PrimeField> Deserialize<'de> for FieldWrap<F, F> { impl<'de> Deserialize<'de> for FieldWrap<Fr> {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> { fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
let bytes: Vec<u8> = Deserialize::deserialize(d)?; let repr = FrRepr(Deserialize::deserialize(d)?);
let mut repr = F::zero().into_repr(); Ok(FieldWrap(Fr::from_repr(repr).map_err(|_| {
repr.read_be(&bytes[..])
.map_err(|_| D::Error::custom("failed to write bytes"))?;
Ok(FieldWrap::new(F::from_repr(repr).map_err(|_| {
D::Error::custom("invalid field element representation") D::Error::custom("invalid field element representation")
})?)) })?))
} }
} }
pub fn serialize<S, F>(vec: &[F], s: S) -> Result<S::Ok, S::Error> pub fn serialize<S: Serializer>(vec: &[Fr], s: S) -> Result<S::Ok, S::Error> {
where let wrap_vec: Vec<FieldWrap<&Fr>> = vec.iter().map(FieldWrap).collect();
S: Serializer,
F: PrimeField,
{
let wrap_vec: Vec<FieldWrap<F, &F>> = vec.iter().map(FieldWrap::new).collect();
wrap_vec.serialize(s) wrap_vec.serialize(s)
} }
pub fn deserialize<'de, D, F>(d: D) -> Result<Vec<F>, D::Error> pub fn deserialize<'de, D: Deserializer<'de>>(d: D) -> Result<Vec<Fr>, D::Error> {
where let wrap_vec = <Vec<FieldWrap<Fr>>>::deserialize(d)?;
D: Deserializer<'de>, Ok(wrap_vec.into_iter().map(FieldWrap::into_inner).collect())
F: PrimeField,
{
let wrap_vec = <Vec<FieldWrap<F, F>>>::deserialize(d)?;
Ok(wrap_vec.into_iter().map(|FieldWrap(f, _)| f).collect())
} }
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::super::PEngine;
use bincode; use bincode;
use pairing::Engine;
use rand::{self, Rng}; use rand::{self, Rng};
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use poly::BivarPoly; use poly::BivarPoly;
use {Fr, G1};
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct Vecs<E: Engine> { pub struct Vecs {
#[serde(with = "super::projective_vec")] #[serde(with = "super::projective_vec")]
curve_points: Vec<E::G1>, curve_points: Vec<G1>,
#[serde(with = "super::field_vec")] #[serde(with = "super::field_vec")]
field_elements: Vec<E::Fr>, field_elements: Vec<Fr>,
} }
impl<E: Engine> PartialEq for Vecs<E> { impl PartialEq for Vecs {
fn eq(&self, other: &Self) -> bool { fn eq(&self, other: &Self) -> bool {
self.curve_points == other.curve_points && self.field_elements == other.field_elements self.curve_points == other.curve_points && self.field_elements == other.field_elements
} }
@ -222,7 +223,7 @@ mod tests {
#[test] #[test]
fn vecs() { fn vecs() {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let vecs: Vecs<PEngine> = Vecs { let vecs = Vecs {
curve_points: rng.gen_iter().take(10).collect(), curve_points: rng.gen_iter().take(10).collect(),
field_elements: rng.gen_iter().take(10).collect(), field_elements: rng.gen_iter().take(10).collect(),
}; };

Loading…
Cancel
Save