mirror of https://github.com/poanetwork/hbbft.git
Merge pull request #178 from poanetwork/afck-hb-split
Split honey_badger into submodules.
This commit is contained in:
commit
b3e1452a3a
|
@ -0,0 +1,49 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
|
/// A batch of contributions the algorithm has output.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct Batch<C, NodeUid> {
|
||||||
|
pub epoch: u64,
|
||||||
|
pub contributions: BTreeMap<NodeUid, C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, NodeUid: Ord> Batch<C, NodeUid> {
|
||||||
|
/// Returns an iterator over references to all transactions included in the batch.
|
||||||
|
pub fn iter<'a>(&'a self) -> impl Iterator<Item = <&'a C as IntoIterator>::Item>
|
||||||
|
where
|
||||||
|
&'a C: IntoIterator,
|
||||||
|
{
|
||||||
|
self.contributions.values().flat_map(|item| item)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns an iterator over all transactions included in the batch. Consumes the batch.
|
||||||
|
pub fn into_tx_iter(self) -> impl Iterator<Item = <C as IntoIterator>::Item>
|
||||||
|
where
|
||||||
|
C: IntoIterator,
|
||||||
|
{
|
||||||
|
self.contributions.into_iter().flat_map(|(_, vec)| vec)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of transactions in the batch (without detecting duplicates).
|
||||||
|
pub fn len<Tx>(&self) -> usize
|
||||||
|
where
|
||||||
|
C: AsRef<[Tx]>,
|
||||||
|
{
|
||||||
|
self.contributions
|
||||||
|
.values()
|
||||||
|
.map(C::as_ref)
|
||||||
|
.map(<[Tx]>::len)
|
||||||
|
.sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns `true` if the batch contains no transactions.
|
||||||
|
pub fn is_empty<Tx>(&self) -> bool
|
||||||
|
where
|
||||||
|
C: AsRef<[Tx]>,
|
||||||
|
{
|
||||||
|
self.contributions
|
||||||
|
.values()
|
||||||
|
.map(C::as_ref)
|
||||||
|
.all(<[Tx]>::is_empty)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::hash::Hash;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use rand::Rand;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::HoneyBadger;
|
||||||
|
use messaging::NetworkInfo;
|
||||||
|
|
||||||
|
/// A Honey Badger builder, to configure the parameters and create new instances of `HoneyBadger`.
|
||||||
|
pub struct HoneyBadgerBuilder<C, NodeUid> {
|
||||||
|
/// Shared network data.
|
||||||
|
netinfo: Arc<NetworkInfo<NodeUid>>,
|
||||||
|
/// The maximum number of future epochs for which we handle messages simultaneously.
|
||||||
|
max_future_epochs: usize,
|
||||||
|
_phantom: PhantomData<C>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, NodeUid> HoneyBadgerBuilder<C, NodeUid>
|
||||||
|
where
|
||||||
|
C: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
|
||||||
|
NodeUid: Ord + Clone + Debug + Rand,
|
||||||
|
{
|
||||||
|
/// Returns a new `HoneyBadgerBuilder` configured to use the node IDs and cryptographic keys
|
||||||
|
/// specified by `netinfo`.
|
||||||
|
pub fn new(netinfo: Arc<NetworkInfo<NodeUid>>) -> Self {
|
||||||
|
HoneyBadgerBuilder {
|
||||||
|
netinfo,
|
||||||
|
max_future_epochs: 3,
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the maximum number of future epochs for which we handle messages simultaneously.
|
||||||
|
pub fn max_future_epochs(&mut self, max_future_epochs: usize) -> &mut Self {
|
||||||
|
self.max_future_epochs = max_future_epochs;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a new Honey Badger instance.
|
||||||
|
pub fn build(&self) -> HoneyBadger<C, NodeUid> {
|
||||||
|
HoneyBadger {
|
||||||
|
netinfo: self.netinfo.clone(),
|
||||||
|
epoch: 0,
|
||||||
|
has_input: false,
|
||||||
|
common_subsets: BTreeMap::new(),
|
||||||
|
max_future_epochs: self.max_future_epochs as u64,
|
||||||
|
incoming_queue: BTreeMap::new(),
|
||||||
|
received_shares: BTreeMap::new(),
|
||||||
|
decrypted_contributions: BTreeMap::new(),
|
||||||
|
ciphertexts: BTreeMap::new(),
|
||||||
|
_phantom: PhantomData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,67 @@
|
||||||
|
use std::fmt::{self, Display, Formatter};
|
||||||
|
|
||||||
|
use bincode;
|
||||||
|
use failure::{Backtrace, Context, Fail};
|
||||||
|
|
||||||
|
use common_subset;
|
||||||
|
|
||||||
|
/// Honey badger error variants.
|
||||||
|
#[derive(Debug, Fail)]
|
||||||
|
pub enum ErrorKind {
|
||||||
|
#[fail(display = "ProposeBincode error: {}", _0)]
|
||||||
|
ProposeBincode(bincode::ErrorKind),
|
||||||
|
#[fail(display = "ProposeCommonSubset0 error: {}", _0)]
|
||||||
|
ProposeCommonSubset0(common_subset::Error),
|
||||||
|
#[fail(display = "ProposeCommonSubset1 error: {}", _0)]
|
||||||
|
ProposeCommonSubset1(common_subset::Error),
|
||||||
|
#[fail(display = "HandleCommonMessageCommonSubset0 error: {}", _0)]
|
||||||
|
HandleCommonMessageCommonSubset0(common_subset::Error),
|
||||||
|
#[fail(display = "HandleCommonMessageCommonSubset1 error: {}", _0)]
|
||||||
|
HandleCommonMessageCommonSubset1(common_subset::Error),
|
||||||
|
#[fail(display = "Unknown sender")]
|
||||||
|
UnknownSender,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A honey badger error.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Error {
|
||||||
|
inner: Context<ErrorKind>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Fail for Error {
|
||||||
|
fn cause(&self) -> Option<&Fail> {
|
||||||
|
self.inner.cause()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn backtrace(&self) -> Option<&Backtrace> {
|
||||||
|
self.inner.backtrace()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub fn kind(&self) -> &ErrorKind {
|
||||||
|
self.inner.get_context()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ErrorKind> for Error {
|
||||||
|
fn from(kind: ErrorKind) -> Error {
|
||||||
|
Error {
|
||||||
|
inner: Context::new(kind),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Context<ErrorKind>> for Error {
|
||||||
|
fn from(inner: Context<ErrorKind>) -> Error {
|
||||||
|
Error { inner }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||||
|
Display::fmt(&self.inner, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Result<T> = ::std::result::Result<T, Error>;
|
|
@ -1,31 +1,6 @@
|
||||||
//! # Honey Badger
|
|
||||||
//!
|
|
||||||
//! Honey Badger allows a network of _N_ nodes with at most _f_ faulty ones,
|
|
||||||
//! where _3 f < N_, to input "contributions" - any kind of data -, and to agree on a sequence of
|
|
||||||
//! _batches_ of contributions. The protocol proceeds in _epochs_, starting at number 0, and outputs
|
|
||||||
//! one batch in each epoch. It never terminates: It handles a continuous stream of incoming
|
|
||||||
//! contributions and keeps producing new batches from them. All correct nodes will output the same
|
|
||||||
//! batch for each epoch. Each validator proposes one contribution per epoch, and every batch will
|
|
||||||
//! contain the contributions of at least _N - f_ validators.
|
|
||||||
//!
|
|
||||||
//! ## How it works
|
|
||||||
//!
|
|
||||||
//! In every epoch, every validator encrypts their contribution and proposes it to the others.
|
|
||||||
//! A `CommonSubset` instance determines which proposals are accepted and will be part of the new
|
|
||||||
//! batch. Using threshold encryption, the nodes collaboratively decrypt all accepted
|
|
||||||
//! contributions. Invalid contributions (that e.g. cannot be deserialized) are discarded - their
|
|
||||||
//! proposers must be faulty -, and the remaining ones are output as the new batch. The next epoch
|
|
||||||
//! begins as soon as the validators propose new contributions again.
|
|
||||||
//!
|
|
||||||
//! So it is essentially an endlessly repeating `CommonSubset`, but with the proposed values
|
|
||||||
//! encrypted. The encryption makes it harder for an attacker to try and censor a particular value
|
|
||||||
//! by influencing the set of proposals that make it into the common subset, because they don't
|
|
||||||
//! know the decrypted values before the subset is determined.
|
|
||||||
|
|
||||||
use rand::Rand;
|
|
||||||
use std::collections::btree_map::Entry;
|
use std::collections::btree_map::Entry;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::fmt::{self, Debug, Display};
|
use std::fmt::Debug;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
@ -33,147 +8,41 @@ use std::sync::Arc;
|
||||||
|
|
||||||
use bincode;
|
use bincode;
|
||||||
use crypto::{Ciphertext, DecryptionShare};
|
use crypto::{Ciphertext, DecryptionShare};
|
||||||
use failure::{Backtrace, Context, Fail};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use rand::Rand;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
use super::{Batch, Error, ErrorKind, HoneyBadgerBuilder, Message, MessageContent, Result};
|
||||||
use common_subset::{self, CommonSubset};
|
use common_subset::{self, CommonSubset};
|
||||||
use fault_log::{Fault, FaultKind, FaultLog};
|
use fault_log::{Fault, FaultKind, FaultLog};
|
||||||
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
|
use messaging::{self, DistAlgorithm, NetworkInfo, Target};
|
||||||
|
|
||||||
/// Honey badger error variants.
|
|
||||||
#[derive(Debug, Fail)]
|
|
||||||
pub enum ErrorKind {
|
|
||||||
#[fail(display = "ProposeBincode error: {}", _0)]
|
|
||||||
ProposeBincode(bincode::ErrorKind),
|
|
||||||
#[fail(display = "ProposeCommonSubset0 error: {}", _0)]
|
|
||||||
ProposeCommonSubset0(common_subset::Error),
|
|
||||||
#[fail(display = "ProposeCommonSubset1 error: {}", _0)]
|
|
||||||
ProposeCommonSubset1(common_subset::Error),
|
|
||||||
#[fail(display = "HandleCommonMessageCommonSubset0 error: {}", _0)]
|
|
||||||
HandleCommonMessageCommonSubset0(common_subset::Error),
|
|
||||||
#[fail(display = "HandleCommonMessageCommonSubset1 error: {}", _0)]
|
|
||||||
HandleCommonMessageCommonSubset1(common_subset::Error),
|
|
||||||
#[fail(display = "Unknown sender")]
|
|
||||||
UnknownSender,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A honey badger error.
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Error {
|
|
||||||
inner: Context<ErrorKind>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Fail for Error {
|
|
||||||
fn cause(&self) -> Option<&Fail> {
|
|
||||||
self.inner.cause()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn backtrace(&self) -> Option<&Backtrace> {
|
|
||||||
self.inner.backtrace()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error {
|
|
||||||
pub fn kind(&self) -> &ErrorKind {
|
|
||||||
self.inner.get_context()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ErrorKind> for Error {
|
|
||||||
fn from(kind: ErrorKind) -> Error {
|
|
||||||
Error {
|
|
||||||
inner: Context::new(kind),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<Context<ErrorKind>> for Error {
|
|
||||||
fn from(inner: Context<ErrorKind>) -> Error {
|
|
||||||
Error { inner }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for Error {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
Display::fmt(&self.inner, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type Result<T> = ::std::result::Result<T, Error>;
|
|
||||||
|
|
||||||
/// A Honey Badger builder, to configure the parameters and create new instances of `HoneyBadger`.
|
|
||||||
pub struct HoneyBadgerBuilder<C, NodeUid> {
|
|
||||||
/// Shared network data.
|
|
||||||
netinfo: Arc<NetworkInfo<NodeUid>>,
|
|
||||||
/// The maximum number of future epochs for which we handle messages simultaneously.
|
|
||||||
max_future_epochs: usize,
|
|
||||||
_phantom: PhantomData<C>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, NodeUid> HoneyBadgerBuilder<C, NodeUid>
|
|
||||||
where
|
|
||||||
C: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
|
|
||||||
NodeUid: Ord + Clone + Debug + Rand,
|
|
||||||
{
|
|
||||||
/// Returns a new `HoneyBadgerBuilder` configured to use the node IDs and cryptographic keys
|
|
||||||
/// specified by `netinfo`.
|
|
||||||
pub fn new(netinfo: Arc<NetworkInfo<NodeUid>>) -> Self {
|
|
||||||
HoneyBadgerBuilder {
|
|
||||||
netinfo,
|
|
||||||
max_future_epochs: 3,
|
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets the maximum number of future epochs for which we handle messages simultaneously.
|
|
||||||
pub fn max_future_epochs(&mut self, max_future_epochs: usize) -> &mut Self {
|
|
||||||
self.max_future_epochs = max_future_epochs;
|
|
||||||
self
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new Honey Badger instance.
|
|
||||||
pub fn build(&self) -> HoneyBadger<C, NodeUid> {
|
|
||||||
HoneyBadger {
|
|
||||||
netinfo: self.netinfo.clone(),
|
|
||||||
epoch: 0,
|
|
||||||
has_input: false,
|
|
||||||
common_subsets: BTreeMap::new(),
|
|
||||||
max_future_epochs: self.max_future_epochs as u64,
|
|
||||||
incoming_queue: BTreeMap::new(),
|
|
||||||
received_shares: BTreeMap::new(),
|
|
||||||
decrypted_contributions: BTreeMap::new(),
|
|
||||||
ciphertexts: BTreeMap::new(),
|
|
||||||
_phantom: PhantomData,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// An instance of the Honey Badger Byzantine fault tolerant consensus algorithm.
|
/// An instance of the Honey Badger Byzantine fault tolerant consensus algorithm.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct HoneyBadger<C, NodeUid: Rand> {
|
pub struct HoneyBadger<C, NodeUid: Rand> {
|
||||||
/// Shared network data.
|
/// Shared network data.
|
||||||
netinfo: Arc<NetworkInfo<NodeUid>>,
|
pub(super) netinfo: Arc<NetworkInfo<NodeUid>>,
|
||||||
/// The earliest epoch from which we have not yet received output.
|
/// The earliest epoch from which we have not yet received output.
|
||||||
epoch: u64,
|
pub(super) epoch: u64,
|
||||||
/// Whether we have already submitted a proposal for the current epoch.
|
/// Whether we have already submitted a proposal for the current epoch.
|
||||||
has_input: bool,
|
pub(super) has_input: bool,
|
||||||
/// The Asynchronous Common Subset instance that decides which nodes' transactions to include,
|
/// The Asynchronous Common Subset instance that decides which nodes' transactions to include,
|
||||||
/// indexed by epoch.
|
/// indexed by epoch.
|
||||||
common_subsets: BTreeMap<u64, CommonSubset<NodeUid>>,
|
pub(super) common_subsets: BTreeMap<u64, CommonSubset<NodeUid>>,
|
||||||
/// The maximum number of `CommonSubset` instances that we run simultaneously.
|
/// The maximum number of `CommonSubset` instances that we run simultaneously.
|
||||||
max_future_epochs: u64,
|
pub(super) max_future_epochs: u64,
|
||||||
/// Messages for future epochs that couldn't be handled yet.
|
/// Messages for future epochs that couldn't be handled yet.
|
||||||
incoming_queue: BTreeMap<u64, Vec<(NodeUid, MessageContent<NodeUid>)>>,
|
pub(super) incoming_queue: BTreeMap<u64, Vec<(NodeUid, MessageContent<NodeUid>)>>,
|
||||||
/// Received decryption shares for an epoch. Each decryption share has a sender and a
|
/// Received decryption shares for an epoch. Each decryption share has a sender and a
|
||||||
/// proposer. The outer `BTreeMap` has epochs as its key. The next `BTreeMap` has proposers as
|
/// proposer. The outer `BTreeMap` has epochs as its key. The next `BTreeMap` has proposers as
|
||||||
/// its key. The inner `BTreeMap` has the sender as its key.
|
/// its key. The inner `BTreeMap` has the sender as its key.
|
||||||
received_shares: BTreeMap<u64, BTreeMap<NodeUid, BTreeMap<NodeUid, DecryptionShare>>>,
|
pub(super) received_shares:
|
||||||
|
BTreeMap<u64, BTreeMap<NodeUid, BTreeMap<NodeUid, DecryptionShare>>>,
|
||||||
/// Decoded accepted proposals.
|
/// Decoded accepted proposals.
|
||||||
decrypted_contributions: BTreeMap<NodeUid, Vec<u8>>,
|
pub(super) decrypted_contributions: BTreeMap<NodeUid, Vec<u8>>,
|
||||||
/// Ciphertexts output by Common Subset in an epoch.
|
/// Ciphertexts output by Common Subset in an epoch.
|
||||||
ciphertexts: BTreeMap<u64, BTreeMap<NodeUid, Ciphertext>>,
|
pub(super) ciphertexts: BTreeMap<u64, BTreeMap<NodeUid, Ciphertext>>,
|
||||||
_phantom: PhantomData<C>,
|
pub(super) _phantom: PhantomData<C>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Step<C, NodeUid> = messaging::Step<HoneyBadger<C, NodeUid>>;
|
pub type Step<C, NodeUid> = messaging::Step<HoneyBadger<C, NodeUid>>;
|
||||||
|
@ -631,85 +500,3 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A batch of contributions the algorithm has output.
|
|
||||||
#[derive(Clone, Debug)]
|
|
||||||
pub struct Batch<C, NodeUid> {
|
|
||||||
pub epoch: u64,
|
|
||||||
pub contributions: BTreeMap<NodeUid, C>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<C, NodeUid: Ord> Batch<C, NodeUid> {
|
|
||||||
/// Returns an iterator over references to all transactions included in the batch.
|
|
||||||
pub fn iter<'a>(&'a self) -> impl Iterator<Item = <&'a C as IntoIterator>::Item>
|
|
||||||
where
|
|
||||||
&'a C: IntoIterator,
|
|
||||||
{
|
|
||||||
self.contributions.values().flat_map(|item| item)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an iterator over all transactions included in the batch. Consumes the batch.
|
|
||||||
pub fn into_tx_iter(self) -> impl Iterator<Item = <C as IntoIterator>::Item>
|
|
||||||
where
|
|
||||||
C: IntoIterator,
|
|
||||||
{
|
|
||||||
self.contributions.into_iter().flat_map(|(_, vec)| vec)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of transactions in the batch (without detecting duplicates).
|
|
||||||
pub fn len<Tx>(&self) -> usize
|
|
||||||
where
|
|
||||||
C: AsRef<[Tx]>,
|
|
||||||
{
|
|
||||||
self.contributions
|
|
||||||
.values()
|
|
||||||
.map(C::as_ref)
|
|
||||||
.map(<[Tx]>::len)
|
|
||||||
.sum()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns `true` if the batch contains no transactions.
|
|
||||||
pub fn is_empty<Tx>(&self) -> bool
|
|
||||||
where
|
|
||||||
C: AsRef<[Tx]>,
|
|
||||||
{
|
|
||||||
self.contributions
|
|
||||||
.values()
|
|
||||||
.map(C::as_ref)
|
|
||||||
.all(<[Tx]>::is_empty)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The content of a `HoneyBadger` message. It should be further annotated with an epoch.
|
|
||||||
#[derive(Clone, Debug, Deserialize, Rand, Serialize)]
|
|
||||||
pub enum MessageContent<NodeUid: Rand> {
|
|
||||||
/// A message belonging to the common subset algorithm in the given epoch.
|
|
||||||
CommonSubset(common_subset::Message<NodeUid>),
|
|
||||||
/// A decrypted share of the output of `proposer_id`.
|
|
||||||
DecryptionShare {
|
|
||||||
proposer_id: NodeUid,
|
|
||||||
share: DecryptionShare,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<NodeUid: Rand> MessageContent<NodeUid> {
|
|
||||||
pub fn with_epoch(self, epoch: u64) -> Message<NodeUid> {
|
|
||||||
Message {
|
|
||||||
epoch,
|
|
||||||
content: self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A message sent to or received from another node's Honey Badger instance.
|
|
||||||
#[derive(Clone, Debug, Deserialize, Rand, Serialize)]
|
|
||||||
pub struct Message<NodeUid: Rand> {
|
|
||||||
epoch: u64,
|
|
||||||
content: MessageContent<NodeUid>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<NodeUid: Rand> Message<NodeUid> {
|
|
||||||
pub fn epoch(&self) -> u64 {
|
|
||||||
self.epoch
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
use crypto::DecryptionShare;
|
||||||
|
use rand::Rand;
|
||||||
|
|
||||||
|
use common_subset;
|
||||||
|
|
||||||
|
/// The content of a `HoneyBadger` message. It should be further annotated with an epoch.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Rand, Serialize)]
|
||||||
|
pub enum MessageContent<NodeUid: Rand> {
|
||||||
|
/// A message belonging to the common subset algorithm in the given epoch.
|
||||||
|
CommonSubset(common_subset::Message<NodeUid>),
|
||||||
|
/// A decrypted share of the output of `proposer_id`.
|
||||||
|
DecryptionShare {
|
||||||
|
proposer_id: NodeUid,
|
||||||
|
share: DecryptionShare,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<NodeUid: Rand> MessageContent<NodeUid> {
|
||||||
|
pub fn with_epoch(self, epoch: u64) -> Message<NodeUid> {
|
||||||
|
Message {
|
||||||
|
epoch,
|
||||||
|
content: self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A message sent to or received from another node's Honey Badger instance.
|
||||||
|
#[derive(Clone, Debug, Deserialize, Rand, Serialize)]
|
||||||
|
pub struct Message<NodeUid: Rand> {
|
||||||
|
pub(super) epoch: u64,
|
||||||
|
pub(super) content: MessageContent<NodeUid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<NodeUid: Rand> Message<NodeUid> {
|
||||||
|
pub fn epoch(&self) -> u64 {
|
||||||
|
self.epoch
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
//! # Honey Badger
|
||||||
|
//!
|
||||||
|
//! Honey Badger allows a network of _N_ nodes with at most _f_ faulty ones,
|
||||||
|
//! where _3 f < N_, to input "contributions" - any kind of data -, and to agree on a sequence of
|
||||||
|
//! _batches_ of contributions. The protocol proceeds in _epochs_, starting at number 0, and outputs
|
||||||
|
//! one batch in each epoch. It never terminates: It handles a continuous stream of incoming
|
||||||
|
//! contributions and keeps producing new batches from them. All correct nodes will output the same
|
||||||
|
//! batch for each epoch. Each validator proposes one contribution per epoch, and every batch will
|
||||||
|
//! contain the contributions of at least _N - f_ validators.
|
||||||
|
//!
|
||||||
|
//! ## How it works
|
||||||
|
//!
|
||||||
|
//! In every epoch, every validator encrypts their contribution and proposes it to the others.
|
||||||
|
//! A `CommonSubset` instance determines which proposals are accepted and will be part of the new
|
||||||
|
//! batch. Using threshold encryption, the nodes collaboratively decrypt all accepted
|
||||||
|
//! contributions. Invalid contributions (that e.g. cannot be deserialized) are discarded - their
|
||||||
|
//! proposers must be faulty -, and the remaining ones are output as the new batch. The next epoch
|
||||||
|
//! begins as soon as the validators propose new contributions again.
|
||||||
|
//!
|
||||||
|
//! So it is essentially an endlessly repeating `CommonSubset`, but with the proposed values
|
||||||
|
//! encrypted. The encryption makes it harder for an attacker to try and censor a particular value
|
||||||
|
//! by influencing the set of proposals that make it into the common subset, because they don't
|
||||||
|
//! know the decrypted values before the subset is determined.
|
||||||
|
|
||||||
|
mod batch;
|
||||||
|
mod builder;
|
||||||
|
mod error;
|
||||||
|
mod honey_badger;
|
||||||
|
mod message;
|
||||||
|
|
||||||
|
pub use self::batch::Batch;
|
||||||
|
pub use self::builder::HoneyBadgerBuilder;
|
||||||
|
pub use self::error::{Error, ErrorKind, Result};
|
||||||
|
pub use self::honey_badger::{HoneyBadger, Step};
|
||||||
|
pub use self::message::{Message, MessageContent};
|
|
@ -100,6 +100,8 @@
|
||||||
|
|
||||||
// TODO: Remove this once https://github.com/rust-lang-nursery/error-chain/issues/245 is resolved.
|
// TODO: Remove this once https://github.com/rust-lang-nursery/error-chain/issues/245 is resolved.
|
||||||
#![allow(renamed_and_removed_lints)]
|
#![allow(renamed_and_removed_lints)]
|
||||||
|
// We put algorithm structs in `src/algorithm/algorithm.rs`.
|
||||||
|
#![cfg_attr(feature = "cargo-clippy", allow(module_inception))]
|
||||||
|
|
||||||
extern crate bincode;
|
extern crate bincode;
|
||||||
extern crate byteorder;
|
extern crate byteorder;
|
||||||
|
|
Loading…
Reference in New Issue