2018-08-03 06:24:49 -07:00
|
|
|
use std::collections::btree_map::Entry;
|
2018-10-25 05:44:28 -07:00
|
|
|
use std::collections::{BTreeMap, BTreeSet};
|
2018-10-24 00:42:59 -07:00
|
|
|
use std::fmt::{self, Display};
|
2018-08-03 06:24:49 -07:00
|
|
|
use std::marker::PhantomData;
|
2018-09-29 18:46:42 -07:00
|
|
|
use std::mem::replace;
|
2018-10-24 00:42:59 -07:00
|
|
|
use std::result;
|
2018-08-03 06:24:49 -07:00
|
|
|
use std::sync::Arc;
|
|
|
|
|
|
|
|
use bincode;
|
|
|
|
use crypto::Ciphertext;
|
2018-11-01 03:22:40 -07:00
|
|
|
use log::error;
|
2018-10-24 13:46:44 -07:00
|
|
|
use rand::{Rand, Rng};
|
2018-10-24 02:38:14 -07:00
|
|
|
use serde::{de::DeserializeOwned, Serialize};
|
2018-10-29 07:36:56 -07:00
|
|
|
use serde_derive::Serialize;
|
2018-08-03 06:24:49 -07:00
|
|
|
|
|
|
|
use super::{Batch, ErrorKind, MessageContent, Result, Step};
|
|
|
|
use fault_log::{Fault, FaultKind, FaultLog};
|
2018-09-20 05:34:40 -07:00
|
|
|
use subset::{self as cs, Subset, SubsetOutput};
|
2018-08-03 06:24:49 -07:00
|
|
|
use threshold_decryption::{self as td, ThresholdDecryption};
|
2018-10-10 07:11:27 -07:00
|
|
|
use {Contribution, DistAlgorithm, NetworkInfo, NodeIdT};
|
2018-08-03 06:24:49 -07:00
|
|
|
|
2018-10-24 00:42:59 -07:00
|
|
|
type CsStep<N> = cs::Step<N, EpochId>;
|
|
|
|
|
2018-08-03 06:24:49 -07:00
|
|
|
/// The status of an encrypted contribution.
|
|
|
|
#[derive(Debug)]
|
|
|
|
enum DecryptionState<N> {
|
|
|
|
/// Decryption is still ongoing; we are waiting for decryption shares and/or ciphertext.
|
|
|
|
Ongoing(Box<ThresholdDecryption<N>>),
|
|
|
|
/// Decryption is complete. This contains the plaintext.
|
|
|
|
Complete(Vec<u8>),
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<N> DecryptionState<N>
|
|
|
|
where
|
2018-08-29 09:08:35 -07:00
|
|
|
N: NodeIdT + Rand,
|
2018-08-03 06:24:49 -07:00
|
|
|
{
|
|
|
|
/// Creates a new `ThresholdDecryption` instance, waiting for shares and a ciphertext.
|
|
|
|
fn new(netinfo: Arc<NetworkInfo<N>>) -> Self {
|
|
|
|
DecryptionState::Ongoing(Box::new(ThresholdDecryption::new(netinfo)))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Handles a message containing a decryption share.
|
|
|
|
fn handle_message(&mut self, sender_id: &N, msg: td::Message) -> td::Result<td::Step<N>> {
|
|
|
|
match self {
|
|
|
|
DecryptionState::Ongoing(ref mut td) => td.handle_message(sender_id, msg),
|
|
|
|
DecryptionState::Complete(_) => Ok(td::Step::default()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Handles a ciphertext input.
|
|
|
|
fn set_ciphertext(&mut self, ciphertext: Ciphertext) -> td::Result<td::Step<N>> {
|
|
|
|
match self {
|
2018-11-06 08:26:48 -08:00
|
|
|
DecryptionState::Ongoing(ref mut td) => {
|
|
|
|
td.set_ciphertext(ciphertext)?;
|
|
|
|
td.start_decryption()
|
|
|
|
}
|
2018-08-03 06:24:49 -07:00
|
|
|
DecryptionState::Complete(_) => Ok(td::Step::default()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The status of the subset algorithm.
|
|
|
|
#[derive(Debug)]
|
|
|
|
enum SubsetState<N: Rand> {
|
|
|
|
/// The algorithm is ongoing: the set of accepted contributions is still undecided.
|
2018-10-24 00:42:59 -07:00
|
|
|
Ongoing(Subset<N, EpochId>),
|
2018-08-03 06:24:49 -07:00
|
|
|
/// The algorithm is complete. This contains the set of accepted proposers.
|
|
|
|
Complete(BTreeSet<N>),
|
|
|
|
}
|
|
|
|
|
2018-08-08 02:11:53 -07:00
|
|
|
impl<N> SubsetState<N>
|
|
|
|
where
|
2018-08-29 09:08:35 -07:00
|
|
|
N: NodeIdT + Rand,
|
2018-08-08 02:11:53 -07:00
|
|
|
{
|
|
|
|
/// Provides input to the Subset instance, unless it has already completed.
|
2018-10-24 00:42:59 -07:00
|
|
|
fn handle_input(&mut self, proposal: Vec<u8>) -> Result<CsStep<N>> {
|
2018-08-08 02:11:53 -07:00
|
|
|
match self {
|
2018-08-29 08:28:02 -07:00
|
|
|
SubsetState::Ongoing(ref mut cs) => cs.handle_input(proposal),
|
2018-08-08 02:11:53 -07:00
|
|
|
SubsetState::Complete(_) => return Ok(cs::Step::default()),
|
2018-10-23 22:23:09 -07:00
|
|
|
}.map_err(|err| ErrorKind::InputSubset(err).into())
|
2018-08-08 02:11:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Handles a message in the Subset instance, unless it has already completed.
|
2018-10-24 00:42:59 -07:00
|
|
|
fn handle_message(&mut self, sender_id: &N, msg: cs::Message<N>) -> Result<CsStep<N>> {
|
2018-08-08 02:11:53 -07:00
|
|
|
match self {
|
|
|
|
SubsetState::Ongoing(ref mut cs) => cs.handle_message(sender_id, msg),
|
|
|
|
SubsetState::Complete(_) => return Ok(cs::Step::default()),
|
2018-10-23 22:23:09 -07:00
|
|
|
}.map_err(|err| ErrorKind::HandleSubsetMessage(err).into())
|
2018-08-08 02:11:53 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the number of contributions that we have already received or, after completion, how
|
|
|
|
/// many have been accepted.
|
|
|
|
pub fn received_proposals(&self) -> usize {
|
|
|
|
match self {
|
|
|
|
SubsetState::Ongoing(ref cs) => cs.received_proposals(),
|
|
|
|
SubsetState::Complete(ref proposer_ids) => proposer_ids.len(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the IDs of the accepted proposers, if that has already been decided.
|
|
|
|
pub fn accepted_ids(&self) -> Option<&BTreeSet<N>> {
|
|
|
|
match self {
|
|
|
|
SubsetState::Ongoing(_) => None,
|
|
|
|
SubsetState::Complete(ref ids) => Some(ids),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-29 18:46:42 -07:00
|
|
|
/// A flag used when constructing an `EpochState` to determine which behavior to use when receiving
|
|
|
|
/// proposals from a `Subset` instance.
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
pub enum SubsetHandlingStrategy {
|
2018-10-03 08:04:27 -07:00
|
|
|
/// Sets the `EpochState` to return proposals as they are contributed.
|
2018-09-29 18:46:42 -07:00
|
|
|
Incremental,
|
2018-10-03 08:04:27 -07:00
|
|
|
/// Sets the `EpochState` to return all received proposals once consensus has been finalized.
|
2018-09-29 18:46:42 -07:00
|
|
|
AllAtEnd,
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Used in an `EpochState` to encapsulate the state necessary to maintain each
|
|
|
|
/// `SubsetHandlingStrategy`.
|
|
|
|
#[derive(Debug, Clone)]
|
2018-10-03 08:04:27 -07:00
|
|
|
enum SubsetHandler<N> {
|
2018-09-29 18:46:42 -07:00
|
|
|
Incremental,
|
|
|
|
AllAtEnd(Vec<(N, Vec<u8>)>),
|
|
|
|
}
|
|
|
|
|
2018-10-03 08:04:27 -07:00
|
|
|
/// The result of a call to `SubsetHandler::handle(...)`.
|
|
|
|
struct SubsetHandleData<N> {
|
|
|
|
/// The number of contributions propagated from the handler.
|
2018-09-29 18:46:42 -07:00
|
|
|
contributions: Vec<(N, Vec<u8>)>,
|
2018-10-03 08:04:27 -07:00
|
|
|
/// Indicates whether the underlying `Subset` algorithm has achieved consensus and whether
|
|
|
|
/// there may be more contributions or not.
|
2018-09-29 18:46:42 -07:00
|
|
|
is_done: bool,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<N> SubsetHandler<N> {
|
|
|
|
fn handle(&mut self, o: SubsetOutput<N>) -> SubsetHandleData<N> {
|
|
|
|
use self::SubsetHandler::*;
|
|
|
|
use self::SubsetOutput::*;
|
|
|
|
let contributions;
|
|
|
|
let is_done;
|
|
|
|
match o {
|
|
|
|
Contribution(proposer_id, data) => {
|
|
|
|
let proposal = (proposer_id, data);
|
|
|
|
contributions = match self {
|
|
|
|
Incremental => vec![proposal],
|
|
|
|
AllAtEnd(cs) => {
|
|
|
|
cs.push(proposal);
|
|
|
|
vec![]
|
|
|
|
}
|
|
|
|
};
|
|
|
|
is_done = false;
|
|
|
|
}
|
|
|
|
Done => {
|
|
|
|
contributions = match self {
|
|
|
|
Incremental => vec![],
|
|
|
|
AllAtEnd(cs) => replace(cs, vec![]),
|
|
|
|
};
|
|
|
|
is_done = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SubsetHandleData {
|
|
|
|
contributions,
|
|
|
|
is_done,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<N> From<SubsetHandlingStrategy> for SubsetHandler<N> {
|
|
|
|
fn from(s: SubsetHandlingStrategy) -> Self {
|
|
|
|
use self::SubsetHandlingStrategy::*;
|
|
|
|
match s {
|
|
|
|
Incremental => SubsetHandler::Incremental,
|
|
|
|
AllAtEnd => SubsetHandler::AllAtEnd(Vec::new()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-03 06:24:49 -07:00
|
|
|
/// The sub-algorithms and their intermediate results for a single epoch.
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct EpochState<C, N: Rand> {
|
|
|
|
/// Our epoch number.
|
|
|
|
epoch: u64,
|
|
|
|
/// Shared network data.
|
|
|
|
netinfo: Arc<NetworkInfo<N>>,
|
|
|
|
/// The status of the subset algorithm.
|
|
|
|
subset: SubsetState<N>,
|
|
|
|
/// The status of threshold decryption, by proposer.
|
|
|
|
decryption: BTreeMap<N, DecryptionState<N>>,
|
2018-09-20 05:34:40 -07:00
|
|
|
/// Nodes found so far in `Subset` output.
|
|
|
|
accepted_proposers: BTreeSet<N>,
|
2018-09-29 18:46:42 -07:00
|
|
|
/// Determines the behavior upon receiving proposals from `subset`.
|
|
|
|
subset_handler: SubsetHandler<N>,
|
2018-10-23 21:21:59 -07:00
|
|
|
require_decryption: bool,
|
2018-08-03 06:24:49 -07:00
|
|
|
_phantom: PhantomData<C>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<C, N> EpochState<C, N>
|
|
|
|
where
|
2018-10-24 02:38:14 -07:00
|
|
|
C: Contribution + Serialize + DeserializeOwned,
|
2018-08-29 09:08:35 -07:00
|
|
|
N: NodeIdT + Rand,
|
2018-08-03 06:24:49 -07:00
|
|
|
{
|
2018-08-14 06:06:51 -07:00
|
|
|
/// Creates a new `Subset` instance.
|
2018-09-29 18:46:42 -07:00
|
|
|
pub fn new(
|
|
|
|
netinfo: Arc<NetworkInfo<N>>,
|
2018-10-24 00:42:59 -07:00
|
|
|
hb_id: u64,
|
2018-09-29 18:46:42 -07:00
|
|
|
epoch: u64,
|
|
|
|
subset_handling_strategy: SubsetHandlingStrategy,
|
2018-10-23 21:21:59 -07:00
|
|
|
require_decryption: bool,
|
2018-09-29 18:46:42 -07:00
|
|
|
) -> Result<Self> {
|
2018-10-24 00:42:59 -07:00
|
|
|
let epoch_id = EpochId { hb_id, epoch };
|
2018-11-01 03:22:40 -07:00
|
|
|
let cs = Subset::new(netinfo.clone(), epoch_id).map_err(ErrorKind::CreateSubset)?;
|
2018-08-03 06:24:49 -07:00
|
|
|
Ok(EpochState {
|
|
|
|
epoch,
|
|
|
|
netinfo,
|
|
|
|
subset: SubsetState::Ongoing(cs),
|
|
|
|
decryption: BTreeMap::default(),
|
2018-09-20 05:34:40 -07:00
|
|
|
accepted_proposers: Default::default(),
|
2018-09-29 18:46:42 -07:00
|
|
|
subset_handler: subset_handling_strategy.into(),
|
2018-10-23 22:12:12 -07:00
|
|
|
require_decryption,
|
2018-08-03 06:24:49 -07:00
|
|
|
_phantom: PhantomData,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// If the instance hasn't terminated yet, inputs our encrypted contribution.
|
2018-10-30 23:08:09 -07:00
|
|
|
pub fn propose<R: Rng>(&mut self, proposal: &C, rng: &mut R) -> Result<Step<C, N>> {
|
2018-10-25 11:38:16 -07:00
|
|
|
let ser_prop =
|
|
|
|
bincode::serialize(&proposal).map_err(|err| ErrorKind::ProposeBincode(*err))?;
|
2018-10-24 13:46:44 -07:00
|
|
|
let cs_step = self.subset.handle_input(if self.require_decryption {
|
|
|
|
let ciphertext = self
|
|
|
|
.netinfo
|
|
|
|
.public_key_set()
|
|
|
|
.public_key()
|
2018-10-25 11:38:16 -07:00
|
|
|
.encrypt_with_rng(rng, ser_prop);
|
2018-10-24 13:46:44 -07:00
|
|
|
bincode::serialize(&ciphertext).map_err(|err| ErrorKind::ProposeBincode(*err))?
|
|
|
|
} else {
|
2018-10-25 11:38:16 -07:00
|
|
|
ser_prop
|
2018-10-24 13:46:44 -07:00
|
|
|
})?;
|
2018-08-03 06:24:49 -07:00
|
|
|
self.process_subset(cs_step)
|
|
|
|
}
|
|
|
|
|
2018-08-08 02:11:53 -07:00
|
|
|
/// Returns the number of contributions that we have already received or, after completion, how
|
|
|
|
/// many have been accepted.
|
2018-08-03 06:24:49 -07:00
|
|
|
pub fn received_proposals(&self) -> usize {
|
2018-08-08 02:11:53 -07:00
|
|
|
self.subset.received_proposals()
|
2018-08-03 06:24:49 -07:00
|
|
|
}
|
|
|
|
|
2018-08-14 06:06:51 -07:00
|
|
|
/// Handles a message for the Subset or a Threshold Decryption instance.
|
2018-08-03 06:24:49 -07:00
|
|
|
pub fn handle_message_content(
|
|
|
|
&mut self,
|
|
|
|
sender_id: &N,
|
|
|
|
content: MessageContent<N>,
|
|
|
|
) -> Result<Step<C, N>> {
|
|
|
|
match content {
|
2018-08-14 06:06:51 -07:00
|
|
|
MessageContent::Subset(cs_msg) => {
|
2018-08-08 02:11:53 -07:00
|
|
|
let cs_step = self.subset.handle_message(sender_id, cs_msg)?;
|
2018-08-03 06:24:49 -07:00
|
|
|
self.process_subset(cs_step)
|
|
|
|
}
|
|
|
|
MessageContent::DecryptionShare { proposer_id, share } => {
|
2018-08-08 02:11:53 -07:00
|
|
|
if let Some(ref ids) = self.subset.accepted_ids() {
|
|
|
|
if !ids.contains(&proposer_id) {
|
2018-08-03 06:24:49 -07:00
|
|
|
let fault_kind = FaultKind::UnexpectedDecryptionShare;
|
|
|
|
return Ok(Fault::new(sender_id.clone(), fault_kind).into());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let td_step = match self.decryption.entry(proposer_id.clone()) {
|
|
|
|
Entry::Occupied(entry) => entry.into_mut(),
|
|
|
|
Entry::Vacant(entry) => {
|
|
|
|
entry.insert(DecryptionState::new(self.netinfo.clone()))
|
|
|
|
}
|
2018-10-23 22:23:09 -07:00
|
|
|
}.handle_message(sender_id, share)
|
2018-08-31 06:57:10 -07:00
|
|
|
.map_err(ErrorKind::ThresholdDecryption)?;
|
2018-08-03 06:24:49 -07:00
|
|
|
self.process_decryption(proposer_id, td_step)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// When contributions of transactions have been decrypted for all valid proposers in this
|
|
|
|
/// epoch, moves those contributions into a batch, outputs the batch and updates the epoch.
|
|
|
|
pub fn try_output_batch(&self) -> Option<(Batch<C, N>, FaultLog<N>)> {
|
2018-08-08 02:11:53 -07:00
|
|
|
let proposer_ids = self.subset.accepted_ids()?;
|
2018-10-18 03:13:43 -07:00
|
|
|
let mut plaintexts = Vec::new();
|
|
|
|
// Collect accepted plaintexts. Return if some are not decrypted yet.
|
|
|
|
for id in proposer_ids {
|
|
|
|
match self.decryption.get(id) {
|
|
|
|
None | Some(DecryptionState::Ongoing(_)) => return None,
|
|
|
|
Some(DecryptionState::Complete(ref pt)) => plaintexts.push((id.clone(), pt)),
|
|
|
|
}
|
2018-08-03 06:24:49 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut fault_log = FaultLog::default();
|
|
|
|
let mut batch = Batch {
|
|
|
|
epoch: self.epoch,
|
|
|
|
contributions: BTreeMap::new(),
|
|
|
|
};
|
|
|
|
// Deserialize the output. If it fails, the proposer of that item is faulty.
|
|
|
|
for (id, plaintext) in plaintexts {
|
|
|
|
match bincode::deserialize::<C>(plaintext) {
|
|
|
|
Ok(contrib) => {
|
|
|
|
batch.contributions.insert(id, contrib);
|
|
|
|
}
|
|
|
|
Err(_) => fault_log.append(id, FaultKind::BatchDeserializationFailed),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Some((batch, fault_log))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Checks whether the subset has output, and if it does, sends out our decryption shares.
|
2018-10-24 00:42:59 -07:00
|
|
|
fn process_subset(&mut self, cs_step: CsStep<N>) -> Result<Step<C, N>> {
|
2018-08-03 06:24:49 -07:00
|
|
|
let mut step = Step::default();
|
2018-10-25 05:44:28 -07:00
|
|
|
let cs_outputs = step.extend_with(cs_step, |cs_msg| {
|
2018-08-14 06:06:51 -07:00
|
|
|
MessageContent::Subset(cs_msg).with_epoch(self.epoch)
|
2018-08-03 06:24:49 -07:00
|
|
|
});
|
2018-09-20 05:34:40 -07:00
|
|
|
let mut has_seen_done = false;
|
|
|
|
for cs_output in cs_outputs {
|
|
|
|
if has_seen_done {
|
2018-11-01 03:22:40 -07:00
|
|
|
// TODO: Is there any way we can statically guarantee that?
|
2018-09-20 05:34:40 -07:00
|
|
|
error!("`SubsetOutput::Done` was not the last `SubsetOutput`");
|
|
|
|
}
|
|
|
|
|
2018-09-29 18:46:42 -07:00
|
|
|
let SubsetHandleData {
|
|
|
|
contributions,
|
|
|
|
is_done,
|
|
|
|
} = self.subset_handler.handle(cs_output);
|
|
|
|
|
|
|
|
for (k, v) in contributions {
|
2018-10-23 21:21:59 -07:00
|
|
|
step.extend(if self.require_decryption {
|
|
|
|
self.send_decryption_share(k.clone(), &v)?
|
|
|
|
} else {
|
2018-10-25 11:39:00 -07:00
|
|
|
self.decryption
|
|
|
|
.insert(k.clone(), DecryptionState::Complete(v));
|
2018-10-25 11:38:16 -07:00
|
|
|
Step::default()
|
2018-10-23 21:21:59 -07:00
|
|
|
});
|
2018-09-29 18:46:42 -07:00
|
|
|
self.accepted_proposers.insert(k);
|
|
|
|
}
|
|
|
|
|
|
|
|
if is_done {
|
|
|
|
self.subset = SubsetState::Complete(self.accepted_proposers.clone());
|
|
|
|
let faulty_shares: Vec<_> = self
|
|
|
|
.decryption
|
|
|
|
.keys()
|
|
|
|
.filter(|id| !self.accepted_proposers.contains(id))
|
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
for id in faulty_shares {
|
|
|
|
if let Some(DecryptionState::Ongoing(td)) = self.decryption.remove(&id) {
|
|
|
|
for id in td.sender_ids() {
|
|
|
|
let fault_kind = FaultKind::UnexpectedDecryptionShare;
|
|
|
|
step.fault_log.append(id.clone(), fault_kind);
|
2018-09-20 05:34:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-09-29 18:46:42 -07:00
|
|
|
has_seen_done = true;
|
2018-09-20 05:34:40 -07:00
|
|
|
}
|
2018-08-03 06:24:49 -07:00
|
|
|
}
|
|
|
|
Ok(step)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Processes a Threshold Decryption step.
|
|
|
|
fn process_decryption(&mut self, proposer_id: N, td_step: td::Step<N>) -> Result<Step<C, N>> {
|
|
|
|
let mut step = Step::default();
|
|
|
|
let opt_output = step.extend_with(td_step, |share| {
|
|
|
|
MessageContent::DecryptionShare {
|
|
|
|
proposer_id: proposer_id.clone(),
|
|
|
|
share,
|
2018-10-23 22:23:09 -07:00
|
|
|
}.with_epoch(self.epoch)
|
2018-08-03 06:24:49 -07:00
|
|
|
});
|
|
|
|
if let Some(output) = opt_output.into_iter().next() {
|
|
|
|
self.decryption
|
|
|
|
.insert(proposer_id, DecryptionState::Complete(output));
|
|
|
|
}
|
|
|
|
Ok(step)
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Given the output of the Subset algorithm, inputs the ciphertexts into the Threshold
|
|
|
|
/// Decryption instances and sends our own decryption shares.
|
2018-09-20 05:34:40 -07:00
|
|
|
fn send_decryption_share(&mut self, proposer_id: N, v: &[u8]) -> Result<Step<C, N>> {
|
|
|
|
let ciphertext: Ciphertext = match bincode::deserialize(v) {
|
|
|
|
Ok(ciphertext) => ciphertext,
|
2018-11-01 03:22:40 -07:00
|
|
|
Err(_) => {
|
|
|
|
return Ok(Fault::new(proposer_id, FaultKind::DeserializeCiphertext).into());
|
2018-08-03 06:24:49 -07:00
|
|
|
}
|
2018-09-20 05:34:40 -07:00
|
|
|
};
|
|
|
|
let td_result = match self.decryption.entry(proposer_id.clone()) {
|
|
|
|
Entry::Occupied(entry) => entry.into_mut(),
|
|
|
|
Entry::Vacant(entry) => entry.insert(DecryptionState::new(self.netinfo.clone())),
|
2018-10-23 22:23:09 -07:00
|
|
|
}.set_ciphertext(ciphertext);
|
2018-09-20 05:34:40 -07:00
|
|
|
match td_result {
|
|
|
|
Ok(td_step) => self.process_decryption(proposer_id, td_step),
|
|
|
|
Err(td::Error::InvalidCiphertext(_)) => {
|
2018-11-01 03:22:40 -07:00
|
|
|
Ok(Fault::new(proposer_id, FaultKind::InvalidCiphertext).into())
|
2018-08-03 06:24:49 -07:00
|
|
|
}
|
2018-09-20 05:34:40 -07:00
|
|
|
Err(err) => Err(ErrorKind::ThresholdDecryption(err).into()),
|
2018-08-03 06:24:49 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-10-24 00:42:59 -07:00
|
|
|
|
|
|
|
/// A session identifier for a `Subset` sub-algorithm run within an epoch. It consists of the epoch
|
|
|
|
/// number, and an optional `HoneyBadger` session identifier.
|
|
|
|
#[derive(Clone, Debug, Serialize)]
|
|
|
|
struct EpochId {
|
|
|
|
hb_id: u64,
|
|
|
|
epoch: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Display for EpochId {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
|
|
|
|
write!(f, "{}/{}", self.hb_id, self.epoch)
|
|
|
|
}
|
|
|
|
}
|