mirror of https://github.com/poanetwork/hbbft.git
Remove non-threshold keys from NetworkInfo.
This commit is contained in:
parent
66033a9f7f
commit
0e50c2f473
|
@ -32,7 +32,7 @@ log = "0.4.6"
|
||||||
rand = "0.6.5"
|
rand = "0.6.5"
|
||||||
rand_derive = "0.5.0"
|
rand_derive = "0.5.0"
|
||||||
reed-solomon-erasure = "3.1.1"
|
reed-solomon-erasure = "3.1.1"
|
||||||
serde = { version = "1.0.89", features = ["derive"] }
|
serde = { version = "1.0.89", features = ["derive", "rc"] }
|
||||||
threshold_crypto = "0.3.1"
|
threshold_crypto = "0.3.1"
|
||||||
tiny-keccak = "1.4"
|
tiny-keccak = "1.4"
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,11 @@ use rand_derive::Rand;
|
||||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||||
use signifix::metric;
|
use signifix::metric;
|
||||||
|
|
||||||
|
use hbbft::crypto::SecretKey;
|
||||||
use hbbft::dynamic_honey_badger::DynamicHoneyBadger;
|
use hbbft::dynamic_honey_badger::DynamicHoneyBadger;
|
||||||
use hbbft::queueing_honey_badger::{Batch, QueueingHoneyBadger};
|
use hbbft::queueing_honey_badger::{Batch, QueueingHoneyBadger};
|
||||||
use hbbft::sender_queue::{Message, SenderQueue};
|
use hbbft::sender_queue::{Message, SenderQueue};
|
||||||
use hbbft::{ConsensusProtocol, CpStep, NetworkInfo, Step, Target};
|
use hbbft::{to_pub_keys, ConsensusProtocol, CpStep, NetworkInfo, PubKeyMap, Step, Target};
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
const USAGE: &str = "
|
const USAGE: &str = "
|
||||||
|
@ -247,13 +248,19 @@ where
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> TestNetwork<D>
|
) -> TestNetwork<D>
|
||||||
where
|
where
|
||||||
F: Fn(NetworkInfo<NodeId>, &mut R) -> (D, CpStep<D>),
|
F: Fn(NetworkInfo<NodeId>, SecretKey, PubKeyMap<NodeId>, &mut R) -> (D, CpStep<D>),
|
||||||
{
|
{
|
||||||
let node_ids = (0..(good_num + adv_num)).map(NodeId);
|
let node_ids = (0..(good_num + adv_num)).map(NodeId);
|
||||||
let netinfos =
|
|
||||||
NetworkInfo::generate_map(node_ids, rng).expect("Failed to create `NetworkInfo` map");
|
// Generate keys for signing and encrypting messages, and for threshold cryptography.
|
||||||
|
let sec_keys: BTreeMap<_, SecretKey> = node_ids.map(|id| (id, rng.gen())).collect();
|
||||||
|
let pub_keys = to_pub_keys(&sec_keys);
|
||||||
|
let netinfos = NetworkInfo::generate_map(pub_keys.keys().cloned(), rng)
|
||||||
|
.expect("Failed to create `NetworkInfo` map");
|
||||||
|
|
||||||
let new_node = |(id, netinfo): (NodeId, NetworkInfo<_>)| {
|
let new_node = |(id, netinfo): (NodeId, NetworkInfo<_>)| {
|
||||||
(id, TestNode::new(new_algo(netinfo, rng), hw_quality))
|
let algo = new_algo(netinfo, sec_keys[&id].clone(), pub_keys.clone(), rng);
|
||||||
|
(id, TestNode::new(algo, hw_quality))
|
||||||
};
|
};
|
||||||
let mut network = TestNetwork {
|
let mut network = TestNetwork {
|
||||||
nodes: netinfos.into_iter().map(new_node).collect(),
|
nodes: netinfos.into_iter().map(new_node).collect(),
|
||||||
|
@ -416,10 +423,10 @@ fn main() {
|
||||||
.map(|_| rng.sample_iter(&Standard).take(args.flag_tx_size).collect())
|
.map(|_| rng.sample_iter(&Standard).take(args.flag_tx_size).collect())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let new_honey_badger = |netinfo: NetworkInfo<NodeId>, rng: &mut OsRng| {
|
let new_honey_badger = |netinfo: NetworkInfo<NodeId>, secret_key, pub_keys, rng: &mut OsRng| {
|
||||||
let our_id = *netinfo.our_id();
|
let our_id = *netinfo.our_id();
|
||||||
let peer_ids: Vec<_> = netinfo.other_ids().cloned().collect();
|
let peer_ids: Vec<_> = netinfo.other_ids().cloned().collect();
|
||||||
let dhb = DynamicHoneyBadger::builder().build(netinfo);
|
let dhb = DynamicHoneyBadger::builder().build(netinfo, secret_key, pub_keys);
|
||||||
let (qhb, qhb_step) = QueueingHoneyBadger::builder(dhb)
|
let (qhb, qhb_step) = QueueingHoneyBadger::builder(dhb)
|
||||||
.batch_size(args.flag_b)
|
.batch_size(args.flag_b)
|
||||||
.build_with_transactions(txs.clone(), rng)
|
.build_with_transactions(txs.clone(), rng)
|
||||||
|
|
|
@ -28,9 +28,13 @@ use std::{cmp, env, fmt, fs, io, ops, process, time};
|
||||||
|
|
||||||
use rand::{self, Rng};
|
use rand::{self, Rng};
|
||||||
|
|
||||||
|
use hbbft::crypto::SecretKey;
|
||||||
use hbbft::dynamic_honey_badger::Batch;
|
use hbbft::dynamic_honey_badger::Batch;
|
||||||
use hbbft::sender_queue::SenderQueueableOutput;
|
use hbbft::sender_queue::SenderQueueableOutput;
|
||||||
use hbbft::{self, ConsensusProtocol, Contribution, CpStep, Fault, NetworkInfo, NodeIdT, Step};
|
use hbbft::{
|
||||||
|
self, to_pub_keys, ConsensusProtocol, Contribution, CpStep, Fault, NetworkInfo, NodeIdT,
|
||||||
|
PubKeyMap, Step,
|
||||||
|
};
|
||||||
|
|
||||||
pub use self::adversary::Adversary;
|
pub use self::adversary::Adversary;
|
||||||
pub use self::err::CrankError;
|
pub use self::err::CrankError;
|
||||||
|
@ -281,6 +285,10 @@ where
|
||||||
{
|
{
|
||||||
/// The node ID for the new node.
|
/// The node ID for the new node.
|
||||||
pub id: D::NodeId,
|
pub id: D::NodeId,
|
||||||
|
/// This node's secret key.
|
||||||
|
pub secret_key: SecretKey,
|
||||||
|
/// The validators' public keys.
|
||||||
|
pub pub_keys: PubKeyMap<D::NodeId>,
|
||||||
/// Network info struct, containing keys and other information.
|
/// Network info struct, containing keys and other information.
|
||||||
pub netinfo: NetworkInfo<D::NodeId>,
|
pub netinfo: NetworkInfo<D::NodeId>,
|
||||||
/// Whether or not the node is marked faulty.
|
/// Whether or not the node is marked faulty.
|
||||||
|
@ -749,8 +757,13 @@ where
|
||||||
I: IntoIterator<Item = D::NodeId>,
|
I: IntoIterator<Item = D::NodeId>,
|
||||||
R: rand::Rng,
|
R: rand::Rng,
|
||||||
{
|
{
|
||||||
|
// Generate keys for signing and encrypting messages.
|
||||||
|
let sec_keys: BTreeMap<_, SecretKey> =
|
||||||
|
node_ids.into_iter().map(|id| (id, rng.gen())).collect();
|
||||||
|
let pub_keys: PubKeyMap<D::NodeId> = to_pub_keys(sec_keys.iter());
|
||||||
|
|
||||||
// Generate a new set of cryptographic keys for threshold cryptography.
|
// Generate a new set of cryptographic keys for threshold cryptography.
|
||||||
let net_infos = NetworkInfo::generate_map(node_ids, &mut rng)
|
let net_infos = NetworkInfo::generate_map(pub_keys.keys().cloned(), &mut rng)
|
||||||
.map_err(CrankError::InitialKeyGeneration)?;
|
.map_err(CrankError::InitialKeyGeneration)?;
|
||||||
|
|
||||||
assert!(
|
assert!(
|
||||||
|
@ -769,6 +782,8 @@ where
|
||||||
|
|
||||||
let (algorithm, step) = cons(NewNodeInfo {
|
let (algorithm, step) = cons(NewNodeInfo {
|
||||||
id: id.clone(),
|
id: id.clone(),
|
||||||
|
secret_key: sec_keys[&id].clone(),
|
||||||
|
pub_keys: pub_keys.clone(),
|
||||||
netinfo,
|
netinfo,
|
||||||
faulty: is_faulty,
|
faulty: is_faulty,
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::BTreeMap;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::{ChangeState, JoinPlan, Params};
|
use super::{ChangeState, JoinPlan, Params};
|
||||||
use crate::{NetworkInfo, NodeIdT};
|
use crate::{NetworkInfo, NodeIdT, PubKeyMap};
|
||||||
|
|
||||||
/// A batch of transactions the algorithm has output.
|
/// A batch of transactions the algorithm has output.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
@ -16,6 +16,8 @@ pub struct Batch<C, N: Ord> {
|
||||||
/// The current state of adding or removing a node: whether any is in progress, or completed
|
/// The current state of adding or removing a node: whether any is in progress, or completed
|
||||||
/// this epoch.
|
/// this epoch.
|
||||||
pub(super) change: ChangeState<N>,
|
pub(super) change: ChangeState<N>,
|
||||||
|
/// The current set of public keys.
|
||||||
|
pub(super) pub_keys: PubKeyMap<N>,
|
||||||
/// The network info that applies to the _next_ epoch.
|
/// The network info that applies to the _next_ epoch.
|
||||||
pub(super) netinfo: Arc<NetworkInfo<N>>,
|
pub(super) netinfo: Arc<NetworkInfo<N>>,
|
||||||
/// Parameters controlling Honey Badger's behavior and performance.
|
/// Parameters controlling Honey Badger's behavior and performance.
|
||||||
|
@ -39,6 +41,11 @@ impl<C, N: NodeIdT> Batch<C, N> {
|
||||||
&self.change
|
&self.change
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the map of public keys, by node ID.
|
||||||
|
pub fn public_keys(&self) -> &PubKeyMap<N> {
|
||||||
|
&self.pub_keys
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the `NetworkInfo` containing the information about the validators that will produce
|
/// Returns the `NetworkInfo` containing the information about the validators that will produce
|
||||||
/// the _next_ epoch after this one.
|
/// the _next_ epoch after this one.
|
||||||
pub fn network_info(&self) -> &Arc<NetworkInfo<N>> {
|
pub fn network_info(&self) -> &Arc<NetworkInfo<N>> {
|
||||||
|
@ -98,8 +105,8 @@ impl<C, N: NodeIdT> Batch<C, N> {
|
||||||
Some(JoinPlan {
|
Some(JoinPlan {
|
||||||
era: self.epoch + 1,
|
era: self.epoch + 1,
|
||||||
change: self.change.clone(),
|
change: self.change.clone(),
|
||||||
|
pub_keys: self.pub_keys.clone(),
|
||||||
pub_key_set: self.netinfo.public_key_set().clone(),
|
pub_key_set: self.netinfo.public_key_set().clone(),
|
||||||
pub_keys: self.netinfo.public_key_map().clone(),
|
|
||||||
params: self.params.clone(),
|
params: self.params.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -114,8 +121,8 @@ impl<C, N: NodeIdT> Batch<C, N> {
|
||||||
&& self.era == other.era
|
&& self.era == other.era
|
||||||
&& self.contributions == other.contributions
|
&& self.contributions == other.contributions
|
||||||
&& self.change == other.change
|
&& self.change == other.change
|
||||||
|
&& self.pub_keys == other.pub_keys
|
||||||
&& self.netinfo.public_key_set() == other.netinfo.public_key_set()
|
&& self.netinfo.public_key_set() == other.netinfo.public_key_set()
|
||||||
&& self.netinfo.public_key_map() == other.netinfo.public_key_map()
|
|
||||||
&& self.params == other.params
|
&& self.params == other.params
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,9 +6,9 @@ use std::sync::Arc;
|
||||||
use crate::crypto::{SecretKey, SecretKeySet};
|
use crate::crypto::{SecretKey, SecretKeySet};
|
||||||
use serde::{de::DeserializeOwned, Serialize};
|
use serde::{de::DeserializeOwned, Serialize};
|
||||||
|
|
||||||
use super::{DynamicHoneyBadger, EncryptionSchedule, JoinPlan, Result, Step, VoteCounter};
|
use super::{DynamicHoneyBadger, EncryptionSchedule, JoinPlan, Result, Step};
|
||||||
use crate::honey_badger::{HoneyBadger, Params, SubsetHandlingStrategy};
|
use crate::honey_badger::{Params, SubsetHandlingStrategy};
|
||||||
use crate::{Contribution, NetworkInfo, NodeIdT};
|
use crate::{to_pub_keys, Contribution, NetworkInfo, NodeIdT, PubKeyMap};
|
||||||
|
|
||||||
/// A Dynamic Honey Badger builder, to configure the parameters and create new instances of
|
/// A Dynamic Honey Badger builder, to configure the parameters and create new instances of
|
||||||
/// `DynamicHoneyBadger`.
|
/// `DynamicHoneyBadger`.
|
||||||
|
@ -84,30 +84,20 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new Dynamic Honey Badger instance with an empty buffer.
|
/// Creates a new Dynamic Honey Badger instance with an empty buffer.
|
||||||
pub fn build(&mut self, netinfo: NetworkInfo<N>) -> DynamicHoneyBadger<C, N> {
|
pub fn build(
|
||||||
let DynamicHoneyBadgerBuilder {
|
&mut self,
|
||||||
era,
|
netinfo: NetworkInfo<N>,
|
||||||
epoch,
|
secret_key: SecretKey,
|
||||||
params,
|
pub_keys: PubKeyMap<N>,
|
||||||
_phantom,
|
) -> DynamicHoneyBadger<C, N> {
|
||||||
} = self;
|
DynamicHoneyBadger::new(
|
||||||
let arc_netinfo = Arc::new(netinfo.clone());
|
secret_key,
|
||||||
|
pub_keys,
|
||||||
let honey_badger = HoneyBadger::builder(arc_netinfo.clone())
|
Arc::new(netinfo),
|
||||||
.session_id(*era)
|
self.params.clone(),
|
||||||
.epoch(*epoch)
|
self.era,
|
||||||
.params(params.clone())
|
self.epoch,
|
||||||
.build();
|
)
|
||||||
|
|
||||||
DynamicHoneyBadger {
|
|
||||||
netinfo,
|
|
||||||
max_future_epochs: params.max_future_epochs,
|
|
||||||
era: *era,
|
|
||||||
vote_counter: VoteCounter::new(arc_netinfo, 0),
|
|
||||||
key_gen_msg_buffer: Vec::new(),
|
|
||||||
honey_badger,
|
|
||||||
key_gen_state: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `DynamicHoneyBadger` configured to start a new network as a single validator.
|
/// Creates a new `DynamicHoneyBadger` configured to start a new network as a single validator.
|
||||||
|
@ -120,9 +110,9 @@ where
|
||||||
let pk_set = sk_set.public_keys();
|
let pk_set = sk_set.public_keys();
|
||||||
let sks = sk_set.secret_key_share(0);
|
let sks = sk_set.secret_key_share(0);
|
||||||
let sk = rng.gen::<SecretKey>();
|
let sk = rng.gen::<SecretKey>();
|
||||||
let pub_keys = once((our_id.clone(), sk.public_key())).collect();
|
let pub_keys = to_pub_keys(once((&our_id, &sk)));
|
||||||
let netinfo = NetworkInfo::new(our_id, sks, pk_set, sk, pub_keys);
|
let netinfo = NetworkInfo::new(our_id.clone(), sks, pk_set, once(our_id));
|
||||||
Ok(self.build(netinfo))
|
Ok(self.build(netinfo, sk, pub_keys))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new `DynamicHoneyBadger` configured to join the network at the epoch specified in
|
/// Creates a new `DynamicHoneyBadger` configured to join the network at the epoch specified in
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use std::collections::BTreeMap;
|
|
||||||
|
|
||||||
use crate::crypto::PublicKey;
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::EncryptionSchedule;
|
use super::EncryptionSchedule;
|
||||||
|
use crate::PubKeyMap;
|
||||||
|
|
||||||
/// A node change action: adding or removing a node.
|
/// A node change action: adding or removing a node.
|
||||||
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)]
|
#[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)]
|
||||||
|
@ -11,7 +9,7 @@ pub enum Change<N: Ord> {
|
||||||
/// Change the set of validators to the one in the provided map. There are no restrictions on
|
/// Change the set of validators to the one in the provided map. There are no restrictions on
|
||||||
/// the new set of validators. In particular, it can be disjoint with the current set of
|
/// the new set of validators. In particular, it can be disjoint with the current set of
|
||||||
/// validators.
|
/// validators.
|
||||||
NodeChange(BTreeMap<N, PublicKey>),
|
NodeChange(PubKeyMap<N>),
|
||||||
/// Change the threshold encryption schedule.
|
/// Change the threshold encryption schedule.
|
||||||
/// Increase frequency to prevent censorship or decrease frequency for increased throughput.
|
/// Increase frequency to prevent censorship or decrease frequency for increased throughput.
|
||||||
EncryptionSchedule(EncryptionSchedule),
|
EncryptionSchedule(EncryptionSchedule),
|
||||||
|
|
|
@ -17,29 +17,29 @@ use super::{
|
||||||
};
|
};
|
||||||
use crate::fault_log::{Fault, FaultLog};
|
use crate::fault_log::{Fault, FaultLog};
|
||||||
use crate::honey_badger::{self, HoneyBadger, Message as HbMessage};
|
use crate::honey_badger::{self, HoneyBadger, Message as HbMessage};
|
||||||
|
use crate::sync_key_gen::{Ack, AckOutcome, Part, PartOutcome, PubKeyMap, SyncKeyGen};
|
||||||
use crate::sync_key_gen::{Ack, AckOutcome, Part, PartOutcome, SyncKeyGen};
|
use crate::{util, ConsensusProtocol, Contribution, Epoched, NetworkInfo, NodeIdT, Target};
|
||||||
use crate::util;
|
|
||||||
use crate::{ConsensusProtocol, Contribution, Epoched, NetworkInfo, NodeIdT, Target};
|
|
||||||
|
|
||||||
/// A Honey Badger instance that can handle adding and removing nodes.
|
/// A Honey Badger instance that can handle adding and removing nodes.
|
||||||
#[derive(Derivative)]
|
#[derive(Derivative)]
|
||||||
#[derivative(Debug)]
|
#[derivative(Debug)]
|
||||||
pub struct DynamicHoneyBadger<C, N: Ord> {
|
pub struct DynamicHoneyBadger<C, N: Ord> {
|
||||||
/// Shared network data.
|
/// This node's secret key.
|
||||||
pub(super) netinfo: NetworkInfo<N>,
|
secret_key: SecretKey,
|
||||||
|
/// The validators' public keys.
|
||||||
|
pub_keys: PubKeyMap<N>,
|
||||||
/// The maximum number of future epochs for which we handle messages simultaneously.
|
/// The maximum number of future epochs for which we handle messages simultaneously.
|
||||||
pub(super) max_future_epochs: u64,
|
max_future_epochs: u64,
|
||||||
/// The first epoch after the latest node change.
|
/// The first epoch after the latest node change.
|
||||||
pub(super) era: u64,
|
era: u64,
|
||||||
/// The buffer and counter for the pending and committed change votes.
|
/// The buffer and counter for the pending and committed change votes.
|
||||||
pub(super) vote_counter: VoteCounter<N>,
|
vote_counter: VoteCounter<N>,
|
||||||
/// Pending node transactions that we will propose in the next epoch.
|
/// Pending node transactions that we will propose in the next epoch.
|
||||||
pub(super) key_gen_msg_buffer: Vec<SignedKeyGenMsg<N>>,
|
key_gen_msg_buffer: Vec<SignedKeyGenMsg<N>>,
|
||||||
/// The `HoneyBadger` instance with the current set of nodes.
|
/// The `HoneyBadger` instance with the current set of nodes.
|
||||||
pub(super) honey_badger: HoneyBadger<InternalContrib<C, N>, N>,
|
honey_badger: HoneyBadger<InternalContrib<C, N>, N>,
|
||||||
/// The current key generation process, and the change it applies to.
|
/// The current key generation process, and the change it applies to.
|
||||||
pub(super) key_gen_state: Option<KeyGenState<N>>,
|
key_gen_state: Option<KeyGenState<N>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, N> ConsensusProtocol for DynamicHoneyBadger<C, N>
|
impl<C, N> ConsensusProtocol for DynamicHoneyBadger<C, N>
|
||||||
|
@ -77,7 +77,7 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn our_id(&self) -> &N {
|
fn our_id(&self) -> &N {
|
||||||
self.netinfo.our_id()
|
self.netinfo().our_id()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,6 +91,35 @@ where
|
||||||
DynamicHoneyBadgerBuilder::new()
|
DynamicHoneyBadgerBuilder::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a new `DynamicHoneyBadger`.
|
||||||
|
pub fn new(
|
||||||
|
secret_key: SecretKey,
|
||||||
|
pub_keys: PubKeyMap<N>,
|
||||||
|
netinfo: Arc<NetworkInfo<N>>,
|
||||||
|
params: Params,
|
||||||
|
era: u64,
|
||||||
|
epoch: u64,
|
||||||
|
) -> Self {
|
||||||
|
let max_future_epochs = params.max_future_epochs;
|
||||||
|
let our_id = netinfo.our_id().clone();
|
||||||
|
let honey_badger = HoneyBadger::builder(netinfo)
|
||||||
|
.session_id(era)
|
||||||
|
.params(params)
|
||||||
|
.epoch(epoch)
|
||||||
|
.build();
|
||||||
|
let vote_counter = VoteCounter::new(our_id, secret_key.clone(), pub_keys.clone(), era);
|
||||||
|
DynamicHoneyBadger {
|
||||||
|
secret_key,
|
||||||
|
pub_keys,
|
||||||
|
max_future_epochs,
|
||||||
|
era,
|
||||||
|
vote_counter,
|
||||||
|
key_gen_msg_buffer: Vec::new(),
|
||||||
|
honey_badger,
|
||||||
|
key_gen_state: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Creates a new `DynamicHoneyBadger` ready to join the network specified in the `JoinPlan`.
|
/// Creates a new `DynamicHoneyBadger` ready to join the network specified in the `JoinPlan`.
|
||||||
pub fn new_joining<R: Rng>(
|
pub fn new_joining<R: Rng>(
|
||||||
our_id: N,
|
our_id: N,
|
||||||
|
@ -98,34 +127,22 @@ where
|
||||||
join_plan: JoinPlan<N>,
|
join_plan: JoinPlan<N>,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Result<(Self, Step<C, N>)> {
|
) -> Result<(Self, Step<C, N>)> {
|
||||||
let netinfo = NetworkInfo::new(
|
let JoinPlan {
|
||||||
our_id,
|
era,
|
||||||
None,
|
change,
|
||||||
join_plan.pub_key_set,
|
pub_keys,
|
||||||
secret_key,
|
pub_key_set,
|
||||||
join_plan.pub_keys,
|
params,
|
||||||
);
|
} = join_plan;
|
||||||
let max_future_epochs = join_plan.params.max_future_epochs;
|
let netinfo = Arc::new(NetworkInfo::new(our_id, None, pub_key_set, pub_keys.keys()));
|
||||||
let arc_netinfo = Arc::new(netinfo.clone());
|
let mut dhb = DynamicHoneyBadger::new(secret_key, pub_keys, netinfo, params, era, 0);
|
||||||
let honey_badger = HoneyBadger::builder(arc_netinfo.clone())
|
let step = match change {
|
||||||
.session_id(join_plan.era)
|
ChangeState::InProgress(Change::NodeChange(new_pub_keys)) => {
|
||||||
.params(join_plan.params)
|
dhb.update_key_gen(join_plan.era, new_pub_keys, rng)?
|
||||||
.build();
|
}
|
||||||
let mut dhb = DynamicHoneyBadger {
|
ChangeState::InProgress(Change::EncryptionSchedule(..))
|
||||||
netinfo,
|
| ChangeState::None
|
||||||
max_future_epochs,
|
| ChangeState::Complete(..) => Step::default(),
|
||||||
era: join_plan.era,
|
|
||||||
vote_counter: VoteCounter::new(arc_netinfo, join_plan.era),
|
|
||||||
key_gen_msg_buffer: Vec::new(),
|
|
||||||
honey_badger,
|
|
||||||
key_gen_state: None,
|
|
||||||
};
|
|
||||||
let step = match join_plan.change {
|
|
||||||
ChangeState::InProgress(ref change) => match change {
|
|
||||||
Change::NodeChange(change) => dhb.update_key_gen(join_plan.era, change, rng)?,
|
|
||||||
_ => Step::default(),
|
|
||||||
},
|
|
||||||
ChangeState::None | ChangeState::Complete(..) => Step::default(),
|
|
||||||
};
|
};
|
||||||
Ok((dhb, step))
|
Ok((dhb, step))
|
||||||
}
|
}
|
||||||
|
@ -167,7 +184,7 @@ where
|
||||||
/// This stores a pending vote for the change. It will be included in some future batch, and
|
/// This stores a pending vote for the change. It will be included in some future batch, and
|
||||||
/// once enough validators have been voted for the same change, it will take effect.
|
/// once enough validators have been voted for the same change, it will take effect.
|
||||||
pub fn vote_for(&mut self, change: Change<N>) -> Result<Step<C, N>> {
|
pub fn vote_for(&mut self, change: Change<N>) -> Result<Step<C, N>> {
|
||||||
if !self.netinfo.is_validator() {
|
if !self.netinfo().is_validator() {
|
||||||
return Ok(Step::default()); // TODO: Return an error?
|
return Ok(Step::default()); // TODO: Return an error?
|
||||||
}
|
}
|
||||||
let signed_vote = self.vote_counter.sign_vote_for(change)?.clone();
|
let signed_vote = self.vote_counter.sign_vote_for(change)?.clone();
|
||||||
|
@ -180,9 +197,9 @@ where
|
||||||
/// This stores a pending vote for the change. It will be included in some future batch, and
|
/// This stores a pending vote for the change. It will be included in some future batch, and
|
||||||
/// once enough validators have been voted for the same change, it will take effect.
|
/// once enough validators have been voted for the same change, it will take effect.
|
||||||
pub fn vote_to_add(&mut self, node_id: N, pub_key: PublicKey) -> Result<Step<C, N>> {
|
pub fn vote_to_add(&mut self, node_id: N, pub_key: PublicKey) -> Result<Step<C, N>> {
|
||||||
let mut pub_keys = self.netinfo.public_key_map().clone();
|
let mut pub_keys = (*self.pub_keys).clone();
|
||||||
pub_keys.insert(node_id, pub_key);
|
pub_keys.insert(node_id, pub_key);
|
||||||
self.vote_for(Change::NodeChange(pub_keys))
|
self.vote_for(Change::NodeChange(Arc::new(pub_keys)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Casts a vote to demote a validator to observer.
|
/// Casts a vote to demote a validator to observer.
|
||||||
|
@ -190,9 +207,9 @@ where
|
||||||
/// This stores a pending vote for the change. It will be included in some future batch, and
|
/// This stores a pending vote for the change. It will be included in some future batch, and
|
||||||
/// once enough validators have been voted for the same change, it will take effect.
|
/// once enough validators have been voted for the same change, it will take effect.
|
||||||
pub fn vote_to_remove(&mut self, node_id: &N) -> Result<Step<C, N>> {
|
pub fn vote_to_remove(&mut self, node_id: &N) -> Result<Step<C, N>> {
|
||||||
let mut pub_keys = self.netinfo.public_key_map().clone();
|
let mut pub_keys = (*self.pub_keys).clone();
|
||||||
pub_keys.remove(node_id);
|
pub_keys.remove(node_id);
|
||||||
self.vote_for(Change::NodeChange(pub_keys))
|
self.vote_for(Change::NodeChange(Arc::new(pub_keys)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Handles a message received from `sender_id`.
|
/// Handles a message received from `sender_id`.
|
||||||
|
@ -225,9 +242,19 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the secret key used to sign votes and key generation messages.
|
||||||
|
pub fn secret_key(&self) -> &SecretKey {
|
||||||
|
&self.secret_key
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the map of public keys, by node ID.
|
||||||
|
pub fn public_keys(&self) -> &PubKeyMap<N> {
|
||||||
|
&self.pub_keys
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the information about the node IDs in the network, and the cryptographic keys.
|
/// Returns the information about the node IDs in the network, and the cryptographic keys.
|
||||||
pub fn netinfo(&self) -> &NetworkInfo<N> {
|
pub fn netinfo(&self) -> &Arc<NetworkInfo<N>> {
|
||||||
&self.netinfo
|
&self.honey_badger.netinfo()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the internal managed `HoneyBadger` instance.
|
/// Returns a reference to the internal managed `HoneyBadger` instance.
|
||||||
|
@ -245,7 +272,7 @@ where
|
||||||
if self.has_input() {
|
if self.has_input() {
|
||||||
return false; // We have already proposed.
|
return false; // We have already proposed.
|
||||||
}
|
}
|
||||||
if self.honey_badger.received_proposals() > self.netinfo.num_faulty() {
|
if self.honey_badger.received_proposals() > self.netinfo().num_faulty() {
|
||||||
return true; // At least one correct node wants to move on to the next epoch.
|
return true; // At least one correct node wants to move on to the next epoch.
|
||||||
}
|
}
|
||||||
let is_our_vote = |signed_vote: &SignedVote<_>| signed_vote.voter() == self.our_id();
|
let is_our_vote = |signed_vote: &SignedVote<_>| signed_vote.voter() == self.our_id();
|
||||||
|
@ -268,7 +295,7 @@ where
|
||||||
message: HbMessage<N>,
|
message: HbMessage<N>,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Result<Step<C, N>> {
|
) -> Result<Step<C, N>> {
|
||||||
if !self.netinfo.is_node_validator(sender_id) {
|
if !self.netinfo().is_node_validator(sender_id) {
|
||||||
return Err(Error::UnknownSender);
|
return Err(Error::UnknownSender);
|
||||||
}
|
}
|
||||||
// Handle the message.
|
// Handle the message.
|
||||||
|
@ -357,15 +384,19 @@ where
|
||||||
let change = if let Some(kgs) = self.take_ready_key_gen() {
|
let change = if let Some(kgs) = self.take_ready_key_gen() {
|
||||||
// If DKG completed, apply the change, restart Honey Badger, and inform the user.
|
// If DKG completed, apply the change, restart Honey Badger, and inform the user.
|
||||||
debug!("{}: DKG for complete for: {:?}", self, kgs.public_keys());
|
debug!("{}: DKG for complete for: {:?}", self, kgs.public_keys());
|
||||||
self.netinfo = kgs.key_gen.into_network_info().map_err(Error::SyncKeyGen)?;
|
self.pub_keys = kgs.key_gen.public_keys().clone();
|
||||||
|
let (pk_set, sk_share) = kgs.key_gen.generate().map_err(Error::SyncKeyGen)?;
|
||||||
|
let our_id = self.our_id().clone();
|
||||||
|
let all_ids = self.pub_keys.keys();
|
||||||
|
let netinfo = Arc::new(NetworkInfo::new(our_id, sk_share, pk_set, all_ids));
|
||||||
let params = self.honey_badger.params().clone();
|
let params = self.honey_badger.params().clone();
|
||||||
self.restart_honey_badger(batch_epoch + 1, params);
|
self.restart_honey_badger(batch_epoch + 1, params, netinfo);
|
||||||
ChangeState::Complete(Change::NodeChange(self.netinfo.public_key_map().clone()))
|
ChangeState::Complete(Change::NodeChange(self.pub_keys.clone()))
|
||||||
} else if let Some(change) = self.vote_counter.compute_winner().cloned() {
|
} else if let Some(change) = self.vote_counter.compute_winner().cloned() {
|
||||||
// If there is a new change, restart DKG. Inform the user about the current change.
|
// If there is a new change, restart DKG. Inform the user about the current change.
|
||||||
match change {
|
match change {
|
||||||
Change::NodeChange(ref pub_keys) => {
|
Change::NodeChange(ref pub_keys) => {
|
||||||
step.extend(self.update_key_gen(batch_epoch + 1, pub_keys, rng)?);
|
step.extend(self.update_key_gen(batch_epoch + 1, pub_keys.clone(), rng)?);
|
||||||
}
|
}
|
||||||
Change::EncryptionSchedule(schedule) => {
|
Change::EncryptionSchedule(schedule) => {
|
||||||
self.update_encryption_schedule(batch_epoch + 1, schedule);
|
self.update_encryption_schedule(batch_epoch + 1, schedule);
|
||||||
|
@ -382,7 +413,8 @@ where
|
||||||
epoch: batch_epoch,
|
epoch: batch_epoch,
|
||||||
era: batch_era,
|
era: batch_era,
|
||||||
change,
|
change,
|
||||||
netinfo: Arc::new(self.netinfo.clone()),
|
pub_keys: self.pub_keys.clone(),
|
||||||
|
netinfo: self.netinfo().clone(),
|
||||||
contributions: batch_contributions,
|
contributions: batch_contributions,
|
||||||
params: self.honey_badger.params().clone(),
|
params: self.honey_badger.params().clone(),
|
||||||
});
|
});
|
||||||
|
@ -394,7 +426,7 @@ where
|
||||||
pub(super) fn update_encryption_schedule(&mut self, era: u64, schedule: EncryptionSchedule) {
|
pub(super) fn update_encryption_schedule(&mut self, era: u64, schedule: EncryptionSchedule) {
|
||||||
let mut params = self.honey_badger.params().clone();
|
let mut params = self.honey_badger.params().clone();
|
||||||
params.encryption_schedule = schedule;
|
params.encryption_schedule = schedule;
|
||||||
self.restart_honey_badger(era, params);
|
self.restart_honey_badger(era, params, self.netinfo().clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If the winner of the vote has changed, restarts Key Generation for the set of nodes implied
|
/// If the winner of the vote has changed, restarts Key Generation for the set of nodes implied
|
||||||
|
@ -402,20 +434,20 @@ where
|
||||||
pub(super) fn update_key_gen<R: Rng>(
|
pub(super) fn update_key_gen<R: Rng>(
|
||||||
&mut self,
|
&mut self,
|
||||||
era: u64,
|
era: u64,
|
||||||
pub_keys: &BTreeMap<N, PublicKey>,
|
pub_keys: PubKeyMap<N>,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Result<Step<C, N>> {
|
) -> Result<Step<C, N>> {
|
||||||
if self.key_gen_state.as_ref().map(KeyGenState::public_keys) == Some(pub_keys) {
|
if self.key_gen_state.as_ref().map(KeyGenState::public_keys) == Some(&pub_keys) {
|
||||||
return Ok(Step::default()); // The change is the same as before. Continue DKG as is.
|
return Ok(Step::default()); // The change is the same as before. Continue DKG as is.
|
||||||
}
|
}
|
||||||
debug!("{}: Restarting DKG for {:?}.", self, pub_keys);
|
debug!("{}: Restarting DKG for {:?}.", self, pub_keys);
|
||||||
let params = self.honey_badger.params().clone();
|
let params = self.honey_badger.params().clone();
|
||||||
self.restart_honey_badger(era, params);
|
self.restart_honey_badger(era, params, self.netinfo().clone());
|
||||||
let threshold = util::max_faulty(pub_keys.len());
|
let threshold = util::max_faulty(pub_keys.len());
|
||||||
let sk = self.netinfo.secret_key().clone();
|
let sk = self.secret_key.clone();
|
||||||
let our_id = self.our_id().clone();
|
let our_id = self.our_id().clone();
|
||||||
let (key_gen, part) = SyncKeyGen::new(our_id, sk, pub_keys.clone(), threshold, rng)
|
let (key_gen, part) =
|
||||||
.map_err(Error::SyncKeyGen)?;
|
SyncKeyGen::new(our_id, sk, pub_keys, threshold, rng).map_err(Error::SyncKeyGen)?;
|
||||||
self.key_gen_state = Some(KeyGenState::new(key_gen));
|
self.key_gen_state = Some(KeyGenState::new(key_gen));
|
||||||
if let Some(part) = part {
|
if let Some(part) = part {
|
||||||
self.send_transaction(KeyGenMessage::Part(part))
|
self.send_transaction(KeyGenMessage::Part(part))
|
||||||
|
@ -425,11 +457,15 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts a new `HoneyBadger` instance and resets the vote counter.
|
/// Starts a new `HoneyBadger` instance and resets the vote counter.
|
||||||
fn restart_honey_badger(&mut self, era: u64, params: Params) {
|
fn restart_honey_badger(&mut self, era: u64, params: Params, netinfo: Arc<NetworkInfo<N>>) {
|
||||||
self.era = era;
|
self.era = era;
|
||||||
self.key_gen_msg_buffer.retain(|kg_msg| kg_msg.0 >= era);
|
self.key_gen_msg_buffer.retain(|kg_msg| kg_msg.0 >= era);
|
||||||
let netinfo = Arc::new(self.netinfo.clone());
|
self.vote_counter = VoteCounter::new(
|
||||||
self.vote_counter = VoteCounter::new(netinfo.clone(), era);
|
self.our_id().clone(),
|
||||||
|
self.secret_key.clone(),
|
||||||
|
self.pub_keys.clone(),
|
||||||
|
era,
|
||||||
|
);
|
||||||
self.honey_badger = HoneyBadger::builder(netinfo)
|
self.honey_badger = HoneyBadger::builder(netinfo)
|
||||||
.session_id(era)
|
.session_id(era)
|
||||||
.params(params)
|
.params(params)
|
||||||
|
@ -487,8 +523,8 @@ where
|
||||||
/// Signs and sends a `KeyGenMessage` and also tries to commit it.
|
/// Signs and sends a `KeyGenMessage` and also tries to commit it.
|
||||||
fn send_transaction(&mut self, kg_msg: KeyGenMessage) -> Result<Step<C, N>> {
|
fn send_transaction(&mut self, kg_msg: KeyGenMessage) -> Result<Step<C, N>> {
|
||||||
let ser = bincode::serialize(&kg_msg).map_err(|err| Error::SerializeKeyGen(*err))?;
|
let ser = bincode::serialize(&kg_msg).map_err(|err| Error::SerializeKeyGen(*err))?;
|
||||||
let sig = Box::new(self.netinfo.secret_key().sign(ser));
|
let sig = Box::new(self.secret_key.sign(ser));
|
||||||
if self.netinfo.is_validator() {
|
if self.netinfo().is_validator() {
|
||||||
let our_id = self.our_id().clone();
|
let our_id = self.our_id().clone();
|
||||||
let signed_msg = SignedKeyGenMsg(self.era, our_id, kg_msg.clone(), *sig.clone());
|
let signed_msg = SignedKeyGenMsg(self.era, our_id, kg_msg.clone(), *sig.clone());
|
||||||
self.key_gen_msg_buffer.push(signed_msg);
|
self.key_gen_msg_buffer.push(signed_msg);
|
||||||
|
@ -527,7 +563,7 @@ where
|
||||||
let ser = bincode::serialize(kg_msg).map_err(|err| Error::SerializeKeyGen(*err))?;
|
let ser = bincode::serialize(kg_msg).map_err(|err| Error::SerializeKeyGen(*err))?;
|
||||||
let verify = |opt_pk: Option<&PublicKey>| opt_pk.map_or(false, |pk| pk.verify(&sig, &ser));
|
let verify = |opt_pk: Option<&PublicKey>| opt_pk.map_or(false, |pk| pk.verify(&sig, &ser));
|
||||||
let kgs = self.key_gen_state.as_ref();
|
let kgs = self.key_gen_state.as_ref();
|
||||||
let current_key = self.netinfo.public_key(node_id);
|
let current_key = self.pub_keys.get(node_id);
|
||||||
let candidate_key = kgs.and_then(|kgs| kgs.public_keys().get(node_id));
|
let candidate_key = kgs.and_then(|kgs| kgs.public_keys().get(node_id));
|
||||||
Ok(verify(current_key) || verify(candidate_key))
|
Ok(verify(current_key) || verify(candidate_key))
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,13 +74,13 @@ mod votes;
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use crate::crypto::{PublicKey, PublicKeySet, Signature};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use self::votes::{SignedVote, VoteCounter};
|
use self::votes::SignedVote;
|
||||||
|
use crate::crypto::{PublicKeySet, Signature};
|
||||||
use crate::honey_badger::{EncryptionSchedule, Message as HbMessage, Params};
|
use crate::honey_badger::{EncryptionSchedule, Message as HbMessage, Params};
|
||||||
use crate::sync_key_gen::{Ack, Part, SyncKeyGen};
|
use crate::sync_key_gen::{Ack, Part, SyncKeyGen};
|
||||||
use crate::NodeIdT;
|
use crate::{NodeIdT, PubKeyMap};
|
||||||
|
|
||||||
pub use self::batch::Batch;
|
pub use self::batch::Batch;
|
||||||
pub use self::builder::DynamicHoneyBadgerBuilder;
|
pub use self::builder::DynamicHoneyBadgerBuilder;
|
||||||
|
@ -135,16 +135,17 @@ impl<N: Ord> Message<N> {
|
||||||
/// The information a new node requires to join the network as an observer. It contains the state
|
/// The information a new node requires to join the network as an observer. It contains the state
|
||||||
/// of voting and key generation after a specific epoch, so that the new node will be in sync if it
|
/// of voting and key generation after a specific epoch, so that the new node will be in sync if it
|
||||||
/// joins in the next one.
|
/// joins in the next one.
|
||||||
|
// TODO: Remove serde "rc" feature and deduplicate `pub_keys` and `change`. Also: validate.
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct JoinPlan<N: Ord> {
|
pub struct JoinPlan<N: Ord> {
|
||||||
/// The first epoch the new node will observe.
|
/// The first epoch the new node will observe.
|
||||||
era: u64,
|
era: u64,
|
||||||
/// The current change. If `InProgress`, key generation for it is beginning at `epoch`.
|
/// The current change. If `InProgress`, key generation for it is beginning at `epoch`.
|
||||||
change: ChangeState<N>,
|
change: ChangeState<N>,
|
||||||
|
/// The current set of public keys.
|
||||||
|
pub_keys: PubKeyMap<N>,
|
||||||
/// The current public key set for threshold cryptography.
|
/// The current public key set for threshold cryptography.
|
||||||
pub_key_set: PublicKeySet,
|
pub_key_set: PublicKeySet,
|
||||||
/// The public keys of the current validators.
|
|
||||||
pub_keys: BTreeMap<N, PublicKey>,
|
|
||||||
/// Parameters controlling Honey Badger's behavior and performance.
|
/// Parameters controlling Honey Badger's behavior and performance.
|
||||||
params: Params,
|
params: Params,
|
||||||
}
|
}
|
||||||
|
@ -181,7 +182,7 @@ impl<N: NodeIdT> KeyGenState<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the map of new validators and their public keys.
|
/// Returns the map of new validators and their public keys.
|
||||||
fn public_keys(&self) -> &BTreeMap<N, PublicKey> {
|
fn public_keys(&self) -> &PubKeyMap<N> {
|
||||||
self.key_gen.public_keys()
|
self.key_gen.public_keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,11 @@
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::sync::Arc;
|
|
||||||
|
|
||||||
use crate::crypto::Signature;
|
use crate::crypto::{SecretKey, Signature};
|
||||||
use bincode;
|
use bincode;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::{Change, Error, FaultKind, Result};
|
use super::{Change, Error, FaultKind, Result};
|
||||||
use crate::fault_log;
|
use crate::{fault_log, util, NodeIdT, PubKeyMap};
|
||||||
use crate::{NetworkInfo, NodeIdT};
|
|
||||||
|
|
||||||
pub type FaultLog<N> = fault_log::FaultLog<N, FaultKind>;
|
pub type FaultLog<N> = fault_log::FaultLog<N, FaultKind>;
|
||||||
|
|
||||||
|
@ -17,8 +15,14 @@ pub type FaultLog<N> = fault_log::FaultLog<N, FaultKind>;
|
||||||
/// the epochs since the last reset the current _era_.
|
/// the epochs since the last reset the current _era_.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct VoteCounter<N: Ord> {
|
pub struct VoteCounter<N: Ord> {
|
||||||
/// Shared network data.
|
/// This node's ID.
|
||||||
netinfo: Arc<NetworkInfo<N>>,
|
// TODO: Make optional for observers?
|
||||||
|
our_id: N,
|
||||||
|
/// This node's secret key,
|
||||||
|
// TODO: Make optional for observers?
|
||||||
|
secret_key: SecretKey,
|
||||||
|
/// The map of public keys.
|
||||||
|
pub_keys: PubKeyMap<N>,
|
||||||
/// The epoch when voting was reset.
|
/// The epoch when voting was reset.
|
||||||
era: u64,
|
era: u64,
|
||||||
/// Pending node transactions that we will propose in the next epoch.
|
/// Pending node transactions that we will propose in the next epoch.
|
||||||
|
@ -33,10 +37,12 @@ where
|
||||||
N: NodeIdT + Serialize,
|
N: NodeIdT + Serialize,
|
||||||
{
|
{
|
||||||
/// Creates a new `VoteCounter` object with empty buffer and counter.
|
/// Creates a new `VoteCounter` object with empty buffer and counter.
|
||||||
pub fn new(netinfo: Arc<NetworkInfo<N>>, era: u64) -> Self {
|
pub fn new(our_id: N, secret_key: SecretKey, pub_keys: PubKeyMap<N>, era: u64) -> Self {
|
||||||
VoteCounter {
|
VoteCounter {
|
||||||
|
our_id,
|
||||||
|
secret_key,
|
||||||
|
pub_keys: pub_keys.clone(),
|
||||||
era,
|
era,
|
||||||
netinfo,
|
|
||||||
pending: BTreeMap::new(),
|
pending: BTreeMap::new(),
|
||||||
committed: BTreeMap::new(),
|
committed: BTreeMap::new(),
|
||||||
}
|
}
|
||||||
|
@ -44,7 +50,7 @@ where
|
||||||
|
|
||||||
/// Creates a signed vote for the given change, and inserts it into the pending votes buffer.
|
/// Creates a signed vote for the given change, and inserts it into the pending votes buffer.
|
||||||
pub fn sign_vote_for(&mut self, change: Change<N>) -> Result<&SignedVote<N>> {
|
pub fn sign_vote_for(&mut self, change: Change<N>) -> Result<&SignedVote<N>> {
|
||||||
let voter = self.netinfo.our_id().clone();
|
let voter = self.our_id.clone();
|
||||||
let vote = Vote {
|
let vote = Vote {
|
||||||
change,
|
change,
|
||||||
era: self.era,
|
era: self.era,
|
||||||
|
@ -54,7 +60,7 @@ where
|
||||||
let signed_vote = SignedVote {
|
let signed_vote = SignedVote {
|
||||||
vote,
|
vote,
|
||||||
voter: voter.clone(),
|
voter: voter.clone(),
|
||||||
sig: self.netinfo.secret_key().sign(ser_vote),
|
sig: self.secret_key.sign(ser_vote),
|
||||||
};
|
};
|
||||||
self.pending.remove(&voter);
|
self.pending.remove(&voter);
|
||||||
Ok(self.pending.entry(voter).or_insert(signed_vote))
|
Ok(self.pending.entry(voter).or_insert(signed_vote))
|
||||||
|
@ -141,7 +147,7 @@ where
|
||||||
let change = &vote.change;
|
let change = &vote.change;
|
||||||
let entry = vote_counts.entry(change).or_insert(0);
|
let entry = vote_counts.entry(change).or_insert(0);
|
||||||
*entry += 1;
|
*entry += 1;
|
||||||
if *entry > self.netinfo.num_faulty() {
|
if *entry > util::max_faulty(self.pub_keys.len()) {
|
||||||
return Some(change);
|
return Some(change);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +158,7 @@ where
|
||||||
fn validate(&self, signed_vote: &SignedVote<N>) -> Result<bool> {
|
fn validate(&self, signed_vote: &SignedVote<N>) -> Result<bool> {
|
||||||
let ser_vote =
|
let ser_vote =
|
||||||
bincode::serialize(&signed_vote.vote).map_err(|err| Error::SerializeVote(*err))?;
|
bincode::serialize(&signed_vote.vote).map_err(|err| Error::SerializeVote(*err))?;
|
||||||
let pk_opt = self.netinfo.public_key(&signed_vote.voter);
|
let pk_opt = self.pub_keys.get(&signed_vote.voter);
|
||||||
Ok(pk_opt.map_or(false, |pk| pk.verify(&signed_vote.sig, ser_vote)))
|
Ok(pk_opt.map_or(false, |pk| pk.verify(&signed_vote.sig, ser_vote)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -188,13 +194,14 @@ impl<N: Ord> SignedVote<N> {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::iter;
|
use std::iter;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::{Change, FaultKind, SignedVote, VoteCounter};
|
use rand::{rngs, Rng};
|
||||||
use crate::fault_log::FaultLog;
|
|
||||||
use crate::NetworkInfo;
|
use super::{Change, FaultKind, SecretKey, SignedVote, VoteCounter};
|
||||||
use rand;
|
use crate::{fault_log::FaultLog, to_pub_keys};
|
||||||
|
|
||||||
/// Returns a vector of `node_num` `VoteCounter`s, and some signed example votes.
|
/// Returns a vector of `node_num` `VoteCounter`s, and some signed example votes.
|
||||||
///
|
///
|
||||||
|
@ -202,21 +209,20 @@ mod tests {
|
||||||
/// the vote by node `i` for making `j` the only validator. Each node signed this for nodes
|
/// the vote by node `i` for making `j` the only validator. Each node signed this for nodes
|
||||||
/// `0`, `1`, ... in order.
|
/// `0`, `1`, ... in order.
|
||||||
fn setup(node_num: usize, era: u64) -> (Vec<VoteCounter<usize>>, Vec<Vec<SignedVote<usize>>>) {
|
fn setup(node_num: usize, era: u64) -> (Vec<VoteCounter<usize>>, Vec<Vec<SignedVote<usize>>>) {
|
||||||
let mut rng = rand::rngs::OsRng::new().expect("could not initialize OsRng");
|
let mut rng = rngs::OsRng::new().expect("could not initialize OsRng");
|
||||||
// Create keys for threshold cryptography.
|
|
||||||
let netinfos = NetworkInfo::generate_map(0..node_num, &mut rng)
|
// Generate keys for signing and encrypting messages.
|
||||||
.expect("Failed to generate `NetworkInfo` map");
|
let sec_keys: BTreeMap<_, SecretKey> = (0..node_num).map(|id| (id, rng.gen())).collect();
|
||||||
let pub_keys = netinfos[&0].public_key_map().clone();
|
let pub_keys = to_pub_keys(&sec_keys);
|
||||||
|
|
||||||
// Create a `VoteCounter` instance for each node.
|
// Create a `VoteCounter` instance for each node.
|
||||||
let create_counter =
|
let create_counter = |(id, sk)| VoteCounter::new(id, sk, pub_keys.clone(), era);
|
||||||
|(_, netinfo): (_, NetworkInfo<_>)| VoteCounter::new(Arc::new(netinfo), era);
|
let mut counters: Vec<_> = sec_keys.into_iter().map(create_counter).collect();
|
||||||
let mut counters: Vec<_> = netinfos.into_iter().map(create_counter).collect();
|
|
||||||
|
|
||||||
// Sign a few votes.
|
// Sign a few votes.
|
||||||
let sign_votes = |counter: &mut VoteCounter<usize>| {
|
let sign_votes = |counter: &mut VoteCounter<usize>| {
|
||||||
(0..node_num)
|
(0..node_num)
|
||||||
.map(|j| Change::NodeChange(iter::once((j, pub_keys[&j])).collect()))
|
.map(|j| Change::NodeChange(Arc::new(iter::once((j, pub_keys[&j])).collect())))
|
||||||
.map(|change| counter.sign_vote_for(change).expect("sign vote").clone())
|
.map(|change| counter.sign_vote_for(change).expect("sign vote").clone())
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
};
|
};
|
||||||
|
|
|
@ -131,6 +131,11 @@ where
|
||||||
self.epoch
|
self.epoch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the information about the node IDs in the network, and the threshold key shares.
|
||||||
|
pub fn netinfo(&self) -> &Arc<NetworkInfo<N>> {
|
||||||
|
&self.netinfo
|
||||||
|
}
|
||||||
|
|
||||||
/// Skips all epochs before the specified one.
|
/// Skips all epochs before the specified one.
|
||||||
///
|
///
|
||||||
/// This must only be called if it is guaranteed to be called in all instances that have not
|
/// This must only be called if it is guaranteed to be called in all instances that have not
|
||||||
|
|
|
@ -143,6 +143,7 @@ pub use crate::crypto::pairing;
|
||||||
pub use crate::fault_log::{Fault, FaultLog};
|
pub use crate::fault_log::{Fault, FaultLog};
|
||||||
pub use crate::messaging::{SourcedMessage, Target, TargetedMessage};
|
pub use crate::messaging::{SourcedMessage, Target, TargetedMessage};
|
||||||
pub use crate::network_info::{NetworkInfo, ValidatorSet};
|
pub use crate::network_info::{NetworkInfo, ValidatorSet};
|
||||||
|
pub use crate::sync_key_gen::{to_pub_keys, PubKeyMap};
|
||||||
pub use crate::traits::{
|
pub use crate::traits::{
|
||||||
ConsensusProtocol, Contribution, CpStep, Epoched, Message, NodeIdT, SessionIdT, Step,
|
ConsensusProtocol, Contribution, CpStep, Epoched, Message, NodeIdT, SessionIdT, Step,
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,7 +2,7 @@ use std::borrow::Borrow;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::crypto::{self, PublicKey, PublicKeySet, PublicKeyShare, SecretKey, SecretKeyShare};
|
use crate::crypto::{self, PublicKeySet, PublicKeyShare, SecretKeyShare};
|
||||||
use rand;
|
use rand;
|
||||||
|
|
||||||
use crate::{util, NodeIdT};
|
use crate::{util, NodeIdT};
|
||||||
|
@ -91,14 +91,10 @@ pub struct NetworkInfo<N> {
|
||||||
is_validator: bool,
|
is_validator: bool,
|
||||||
/// This node's secret key share. Only validators have one.
|
/// This node's secret key share. Only validators have one.
|
||||||
secret_key_share: Option<SecretKeyShare>,
|
secret_key_share: Option<SecretKeyShare>,
|
||||||
/// This node's secret key.
|
|
||||||
secret_key: SecretKey,
|
|
||||||
/// The public key set for threshold cryptography. Each validator has a secret key share.
|
/// The public key set for threshold cryptography. Each validator has a secret key share.
|
||||||
public_key_set: PublicKeySet,
|
public_key_set: PublicKeySet,
|
||||||
/// The validators' public key shares, computed from `public_key_set`.
|
/// The validators' public key shares, computed from `public_key_set`.
|
||||||
public_key_shares: BTreeMap<N, PublicKeyShare>,
|
public_key_shares: BTreeMap<N, PublicKeyShare>,
|
||||||
/// The validators' public keys.
|
|
||||||
public_keys: BTreeMap<N, PublicKey>,
|
|
||||||
/// The indices in the list of sorted validator IDs.
|
/// The indices in the list of sorted validator IDs.
|
||||||
val_set: Arc<ValidatorSet<N>>,
|
val_set: Arc<ValidatorSet<N>>,
|
||||||
}
|
}
|
||||||
|
@ -114,14 +110,13 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
||||||
///
|
///
|
||||||
/// Panics if `public_keys` is empty or the requirement above is not satisfied, i.e. if the
|
/// Panics if `public_keys` is empty or the requirement above is not satisfied, i.e. if the
|
||||||
/// secret key doesn't match the public key or is missing.
|
/// secret key doesn't match the public key or is missing.
|
||||||
pub fn new<SKS: Into<Option<SecretKeyShare>>>(
|
pub fn new<SKS: Into<Option<SecretKeyShare>>, V: Into<ValidatorSet<N>>>(
|
||||||
our_id: N,
|
our_id: N,
|
||||||
secret_key_share: SKS,
|
secret_key_share: SKS,
|
||||||
public_key_set: PublicKeySet,
|
public_key_set: PublicKeySet,
|
||||||
secret_key: SecretKey,
|
val_set: V,
|
||||||
public_keys: BTreeMap<N, PublicKey>,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let val_set = Arc::new(ValidatorSet::from(public_keys.keys()));
|
let val_set = Arc::new(val_set.into());
|
||||||
let is_validator = val_set.contains(&our_id);
|
let is_validator = val_set.contains(&our_id);
|
||||||
let secret_key_share = secret_key_share.into();
|
let secret_key_share = secret_key_share.into();
|
||||||
assert_eq!(is_validator, secret_key_share.is_some());
|
assert_eq!(is_validator, secret_key_share.is_some());
|
||||||
|
@ -139,11 +134,9 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
||||||
our_id,
|
our_id,
|
||||||
is_validator,
|
is_validator,
|
||||||
secret_key_share,
|
secret_key_share,
|
||||||
secret_key,
|
|
||||||
public_key_set,
|
public_key_set,
|
||||||
public_key_shares,
|
public_key_shares,
|
||||||
val_set,
|
val_set,
|
||||||
public_keys,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -192,12 +185,6 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
||||||
self.secret_key_share.as_ref()
|
self.secret_key_share.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns our secret key for encryption and signing.
|
|
||||||
#[inline]
|
|
||||||
pub fn secret_key(&self) -> &SecretKey {
|
|
||||||
&self.secret_key
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the public key set for threshold cryptography.
|
/// Returns the public key set for threshold cryptography.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn public_key_set(&self) -> &PublicKeySet {
|
pub fn public_key_set(&self) -> &PublicKeySet {
|
||||||
|
@ -216,18 +203,6 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
||||||
&self.public_key_shares
|
&self.public_key_shares
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a map of all node IDs to their public keys.
|
|
||||||
#[inline]
|
|
||||||
pub fn public_key(&self, id: &N) -> Option<&PublicKey> {
|
|
||||||
self.public_keys.get(id)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a map of all node IDs to their public keys.
|
|
||||||
#[inline]
|
|
||||||
pub fn public_key_map(&self) -> &BTreeMap<N, PublicKey> {
|
|
||||||
&self.public_keys
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The index of a node in a canonical numbering of all nodes. This is the index where the
|
/// The index of a node in a canonical numbering of all nodes. This is the index where the
|
||||||
/// node appears in `all_ids`.
|
/// node appears in `all_ids`.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -246,7 +221,7 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
||||||
/// observer.
|
/// observer.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_node_validator(&self, id: &N) -> bool {
|
pub fn is_node_validator(&self, id: &N) -> bool {
|
||||||
self.public_keys.contains_key(id)
|
self.val_set.contains(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the set of validator IDs.
|
/// Returns the set of validator IDs.
|
||||||
|
@ -272,29 +247,12 @@ impl<N: NodeIdT> NetworkInfo<N> {
|
||||||
let sk_set = SecretKeySet::random(num_faulty, rng);
|
let sk_set = SecretKeySet::random(num_faulty, rng);
|
||||||
let pk_set = sk_set.public_keys();
|
let pk_set = sk_set.public_keys();
|
||||||
|
|
||||||
// Generate keys for individually signing and encrypting messages.
|
|
||||||
let sec_keys: BTreeMap<_, SecretKey> =
|
|
||||||
all_ids.iter().map(|id| (id.clone(), rng.gen())).collect();
|
|
||||||
let pub_keys: BTreeMap<_, PublicKey> = sec_keys
|
|
||||||
.iter()
|
|
||||||
.map(|(id, sk)| (id.clone(), sk.public_key()))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Create the corresponding `NetworkInfo` for each node.
|
// Create the corresponding `NetworkInfo` for each node.
|
||||||
let create_netinfo = |(i, id): (usize, N)| {
|
let create_netinfo = |(index, id): (usize, &N)| {
|
||||||
let netinfo = NetworkInfo::new(
|
let sks = sk_set.secret_key_share(index);
|
||||||
id.clone(),
|
let netinfo = NetworkInfo::new(id.clone(), sks, pk_set.clone(), &all_ids);
|
||||||
sk_set.secret_key_share(i),
|
Ok((id.clone(), netinfo))
|
||||||
pk_set.clone(),
|
|
||||||
sec_keys[&id].clone(),
|
|
||||||
pub_keys.clone(),
|
|
||||||
);
|
|
||||||
Ok((id, netinfo))
|
|
||||||
};
|
};
|
||||||
all_ids
|
all_ids.iter().enumerate().map(create_netinfo).collect()
|
||||||
.into_iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(create_netinfo)
|
|
||||||
.collect()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,7 @@ where
|
||||||
fn participant_change(&self) -> Option<BTreeSet<N>> {
|
fn participant_change(&self) -> Option<BTreeSet<N>> {
|
||||||
if let ChangeState::InProgress(Change::NodeChange(pub_keys)) = self.change() {
|
if let ChangeState::InProgress(Change::NodeChange(pub_keys)) = self.change() {
|
||||||
let candidates = pub_keys.keys();
|
let candidates = pub_keys.keys();
|
||||||
let current_validators: BTreeSet<&N> =
|
let current_validators: BTreeSet<&N> = self.public_keys().keys().collect();
|
||||||
self.network_info().public_key_map().keys().collect();
|
|
||||||
let participants = candidates.chain(current_validators).cloned().collect();
|
let participants = candidates.chain(current_validators).cloned().collect();
|
||||||
Some(participants)
|
Some(participants)
|
||||||
} else if let ChangeState::Complete(Change::NodeChange(pub_keys)) = self.change() {
|
} else if let ChangeState::Complete(Change::NodeChange(pub_keys)) = self.change() {
|
||||||
|
@ -143,7 +142,7 @@ where
|
||||||
if !self.is_removed {
|
if !self.is_removed {
|
||||||
return Err(Error::DynamicHoneyBadgerNotRemoved);
|
return Err(Error::DynamicHoneyBadgerNotRemoved);
|
||||||
}
|
}
|
||||||
let secret_key = self.algo().netinfo().secret_key().clone();
|
let secret_key = self.algo().secret_key().clone();
|
||||||
let id = self.algo().netinfo().our_id().clone();
|
let id = self.algo().netinfo().our_id().clone();
|
||||||
let (dhb, dhb_step) =
|
let (dhb, dhb_step) =
|
||||||
DynamicHoneyBadger::new_joining(id.clone(), secret_key, join_plan, rng)
|
DynamicHoneyBadger::new_joining(id.clone(), secret_key, join_plan, rng)
|
||||||
|
|
|
@ -57,23 +57,20 @@
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! use std::collections::BTreeMap;
|
//! use std::collections::BTreeMap;
|
||||||
|
//! use std::sync::Arc;
|
||||||
//!
|
//!
|
||||||
//! use threshold_crypto::{PublicKey, SecretKey, SignatureShare};
|
//! use threshold_crypto::{SecretKey, SignatureShare};
|
||||||
//! use hbbft::sync_key_gen::{AckOutcome, PartOutcome, SyncKeyGen};
|
//! use hbbft::sync_key_gen::{to_pub_keys, AckOutcome, PartOutcome, PubKeyMap, SyncKeyGen};
|
||||||
//!
|
//!
|
||||||
//! // Use the OS random number generator for any randomness:
|
//! // Use the OS random number generator for any randomness:
|
||||||
//! let mut rng = rand::OsRng::new().expect("Could not open OS random number generator.");
|
//! let mut rng = rand::rngs::OsRng::new().expect("Could not open OS random number generator.");
|
||||||
//!
|
//!
|
||||||
//! // Two out of four shares will suffice to sign or encrypt something.
|
//! // Two out of four shares will suffice to sign or encrypt something.
|
||||||
//! let (threshold, node_num) = (1, 4);
|
//! let (threshold, node_num) = (1, 4);
|
||||||
//!
|
//!
|
||||||
//! // Generate individual key pairs for encryption. These are not suitable for threshold schemes.
|
//! // Generate individual key pairs for encryption. These are not suitable for threshold schemes.
|
||||||
//! let sec_keys: Vec<SecretKey> = (0..node_num).map(|_| rand::random()).collect();
|
//! let sec_keys: Vec<SecretKey> = (0..node_num).map(|_| rand::random()).collect();
|
||||||
//! let pub_keys: BTreeMap<usize, PublicKey> = sec_keys
|
//! let pub_keys = to_pub_keys(sec_keys.iter().enumerate());
|
||||||
//! .iter()
|
|
||||||
//! .map(SecretKey::public_key)
|
|
||||||
//! .enumerate()
|
|
||||||
//! .collect();
|
|
||||||
//!
|
//!
|
||||||
//! // Create the `SyncKeyGen` instances. The constructor also outputs the part that needs to
|
//! // Create the `SyncKeyGen` instances. The constructor also outputs the part that needs to
|
||||||
//! // be sent to all other participants, so we save the parts together with their sender ID.
|
//! // be sent to all other participants, so we save the parts together with their sender ID.
|
||||||
|
@ -174,8 +171,15 @@
|
||||||
//! method above. The sum of the secret keys we received from each node is then used as our secret
|
//! method above. The sum of the secret keys we received from each node is then used as our secret
|
||||||
//! key. No single node knows the secret master key.
|
//! key. No single node knows the secret master key.
|
||||||
|
|
||||||
|
use std::borrow::Borrow;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::fmt::{self, Debug, Formatter};
|
use std::fmt::{self, Debug, Formatter};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use bincode;
|
||||||
|
use failure::Fail;
|
||||||
|
use rand;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::crypto::{
|
use crate::crypto::{
|
||||||
error::Error as CryptoError,
|
error::Error as CryptoError,
|
||||||
|
@ -184,12 +188,22 @@ use crate::crypto::{
|
||||||
Ciphertext, Fr, G1Affine, PublicKey, PublicKeySet, SecretKey, SecretKeyShare,
|
Ciphertext, Fr, G1Affine, PublicKey, PublicKeySet, SecretKey, SecretKeyShare,
|
||||||
};
|
};
|
||||||
use crate::pairing::{CurveAffine, Field};
|
use crate::pairing::{CurveAffine, Field};
|
||||||
use bincode;
|
use crate::NodeIdT;
|
||||||
use failure::Fail;
|
|
||||||
use rand;
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
|
|
||||||
use crate::{NetworkInfo, NodeIdT};
|
/// A map assigning to each node ID a public key, wrapped in an `Arc`.
|
||||||
|
pub type PubKeyMap<N> = Arc<BTreeMap<N, PublicKey>>;
|
||||||
|
|
||||||
|
/// Returns a `PubKeyMap` corresponding to the given secret keys.
|
||||||
|
///
|
||||||
|
/// This is mostly useful for setting up test networks.
|
||||||
|
pub fn to_pub_keys<'a, I, B, N: NodeIdT + 'a>(sec_keys: I) -> PubKeyMap<N>
|
||||||
|
where
|
||||||
|
B: Borrow<N>,
|
||||||
|
I: IntoIterator<Item = (B, &'a SecretKey)>,
|
||||||
|
{
|
||||||
|
let to_pub = |(id, sk): I::Item| (id.borrow().clone(), sk.public_key());
|
||||||
|
Arc::new(sec_keys.into_iter().map(to_pub).collect())
|
||||||
|
}
|
||||||
|
|
||||||
/// A local error while handling an `Ack` or `Part` message, that was not caused by that message
|
/// A local error while handling an `Ack` or `Part` message, that was not caused by that message
|
||||||
/// being invalid.
|
/// being invalid.
|
||||||
|
@ -307,7 +321,7 @@ pub struct SyncKeyGen<N> {
|
||||||
/// Our secret key.
|
/// Our secret key.
|
||||||
sec_key: SecretKey,
|
sec_key: SecretKey,
|
||||||
/// The public keys of all nodes, by node ID.
|
/// The public keys of all nodes, by node ID.
|
||||||
pub_keys: BTreeMap<N, PublicKey>,
|
pub_keys: PubKeyMap<N>,
|
||||||
/// Proposed bivariate polynomials.
|
/// Proposed bivariate polynomials.
|
||||||
parts: BTreeMap<u64, ProposalState>,
|
parts: BTreeMap<u64, ProposalState>,
|
||||||
/// The degree of the generated polynomial.
|
/// The degree of the generated polynomial.
|
||||||
|
@ -323,7 +337,7 @@ impl<N: NodeIdT> SyncKeyGen<N> {
|
||||||
pub fn new<R: rand::Rng>(
|
pub fn new<R: rand::Rng>(
|
||||||
our_id: N,
|
our_id: N,
|
||||||
sec_key: SecretKey,
|
sec_key: SecretKey,
|
||||||
pub_keys: BTreeMap<N, PublicKey>,
|
pub_keys: PubKeyMap<N>,
|
||||||
threshold: usize,
|
threshold: usize,
|
||||||
rng: &mut R,
|
rng: &mut R,
|
||||||
) -> Result<(SyncKeyGen<N>, Option<Part>), Error> {
|
) -> Result<(SyncKeyGen<N>, Option<Part>), Error> {
|
||||||
|
@ -359,7 +373,7 @@ impl<N: NodeIdT> SyncKeyGen<N> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the map of participating nodes and their public keys.
|
/// Returns the map of participating nodes and their public keys.
|
||||||
pub fn public_keys(&self) -> &BTreeMap<N, PublicKey> {
|
pub fn public_keys(&self) -> &PubKeyMap<N> {
|
||||||
&self.pub_keys
|
&self.pub_keys
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -461,17 +475,6 @@ impl<N: NodeIdT> SyncKeyGen<N> {
|
||||||
Ok((pk_commit.into(), opt_sk))
|
Ok((pk_commit.into(), opt_sk))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Consumes the instance, generates the key set and returns a new `NetworkInfo` with the new
|
|
||||||
/// keys.
|
|
||||||
///
|
|
||||||
/// All participating nodes must have handled the exact same sequence of `Part` and `Ack`
|
|
||||||
/// messages before calling this method. Otherwise their key shares will not match.
|
|
||||||
pub fn into_network_info(self) -> Result<NetworkInfo<N>, Error> {
|
|
||||||
let (pk_set, sk_share) = self.generate()?;
|
|
||||||
let netinfo = NetworkInfo::new(self.our_id, sk_share, pk_set, self.sec_key, self.pub_keys);
|
|
||||||
Ok(netinfo)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the number of nodes participating in the key generation.
|
/// Returns the number of nodes participating in the key generation.
|
||||||
pub fn num_nodes(&self) -> usize {
|
pub fn num_nodes(&self) -> usize {
|
||||||
self.pub_keys.len()
|
self.pub_keys.len()
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
use std::sync::Arc;
|
||||||
use std::time;
|
use std::time;
|
||||||
|
|
||||||
use hbbft::dynamic_honey_badger::{
|
use hbbft::dynamic_honey_badger::{
|
||||||
Batch, Change, ChangeState, DynamicHoneyBadger, Input, JoinPlan,
|
Batch, Change, ChangeState, DynamicHoneyBadger, Input, JoinPlan,
|
||||||
};
|
};
|
||||||
use hbbft::sender_queue::{SenderQueue, Step};
|
use hbbft::sender_queue::{SenderQueue, Step};
|
||||||
use hbbft::{util, Epoched};
|
use hbbft::{util, Epoched, PubKeyMap};
|
||||||
use hbbft_testing::adversary::{Adversary, ReorderingAdversary};
|
use hbbft_testing::adversary::{Adversary, ReorderingAdversary};
|
||||||
use hbbft_testing::proptest::{gen_seed, NetworkDimension, TestRng, TestRngSeed};
|
use hbbft_testing::proptest::{gen_seed, NetworkDimension, TestRng, TestRngSeed};
|
||||||
use hbbft_testing::{NetBuilder, NewNodeInfo, Node, VirtualNet};
|
use hbbft_testing::{NetBuilder, NewNodeInfo, Node, VirtualNet};
|
||||||
use proptest::{prelude::ProptestConfig, prop_compose, proptest};
|
use proptest::{prelude::ProptestConfig, prop_compose, proptest};
|
||||||
use rand::{seq::SliceRandom, SeedableRng};
|
use rand::{seq::SliceRandom, SeedableRng};
|
||||||
use threshold_crypto::PublicKey;
|
|
||||||
|
|
||||||
type DHB = SenderQueue<DynamicHoneyBadger<Vec<usize>, usize>>;
|
type DHB = SenderQueue<DynamicHoneyBadger<Vec<usize>, usize>>;
|
||||||
|
|
||||||
|
@ -108,7 +108,8 @@ fn do_drop_and_re_add(cfg: TestConfig) {
|
||||||
if id < num_faulty { "faulty" } else { "correct" },
|
if id < num_faulty { "faulty" } else { "correct" },
|
||||||
id
|
id
|
||||||
);
|
);
|
||||||
let dhb = DynamicHoneyBadger::builder().build(node.netinfo.clone());
|
let netinfo = node.netinfo.clone();
|
||||||
|
let dhb = DynamicHoneyBadger::builder().build(netinfo, node.secret_key, node.pub_keys);
|
||||||
SenderQueue::builder(dhb, node.netinfo.other_ids().cloned()).build(node.id)
|
SenderQueue::builder(dhb, node.netinfo.other_ids().cloned()).build(node.id)
|
||||||
})
|
})
|
||||||
.build(&mut rng)
|
.build(&mut rng)
|
||||||
|
@ -140,17 +141,13 @@ fn do_drop_and_re_add(cfg: TestConfig) {
|
||||||
|
|
||||||
// Afterwards, remove specific nodes from the dynamic honey badger network.
|
// Afterwards, remove specific nodes from the dynamic honey badger network.
|
||||||
let old_pub_keys = state.get_pub_keys();
|
let old_pub_keys = state.get_pub_keys();
|
||||||
let new_pub_keys: BTreeMap<usize, PublicKey> = old_pub_keys
|
let not_removed = |(id, _): &(usize, _)| !nodes_for_remove.contains(id);
|
||||||
.clone()
|
let old_pub_keys_iter = (*old_pub_keys).clone().into_iter();
|
||||||
.into_iter()
|
let new_pub_keys: PubKeyMap<usize> = Arc::new(old_pub_keys_iter.filter(not_removed).collect());
|
||||||
.filter(|(id, _)| !nodes_for_remove.contains(id))
|
let change = Input::Change(Change::NodeChange(new_pub_keys.clone()));
|
||||||
.collect();
|
|
||||||
state
|
state
|
||||||
.net
|
.net
|
||||||
.broadcast_input(
|
.broadcast_input(&change, &mut rng)
|
||||||
&Input::Change(Change::NodeChange(new_pub_keys.clone())),
|
|
||||||
&mut rng,
|
|
||||||
)
|
|
||||||
.expect("broadcasting failed");
|
.expect("broadcasting failed");
|
||||||
|
|
||||||
// We are tracking (correct) nodes' state through the process by ticking them off individually.
|
// We are tracking (correct) nodes' state through the process by ticking them off individually.
|
||||||
|
@ -529,14 +526,13 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns clone of all public keys for this network.
|
/// Returns clone of all public keys for this network.
|
||||||
fn get_pub_keys(&self) -> BTreeMap<usize, PublicKey> {
|
fn get_pub_keys(&self) -> PubKeyMap<usize> {
|
||||||
self.net
|
self.net
|
||||||
.get(0)
|
.get(0)
|
||||||
.expect("network should have at least one node")
|
.expect("network should have at least one node")
|
||||||
.algorithm()
|
.algorithm()
|
||||||
.algo()
|
.algo()
|
||||||
.netinfo()
|
.public_keys()
|
||||||
.public_key_map()
|
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use std::sync::Arc;
|
||||||
use hbbft::dynamic_honey_badger::{DynamicHoneyBadger, JoinPlan};
|
use hbbft::dynamic_honey_badger::{DynamicHoneyBadger, JoinPlan};
|
||||||
use hbbft::queueing_honey_badger::{Change, ChangeState, Input, QueueingHoneyBadger};
|
use hbbft::queueing_honey_badger::{Change, ChangeState, Input, QueueingHoneyBadger};
|
||||||
use hbbft::sender_queue::{Message, SenderQueue, Step};
|
use hbbft::sender_queue::{Message, SenderQueue, Step};
|
||||||
use hbbft::{util, NetworkInfo};
|
use hbbft::util;
|
||||||
use hbbft_testing::adversary::{Adversary, NodeOrderAdversary, ReorderingAdversary};
|
use hbbft_testing::adversary::{Adversary, NodeOrderAdversary, ReorderingAdversary};
|
||||||
use hbbft_testing::proptest::{gen_seed, TestRng, TestRngSeed};
|
use hbbft_testing::proptest::{gen_seed, TestRng, TestRngSeed};
|
||||||
use hbbft_testing::{NetBuilder, NewNodeInfo, Node, VirtualNet};
|
use hbbft_testing::{NetBuilder, NewNodeInfo, Node, VirtualNet};
|
||||||
|
@ -16,16 +16,17 @@ use proptest::{prelude::ProptestConfig, proptest};
|
||||||
use rand::{Rng, SeedableRng};
|
use rand::{Rng, SeedableRng};
|
||||||
|
|
||||||
type NodeId = u16;
|
type NodeId = u16;
|
||||||
type QHB = SenderQueue<QueueingHoneyBadger<usize, NodeId, Vec<usize>>>;
|
type QHB = QueueingHoneyBadger<usize, NodeId, Vec<usize>>;
|
||||||
|
type SQ = SenderQueue<QHB>;
|
||||||
|
|
||||||
// Send the second half of the transactions to the specified node.
|
// Send the second half of the transactions to the specified node.
|
||||||
fn input_second_half<A>(
|
fn input_second_half<A>(
|
||||||
net: &mut VirtualNet<QHB, A>,
|
net: &mut VirtualNet<SQ, A>,
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
num_txs: usize,
|
num_txs: usize,
|
||||||
mut rng: &mut TestRng,
|
mut rng: &mut TestRng,
|
||||||
) where
|
) where
|
||||||
A: Adversary<QHB>,
|
A: Adversary<SQ>,
|
||||||
{
|
{
|
||||||
for tx in (num_txs / 2)..num_txs {
|
for tx in (num_txs / 2)..num_txs {
|
||||||
let _ = net.send_input(id, Input::User(tx), &mut rng);
|
let _ = net.send_input(id, Input::User(tx), &mut rng);
|
||||||
|
@ -33,28 +34,28 @@ fn input_second_half<A>(
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Proposes `num_txs` values and expects nodes to output and order them.
|
/// Proposes `num_txs` values and expects nodes to output and order them.
|
||||||
fn test_queueing_honey_badger<A>(mut net: VirtualNet<QHB, A>, num_txs: usize, mut rng: &mut TestRng)
|
fn test_queueing_honey_badger<A>(mut net: VirtualNet<SQ, A>, num_txs: usize, mut rng: &mut TestRng)
|
||||||
where
|
where
|
||||||
A: Adversary<QHB>,
|
A: Adversary<SQ>,
|
||||||
{
|
{
|
||||||
let netinfo = net
|
// Make two copies of all public keys.
|
||||||
|
let pub_keys_add = net
|
||||||
.correct_nodes()
|
.correct_nodes()
|
||||||
.nth(0)
|
.nth(0)
|
||||||
.expect("At least one correct node needs to exist")
|
.expect("At least one correct node needs to exist")
|
||||||
.algorithm()
|
.algorithm()
|
||||||
.algo()
|
.algo()
|
||||||
.netinfo()
|
.dyn_hb()
|
||||||
|
.public_keys()
|
||||||
.clone();
|
.clone();
|
||||||
|
|
||||||
// Make two copies of all public keys.
|
|
||||||
let pub_keys_add = netinfo.public_key_map().clone();
|
|
||||||
let mut pub_keys_rm = pub_keys_add.clone();
|
let mut pub_keys_rm = pub_keys_add.clone();
|
||||||
|
|
||||||
// Get the first correct node id as candidate for removal/re-adding.
|
// Get the first correct node id as candidate for removal/re-adding.
|
||||||
let first_correct_node = *net.correct_nodes().nth(0).unwrap().id();
|
let first_correct_node = *net.correct_nodes().nth(0).unwrap().id();
|
||||||
|
|
||||||
// Remove the first correct node, which is to be removed.
|
// Remove the first correct node, which is to be removed.
|
||||||
pub_keys_rm.remove(&first_correct_node);
|
Arc::make_mut(&mut pub_keys_rm).remove(&first_correct_node);
|
||||||
|
|
||||||
// Broadcast public keys of all nodes except for the node to be removed.
|
// Broadcast public keys of all nodes except for the node to be removed.
|
||||||
let _ = net.broadcast_input(
|
let _ = net.broadcast_input(
|
||||||
|
@ -69,7 +70,7 @@ where
|
||||||
|
|
||||||
// Closure for checking the output of a node for ChangeSet completion containing
|
// Closure for checking the output of a node for ChangeSet completion containing
|
||||||
// all nodes but the removed node.
|
// all nodes but the removed node.
|
||||||
let has_remove = |node: &Node<QHB>| {
|
let has_remove = |node: &Node<SQ>| {
|
||||||
node.outputs().iter().any(|batch| match batch.change() {
|
node.outputs().iter().any(|batch| match batch.change() {
|
||||||
ChangeState::Complete(Change::NodeChange(pub_keys)) => pub_keys == &pub_keys_rm,
|
ChangeState::Complete(Change::NodeChange(pub_keys)) => pub_keys == &pub_keys_rm,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -78,7 +79,7 @@ where
|
||||||
|
|
||||||
// Closure for checking the output of a node for ChangeSet completion containing
|
// Closure for checking the output of a node for ChangeSet completion containing
|
||||||
// all nodes, including the previously removed node.
|
// all nodes, including the previously removed node.
|
||||||
let has_add = |node: &Node<QHB>| {
|
let has_add = |node: &Node<SQ>| {
|
||||||
node.outputs().iter().any(|batch| match batch.change() {
|
node.outputs().iter().any(|batch| match batch.change() {
|
||||||
ChangeState::Complete(Change::NodeChange(pub_keys)) => pub_keys == &pub_keys_add,
|
ChangeState::Complete(Change::NodeChange(pub_keys)) => pub_keys == &pub_keys_add,
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -86,7 +87,7 @@ where
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns `true` if the node has not output all changes or transactions yet.
|
// Returns `true` if the node has not output all changes or transactions yet.
|
||||||
let node_busy = |node: &Node<QHB>| {
|
let node_busy = |node: &Node<SQ>| {
|
||||||
!has_remove(node) || !has_add(node) || !node.algorithm().algo().queue().is_empty()
|
!has_remove(node) || !has_add(node) || !node.algorithm().algo().queue().is_empty()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -106,7 +107,7 @@ where
|
||||||
let mut rejoined_first_correct = false;
|
let mut rejoined_first_correct = false;
|
||||||
// The removed first correct node which is to be restarted as soon as all remaining
|
// The removed first correct node which is to be restarted as soon as all remaining
|
||||||
// validators agreed to add it back.
|
// validators agreed to add it back.
|
||||||
let mut saved_first_correct: Option<Node<QHB>> = None;
|
let mut saved_first_correct: Option<Node<SQ>> = None;
|
||||||
|
|
||||||
// Handle messages in random order until all nodes have output all transactions.
|
// Handle messages in random order until all nodes have output all transactions.
|
||||||
while net.correct_nodes().any(node_busy) {
|
while net.correct_nodes().any(node_busy) {
|
||||||
|
@ -186,14 +187,14 @@ where
|
||||||
|
|
||||||
/// Restarts specified node on the test network for adding it back as a validator.
|
/// Restarts specified node on the test network for adding it back as a validator.
|
||||||
fn restart_node_for_add<R, A>(
|
fn restart_node_for_add<R, A>(
|
||||||
net: &mut VirtualNet<QHB, A>,
|
net: &mut VirtualNet<SQ, A>,
|
||||||
mut node: Node<QHB>,
|
mut node: Node<SQ>,
|
||||||
join_plan: JoinPlan<NodeId>,
|
join_plan: JoinPlan<NodeId>,
|
||||||
mut rng: &mut R,
|
mut rng: &mut R,
|
||||||
) -> Step<QueueingHoneyBadger<usize, NodeId, Vec<usize>>>
|
) -> Step<QueueingHoneyBadger<usize, NodeId, Vec<usize>>>
|
||||||
where
|
where
|
||||||
R: rand::Rng,
|
R: rand::Rng,
|
||||||
A: Adversary<QHB>,
|
A: Adversary<SQ>,
|
||||||
{
|
{
|
||||||
let our_id = *node.id();
|
let our_id = *node.id();
|
||||||
println!("Restarting node {} with {:?}", node.id(), join_plan);
|
println!("Restarting node {} with {:?}", node.id(), join_plan);
|
||||||
|
@ -206,7 +207,7 @@ where
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let secret_key = node.algorithm().algo().netinfo().secret_key().clone();
|
let secret_key = node.algorithm().algo().dyn_hb().secret_key().clone();
|
||||||
let (qhb, qhb_step) =
|
let (qhb, qhb_step) =
|
||||||
QueueingHoneyBadger::builder_joining(our_id, secret_key, join_plan, &mut rng)
|
QueueingHoneyBadger::builder_joining(our_id, secret_key, join_plan, &mut rng)
|
||||||
.and_then(|builder| builder.batch_size(3).build(&mut rng))
|
.and_then(|builder| builder.batch_size(3).build(&mut rng))
|
||||||
|
@ -220,18 +221,17 @@ where
|
||||||
|
|
||||||
// Allow passing `netinfo` by value. `TestNetwork` expects this function signature.
|
// Allow passing `netinfo` by value. `TestNetwork` expects this function signature.
|
||||||
#[allow(clippy::needless_pass_by_value)]
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
fn new_queueing_hb(
|
fn new_queueing_hb(node_info: NewNodeInfo<SQ>, seed: TestRngSeed) -> (SQ, Step<QHB>) {
|
||||||
netinfo: Arc<NetworkInfo<NodeId>>,
|
|
||||||
seed: TestRngSeed,
|
|
||||||
) -> (QHB, Step<QueueingHoneyBadger<usize, NodeId, Vec<usize>>>) {
|
|
||||||
let mut rng: TestRng = TestRng::from_seed(seed);
|
let mut rng: TestRng = TestRng::from_seed(seed);
|
||||||
let peer_ids = netinfo.other_ids().cloned();
|
let peer_ids = node_info.netinfo.other_ids().cloned();
|
||||||
let dhb = DynamicHoneyBadger::builder().build((*netinfo).clone());
|
let netinfo = node_info.netinfo.clone();
|
||||||
|
let dhb =
|
||||||
|
DynamicHoneyBadger::builder().build(netinfo, node_info.secret_key, node_info.pub_keys);
|
||||||
let (qhb, qhb_step) = QueueingHoneyBadger::builder(dhb)
|
let (qhb, qhb_step) = QueueingHoneyBadger::builder(dhb)
|
||||||
.batch_size(3)
|
.batch_size(3)
|
||||||
.build(&mut rng)
|
.build(&mut rng)
|
||||||
.expect("failed to build QueueingHoneyBadger");
|
.expect("failed to build QueueingHoneyBadger");
|
||||||
let our_id = *netinfo.our_id();
|
let our_id = *node_info.netinfo.our_id();
|
||||||
let (sq, mut step) = SenderQueue::builder(qhb, peer_ids).build(our_id);
|
let (sq, mut step) = SenderQueue::builder(qhb, peer_ids).build(our_id);
|
||||||
let output = step.extend_with(qhb_step, |fault| fault, Message::from);
|
let output = step.extend_with(qhb_step, |fault| fault, Message::from);
|
||||||
assert!(output.is_empty());
|
assert!(output.is_empty());
|
||||||
|
@ -243,7 +243,7 @@ fn test_queueing_honey_badger_different_sizes<A, F>(
|
||||||
num_txs: usize,
|
num_txs: usize,
|
||||||
seed: TestRngSeed,
|
seed: TestRngSeed,
|
||||||
) where
|
) where
|
||||||
A: Adversary<QHB>,
|
A: Adversary<SQ>,
|
||||||
F: Fn() -> A,
|
F: Fn() -> A,
|
||||||
{
|
{
|
||||||
// This returns an error in all but the first test.
|
// This returns an error in all but the first test.
|
||||||
|
@ -272,7 +272,7 @@ fn test_queueing_honey_badger_different_sizes<A, F>(
|
||||||
// needs to be mutable, while we are in a function which captures immutably.
|
// needs to be mutable, while we are in a function which captures immutably.
|
||||||
// To avoid convoluted clone/borrow constructs we pass a TestRngSeed
|
// To avoid convoluted clone/borrow constructs we pass a TestRngSeed
|
||||||
// rather than a TestRng instance.
|
// rather than a TestRng instance.
|
||||||
new_queueing_hb(Arc::new(node_info.netinfo), seed)
|
new_queueing_hb(node_info, seed)
|
||||||
})
|
})
|
||||||
.build(&mut rng)
|
.build(&mut rng)
|
||||||
.expect("Could not construct test network.");
|
.expect("Could not construct test network.");
|
||||||
|
|
|
@ -3,18 +3,14 @@
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
use hbbft::crypto::{PublicKey, SecretKey};
|
use hbbft::crypto::SecretKey;
|
||||||
use hbbft::sync_key_gen::{PartOutcome, SyncKeyGen};
|
use hbbft::sync_key_gen::{to_pub_keys, PartOutcome, SyncKeyGen};
|
||||||
use hbbft::util;
|
use hbbft::util;
|
||||||
|
|
||||||
fn test_sync_key_gen_with(threshold: usize, node_num: usize) {
|
fn test_sync_key_gen_with(threshold: usize, node_num: usize) {
|
||||||
// Generate individual key pairs for encryption. These are not suitable for threshold schemes.
|
// Generate individual key pairs for encryption. These are not suitable for threshold schemes.
|
||||||
let sec_keys: Vec<SecretKey> = (0..node_num).map(|_| SecretKey::random()).collect();
|
let sec_keys: Vec<SecretKey> = (0..node_num).map(|_| SecretKey::random()).collect();
|
||||||
let pub_keys: BTreeMap<usize, PublicKey> = sec_keys
|
let pub_keys = to_pub_keys(sec_keys.iter().enumerate());
|
||||||
.iter()
|
|
||||||
.map(SecretKey::public_key)
|
|
||||||
.enumerate()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// Create the `SyncKeyGen` instances and initial proposals.
|
// Create the `SyncKeyGen` instances and initial proposals.
|
||||||
let mut nodes = Vec::new();
|
let mut nodes = Vec::new();
|
||||||
|
|
Loading…
Reference in New Issue