Added error handling for mlock errors in threshold_crypto crate.

This commit is contained in:
DrPeterVanNostrand 2018-08-06 14:53:37 +00:00
parent 8cc60698db
commit 8ab58d35d4
13 changed files with 122 additions and 46 deletions

View File

@ -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

View File

@ -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

View File

@ -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))
};

View File

@ -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();

View File

@ -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

View File

@ -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))

View File

@ -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)

View File

@ -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 =

View File

@ -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()

View File

@ -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.

View File

@ -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");

View File

@ -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(

View File

@ -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);