Separate keys and key shares.

This commit is contained in:
Andreas Fackler 2018-07-17 15:54:12 +02:00
parent 2d9b872484
commit 15cc6ffddd
22 changed files with 353 additions and 249 deletions

View File

@ -29,7 +29,7 @@ env:
- RUST_NEXT=nightly-2018-07-13
script:
- cargo +${RUST_NEXT} clippy -- --deny clippy
- cargo +${RUST_NEXT} clippy --tests -- --deny clippy
- cargo +${RUST_NEXT} clippy --tests --examples -- --deny clippy
- cargo +${RUST_NEXT} clippy --all-features -- --deny clippy
- cargo +${RUST_NEXT} clippy --all-features --tests -- --deny clippy
- cargo +${RUST_NEXT} fmt -- --check

View File

@ -44,7 +44,7 @@ use std::{io, iter, process, thread, time};
use hbbft::broadcast::{Broadcast, BroadcastMessage};
use hbbft::crypto::poly::Poly;
use hbbft::crypto::SecretKeySet;
use hbbft::crypto::{SecretKey, SecretKeySet};
use hbbft::messaging::{DistAlgorithm, NetworkInfo, SourcedMessage};
use hbbft::proto::message::BroadcastProto;
use network::commst;
@ -107,10 +107,15 @@ impl<T: Clone + Debug + AsRef<[u8]> + PartialEq + Send + Sync + From<Vec<u8>> +
// keys here. A fully-featured application would need to take appropriately initialized keys
// from elsewhere.
let secret_key_set = SecretKeySet::from(Poly::zero());
let secret_key = secret_key_set.secret_key_share(our_id as u64);
let public_key_set = secret_key_set.public_keys();
let sk_share = secret_key_set.secret_key_share(our_id as u64);
let pub_key_set = secret_key_set.public_keys();
let sk = SecretKey::default();
let pub_keys = all_ids
.iter()
.map(|id| (*id, SecretKey::default().public_key()))
.collect();
let netinfo = NetworkInfo::new(our_id, all_ids.clone(), secret_key, public_key_set);
let netinfo = NetworkInfo::new(our_id, sk_share, pub_key_set, sk, pub_keys);
if value.is_some() != (our_id == 0) {
panic!("Exactly the first node must propose a value.");

View File

@ -13,7 +13,7 @@ extern crate serde;
extern crate serde_derive;
extern crate signifix;
use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::collections::{BTreeMap, VecDeque};
use std::time::{Duration, Instant};
use std::{cmp, u64};
@ -25,7 +25,7 @@ use serde::de::DeserializeOwned;
use serde::Serialize;
use signifix::{metric, TryFrom};
use hbbft::crypto::SecretKeySet;
use hbbft::dynamic_honey_badger::DynamicHoneyBadger;
use hbbft::messaging::{DistAlgorithm, NetworkInfo, Step, Target};
use hbbft::queueing_honey_badger::{Batch, QueueingHoneyBadger};
@ -246,22 +246,19 @@ where
/// Creates a new network with `good_num` good nodes, and `dead_num` dead nodes.
pub fn new<F>(
good_num: usize,
dead_num: usize,
adv_num: usize,
new_algo: F,
hw_quality: HwQuality,
) -> TestNetwork<D>
where
F: Fn(NodeUid, BTreeSet<NodeUid>) -> D,
F: Fn(NetworkInfo<NodeUid>) -> D,
{
let node_ids: BTreeSet<NodeUid> = (0..(good_num + dead_num)).map(NodeUid).collect();
let new_node_by_id = |id: NodeUid| {
(
id,
TestNode::new(new_algo(id, node_ids.clone()), hw_quality),
)
let netinfos = NetworkInfo::generate_map((0..(good_num + adv_num)).map(NodeUid));
let new_node = |(uid, netinfo): (NodeUid, NetworkInfo<_>)| {
(uid, TestNode::new(new_algo(netinfo), hw_quality))
};
let mut network = TestNetwork {
nodes: (0..good_num).map(NodeUid).map(new_node_by_id).collect(),
nodes: netinfos.into_iter().map(new_node).collect(),
};
let initial_msgs: Vec<_> = network
.nodes
@ -363,8 +360,8 @@ impl EpochInfo {
println!(
"{:>5} {:6} {:6} {:5} {:9} {:>9}B",
batch.epoch().to_string().cyan(),
min_t.as_secs() * 1000 + max_t.subsec_nanos() as u64 / 1_000_000,
max_t.as_secs() * 1000 + max_t.subsec_nanos() as u64 / 1_000_000,
min_t.as_secs() * 1000 + u64::from(max_t.subsec_nanos()) / 1_000_000,
max_t.as_secs() * 1000 + u64::from(max_t.subsec_nanos()) / 1_000_000,
txs,
network.message_count() / network.nodes.len(),
metric::Signifix::try_from(network.message_size() / network.nodes.len() as u64)
@ -433,19 +430,14 @@ fn main() {
println!();
let num_good_nodes = args.flag_n - args.flag_f;
let txs = (0..args.flag_txs).map(|_| Transaction::new(args.flag_tx_size));
let sk_set = SecretKeySet::random(args.flag_f, &mut rand::thread_rng());
let pk_set = sk_set.public_keys();
let new_honey_badger = |id: NodeUid, all_ids: BTreeSet<NodeUid>| {
let netinfo = NetworkInfo::new(
id,
all_ids,
sk_set.secret_key_share(id.0 as u64),
pk_set.clone(),
);
QueueingHoneyBadger::builder(netinfo)
let new_honey_badger = |netinfo: NetworkInfo<NodeUid>| {
let dyn_hb = DynamicHoneyBadger::builder(netinfo)
.build()
.expect("instantiate DynamicHoneyBadger");
QueueingHoneyBadger::builder(dyn_hb)
.batch_size(args.flag_b)
.build_with_transactions(txs.clone())
.expect("Instantiate honey_badger")
.expect("instantiate QueueingHoneyBadger")
};
let hw_quality = HwQuality {
latency: Duration::from_millis(args.flag_lag),

View File

@ -271,7 +271,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
proposer_id: NodeUid,
) -> AgreementResult<Self> {
let invocation_id = netinfo.invocation_id();
if let Some(&proposer_i) = netinfo.node_index(&proposer_id) {
if let Some(proposer_i) = netinfo.node_index(&proposer_id) {
Ok(Agreement {
netinfo: netinfo.clone(),
session_id,
@ -670,7 +670,7 @@ impl<NodeUid: Clone + Debug + Ord> Agreement<NodeUid> {
let nonce = Nonce::new(
self.netinfo.invocation_id().as_ref(),
self.session_id,
*self.netinfo.node_index(&self.proposer_id).unwrap(),
self.netinfo.node_index(&self.proposer_id).unwrap(),
self.epoch,
);
// TODO: Don't spend time creating a `CommonCoin` instance in epochs where the common coin

View File

@ -65,23 +65,13 @@
//! const NUM_NODES: u64 = 7;
//! const PROPOSER_ID: u64 = 3;
//!
//! // Create set of node ids.
//! let all_uids: BTreeSet<_> = (0..NUM_NODES).collect();
//!
//! // Secret keys are required to complete the NetworkInfo structure, but not used in the
//! // broadcast algorithm.
//! let mut rng = thread_rng();
//! let secret_keys = SecretKeySet::random(4, &mut rng);
//!
//! // Create initial nodes by instantiating a `NetworkInfo` for each:
//! let mut nodes: BTreeMap<_, _> = all_uids.iter().cloned().map(|i| {
//! let netinfo = NetworkInfo::new(
//! i,
//! all_uids.clone(),
//! secret_keys.secret_key_share(i),
//! secret_keys.public_keys(),
//! );
//! // Create a random set of keys for testing.
//! let netinfos = NetworkInfo::generate_map(0..NUM_NODES);
//!
//! // Create initial nodes by instantiating a `Broadcast` for each:
//! let mut nodes: BTreeMap<_, _> = netinfos.into_iter().map(|(i, netinfo)| {
//! let bc = Broadcast::new(Arc::new(netinfo), PROPOSER_ID)
//! .expect("could not instantiate Broadcast");
//!
@ -267,7 +257,7 @@ impl<NodeUid: Debug + Clone + Ord> DistAlgorithm for Broadcast<NodeUid> {
sender_id: &NodeUid,
message: Self::Message,
) -> BroadcastResult<BroadcastStep<NodeUid>> {
if !self.netinfo.all_uids().contains(sender_id) {
if !self.netinfo.is_node_validator(sender_id) {
return Err(ErrorKind::UnknownSender.into());
}
let fault_log = match message {
@ -538,7 +528,6 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
let mut leaf_values: Vec<Option<Box<[u8]>>> = self
.netinfo
.all_uids()
.iter()
.map(|id| {
self.echos.get(id).and_then(|p| {
if p.root_hash.as_slice() == hash {
@ -555,11 +544,6 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
Ok(())
}
/// Returns `i` if `node_id` is the `i`-th ID among all participating nodes.
fn index_of_node(&self, node_id: &NodeUid) -> Option<usize> {
self.netinfo.all_uids().iter().position(|id| id == node_id)
}
/// Returns `true` if the proof is valid and has the same index as the node ID. Otherwise
/// logs an info message.
fn validate_proof(&self, p: &Proof<Vec<u8>>, id: &NodeUid) -> bool {
@ -570,7 +554,7 @@ impl<NodeUid: Debug + Clone + Ord> Broadcast<NodeUid> {
HexProof(&p)
);
false
} else if self.index_of_node(id) != Some(p.value[0] as usize)
} else if self.netinfo.node_index(id) != Some(p.value[0] as usize)
|| p.index(self.netinfo.num_nodes()) != p.value[0] as usize
{
info!(

View File

@ -26,7 +26,7 @@ use std::fmt::Debug;
use std::sync::Arc;
use crypto::error as cerror;
use crypto::Signature;
use crypto::{Signature, SignatureShare};
use fault_log::{FaultKind, FaultLog};
use messaging::{DistAlgorithm, NetworkInfo, Step, Target, TargetedMessage};
@ -46,14 +46,14 @@ error_chain! {
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Rand)]
pub struct CommonCoinMessage(Signature);
pub struct CommonCoinMessage(SignatureShare);
impl CommonCoinMessage {
pub fn new(sig: Signature) -> Self {
pub fn new(sig: SignatureShare) -> Self {
CommonCoinMessage(sig)
}
pub fn to_sig(&self) -> &Signature {
pub fn to_sig(&self) -> &SignatureShare {
&self.0
}
}
@ -71,7 +71,7 @@ pub struct CommonCoin<NodeUid, T> {
/// Outgoing message queue.
messages: VecDeque<CommonCoinMessage>,
/// All received threshold signature shares.
received_shares: BTreeMap<NodeUid, Signature>,
received_shares: BTreeMap<NodeUid, SignatureShare>,
/// Whether we provided input to the common coin.
had_input: bool,
/// Termination flag.
@ -163,13 +163,17 @@ where
self.try_output()?;
return Ok(FaultLog::new());
}
let share = self.netinfo.secret_key().sign(&self.nonce);
let share = self.netinfo.secret_key_share().sign(&self.nonce);
self.messages.push_back(CommonCoinMessage(share.clone()));
let id = self.netinfo.our_uid().clone();
self.handle_share(&id, share)
}
fn handle_share(&mut self, sender_id: &NodeUid, share: Signature) -> Result<FaultLog<NodeUid>> {
fn handle_share(
&mut self,
sender_id: &NodeUid,
share: SignatureShare,
) -> Result<FaultLog<NodeUid>> {
if let Some(pk_i) = self.netinfo.public_key_share(sender_id) {
if !pk_i.verify(&share, &self.nonce) {
// Log the faulty node and ignore the invalid share.
@ -206,13 +210,13 @@ where
fn combine_and_verify_sig(&self) -> Result<Signature> {
// Pass the indices of sender nodes to `combine_signatures`.
let ids_shares: BTreeMap<&NodeUid, &Signature> = self.received_shares.iter().collect();
let ids_shares: BTreeMap<&NodeUid, &SignatureShare> = self.received_shares.iter().collect();
let ids_u64: BTreeMap<&NodeUid, u64> = ids_shares
.keys()
.map(|&id| (id, *self.netinfo.node_index(id).unwrap() as u64))
.map(|&id| (id, self.netinfo.node_index(id).unwrap() as u64))
.collect();
// Convert indices to `u64` which is an interface type for `pairing`.
let shares: BTreeMap<&u64, &Signature> = ids_shares
let shares: BTreeMap<&u64, &SignatureShare> = ids_shares
.iter()
.map(|(id, &share)| (&ids_u64[id], share))
.collect();

View File

@ -159,10 +159,10 @@ impl<NodeUid: Clone + Debug + Ord + Rand> CommonSubset<NodeUid> {
// Create all agreement instances.
let mut agreement_instances: BTreeMap<NodeUid, Agreement<NodeUid>> = BTreeMap::new();
for proposer_id in netinfo.all_uids().iter().cloned() {
for proposer_id in netinfo.all_uids() {
agreement_instances.insert(
proposer_id.clone(),
Agreement::new(netinfo.clone(), session_id, proposer_id)?,
Agreement::new(netinfo.clone(), session_id, proposer_id.clone())?,
);
}

View File

@ -28,7 +28,7 @@ const CHACHA_RNG_SEED_SIZE: usize = 8;
const ERR_OS_RNG: &str = "could not initialize the OS random number generator";
/// A public key, or a public key share.
/// A public key.
#[derive(Deserialize, Serialize, Copy, Clone, PartialEq, Eq)]
pub struct PublicKey(#[serde(with = "serde_impl::projective")] G1);
@ -57,13 +57,6 @@ impl PublicKey {
self.verify_g2(sig, hash_g2(msg))
}
/// Returns `true` if the decryption share matches the ciphertext.
pub fn verify_decryption_share(&self, share: &DecryptionShare, ct: &Ciphertext) -> bool {
let Ciphertext(ref u, ref v, ref w) = *ct;
let hash = hash_g1_g2(*u, v);
Bls12::pairing(share.0, hash) == Bls12::pairing(self.0, *w)
}
/// Encrypts the message.
pub fn encrypt<M: AsRef<[u8]>>(&self, msg: M) -> Ciphertext {
let r: Fr = OsRng::new().expect(ERR_OS_RNG).gen();
@ -82,8 +75,44 @@ impl PublicKey {
}
}
/// A signature, or a signature share.
// note: random signatures can be generated for testing
/// A public key share.
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, Hash)]
pub struct PublicKeyShare(PublicKey);
impl fmt::Debug for PublicKeyShare {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let uncomp = (self.0).0.into_affine().into_uncompressed();
let bytes = uncomp.as_ref();
write!(f, "PublicKeyShare({:?})", HexBytes(bytes))
}
}
impl PublicKeyShare {
/// Returns `true` if the signature matches the element of `G2`.
pub fn verify_g2<H: Into<G2Affine>>(&self, sig: &SignatureShare, hash: H) -> bool {
self.0.verify_g2(&sig.0, hash)
}
/// Returns `true` if the signature matches the message.
pub fn verify<M: AsRef<[u8]>>(&self, sig: &SignatureShare, msg: M) -> bool {
self.verify_g2(sig, hash_g2(msg))
}
/// Returns `true` if the decryption share matches the ciphertext.
pub fn verify_decryption_share(&self, share: &DecryptionShare, ct: &Ciphertext) -> bool {
let Ciphertext(ref u, ref v, ref w) = *ct;
let hash = hash_g1_g2(*u, v);
Bls12::pairing(share.0, hash) == Bls12::pairing((self.0).0, *w)
}
/// Returns a byte string representation of the public key share.
pub fn to_bytes(&self) -> Vec<u8> {
self.0.to_bytes()
}
}
/// A signature.
// Note: Random signatures can be generated for testing.
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, Rand)]
pub struct Signature(#[serde(with = "serde_impl::projective")] G2);
@ -112,7 +141,20 @@ impl Signature {
}
}
/// A secret key, or a secret key share.
/// A signature share.
// Note: Random signature shares can be generated for testing.
#[derive(Deserialize, Serialize, Clone, PartialEq, Eq, Rand, Hash)]
pub struct SignatureShare(pub(crate) Signature);
impl fmt::Debug for SignatureShare {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let uncomp = (self.0).0.into_affine().into_uncompressed();
let bytes = uncomp.as_ref();
write!(f, "SignatureShare({:?})", HexBytes(bytes))
}
}
/// A secret key.
#[derive(Clone, PartialEq, Eq, Rand)]
pub struct SecretKey(Fr);
@ -169,13 +211,47 @@ impl SecretKey {
let g = u.into_affine().mul(self.0);
Some(xor_vec(&hash_bytes(g, v.len()), v))
}
}
/// A secret key share.
#[derive(Clone, PartialEq, Eq, Rand, Default)]
pub struct SecretKeyShare(SecretKey);
impl fmt::Debug for SecretKeyShare {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let uncomp = self.0.public_key().0.into_affine().into_uncompressed();
let bytes = uncomp.as_ref();
write!(f, "SecretKeyShare({:?})", HexBytes(bytes))
}
}
impl SecretKeyShare {
/// Creates a secret key share from an existing value
pub fn from_value(f: Fr) -> Self {
SecretKeyShare(SecretKey::from_value(f))
}
/// Returns the matching public key share.
pub fn public_key_share(&self) -> PublicKeyShare {
PublicKeyShare(self.0.public_key())
}
/// Signs the given element of `G2`.
pub fn sign_g2<H: Into<G2Affine>>(&self, hash: H) -> SignatureShare {
SignatureShare(self.0.sign_g2(hash))
}
/// Signs the given message.
pub fn sign<M: AsRef<[u8]>>(&self, msg: M) -> SignatureShare {
SignatureShare(self.0.sign(msg))
}
/// Returns a decryption share, or `None`, if the ciphertext isn't valid.
pub fn decrypt_share(&self, ct: &Ciphertext) -> Option<DecryptionShare> {
if !ct.verify() {
return None;
}
Some(DecryptionShare(ct.0.into_affine().mul(self.0)))
Some(DecryptionShare(ct.0.into_affine().mul((self.0).0)))
}
}
@ -249,17 +325,18 @@ impl PublicKeySet {
}
/// Returns the `i`-th public key share.
pub fn public_key_share<T: Into<FrRepr>>(&self, i: T) -> PublicKey {
PublicKey(self.commit.evaluate(from_repr_plus_1::<Fr>(i.into())))
pub fn public_key_share<T: Into<FrRepr>>(&self, i: T) -> PublicKeyShare {
let value = self.commit.evaluate(from_repr_plus_1::<Fr>(i.into()));
PublicKeyShare(PublicKey(value))
}
/// Combines the shares into a signature that can be verified with the main public key.
pub fn combine_signatures<'a, ITR, IND>(&self, shares: ITR) -> Result<Signature>
where
ITR: IntoIterator<Item = (&'a IND, &'a Signature)>,
ITR: IntoIterator<Item = (&'a IND, &'a SignatureShare)>,
IND: Into<FrRepr> + Clone + 'a,
{
let samples = shares.into_iter().map(|(i, share)| (i, &share.0));
let samples = shares.into_iter().map(|(i, share)| (i, &(share.0).0));
Ok(Signature(interpolate(self.commit.degree() + 1, samples)?))
}
@ -304,8 +381,9 @@ impl SecretKeySet {
}
/// Returns the `i`-th secret key share.
pub fn secret_key_share<T: Into<FrRepr>>(&self, i: T) -> SecretKey {
SecretKey(self.poly.evaluate(from_repr_plus_1::<Fr>(i.into())))
pub fn secret_key_share<T: Into<FrRepr>>(&self, i: T) -> SecretKeyShare {
let value = self.poly.evaluate(from_repr_plus_1::<Fr>(i.into()));
SecretKeyShare(SecretKey(value))
}
/// Returns the corresponding public key set. That information can be shared publicly.
@ -430,14 +508,14 @@ mod tests {
let pk_set = sk_set.public_keys();
// Make sure the keys are different, and the first coefficient is the main key.
assert_ne!(pk_set.public_key(), pk_set.public_key_share(0));
assert_ne!(pk_set.public_key(), pk_set.public_key_share(1));
assert_ne!(pk_set.public_key(), pk_set.public_key_share(2));
assert_ne!(pk_set.public_key(), pk_set.public_key_share(0).0);
assert_ne!(pk_set.public_key(), pk_set.public_key_share(1).0);
assert_ne!(pk_set.public_key(), pk_set.public_key_share(2).0);
// Make sure we don't hand out the main secret key to anyone.
assert_ne!(sk_set.secret_key(), sk_set.secret_key_share(0));
assert_ne!(sk_set.secret_key(), sk_set.secret_key_share(1));
assert_ne!(sk_set.secret_key(), sk_set.secret_key_share(2));
assert_ne!(sk_set.secret_key(), sk_set.secret_key_share(0).0);
assert_ne!(sk_set.secret_key(), sk_set.secret_key_share(1).0);
assert_ne!(sk_set.secret_key(), sk_set.secret_key_share(2).0);
let msg = "Totally real news";

View File

@ -1,11 +1,11 @@
use std::collections::{BTreeMap, BTreeSet};
use std::collections::BTreeMap;
use std::fmt::Debug;
use rand::Rand;
use serde::{Deserialize, Serialize};
use super::{ChangeState, JoinPlan};
use crypto::PublicKeySet;
use crypto::{PublicKey, PublicKeySet};
use messaging::NetworkInfo;
/// A batch of transactions the algorithm has output.
@ -19,7 +19,7 @@ pub struct Batch<C, NodeUid> {
/// this epoch.
change: ChangeState<NodeUid>,
/// The public network info, if `change` is not `None`.
pub_netinfo: Option<(BTreeSet<NodeUid>, PublicKeySet)>,
pub_netinfo: Option<(PublicKeySet, BTreeMap<NodeUid, PublicKey>)>,
}
impl<C, NodeUid: Ord + Rand + Clone + Debug> Batch<C, NodeUid> {
@ -90,11 +90,11 @@ impl<C, NodeUid: Ord + Rand + Clone + Debug> Batch<C, NodeUid> {
{
self.pub_netinfo
.as_ref()
.map(|&(ref all_uids, ref pub_key_set)| JoinPlan {
.map(|&(ref pub_key_set, ref pub_keys)| JoinPlan {
epoch: self.epoch + 1,
change: self.change.clone(),
all_uids: all_uids.clone(),
pub_key_set: pub_key_set.clone(),
pub_keys: pub_keys.clone(),
})
}
@ -107,7 +107,10 @@ impl<C, NodeUid: Ord + Rand + Clone + Debug> Batch<C, NodeUid> {
) {
self.change = change;
if self.change != ChangeState::None {
self.pub_netinfo = Some((netinfo.all_uids().clone(), netinfo.public_key_set().clone()));
self.pub_netinfo = Some((
netinfo.public_key_set().clone(),
netinfo.public_key_map().clone(),
));
}
}
}

View File

@ -5,11 +5,11 @@ use std::iter::once;
use std::marker::PhantomData;
use std::sync::Arc;
use rand::{self, Rand};
use rand::{self, Rand, Rng};
use serde::{Deserialize, Serialize};
use super::{ChangeState, DynamicHoneyBadger, JoinPlan, MessageQueue, Result, VoteCounter};
use crypto::{SecretKey, SecretKeySet};
use crypto::{SecretKey, SecretKeySet, SecretKeyShare};
use honey_badger::HoneyBadger;
use messaging::NetworkInfo;
@ -51,8 +51,10 @@ where
let mut rng = rand::thread_rng();
let sk_set = SecretKeySet::random(0, &mut rng);
let pk_set = sk_set.public_keys();
let sk = sk_set.secret_key_share(0);
let netinfo = NetworkInfo::new(our_uid.clone(), once(our_uid).collect(), sk, pk_set);
let sks = sk_set.secret_key_share(0);
let sk: SecretKey = rng.gen();
let pub_keys = once((our_uid.clone(), sk.public_key())).collect();
let netinfo = NetworkInfo::new(our_uid, sks, pk_set, sk, pub_keys);
DynamicHoneyBadgerBuilder::new(netinfo)
}
@ -65,9 +67,10 @@ where
) -> Self {
let netinfo = NetworkInfo::new(
our_uid,
join_plan.all_uids,
secret_key,
SecretKeyShare::default(), // TODO: Should be an option?
join_plan.pub_key_set,
secret_key,
join_plan.pub_keys,
);
DynamicHoneyBadgerBuilder {
netinfo,

View File

@ -45,7 +45,7 @@
//! pending change.
use rand::Rand;
use std::collections::{BTreeSet, VecDeque};
use std::collections::{BTreeMap, VecDeque};
use std::fmt::Debug;
use std::hash::Hash;
use std::mem;
@ -55,7 +55,7 @@ use bincode;
use serde::{Deserialize, Serialize};
use self::votes::{SignedVote, VoteCounter};
use crypto::{PublicKeySet, SecretKey, Signature};
use crypto::{PublicKey, PublicKeySet, SecretKey, SecretKeyShare, Signature};
use fault_log::{FaultKind, FaultLog};
use honey_badger::{HoneyBadger, HoneyBadgerStep, Message as HbMessage};
use messaging::{DistAlgorithm, NetworkInfo, Step, Target, TargetedMessage};
@ -72,7 +72,7 @@ mod change;
mod error;
mod votes;
type KeyGenOutput = (PublicKeySet, Option<SecretKey>);
type KeyGenOutput = (PublicKeySet, Option<SecretKeyShare>);
/// The user input for `DynamicHoneyBadger`.
#[derive(Clone, Debug)]
@ -84,11 +84,7 @@ pub enum Input<C, NodeUid> {
}
/// A Honey Badger instance that can handle adding and removing nodes.
pub struct DynamicHoneyBadger<C, NodeUid: Rand>
where
C: Eq + Serialize + for<'r> Deserialize<'r> + Debug + Hash,
NodeUid: Ord + Clone + Serialize + for<'r> Deserialize<'r> + Debug,
{
pub struct DynamicHoneyBadger<C, NodeUid: Rand> {
/// Shared network data.
netinfo: NetworkInfo<NodeUid>,
/// The maximum number of future epochs for which we handle messages simultaneously.
@ -245,7 +241,7 @@ where
sender_id: &NodeUid,
message: HbMessage<NodeUid>,
) -> Result<FaultLog<NodeUid>> {
if !self.netinfo.all_uids().contains(sender_id) {
if !self.netinfo.is_node_validator(sender_id) {
info!("Unknown sender {:?} of message {:?}", sender_id, message);
return Err(ErrorKind::UnknownSender.into());
}
@ -312,7 +308,7 @@ where
// If DKG completed, apply the change.
debug!("{:?} DKG for {:?} complete!", self.our_id(), change);
// If we are a validator, we received a new secret key. Otherwise keep the old one.
let sk = sk.unwrap_or_else(|| self.netinfo.secret_key().clone());
let sk = sk.unwrap_or_else(|| self.netinfo.secret_key_share().clone());
// Restart Honey Badger in the next epoch, and inform the user about the change.
self.apply_change(&change, pub_key_set, sk, batch.epoch + 1)?;
batch.set_change(ChangeState::Complete(change), &self.netinfo);
@ -344,19 +340,22 @@ where
&mut self,
change: &Change<NodeUid>,
pub_key_set: PublicKeySet,
sk: SecretKey,
sk_share: SecretKeyShare,
epoch: u64,
) -> Result<()> {
self.key_gen = None;
let mut all_uids = self.netinfo.all_uids().clone();
if !match *change {
Change::Remove(ref id) => all_uids.remove(id),
Change::Add(ref id, _) => all_uids.insert(id.clone()),
let mut pub_keys = self.netinfo.public_key_map().clone();
if match *change {
Change::Remove(ref id) => pub_keys.remove(id).is_none(),
Change::Add(ref id, ref pub_key) => {
pub_keys.insert(id.clone(), pub_key.clone()).is_some()
}
} {
info!("No-op change: {:?}", change);
}
let netinfo = NetworkInfo::new(self.our_id().clone(), all_uids, sk, pub_key_set);
self.netinfo = netinfo;
let sk = self.netinfo.secret_key().clone();
let our_id = self.our_id().clone();
self.netinfo = NetworkInfo::new(our_id, sk_share, pub_key_set, sk, pub_keys);
self.restart_honey_badger(epoch)
}
@ -475,7 +474,7 @@ where
kg_msg: &KeyGenMessage,
) -> Result<bool> {
let ser = bincode::serialize(kg_msg)?;
let pk_opt = (self.netinfo.public_key_share(node_id)).or_else(|| {
let pk_opt = (self.netinfo.public_key(node_id)).or_else(|| {
self.key_gen
.iter()
.filter_map(|&(_, ref change): &(_, Change<_>)| match *change {
@ -573,8 +572,8 @@ pub struct JoinPlan<NodeUid: Ord> {
epoch: u64,
/// The current change. If `InProgress`, key generation for it is beginning at `epoch`.
change: ChangeState<NodeUid>,
/// The set of all validators' node IDs.
all_uids: BTreeSet<NodeUid>,
/// The current public key set for threshold cryptography.
pub_key_set: PublicKeySet,
/// The public keys of the nodes taking part in key generation.
pub_keys: BTreeMap<NodeUid, PublicKey>,
}

View File

@ -149,7 +149,7 @@ where
/// Returns `true` if the signature is valid.
fn validate(&self, signed_vote: &SignedVote<NodeUid>) -> Result<bool> {
let ser_vote = bincode::serialize(&signed_vote.vote)?;
let pk_opt = self.netinfo.public_key_share(&signed_vote.voter);
let pk_opt = self.netinfo.public_key(&signed_vote.voter);
Ok(pk_opt.map_or(false, |pk| pk.verify(&signed_vote.sig, ser_vote)))
}
}
@ -181,13 +181,9 @@ impl<NodeUid> SignedVote<NodeUid> {
#[cfg(test)]
mod tests {
use std::collections::BTreeSet;
use std::sync::Arc;
use rand;
use super::{Change, SignedVote, VoteCounter};
use crypto::SecretKeySet;
use fault_log::{FaultKind, FaultLog};
use messaging::NetworkInfo;
@ -197,16 +193,15 @@ mod tests {
/// the vote for `Remove(j)` by node `i`. Each node signed `Remove(0)`, `Remove(1)`, ... in
/// order.
fn setup(node_num: usize, era: u64) -> (Vec<VoteCounter<usize>>, Vec<Vec<SignedVote<usize>>>) {
let mut rng = rand::thread_rng();
let sk_set = SecretKeySet::random(3, &mut rng);
let ids: BTreeSet<usize> = (0..node_num).collect();
let pk_set = sk_set.public_keys();
let create_counter = |id: usize| {
let sk = sk_set.secret_key_share(id as u64);
let netinfo = NetworkInfo::new(id, ids.clone(), sk, pk_set.clone());
VoteCounter::new(Arc::new(netinfo), era)
};
let mut counters: Vec<_> = (0..node_num).map(create_counter).collect();
// Create keys for threshold cryptography.
let netinfos = NetworkInfo::generate_map(0..node_num);
// Create a `VoteCounter` instance for each node.
let create_counter =
|(_, netinfo): (_, NetworkInfo<_>)| VoteCounter::new(Arc::new(netinfo), era);
let mut counters: Vec<_> = netinfos.into_iter().map(create_counter).collect();
// Sign a few votes.
let sign_votes = |counter: &mut VoteCounter<usize>| {
(0..node_num)
.map(Change::Remove)

View File

@ -133,7 +133,7 @@ where
sender_id: &NodeUid,
message: Self::Message,
) -> HoneyBadgerResult<HoneyBadgerStep<C, NodeUid>> {
if !self.netinfo.all_uids().contains(sender_id) {
if !self.netinfo.is_node_validator(sender_id) {
return Err(ErrorKind::UnknownSender.into());
}
let Message { epoch, content } = message;
@ -428,7 +428,7 @@ where
{
let ids_u64: BTreeMap<&NodeUid, u64> = shares
.keys()
.map(|id| (id, *self.netinfo.node_index(id).unwrap() as u64))
.map(|id| (id, self.netinfo.node_index(id).unwrap() as u64))
.collect();
let indexed_shares: BTreeMap<&u64, _> = shares
.into_iter()
@ -492,7 +492,7 @@ where
if !self.netinfo.is_validator() {
return Ok((ciphertext.verify(), FaultLog::new()));
}
let share = match self.netinfo.secret_key().decrypt_share(&ciphertext) {
let share = match self.netinfo.secret_key_share().decrypt_share(&ciphertext) {
None => return Ok((false, FaultLog::new())),
Some(share) => share,
};

View File

@ -1,7 +1,7 @@
use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::fmt::Debug;
use crypto::{PublicKey, PublicKeySet, SecretKey};
use crypto::{PublicKey, PublicKeySet, PublicKeyShare, SecretKey, SecretKeyShare};
use fault_log::FaultLog;
/// Message sent by a given source.
@ -139,16 +139,18 @@ impl<'a, D: DistAlgorithm + 'a> Iterator for MessageIter<'a, D> {
}
}
/// Common data shared between algorithms.
/// Common data shared between algorithms: the nodes' IDs and key shares.
#[derive(Debug, Clone)]
pub struct NetworkInfo<NodeUid> {
our_uid: NodeUid,
all_uids: BTreeSet<NodeUid>,
num_nodes: usize,
num_faulty: usize,
is_validator: bool,
// TODO: Should this be an option? It only makes sense for validators.
secret_key_share: SecretKeyShare,
secret_key: SecretKey,
public_key_set: PublicKeySet,
public_key_shares: BTreeMap<NodeUid, PublicKeyShare>,
public_keys: BTreeMap<NodeUid, PublicKey>,
node_indices: BTreeMap<NodeUid, usize>,
}
@ -156,31 +158,33 @@ pub struct NetworkInfo<NodeUid> {
impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
pub fn new(
our_uid: NodeUid,
all_uids: BTreeSet<NodeUid>,
secret_key: SecretKey,
secret_key_share: SecretKeyShare,
public_key_set: PublicKeySet,
secret_key: SecretKey,
public_keys: BTreeMap<NodeUid, PublicKey>,
) -> Self {
let num_nodes = all_uids.len();
let is_validator = all_uids.contains(&our_uid);
let node_indices: BTreeMap<NodeUid, usize> = all_uids
.iter()
let num_nodes = public_keys.len();
let is_validator = public_keys.contains_key(&our_uid);
let node_indices: BTreeMap<NodeUid, usize> = public_keys
.keys()
.enumerate()
.map(|(n, id)| (id.clone(), n))
.collect();
let public_keys = node_indices
let public_key_shares = node_indices
.iter()
.map(|(id, idx)| (id.clone(), public_key_set.public_key_share(*idx as u64)))
.collect();
NetworkInfo {
our_uid,
all_uids,
num_nodes,
num_faulty: (num_nodes - 1) / 3,
is_validator,
secret_key_share,
secret_key,
public_key_set,
public_keys,
public_key_shares,
node_indices,
public_keys,
}
}
@ -190,8 +194,8 @@ impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
}
/// ID of all nodes in the network.
pub fn all_uids(&self) -> &BTreeSet<NodeUid> {
&self.all_uids
pub fn all_uids(&self) -> impl Iterator<Item = &NodeUid> {
self.public_keys.keys()
}
/// The total number of nodes.
@ -205,27 +209,44 @@ impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
self.num_faulty
}
/// Returns our secret key share for threshold cryptography.
pub fn secret_key_share(&self) -> &SecretKeyShare {
&self.secret_key_share
}
/// Returns our secret key for encryption and signing.
pub fn secret_key(&self) -> &SecretKey {
&self.secret_key
}
/// Returns the public key set for threshold cryptography.
pub fn public_key_set(&self) -> &PublicKeySet {
&self.public_key_set
}
/// Returns the public key share if a node with that ID exists, otherwise `None`.
pub fn public_key_share(&self, id: &NodeUid) -> Option<&PublicKey> {
self.public_keys.get(id)
pub fn public_key_share(&self, id: &NodeUid) -> Option<&PublicKeyShare> {
self.public_key_shares.get(id)
}
/// Returns a map of all node IDs to their public key shares.
pub fn public_key_share_map(&self) -> &BTreeMap<NodeUid, PublicKeyShare> {
&self.public_key_shares
}
/// Returns a map of all node IDs to their public keys.
pub fn public_key(&self, id: &NodeUid) -> Option<&PublicKey> {
self.public_keys.get(id)
}
/// Returns a map of all node IDs to their public keys.
pub fn public_key_map(&self) -> &BTreeMap<NodeUid, PublicKey> {
&self.public_keys
}
/// The index of a node in a canonical numbering of all nodes.
pub fn node_index(&self, id: &NodeUid) -> Option<&usize> {
self.node_indices.get(id)
pub fn node_index(&self, id: &NodeUid) -> Option<usize> {
self.node_indices.get(id).cloned()
}
/// Returns the unique ID of the Honey Badger invocation.
@ -243,4 +264,54 @@ impl<NodeUid: Clone + Ord> NetworkInfo<NodeUid> {
pub fn is_validator(&self) -> bool {
self.is_validator
}
/// Returns `true` if the given node takes part in the consensus itself. If not, it is only an
/// observer.
pub fn is_node_validator(&self, uid: &NodeUid) -> bool {
self.public_keys.contains_key(uid)
}
/// Generates a map of matching `NetworkInfo`s for testing.
pub fn generate_map<I>(uids: I) -> BTreeMap<NodeUid, NetworkInfo<NodeUid>>
where
I: IntoIterator<Item = NodeUid>,
{
use rand::{self, Rng};
use crypto::SecretKeySet;
let mut rng = rand::thread_rng();
let all_uids: BTreeSet<NodeUid> = uids.into_iter().collect();
let num_faulty = (all_uids.len() - 1) / 3;
// Generate the keys for threshold cryptography.
let sk_set = SecretKeySet::random(num_faulty, &mut rng);
let pk_set = sk_set.public_keys();
// Generate keys for individually signing and encrypting messages.
let sec_keys: BTreeMap<_, SecretKey> =
all_uids.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.
let create_netinfo = |(i, uid): (usize, NodeUid)| {
let netinfo = NetworkInfo::new(
uid.clone(),
sk_set.secret_key_share(i as u64),
pk_set.clone(),
sec_keys[&uid].clone(),
pub_keys.clone(),
);
(uid, netinfo)
};
all_uids
.into_iter()
.enumerate()
.map(create_netinfo)
.collect()
}
}

View File

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

View File

@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize};
use dynamic_honey_badger::{self, Batch as DhbBatch, DynamicHoneyBadger, Message};
use fault_log::FaultLog;
use messaging::{DistAlgorithm, NetworkInfo, Step, TargetedMessage};
use messaging::{DistAlgorithm, Step, TargetedMessage};
use transaction_queue::TransactionQueue;
pub use dynamic_honey_badger::{Change, ChangeState, Input};
@ -26,15 +26,11 @@ error_chain!{
/// A Queueing Honey Badger builder, to configure the parameters and create new instances of
/// `QueueingHoneyBadger`.
pub struct QueueingHoneyBadgerBuilder<Tx, NodeUid> {
pub struct QueueingHoneyBadgerBuilder<Tx, NodeUid: Rand> {
/// Shared network data.
netinfo: NetworkInfo<NodeUid>,
dyn_hb: DynamicHoneyBadger<Vec<Tx>, NodeUid>,
/// The target number of transactions to be included in each batch.
batch_size: usize,
/// The epoch at which to join the network.
start_epoch: u64,
/// The maximum number of future epochs for which we handle messages simultaneously.
max_future_epochs: usize,
_phantom: PhantomData<Tx>,
}
@ -45,38 +41,23 @@ where
{
/// Returns a new `QueueingHoneyBadgerBuilder` configured to use the node IDs and cryptographic
/// keys specified by `netinfo`.
pub fn new(netinfo: NetworkInfo<NodeUid>) -> Self {
pub fn new(dyn_hb: DynamicHoneyBadger<Vec<Tx>, NodeUid>) -> Self {
// TODO: Use the defaults from `HoneyBadgerBuilder`.
QueueingHoneyBadgerBuilder {
netinfo,
dyn_hb,
batch_size: 100,
start_epoch: 0,
max_future_epochs: 3,
_phantom: PhantomData,
}
}
/// Sets the target number of transactions per batch.
pub fn batch_size(&mut self, batch_size: usize) -> &mut Self {
pub fn batch_size(mut self, batch_size: usize) -> Self {
self.batch_size = batch_size;
self
}
/// 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
}
/// Sets the epoch at which to join the network as an observer. This requires the node to
/// receive all broadcast messages for `start_epoch` and later.
pub fn start_epoch(&mut self, start_epoch: u64) -> &mut Self {
self.start_epoch = start_epoch;
self
}
/// Creates a new Queueing Honey Badger instance with an empty buffer.
pub fn build(&self) -> QueueingHoneyBadger<Tx, NodeUid>
pub fn build(self) -> QueueingHoneyBadger<Tx, NodeUid>
where
Tx: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
{
@ -86,17 +67,14 @@ where
/// Returns a new Queueing Honey Badger instance that starts with the given transactions in its
/// buffer.
pub fn build_with_transactions<TI>(&self, txs: TI) -> Result<QueueingHoneyBadger<Tx, NodeUid>>
pub fn build_with_transactions<TI>(self, txs: TI) -> Result<QueueingHoneyBadger<Tx, NodeUid>>
where
TI: IntoIterator<Item = Tx>,
Tx: Serialize + for<'r> Deserialize<'r> + Debug + Hash + Eq,
{
let dyn_hb = DynamicHoneyBadger::builder(self.netinfo.clone())
.max_future_epochs(self.max_future_epochs)
.build()?;
let queue = TransactionQueue(txs.into_iter().collect());
let mut qhb = QueueingHoneyBadger {
dyn_hb,
dyn_hb: self.dyn_hb,
queue,
batch_size: self.batch_size,
output: VecDeque::new(),
@ -190,8 +168,10 @@ where
{
/// Returns a new `QueueingHoneyBadgerBuilder` configured to use the node IDs and cryptographic
/// keys specified by `netinfo`.
pub fn builder(netinfo: NetworkInfo<NodeUid>) -> QueueingHoneyBadgerBuilder<Tx, NodeUid> {
QueueingHoneyBadgerBuilder::new(netinfo)
pub fn builder(
dyn_hb: DynamicHoneyBadger<Vec<Tx>, NodeUid>,
) -> QueueingHoneyBadgerBuilder<Tx, NodeUid> {
QueueingHoneyBadgerBuilder::new(dyn_hb)
}
fn step(

View File

@ -43,7 +43,7 @@ use rand::OsRng;
use crypto::poly::{BivarCommitment, BivarPoly, Poly};
use crypto::serde_impl::field_vec::FieldWrap;
use crypto::{Ciphertext, PublicKey, PublicKeySet, SecretKey};
use crypto::{Ciphertext, PublicKey, PublicKeySet, SecretKey, SecretKeyShare};
use fault_log::{FaultKind, FaultLog};
// TODO: No need to send our own row and value to ourselves.
@ -237,7 +237,7 @@ impl<NodeUid: Ord + Clone + Debug> SyncKeyGen<NodeUid> {
///
/// These are only secure if `is_ready` returned `true`. Otherwise it is not guaranteed that
/// none of the nodes knows the secret master key.
pub fn generate(&self) -> (PublicKeySet, Option<SecretKey>) {
pub fn generate(&self) -> (PublicKeySet, Option<SecretKeyShare>) {
let mut pk_commit = Poly::zero().commitment();
let mut opt_sk_val = self.our_idx.map(|_| Fr::zero());
let is_complete = |proposal: &&ProposalState| proposal.is_complete(self.threshold);
@ -248,7 +248,7 @@ impl<NodeUid: Ord + Clone + Debug> SyncKeyGen<NodeUid> {
sk_val.add_assign(&row.evaluate(0));
}
}
let opt_sk = opt_sk_val.map(SecretKey::from_value);
let opt_sk = opt_sk_val.map(SecretKeyShare::from_value);
(pk_commit.into(), opt_sk)
}

View File

@ -21,7 +21,6 @@ use std::sync::Arc;
use rand::Rng;
use hbbft::broadcast::{Broadcast, BroadcastMessage};
use hbbft::crypto::SecretKeySet;
use hbbft::messaging::{DistAlgorithm, NetworkInfo, Target, TargetedMessage};
use network::{
Adversary, MessageScheduler, MessageWithSender, NodeUid, RandomAdversary, SilentAdversary,
@ -78,16 +77,7 @@ impl Adversary<Broadcast<NodeUid>> for ProposeAdversary {
};
// FIXME: Take the correct, known keys from the network.
let mut rng = rand::thread_rng();
let sk_set = SecretKeySet::random(self.adv_nodes.len(), &mut rng);
let pk_set = sk_set.public_keys();
let netinfo = Arc::new(NetworkInfo::new(
id,
node_ids,
sk_set.secret_key_share(0),
pk_set,
));
let netinfo = Arc::new(NetworkInfo::generate_map(node_ids).remove(&id).unwrap());
let mut bc = Broadcast::new(netinfo, id).expect("broadcast instance");
// FIXME: Use the output.
let _ = bc.input(b"Fake news".to_vec()).expect("propose");

View File

@ -97,7 +97,11 @@ where
network.step();
// Once all nodes have processed the removal of node 0, add it again.
if !input_add && network.nodes.values().all(has_remove) {
let pk = network.pk_set.public_key_share(0);
let pk = network.nodes[&NodeUid(0)]
.instance()
.netinfo()
.secret_key()
.public_key();
network.input_all(Input::Change(Change::Add(NodeUid(0), pk)));
input_add = true;
}

View File

@ -100,7 +100,7 @@ impl Adversary<UsizeHoneyBadger> for FaultyShareAdversary {
.public_key()
.encrypt(fake_proposal);
let share = adv_node
.secret_key()
.secret_key_share()
.decrypt_share(&fake_ciphertext)
.expect("decryption share");
// Send the share to remote nodes.

View File

@ -1,11 +1,11 @@
use std::collections::{BTreeMap, BTreeSet, VecDeque};
use std::collections::{BTreeMap, VecDeque};
use std::fmt::{self, Debug};
use std::mem;
use std::sync::Arc;
use rand::{self, Rng};
use hbbft::crypto::{PublicKeySet, SecretKeySet};
use hbbft::crypto::SecretKeyShare;
use hbbft::messaging::{DistAlgorithm, NetworkInfo, Target, TargetedMessage};
/// A node identifier. In the tests, nodes are simply numbered.
@ -355,7 +355,6 @@ pub struct TestNetwork<A: Adversary<D>, D: DistAlgorithm> {
pub nodes: BTreeMap<D::NodeUid, TestNode<D>>,
pub observer: TestNode<D>,
pub adv_nodes: BTreeMap<D::NodeUid, Arc<NetworkInfo<D::NodeUid>>>,
pub pk_set: PublicKeySet,
adversary: A,
}
@ -376,43 +375,31 @@ where
G: Fn(BTreeMap<D::NodeUid, Arc<NetworkInfo<D::NodeUid>>>) -> A,
{
let mut rng = rand::thread_rng();
let sk_set = SecretKeySet::random(adv_num, &mut rng);
let pk_set = sk_set.public_keys();
let mut netinfos = NetworkInfo::generate_map((0..(good_num + adv_num)).map(NodeUid));
let obs_netinfo = {
let node_ni = netinfos.values().next().unwrap();
NetworkInfo::new(
NodeUid(good_num + adv_num),
SecretKeyShare::default(),
node_ni.public_key_set().clone(),
rng.gen(),
node_ni.public_key_map().clone(),
)
};
let adv_netinfos = netinfos.split_off(&NodeUid(good_num));
let node_ids: BTreeSet<NodeUid> = (0..(good_num + adv_num)).map(NodeUid).collect();
let new_node_by_id = |NodeUid(i): NodeUid| {
(
NodeUid(i),
TestNode::new(new_algo(Arc::new(NetworkInfo::new(
NodeUid(i),
node_ids.clone(),
sk_set.secret_key_share(i as u64),
pk_set.clone(),
)))),
)
let new_node = |(uid, netinfo): (NodeUid, NetworkInfo<_>)| {
(uid, TestNode::new(new_algo(Arc::new(netinfo))))
};
let new_adv_node_by_id = |NodeUid(i): NodeUid| {
(
NodeUid(i),
Arc::new(NetworkInfo::new(
NodeUid(i),
node_ids.clone(),
sk_set.secret_key_share(i as u64),
pk_set.clone(),
)),
)
};
let adv_nodes: BTreeMap<D::NodeUid, Arc<NetworkInfo<D::NodeUid>>> = (good_num
..(good_num + adv_num))
.map(NodeUid)
.map(new_adv_node_by_id)
.collect();
let new_adv_node = |(uid, netinfo): (NodeUid, NetworkInfo<_>)| (uid, Arc::new(netinfo));
let adv_nodes: BTreeMap<_, _> = adv_netinfos.into_iter().map(new_adv_node).collect();
let observer = TestNode::new(new_algo(Arc::new(obs_netinfo)));
let mut network = TestNetwork {
nodes: (0..good_num).map(NodeUid).map(new_node_by_id).collect(),
observer: new_node_by_id(NodeUid(good_num + adv_num)).1,
nodes: netinfos.into_iter().map(new_node).collect(),
observer,
adversary: adversary(adv_nodes.clone()),
pk_set: pk_set.clone(),
adv_nodes,
};

View File

@ -19,6 +19,7 @@ use std::cmp;
use std::collections::BTreeMap;
use std::sync::Arc;
use hbbft::dynamic_honey_badger::DynamicHoneyBadger;
use hbbft::messaging::NetworkInfo;
use hbbft::queueing_honey_badger::{Batch, Change, ChangeState, Input, QueueingHoneyBadger};
use itertools::Itertools;
@ -76,7 +77,12 @@ fn test_queueing_honey_badger<A>(
for tx in (num_txs / 2)..num_txs {
network.input_all(Input::User(tx));
}
let pk = network.pk_set.public_key_share(0);
let pk = network.nodes[&NodeUid(0)]
.instance()
.dyn_hb()
.netinfo()
.secret_key()
.public_key();
network.input_all(Input::Change(Change::Add(NodeUid(0), pk)));
input_add = true;
}
@ -102,9 +108,10 @@ where
// Allow passing `netinfo` by value. `TestNetwork` expects this function signature.
#[cfg_attr(feature = "cargo-clippy", allow(needless_pass_by_value))]
fn new_queueing_hb(netinfo: Arc<NetworkInfo<NodeUid>>) -> QueueingHoneyBadger<usize, NodeUid> {
QueueingHoneyBadger::builder((*netinfo).clone())
.batch_size(3)
let dyn_hb = DynamicHoneyBadger::builder((*netinfo).clone())
.build()
.expect("instantiate DHB");
QueueingHoneyBadger::builder(dyn_hb).batch_size(3).build()
}
fn test_queueing_honey_badger_different_sizes<A, F>(new_adversary: F, num_txs: usize)