hbbft/tests/sync_key_gen.rs

102 lines
3.5 KiB
Rust
Raw Normal View History

#![deny(unused_must_use)]
//! Tests for synchronous distributed key generation.
extern crate env_logger;
extern crate hbbft;
extern crate rand;
extern crate threshold_crypto as crypto;
use std::collections::BTreeMap;
use crypto::{PublicKey, SecretKey};
2018-07-19 03:28:15 -07:00
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(|_| SecretKey::random()).collect();
let pub_keys: BTreeMap<usize, PublicKey> = sec_keys
.iter()
.map(SecretKey::public_key)
.enumerate()
.collect();
// Create the `SyncKeyGen` instances and initial proposals.
let mut nodes = Vec::new();
let proposals: Vec<_> = sec_keys
.into_iter()
.enumerate()
.map(|(id, sk)| {
Better proptest persistence through deterministic randomness. (#248) * Add support for RNG instantiation in proptests. * Use `proptest` module strategy to create the rng for `net_dynamic_honey_badger`. * Use seed generation instead of RNG instantiation in tests. * Remove fixed RNG in `generate_map`. * `VirtualNet` now supports setting the random generator through the builder. * Add missing `time_limit` field to `::std::fmt::Debug` trait implementation on `NetBuilder`. * Pass an instantiated random number generator through `NewNodeInfo` as a convenience. * Make the random number generator of `DynamicHoneyBadgerBuilder` configurable, at the cost of now requiring mutability to call `build_first_node()`. * Ensure RNGs are derive from passed in seed in `net_dynamic_hb` tests. * Correct inappropriate use of `random::Random` instead of `Rng::gen` to generate dependent values in `binary_agreement`. The original implementation used `rand::random()`, which will always use the `thread_rng`, ignoring the fact that an RNG has actually been passed in. * Do not use `OsRng` but passed in RNG instead. * Use reference/non-reference passing of rngs more in line with the `rand` crates conventions. * Document `rng` field on `DynamicHoneyBadger`. * Make `SyncKeyGen` work with the extend (`encrypt_with_rng`) API of `threshold_crypto`. * Use passed-in random number generator in `HoneyBadger`. * Create `SubRng` crate in new `util` module to replace `create_rng()`. * Use an RNG seeded from the configure RNG when reinitializing `DynamicHoneyBadger`. * Use the correct branch of `threshold_crypto` with support for passing RNGs.
2018-10-02 07:24:51 -07:00
let (sync_key_gen, proposal) =
SyncKeyGen::new(&mut rand::thread_rng(), id, sk, pub_keys.clone(), threshold)
.unwrap_or_else(|_err| {
panic!("Failed to create `SyncKeyGen` instance #{}", id)
});
nodes.push(sync_key_gen);
proposal
}).collect();
// Handle the first `threshold + 1` proposals. Those should suffice for key generation.
2018-07-19 03:28:15 -07:00
let mut acks = Vec::new();
for (sender_id, proposal) in proposals[..=threshold].iter().enumerate() {
for (node_id, node) in nodes.iter_mut().enumerate() {
let proposal = proposal.clone().expect("proposal");
Better proptest persistence through deterministic randomness. (#248) * Add support for RNG instantiation in proptests. * Use `proptest` module strategy to create the rng for `net_dynamic_honey_badger`. * Use seed generation instead of RNG instantiation in tests. * Remove fixed RNG in `generate_map`. * `VirtualNet` now supports setting the random generator through the builder. * Add missing `time_limit` field to `::std::fmt::Debug` trait implementation on `NetBuilder`. * Pass an instantiated random number generator through `NewNodeInfo` as a convenience. * Make the random number generator of `DynamicHoneyBadgerBuilder` configurable, at the cost of now requiring mutability to call `build_first_node()`. * Ensure RNGs are derive from passed in seed in `net_dynamic_hb` tests. * Correct inappropriate use of `random::Random` instead of `Rng::gen` to generate dependent values in `binary_agreement`. The original implementation used `rand::random()`, which will always use the `thread_rng`, ignoring the fact that an RNG has actually been passed in. * Do not use `OsRng` but passed in RNG instead. * Use reference/non-reference passing of rngs more in line with the `rand` crates conventions. * Document `rng` field on `DynamicHoneyBadger`. * Make `SyncKeyGen` work with the extend (`encrypt_with_rng`) API of `threshold_crypto`. * Use passed-in random number generator in `HoneyBadger`. * Create `SubRng` crate in new `util` module to replace `create_rng()`. * Use an RNG seeded from the configure RNG when reinitializing `DynamicHoneyBadger`. * Use the correct branch of `threshold_crypto` with support for passing RNGs.
2018-10-02 07:24:51 -07:00
let ack = match node.handle_part(&mut rand::thread_rng(), &sender_id, proposal) {
2018-07-19 03:28:15 -07:00
Some(PartOutcome::Valid(ack)) => ack,
_ => panic!("invalid proposal"),
};
2018-07-19 03:28:15 -07:00
// Only the first `threshold + 1` manage to commit their `Ack`s.
if node_id <= 2 * threshold {
2018-07-19 03:28:15 -07:00
acks.push((node_id, ack));
}
}
}
2018-07-19 03:28:15 -07:00
// Handle the `Ack`s from `2 * threshold + 1` nodes.
for (sender_id, ack) in acks {
for node in &mut nodes {
2018-07-19 03:28:15 -07:00
assert!(!node.is_ready()); // Not enough `Ack`s yet.
node.handle_ack(&sender_id, ack.clone());
}
}
// 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()
.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().unwrap_or_else(|_| {
panic!(
"Failed to generate `PublicKeySet` and `SecretKeyShare` for node #{}",
idx
)
});
2018-06-27 02:37:05 -07:00
let sk = opt_sk.expect("new secret key");
assert_eq!(pks, pub_key_set);
let sig = sk.sign(msg);
assert!(pks.public_key_share(idx).verify(&sig, msg));
(idx, sig)
}).collect();
let sig = pub_key_set
.combine_signatures(sig_shares.iter().take(threshold + 1))
.expect("signature shares match");
assert!(pub_key_set.public_key().verify(&sig, msg));
}
#[test]
fn test_sync_key_gen() {
// This returns an error in all but the first test.
let _ = env_logger::try_init();
for &node_num in &[1, 2, 3, 4, 8, 15] {
let threshold = (node_num - 1) / 3;
test_sync_key_gen_with(threshold, node_num);
}
}