hbbft/src/common_coin.rs

215 lines
6.5 KiB
Rust
Raw Normal View History

2018-06-08 11:43:27 -07:00
//! Common coin from a given set of keys based on a `pairing` threshold signature scheme.
2018-06-08 11:43:27 -07:00
use std::collections::{BTreeMap, VecDeque};
use std::fmt::Debug;
use std::mem::replace;
use std::rc::Rc;
use pairing::bls12_381::Bls12;
2018-06-08 11:43:27 -07:00
use crypto::error as cerror;
use crypto::Signature;
use messaging::{DistAlgorithm, NetworkInfo, Target, TargetedMessage};
error_chain! {
2018-06-08 11:43:27 -07:00
links {
Crypto(cerror::Error, cerror::ErrorKind);
}
errors {
2018-06-08 11:43:27 -07:00
UnknownSender {
description("unknown sender")
}
VerificationFailed {
description("signature verification failed")
}
}
}
2018-06-08 11:43:27 -07:00
#[cfg_attr(feature = "serialization-serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug, PartialEq)]
pub struct CommonCoinMessage(Signature<Bls12>);
2018-06-09 13:50:36 -07:00
impl CommonCoinMessage {
pub fn new(sig: Signature<Bls12>) -> Self {
CommonCoinMessage(sig)
}
pub fn to_sig(&self) -> &Signature<Bls12> {
&self.0
}
}
2018-06-08 11:43:27 -07:00
/// 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.
#[derive(Debug)]
pub struct CommonCoin<'a, N, T>
where
N: 'a + Debug,
{
netinfo: Rc<NetworkInfo<'a, N>>,
2018-06-08 11:43:27 -07:00
/// The name of this common coin. It is required to be unique for each common coin round.
nonce: T,
/// The result of combination of at least `num_faulty + 1` threshold signature shares.
output: Option<bool>,
/// Outgoing message queue.
messages: VecDeque<CommonCoinMessage>,
/// Incoming messages buffered before we provide input to the common coin.
incoming_queue: VecDeque<(N, Signature<Bls12>)>,
2018-06-08 11:43:27 -07:00
/// All received threshold signature shares.
received_shares: BTreeMap<N, Signature<Bls12>>,
/// Whether we provided input to the common coin.
had_input: bool,
2018-06-08 11:43:27 -07:00
/// Termination flag.
terminated: bool,
}
impl<'a, N, T> DistAlgorithm for CommonCoin<'a, N, T>
where
N: 'a + Clone + Debug + Ord,
2018-06-08 11:43:27 -07:00
T: Clone + AsRef<[u8]>,
{
type NodeUid = N;
type Input = ();
2018-06-08 11:43:27 -07:00
type Output = bool;
type Message = CommonCoinMessage;
type Error = Error;
2018-06-08 11:43:27 -07:00
/// Sends our threshold signature share if not yet sent.
fn input(&mut self, _input: Self::Input) -> Result<()> {
if !self.had_input {
self.had_input = true;
2018-06-08 11:43:27 -07:00
self.get_coin()
} else {
Ok(())
}
}
2018-06-08 11:43:27 -07:00
/// Receives input from a remote node.
fn handle_message(&mut self, sender_id: &Self::NodeUid, message: Self::Message) -> Result<()> {
2018-06-11 09:00:23 -07:00
if self.terminated {
return Ok(());
}
let CommonCoinMessage(share) = message;
if !self.had_input {
self.incoming_queue.push_back((sender_id.clone(), share));
return Ok(());
} else {
let queued_msgs = replace(&mut self.incoming_queue, VecDeque::new());
for (sender_id, msg) in queued_msgs {
self.handle_share(&sender_id, msg)?;
}
}
2018-06-08 11:43:27 -07:00
self.handle_share(sender_id, share)
}
2018-06-08 11:43:27 -07:00
/// Takes the next share of a threshold signature message for multicasting to all other nodes.
fn next_message(&mut self) -> Option<TargetedMessage<Self::Message, Self::NodeUid>> {
2018-06-08 11:43:27 -07:00
self.messages
.pop_front()
.map(|msg| Target::All.message(msg))
}
2018-06-08 11:43:27 -07:00
/// Consumes the output. Once consumed, the output stays `None` forever.
fn next_output(&mut self) -> Option<Self::Output> {
self.output.take()
}
/// Whether the algorithm has terminated.
fn terminated(&self) -> bool {
2018-06-08 11:43:27 -07:00
self.terminated
}
fn our_id(&self) -> &Self::NodeUid {
self.netinfo.our_uid()
}
}
impl<'a, N, T> CommonCoin<'a, N, T>
where
N: 'a + Clone + Debug + Ord,
2018-06-08 11:43:27 -07:00
T: Clone + AsRef<[u8]>,
{
pub fn new(netinfo: Rc<NetworkInfo<'a, N>>, nonce: T) -> Self {
CommonCoin {
netinfo: netinfo.clone(),
2018-06-08 11:43:27 -07:00
nonce,
output: None,
messages: VecDeque::new(),
incoming_queue: VecDeque::new(),
2018-06-08 11:43:27 -07:00
received_shares: BTreeMap::new(),
had_input: false,
2018-06-08 11:43:27 -07:00
terminated: false,
}
}
2018-06-07 09:38:27 -07:00
2018-06-08 11:43:27 -07:00
fn get_coin(&mut self) -> Result<()> {
let share = self.netinfo.secret_key().sign(&self.nonce);
2018-06-09 13:50:36 -07:00
self.messages.push_back(CommonCoinMessage(share.clone()));
2018-06-08 11:43:27 -07:00
let id = self.netinfo.our_uid().clone();
self.handle_share(&id, share)
}
fn handle_share(&mut self, sender_id: &N, share: Signature<Bls12>) -> Result<()> {
let i = self.node_idx(sender_id)?;
let pk_i = self.netinfo.public_key_set().public_key_share(i as u64);
if !pk_i.verify(&share, &self.nonce) {
// Silently ignore the invalid share.
return Ok(());
}
self.received_shares.insert(sender_id.clone(), share);
if self.received_shares.len() > self.netinfo.num_faulty() {
let sig = self.combine_and_verify_sig()?;
// Output the parity of the verified signature.
let parity = sig.parity();
self.output = Some(parity);
self.terminated = true;
}
Ok(())
}
2018-06-08 11:43:27 -07:00
fn combine_and_verify_sig(&self) -> Result<Signature<Bls12>> {
// Pass the indices of sender nodes to `combine_signatures`.
let ids_shares: BTreeMap<&N, &Signature<Bls12>> = self.received_shares.iter().collect();
let ids_u64: BTreeMap<&N, u64> = ids_shares
.keys()
.map(|&id| (id, self.node_idx(id).unwrap()))
.collect();
// Convert indices to `u64` which is an interface type for `pairing`.
let shares: BTreeMap<&u64, &Signature<Bls12>> = ids_shares
.iter()
.map(|(id, &share)| (ids_u64.get(id).unwrap(), share))
.collect();
let sig = self.netinfo.public_key_set().combine_signatures(shares)?;
if !self
.netinfo
.public_key_set()
.public_key()
.verify(&sig, &self.nonce)
{
// Abort
error!(
"{:?} main public key verification failed",
self.netinfo.our_uid()
2018-06-09 13:50:36 -07:00
);
Err(ErrorKind::VerificationFailed.into())
} else {
Ok(sig)
}
}
fn node_idx(&self, id: &N) -> Result<u64> {
if let Some(i) = self.netinfo.node_idx(id) {
Ok(i as u64)
2018-06-08 11:43:27 -07:00
} else {
Err(ErrorKind::UnknownSender.into())
}
2018-06-07 09:38:27 -07:00
}
}