mirror of https://github.com/poanetwork/hbbft.git
Added error handling for mlock errors in threshold_crypto crate.
This commit is contained in:
parent
8cc60698db
commit
8ab58d35d4
|
@ -28,6 +28,7 @@ env:
|
|||
# `beta` after the stable release of Rust 1.28; and finally migrating
|
||||
# everything to `stable` at Rust 1.29.
|
||||
- RUST_NEXT=nightly-2018-07-13
|
||||
- MLOCK_SECRETS=false
|
||||
script:
|
||||
- cargo +${RUST_NEXT} clippy -- --deny clippy
|
||||
- cargo +${RUST_NEXT} clippy --tests --examples -- --deny clippy
|
||||
|
|
|
@ -106,8 +106,11 @@ impl<T: Clone + Debug + AsRef<[u8]> + PartialEq + Send + Sync + From<Vec<u8>> +
|
|||
// required by the interface to all algorithms in Honey Badger. Therefore we set placeholder
|
||||
// keys here. A fully-featured application would need to take appropriately initialized keys
|
||||
// from elsewhere.
|
||||
let secret_key_set = SecretKeySet::from(Poly::zero());
|
||||
let sk_share = secret_key_set.secret_key_share(our_id);
|
||||
let secret_key_set =
|
||||
SecretKeySet::from(Poly::zero().expect("Failed to create an empty `Poly`"));
|
||||
let sk_share = secret_key_set
|
||||
.secret_key_share(our_id)
|
||||
.expect("Failed to create our node's `SecretKeyShare`");
|
||||
let pub_key_set = secret_key_set.public_keys();
|
||||
let sk = SecretKey::default();
|
||||
let pub_keys = all_ids
|
||||
|
|
|
@ -268,7 +268,9 @@ where
|
|||
where
|
||||
F: Fn(NetworkInfo<NodeUid>) -> (D, Step<D>),
|
||||
{
|
||||
let netinfos = NetworkInfo::generate_map((0..(good_num + adv_num)).map(NodeUid));
|
||||
let node_ids = (0..(good_num + adv_num)).map(NodeUid);
|
||||
let netinfos =
|
||||
NetworkInfo::generate_map(node_ids).expect("Failed to create `NetworkInfo` map");
|
||||
let new_node = |(uid, netinfo): (NodeUid, NetworkInfo<_>)| {
|
||||
(uid, TestNode::new(new_algo(netinfo), hw_quality))
|
||||
};
|
||||
|
|
|
@ -70,7 +70,8 @@
|
|||
//! let mut rng = thread_rng();
|
||||
//!
|
||||
//! // Create a random set of keys for testing.
|
||||
//! let netinfos = NetworkInfo::generate_map(0..NUM_NODES);
|
||||
//! let netinfos = NetworkInfo::generate_map(0..NUM_NODES)
|
||||
//! .expect("Failed to create `NetworkInfo` map");
|
||||
//!
|
||||
//! // Create initial nodes by instantiating a `Broadcast` for each.
|
||||
//! let mut nodes = BTreeMap::new();
|
||||
|
|
|
@ -66,15 +66,15 @@ where
|
|||
}
|
||||
|
||||
/// Creates a new `DynamicHoneyBadger` configured to start a new network as a single validator.
|
||||
pub fn build_first_node(&self, our_uid: N) -> DynamicHoneyBadger<C, N> {
|
||||
pub fn build_first_node(&self, our_uid: N) -> Result<DynamicHoneyBadger<C, N>> {
|
||||
let mut rng = rand::thread_rng();
|
||||
let sk_set = SecretKeySet::random(0, &mut rng);
|
||||
let sk_set = SecretKeySet::random(0, &mut rng)?;
|
||||
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: 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);
|
||||
self.build(netinfo)
|
||||
Ok(self.build(netinfo))
|
||||
}
|
||||
|
||||
/// Creates a new `DynamicHoneyBadger` configured to join the network at the epoch specified in
|
||||
|
|
|
@ -275,7 +275,7 @@ where
|
|||
if let Some(kgs) = self.take_ready_key_gen() {
|
||||
// If DKG completed, apply the change, restart Honey Badger, and inform the user.
|
||||
debug!("{:?} DKG for {:?} complete!", self.our_id(), kgs.change);
|
||||
self.netinfo = kgs.key_gen.into_network_info();
|
||||
self.netinfo = kgs.key_gen.into_network_info()?;
|
||||
self.restart_honey_badger(batch.epoch + 1);
|
||||
batch.set_change(ChangeState::Complete(kgs.change), &self.netinfo);
|
||||
} else if let Some(change) = self.vote_counter.compute_winner().cloned() {
|
||||
|
@ -316,7 +316,7 @@ where
|
|||
let threshold = (pub_keys.len() - 1) / 3;
|
||||
let sk = self.netinfo.secret_key().clone();
|
||||
let our_uid = self.our_id().clone();
|
||||
let (key_gen, part) = SyncKeyGen::new(our_uid, sk, pub_keys, threshold);
|
||||
let (key_gen, part) = SyncKeyGen::new(our_uid, sk, pub_keys, threshold)?;
|
||||
self.key_gen_state = Some(KeyGenState::new(key_gen, change.clone()));
|
||||
if let Some(part) = part {
|
||||
self.send_transaction(KeyGenMessage::Part(part))
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
use bincode;
|
||||
use failure::{Backtrace, Context, Fail};
|
||||
use honey_badger;
|
||||
use std::fmt::{self, Display};
|
||||
|
||||
use bincode;
|
||||
use crypto;
|
||||
use failure::{Backtrace, Context, Fail};
|
||||
|
||||
use honey_badger;
|
||||
use sync_key_gen;
|
||||
|
||||
/// Dynamic honey badger error variants.
|
||||
#[derive(Debug, Fail)]
|
||||
pub enum ErrorKind {
|
||||
|
@ -14,6 +18,8 @@ pub enum ErrorKind {
|
|||
SignVoteForBincode(bincode::ErrorKind),
|
||||
#[fail(display = "ValidateBincode error: {}", _0)]
|
||||
ValidateBincode(bincode::ErrorKind),
|
||||
#[fail(display = "Crypto error: {}", _0)]
|
||||
Crypto(crypto::error::Error),
|
||||
#[fail(display = "ProposeHoneyBadger error: {}", _0)]
|
||||
ProposeHoneyBadger(honey_badger::Error),
|
||||
#[fail(
|
||||
|
@ -21,6 +27,8 @@ pub enum ErrorKind {
|
|||
_0
|
||||
)]
|
||||
HandleHoneyBadgerMessageHoneyBadger(honey_badger::Error),
|
||||
#[fail(display = "SyncKeyGen error: {}", _0)]
|
||||
SyncKeyGen(sync_key_gen::Error),
|
||||
#[fail(display = "Unknown sender")]
|
||||
UnknownSender,
|
||||
}
|
||||
|
@ -61,6 +69,22 @@ impl From<Context<ErrorKind>> for Error {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<crypto::error::Error> for Error {
|
||||
fn from(e: crypto::error::Error) -> Error {
|
||||
Error {
|
||||
inner: Context::new(ErrorKind::Crypto(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<sync_key_gen::Error> for Error {
|
||||
fn from(e: sync_key_gen::Error) -> Error {
|
||||
Error {
|
||||
inner: Context::new(ErrorKind::SyncKeyGen(e)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
Display::fmt(&self.inner, f)
|
||||
|
|
|
@ -200,7 +200,8 @@ mod tests {
|
|||
/// order.
|
||||
fn setup(node_num: usize, era: u64) -> (Vec<VoteCounter<usize>>, Vec<Vec<SignedVote<usize>>>) {
|
||||
// Create keys for threshold cryptography.
|
||||
let netinfos = NetworkInfo::generate_map(0..node_num);
|
||||
let netinfos =
|
||||
NetworkInfo::generate_map(0..node_num).expect("Failed to generate `NetworkInfo` map");
|
||||
|
||||
// Create a `VoteCounter` instance for each node.
|
||||
let create_counter =
|
||||
|
|
|
@ -2,7 +2,7 @@ use std::collections::{BTreeMap, BTreeSet, VecDeque};
|
|||
use std::fmt::Debug;
|
||||
use std::iter::once;
|
||||
|
||||
use crypto::{PublicKey, PublicKeySet, PublicKeyShare, SecretKey, SecretKeyShare};
|
||||
use crypto::{self, PublicKey, PublicKeySet, PublicKeyShare, SecretKey, SecretKeyShare};
|
||||
use fault_log::{Fault, FaultLog};
|
||||
use traits::{Message, NodeUidT};
|
||||
|
||||
|
@ -356,7 +356,7 @@ impl<N: NodeUidT> NetworkInfo<N> {
|
|||
}
|
||||
|
||||
/// Generates a map of matching `NetworkInfo`s for testing.
|
||||
pub fn generate_map<I>(uids: I) -> BTreeMap<N, NetworkInfo<N>>
|
||||
pub fn generate_map<I>(uids: I) -> Result<BTreeMap<N, NetworkInfo<N>>, crypto::error::Error>
|
||||
where
|
||||
I: IntoIterator<Item = N>,
|
||||
{
|
||||
|
@ -370,7 +370,7 @@ impl<N: NodeUidT> NetworkInfo<N> {
|
|||
let num_faulty = (all_uids.len() - 1) / 3;
|
||||
|
||||
// Generate the keys for threshold cryptography.
|
||||
let sk_set = SecretKeySet::random(num_faulty, &mut rng);
|
||||
let sk_set = SecretKeySet::random(num_faulty, &mut rng)?;
|
||||
let pk_set = sk_set.public_keys();
|
||||
|
||||
// Generate keys for individually signing and encrypting messages.
|
||||
|
@ -385,12 +385,12 @@ impl<N: NodeUidT> NetworkInfo<N> {
|
|||
let create_netinfo = |(i, uid): (usize, N)| {
|
||||
let netinfo = NetworkInfo::new(
|
||||
uid.clone(),
|
||||
sk_set.secret_key_share(i),
|
||||
sk_set.secret_key_share(i)?,
|
||||
pk_set.clone(),
|
||||
sec_keys[&uid].clone(),
|
||||
pub_keys.clone(),
|
||||
);
|
||||
(uid, netinfo)
|
||||
Ok((uid, netinfo))
|
||||
};
|
||||
all_uids
|
||||
.into_iter()
|
||||
|
|
|
@ -75,7 +75,8 @@
|
|||
//! let mut nodes = BTreeMap::new();
|
||||
//! let mut parts = Vec::new();
|
||||
//! for (id, sk) in sec_keys.into_iter().enumerate() {
|
||||
//! let (sync_key_gen, opt_part) = SyncKeyGen::new(id, sk, pub_keys.clone(), threshold);
|
||||
//! let (sync_key_gen, opt_part) = SyncKeyGen::new(id, sk, pub_keys.clone(), threshold)
|
||||
//! .unwrap_or_else(|_| panic!("Failed to create `SyncKeyGen` instance for node #{}", id));
|
||||
//! nodes.insert(id, sync_key_gen);
|
||||
//! parts.push((id, opt_part.unwrap())); // Would be `None` for observer nodes.
|
||||
//! }
|
||||
|
@ -100,11 +101,14 @@
|
|||
//! }
|
||||
//!
|
||||
//! // We have all the information and can generate the key sets.
|
||||
//! let pub_key_set = nodes[&0].generate().0; // The public key set: identical for all nodes.
|
||||
//! // Generate the public key set; which is identical for all nodes.
|
||||
//! let pub_key_set = nodes[&0].generate().expect("Failed to create `PublicKeySet` from node #0").0;
|
||||
//! let mut secret_key_shares = BTreeMap::new();
|
||||
//! for (&id, node) in &mut nodes {
|
||||
//! assert!(node.is_ready());
|
||||
//! let (pks, opt_sks) = node.generate();
|
||||
//! let (pks, opt_sks) = node.generate().unwrap_or_else(|_|
|
||||
//! panic!("Failed to create `PublicKeySet` and `SecretKeyShare` for node #{}", id)
|
||||
//! );
|
||||
//! assert_eq!(pks, pub_key_set); // All nodes now know the public keys and public key shares.
|
||||
//! let sks = opt_sks.expect("Not an observer node: We receive a secret key share.");
|
||||
//! secret_key_shares.insert(id, sks);
|
||||
|
@ -157,19 +161,32 @@ use std::collections::{BTreeMap, BTreeSet};
|
|||
use std::fmt::{self, Debug, Formatter};
|
||||
|
||||
use bincode;
|
||||
use crypto::poly::{BivarCommitment, BivarPoly, Poly};
|
||||
use crypto::serde_impl::field_vec::FieldWrap;
|
||||
use crypto::{self, Ciphertext, PublicKey, PublicKeySet, SecretKey, SecretKeyShare};
|
||||
use pairing::bls12_381::{Fr, G1Affine};
|
||||
use pairing::{CurveAffine, Field};
|
||||
use rand::OsRng;
|
||||
|
||||
use crypto::poly::{BivarCommitment, BivarPoly, Poly};
|
||||
use crypto::serde_impl::field_vec::FieldWrap;
|
||||
use crypto::{Ciphertext, PublicKey, PublicKeySet, SecretKey, SecretKeyShare};
|
||||
use fault_log::{FaultKind, FaultLog};
|
||||
use messaging::NetworkInfo;
|
||||
use traits::NodeUidT;
|
||||
|
||||
// TODO: No need to send our own row and value to ourselves.
|
||||
|
||||
// A sync-key-gen error.
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Fail)]
|
||||
pub enum Error {
|
||||
#[fail(display = "Crypto error: {}", _0)]
|
||||
Crypto(crypto::error::Error),
|
||||
}
|
||||
|
||||
impl From<crypto::error::Error> for Error {
|
||||
fn from(e: crypto::error::Error) -> Self {
|
||||
Error::Crypto(e)
|
||||
}
|
||||
}
|
||||
|
||||
/// A submission by a validator for the key generation. It must to be sent to all participating
|
||||
/// nodes and handled by all of them, including the one that produced it.
|
||||
///
|
||||
|
@ -270,7 +287,7 @@ impl<N: NodeUidT> SyncKeyGen<N> {
|
|||
sec_key: SecretKey,
|
||||
pub_keys: BTreeMap<N, PublicKey>,
|
||||
threshold: usize,
|
||||
) -> (SyncKeyGen<N>, Option<Part>) {
|
||||
) -> Result<(SyncKeyGen<N>, Option<Part>), Error> {
|
||||
let our_idx = pub_keys
|
||||
.keys()
|
||||
.position(|uid| *uid == our_uid)
|
||||
|
@ -284,18 +301,23 @@ impl<N: NodeUidT> SyncKeyGen<N> {
|
|||
threshold,
|
||||
};
|
||||
if our_idx.is_none() {
|
||||
return (key_gen, None); // No part: we are an observer.
|
||||
return Ok((key_gen, None)); // No part: we are an observer.
|
||||
}
|
||||
let mut rng = OsRng::new().expect("OS random number generator");
|
||||
let our_part = BivarPoly::random(threshold, &mut rng);
|
||||
let our_part = BivarPoly::random(threshold, &mut rng)?;
|
||||
let commit = our_part.commitment();
|
||||
let encrypt = |(i, pk): (usize, &PublicKey)| {
|
||||
let row = our_part.row(i + 1);
|
||||
let row = our_part.row(i + 1)?;
|
||||
let bytes = bincode::serialize(&row).expect("failed to serialize row");
|
||||
pk.encrypt(&bytes)
|
||||
Ok(pk.encrypt(&bytes))
|
||||
};
|
||||
let rows: Vec<_> = key_gen.pub_keys.values().enumerate().map(encrypt).collect();
|
||||
(key_gen, Some(Part(commit, rows)))
|
||||
let rows = key_gen
|
||||
.pub_keys
|
||||
.values()
|
||||
.enumerate()
|
||||
.map(encrypt)
|
||||
.collect::<Result<Vec<_>, Error>>()?;
|
||||
Ok((key_gen, Some(Part(commit, rows))))
|
||||
}
|
||||
|
||||
/// Handles a `Part` message. If it is valid, returns an `Ack` message to be broadcast.
|
||||
|
@ -393,19 +415,24 @@ impl<N: NodeUidT> SyncKeyGen<N> {
|
|||
///
|
||||
/// 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 generate(&self) -> (PublicKeySet, Option<SecretKeyShare>) {
|
||||
let mut pk_commit = Poly::zero().commitment();
|
||||
pub fn generate(&self) -> Result<(PublicKeySet, Option<SecretKeyShare>), Error> {
|
||||
let mut pk_commit = Poly::zero()?.commitment();
|
||||
let mut opt_sk_val = self.our_idx.map(|_| Fr::zero());
|
||||
let is_complete = |part: &&ProposalState| part.is_complete(self.threshold);
|
||||
for part in self.parts.values().filter(is_complete) {
|
||||
pk_commit += part.commit.row(0);
|
||||
if let Some(sk_val) = opt_sk_val.as_mut() {
|
||||
let row: Poly = Poly::interpolate(part.values.iter().take(self.threshold + 1));
|
||||
let row = Poly::interpolate(part.values.iter().take(self.threshold + 1))?;
|
||||
sk_val.add_assign(&row.evaluate(0));
|
||||
}
|
||||
}
|
||||
let opt_sk = opt_sk_val.map(SecretKeyShare::from_value);
|
||||
(pk_commit.into(), opt_sk)
|
||||
let opt_sk = if let Some(mut fr) = opt_sk_val {
|
||||
let sk = SecretKeyShare::from_mut_ptr(&mut fr as *mut Fr)?;
|
||||
Some(sk)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok((pk_commit.into(), opt_sk))
|
||||
}
|
||||
|
||||
/// Consumes the instance, generates the key set and returns a new `NetworkInfo` with the new
|
||||
|
@ -413,10 +440,11 @@ impl<N: NodeUidT> SyncKeyGen<N> {
|
|||
///
|
||||
/// 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) -> NetworkInfo<N> {
|
||||
let (pk_set, opt_sk_share) = self.generate();
|
||||
pub fn into_network_info(self) -> Result<NetworkInfo<N>, Error> {
|
||||
let (pk_set, opt_sk_share) = self.generate()?;
|
||||
let sk_share = opt_sk_share.unwrap_or_default(); // TODO: Make this an option.
|
||||
NetworkInfo::new(self.our_uid, sk_share, pk_set, self.sec_key, self.pub_keys)
|
||||
let netinfo = NetworkInfo::new(self.our_uid, sk_share, pk_set, self.sec_key, self.pub_keys);
|
||||
Ok(netinfo)
|
||||
}
|
||||
|
||||
/// Handles an `Ack` message or returns an error string.
|
||||
|
|
|
@ -78,7 +78,12 @@ impl Adversary<Broadcast<NodeUid>> for ProposeAdversary {
|
|||
};
|
||||
|
||||
// FIXME: Take the correct, known keys from the network.
|
||||
let netinfo = Arc::new(NetworkInfo::generate_map(node_ids).remove(&id).unwrap());
|
||||
let netinfo = Arc::new(
|
||||
NetworkInfo::generate_map(node_ids)
|
||||
.expect("Failed to create `NetworkInfo` map")
|
||||
.remove(&id)
|
||||
.unwrap(),
|
||||
);
|
||||
let mut bc = Broadcast::new(netinfo, id).expect("broadcast instance");
|
||||
// FIXME: Use the output.
|
||||
let step = bc.input(b"Fake news".to_vec()).expect("propose");
|
||||
|
|
|
@ -398,7 +398,9 @@ where
|
|||
G: Fn(BTreeMap<D::NodeUid, Arc<NetworkInfo<D::NodeUid>>>) -> A,
|
||||
{
|
||||
let mut rng = rand::thread_rng();
|
||||
let mut netinfos = NetworkInfo::generate_map((0..(good_num + adv_num)).map(NodeUid));
|
||||
let node_ids = (0..(good_num + adv_num)).map(NodeUid);
|
||||
let mut netinfos =
|
||||
NetworkInfo::generate_map(node_ids).expect("Failed to generate `NetworkInfo` map");
|
||||
let obs_netinfo = {
|
||||
let node_ni = netinfos.values().next().unwrap();
|
||||
NetworkInfo::new(
|
||||
|
|
|
@ -15,7 +15,7 @@ use hbbft::sync_key_gen::{PartOutcome, SyncKeyGen};
|
|||
|
||||
fn test_sync_key_gen_with(threshold: usize, node_num: usize) {
|
||||
// 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(|_| SecretKey::random()).collect();
|
||||
let pub_keys: BTreeMap<usize, PublicKey> = sec_keys
|
||||
.iter()
|
||||
.map(SecretKey::public_key)
|
||||
|
@ -28,7 +28,8 @@ fn test_sync_key_gen_with(threshold: usize, node_num: usize) {
|
|||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, sk)| {
|
||||
let (sync_key_gen, proposal) = SyncKeyGen::new(id, sk, pub_keys.clone(), threshold);
|
||||
let (sync_key_gen, proposal) = SyncKeyGen::new(id, sk, pub_keys.clone(), threshold)
|
||||
.unwrap_or_else(|_err| panic!("Failed to create `SyncKeyGen` instance #{}", id));
|
||||
nodes.push(sync_key_gen);
|
||||
proposal
|
||||
})
|
||||
|
@ -60,13 +61,21 @@ fn test_sync_key_gen_with(threshold: usize, node_num: usize) {
|
|||
|
||||
// Compute the keys and test a threshold signature.
|
||||
let msg = "Help I'm trapped in a unit test factory";
|
||||
let pub_key_set = nodes[0].generate().0;
|
||||
let pub_key_set = nodes[0]
|
||||
.generate()
|
||||
.expect("Failed to generate `PublicKeySet` for node #0")
|
||||
.0;
|
||||
let sig_shares: BTreeMap<_, _> = nodes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(idx, node)| {
|
||||
assert!(node.is_ready());
|
||||
let (pks, opt_sk) = node.generate();
|
||||
let (pks, opt_sk) = node.generate().unwrap_or_else(|_| {
|
||||
panic!(
|
||||
"Failed to generate `PublicKeySet` and `SecretKeyShare` for node #{}",
|
||||
idx
|
||||
)
|
||||
});
|
||||
let sk = opt_sk.expect("new secret key");
|
||||
assert_eq!(pks, pub_key_set);
|
||||
let sig = sk.sign(msg);
|
||||
|
|
Loading…
Reference in New Issue