protobuf serialization

This commit is contained in:
Vladimir Komendantskiy 2018-06-09 21:50:36 +01:00
parent 122f1fc6f1
commit 40eeee90fc
5 changed files with 134 additions and 3 deletions

View File

@ -50,5 +50,6 @@ message AgreementProto {
bool aux = 3;
uint32 conf = 4;
bool term = 5;
bytes coin = 6;
}
}

View File

@ -333,6 +333,7 @@ impl<NodeUid: Clone + Debug + Eq + Hash + Ord> Agreement<NodeUid> {
// round r, and the value Coin_r' = b for some round r' > r."
self.terminated = self.terminated || self.decision == Some(coin);
if self.terminated {
debug!("Node {:?} Agreement terminated", self.netinfo.our_uid());
return Ok(());
}

View File

@ -29,6 +29,16 @@ error_chain! {
#[derive(Clone, Debug, PartialEq)]
pub struct CommonCoinMessage(Signature<Bls12>);
impl CommonCoinMessage {
pub fn new(sig: Signature<Bls12>) -> Self {
CommonCoinMessage(sig)
}
pub fn to_sig(&self) -> &Signature<Bls12> {
&self.0
}
}
/// A common coin algorithm instance. On input, broadcasts our threshold signature share. Upon
/// receiving at least `num_faulty + 1` shares, attempts to combine them into a signature. If that
/// signature is valid, the instance outputs it and terminates; otherwise the instance aborts.
@ -124,8 +134,7 @@ where
fn get_coin(&mut self) -> Result<()> {
let share = self.netinfo.secret_key().sign(&self.nonce);
self.messages
.push_back(CommonCoinMessage(share.clone()));
self.messages.push_back(CommonCoinMessage(share.clone()));
let id = self.netinfo.our_uid().clone();
self.handle_share(&id, share)
}
@ -136,9 +145,19 @@ where
let pk_i = self.netinfo.public_key_set().public_key_share(*i);
if !pk_i.verify(&share, &self.nonce) {
// Silently ignore the invalid share.
debug!(
"{:?} received invalid share from {:?}",
self.netinfo.our_uid(),
sender_id
);
return Ok(());
}
debug!(
"{:?} received a valid share from {:?}",
self.netinfo.our_uid(),
sender_id
);
self.received_shares.insert(sender_id.clone(), share);
let received_shares = &self.received_shares;
if received_shares.len() > self.netinfo.num_faulty() {
@ -161,14 +180,19 @@ where
.verify(&sig, &self.nonce)
{
// Abort
error!(
"{:?} main public key verification failed",
self.netinfo.our_uid()
);
self.terminated = true;
return Err(ErrorKind::VerificationFailed.into())
return Err(ErrorKind::VerificationFailed.into());
}
// Output the parity of the verified signature.
let parity = sig.parity();
self.output = Some(parity);
self.terminated = true;
debug!("{:?} coin is {}", self.netinfo.our_uid(), parity);
}
Ok(())
} else {

View File

@ -517,3 +517,99 @@ mod tests {
assert_eq!(sig, deser_sig);
}
}
#[cfg(feature = "serialization-serde")]
mod serde {
use pairing::{CurveAffine, CurveProjective, EncodedPoint, Engine};
use super::{DecryptionShare, PublicKey, Signature};
use serde::de::Error as DeserializeError;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
const ERR_LEN: &str = "wrong length of deserialized group element";
const ERR_CODE: &str = "deserialized bytes don't encode a group element";
impl<E: Engine> Serialize for PublicKey<E> {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize_projective(&self.0, s)
}
}
impl<'de, E: Engine> Deserialize<'de> for PublicKey<E> {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Ok(PublicKey(deserialize_projective(d)?))
}
}
impl<E: Engine> Serialize for Signature<E> {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize_projective(&self.0, s)
}
}
impl<'de, E: Engine> Deserialize<'de> for Signature<E> {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Ok(Signature(deserialize_projective(d)?))
}
}
impl<E: Engine> Serialize for DecryptionShare<E> {
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
serialize_projective(&self.0, s)
}
}
impl<'de, E: Engine> Deserialize<'de> for DecryptionShare<E> {
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
Ok(DecryptionShare(deserialize_projective(d)?))
}
}
/// Serializes the compressed representation of a group element.
fn serialize_projective<S, C>(c: &C, s: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
C: CurveProjective,
{
c.into_affine().into_compressed().as_ref().serialize(s)
}
/// Deserializes the compressed representation of a group element.
fn deserialize_projective<'de, D, C>(d: D) -> Result<C, D::Error>
where
D: Deserializer<'de>,
C: CurveProjective,
{
let bytes = <Vec<u8>>::deserialize(d)?;
if bytes.len() != <C::Affine as CurveAffine>::Compressed::size() {
return Err(D::Error::custom(ERR_LEN));
}
let mut compressed = <C::Affine as CurveAffine>::Compressed::empty();
compressed.as_mut().copy_from_slice(&bytes);
let to_err = |_| D::Error::custom(ERR_CODE);
Ok(compressed.into_affine().map_err(to_err)?.into_projective())
}
}
#[cfg(feature = "serialization-protobuf")]
pub mod proto {
use super::Signature;
use pairing::{CurveAffine, CurveProjective, EncodedPoint, Engine};
impl<E: Engine> Signature<E> {
pub fn to_vec(&self) -> Vec<u8> {
let comp = self.0.into_affine().into_compressed();
comp.as_ref().to_vec()
}
pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
let mut comp = <E::G2Affine as CurveAffine>::Compressed::empty();
comp.as_mut().copy_from_slice(bytes);
if let Ok(affine) = comp.into_affine() {
Some(Signature(affine.into_projective()))
} else {
None
}
}
}
}

View File

@ -8,6 +8,7 @@ use agreement::bin_values::BinValues;
use agreement::{AgreementContent, AgreementMessage};
use broadcast::BroadcastMessage;
use common_coin::CommonCoinMessage;
use crypto::Signature;
use proto::message::*;
impl From<message::BroadcastProto> for BroadcastMessage {
@ -89,6 +90,10 @@ impl AgreementMessage {
AgreementContent::Term(b) => {
p.set_term(b);
}
AgreementContent::Coin(ccm) => {
let v = ccm.to_sig().to_vec();
p.set_coin(v);
}
}
p
}
@ -111,6 +116,10 @@ impl AgreementMessage {
}.map(|bin_values| AgreementContent::Conf(bin_values).with_epoch(epoch))
} else if mp.has_term() {
Some(AgreementContent::Term(mp.get_term()).with_epoch(epoch))
} else if mp.has_coin() {
Signature::from_bytes(mp.get_coin()).map(|sig| {
AgreementContent::Coin(Box::new(CommonCoinMessage::new(sig))).with_epoch(epoch)
})
} else {
None
}