mirror of https://github.com/poanetwork/hbbft.git
Merge pull request #82 from poanetwork/vk-test-decryption-shares
An adversary sending faulty decryption shares
This commit is contained in:
commit
b3b3994ec1
|
@ -563,7 +563,7 @@ pub enum MessageContent<NodeUid> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<NodeUid> MessageContent<NodeUid> {
|
impl<NodeUid> MessageContent<NodeUid> {
|
||||||
fn with_epoch(self, epoch: u64) -> Message<NodeUid> {
|
pub fn with_epoch(self, epoch: u64) -> Message<NodeUid> {
|
||||||
Message {
|
Message {
|
||||||
epoch,
|
epoch,
|
||||||
content: self,
|
content: self,
|
||||||
|
|
|
@ -79,7 +79,7 @@ where
|
||||||
num_good_nodes, num_faulty_nodes
|
num_good_nodes, num_faulty_nodes
|
||||||
);
|
);
|
||||||
for &input in &[None, Some(false), Some(true)] {
|
for &input in &[None, Some(false), Some(true)] {
|
||||||
let adversary = new_adversary(num_good_nodes, num_faulty_nodes);
|
let adversary = |_| new_adversary(num_good_nodes, num_faulty_nodes);
|
||||||
let new_agreement = |netinfo: Rc<NetworkInfo<NodeUid>>| {
|
let new_agreement = |netinfo: Rc<NetworkInfo<NodeUid>>| {
|
||||||
Agreement::new(netinfo, 0, NodeUid(0)).expect("agreement instance")
|
Agreement::new(netinfo, 0, NodeUid(0)).expect("agreement instance")
|
||||||
};
|
};
|
||||||
|
|
|
@ -129,7 +129,7 @@ where
|
||||||
"Network size: {} good nodes, {} faulty nodes",
|
"Network size: {} good nodes, {} faulty nodes",
|
||||||
num_good_nodes, num_faulty_nodes
|
num_good_nodes, num_faulty_nodes
|
||||||
);
|
);
|
||||||
let adversary = new_adversary(num_good_nodes, num_faulty_nodes);
|
let adversary = |_| new_adversary(num_good_nodes, num_faulty_nodes);
|
||||||
let network = TestNetwork::new(num_good_nodes, num_faulty_nodes, adversary, new_broadcast);
|
let network = TestNetwork::new(num_good_nodes, num_faulty_nodes, adversary, new_broadcast);
|
||||||
test_broadcast(network, proposed_value);
|
test_broadcast(network, proposed_value);
|
||||||
}
|
}
|
||||||
|
@ -137,7 +137,7 @@ where
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_8_broadcast_equal_leaves_silent() {
|
fn test_8_broadcast_equal_leaves_silent() {
|
||||||
let adversary = SilentAdversary::new(MessageScheduler::Random);
|
let adversary = |_| SilentAdversary::new(MessageScheduler::Random);
|
||||||
// Space is ASCII character 32. So 32 spaces will create shards that are all equal, even if the
|
// Space is ASCII character 32. So 32 spaces will create shards that are all equal, even if the
|
||||||
// length of the value is inserted.
|
// length of the value is inserted.
|
||||||
test_broadcast(
|
test_broadcast(
|
||||||
|
|
|
@ -103,7 +103,7 @@ where
|
||||||
let mut count_true = 0;
|
let mut count_true = 0;
|
||||||
let mut count_false = 0;
|
let mut count_false = 0;
|
||||||
for i in 0..num_samples {
|
for i in 0..num_samples {
|
||||||
let adversary = new_adversary(num_good_nodes, num_faulty_nodes);
|
let adversary = |_| new_adversary(num_good_nodes, num_faulty_nodes);
|
||||||
let nonce = format!("My very unique nonce {:x}:{}", unique_id, i);
|
let nonce = format!("My very unique nonce {:x}:{}", unique_id, i);
|
||||||
info!("Nonce: {}", nonce);
|
info!("Nonce: {}", nonce);
|
||||||
let new_common_coin = |netinfo: _| CommonCoin::new(netinfo, nonce.clone());
|
let new_common_coin = |netinfo: _| CommonCoin::new(netinfo, nonce.clone());
|
||||||
|
|
|
@ -58,11 +58,15 @@ fn test_common_subset<A: Adversary<CommonSubset<NodeUid>>>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_network<A: Adversary<CommonSubset<NodeUid>>>(
|
fn new_network<A, F>(
|
||||||
good_num: usize,
|
good_num: usize,
|
||||||
bad_num: usize,
|
bad_num: usize,
|
||||||
adversary: A,
|
adversary: F,
|
||||||
) -> TestNetwork<A, CommonSubset<NodeUid>> {
|
) -> TestNetwork<A, CommonSubset<NodeUid>>
|
||||||
|
where
|
||||||
|
A: Adversary<CommonSubset<NodeUid>>,
|
||||||
|
F: Fn(BTreeMap<NodeUid, Rc<NetworkInfo<NodeUid>>>) -> A,
|
||||||
|
{
|
||||||
// This returns an error in all but the first test.
|
// This returns an error in all but the first test.
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
|
|
||||||
|
@ -80,7 +84,7 @@ fn test_common_subset_3_out_of_4_nodes_propose() {
|
||||||
.iter()
|
.iter()
|
||||||
.map(|id| (*id, proposed_value.clone()))
|
.map(|id| (*id, proposed_value.clone()))
|
||||||
.collect();
|
.collect();
|
||||||
let adversary = SilentAdversary::new(MessageScheduler::First);
|
let adversary = |_| SilentAdversary::new(MessageScheduler::First);
|
||||||
let network = new_network(3, 1, adversary);
|
let network = new_network(3, 1, adversary);
|
||||||
test_common_subset(network, &proposals);
|
test_common_subset(network, &proposals);
|
||||||
}
|
}
|
||||||
|
@ -99,7 +103,7 @@ fn test_common_subset_5_nodes_different_proposed_values() {
|
||||||
.map(NodeUid)
|
.map(NodeUid)
|
||||||
.zip(proposed_values)
|
.zip(proposed_values)
|
||||||
.collect();
|
.collect();
|
||||||
let adversary = SilentAdversary::new(MessageScheduler::Random);
|
let adversary = |_| SilentAdversary::new(MessageScheduler::Random);
|
||||||
let network = new_network(5, 0, adversary);
|
let network = new_network(5, 0, adversary);
|
||||||
test_common_subset(network, &proposals);
|
test_common_subset(network, &proposals);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
//! Network tests for Honey Badger.
|
//! Network tests for Honey Badger.
|
||||||
|
|
||||||
|
extern crate bincode;
|
||||||
extern crate hbbft;
|
extern crate hbbft;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate log;
|
extern crate log;
|
||||||
|
@ -11,15 +12,110 @@ extern crate serde_derive;
|
||||||
|
|
||||||
mod network;
|
mod network;
|
||||||
|
|
||||||
|
use std::collections::BTreeMap;
|
||||||
use std::iter::once;
|
use std::iter::once;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
use hbbft::honey_badger::HoneyBadger;
|
use hbbft::honey_badger::{self, HoneyBadger, MessageContent};
|
||||||
use hbbft::messaging::NetworkInfo;
|
use hbbft::messaging::{NetworkInfo, Target, TargetedMessage};
|
||||||
|
|
||||||
use network::{Adversary, MessageScheduler, NodeUid, SilentAdversary, TestNetwork, TestNode};
|
use network::{
|
||||||
|
Adversary, MessageScheduler, MessageWithSender, NodeUid, SilentAdversary, TestNetwork, TestNode,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// An adversary whose nodes only send messages with incorrect decryption shares.
|
||||||
|
pub struct FaultyShareAdversary {
|
||||||
|
num_good: usize,
|
||||||
|
num_adv: usize,
|
||||||
|
adv_nodes: BTreeMap<NodeUid, Rc<NetworkInfo<NodeUid>>>,
|
||||||
|
scheduler: MessageScheduler,
|
||||||
|
share_triggers: BTreeMap<u64, bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FaultyShareAdversary {
|
||||||
|
/// Creates a new silent adversary with the given message scheduler.
|
||||||
|
pub fn new(
|
||||||
|
num_good: usize,
|
||||||
|
num_adv: usize,
|
||||||
|
adv_nodes: BTreeMap<NodeUid, Rc<NetworkInfo<NodeUid>>>,
|
||||||
|
scheduler: MessageScheduler,
|
||||||
|
) -> FaultyShareAdversary {
|
||||||
|
FaultyShareAdversary {
|
||||||
|
num_good,
|
||||||
|
num_adv,
|
||||||
|
scheduler,
|
||||||
|
share_triggers: BTreeMap::new(),
|
||||||
|
adv_nodes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Adversary<HoneyBadger<usize, NodeUid>> for FaultyShareAdversary {
|
||||||
|
fn pick_node(
|
||||||
|
&self,
|
||||||
|
nodes: &BTreeMap<NodeUid, TestNode<HoneyBadger<usize, NodeUid>>>,
|
||||||
|
) -> NodeUid {
|
||||||
|
self.scheduler.pick_node(nodes)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push_message(
|
||||||
|
&mut self,
|
||||||
|
sender_id: NodeUid,
|
||||||
|
msg: TargetedMessage<honey_badger::Message<NodeUid>, NodeUid>,
|
||||||
|
) {
|
||||||
|
let NodeUid(sender_id) = sender_id;
|
||||||
|
if sender_id < self.num_good {
|
||||||
|
if let TargetedMessage {
|
||||||
|
target: Target::All,
|
||||||
|
message,
|
||||||
|
} = msg
|
||||||
|
{
|
||||||
|
let epoch = message.epoch();
|
||||||
|
// Set the trigger to simulate decryption share messages.
|
||||||
|
self.share_triggers.entry(epoch).or_insert(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn step(&mut self) -> Vec<MessageWithSender<HoneyBadger<usize, NodeUid>>> {
|
||||||
|
let mut outgoing = vec![];
|
||||||
|
let fake_proposal = &Vec::from("X marks the spot");
|
||||||
|
|
||||||
|
for (epoch, trigger_set) in &mut self.share_triggers {
|
||||||
|
if *trigger_set {
|
||||||
|
// Unset the trigger.
|
||||||
|
*trigger_set = false;
|
||||||
|
// Broadcast fake decryption shares from all adversarial nodes.
|
||||||
|
for sender_id in self.num_good..self.num_adv {
|
||||||
|
let adv_node = &self.adv_nodes[&NodeUid(sender_id)];
|
||||||
|
let fake_ciphertext = (*adv_node)
|
||||||
|
.public_key_set()
|
||||||
|
.public_key()
|
||||||
|
.encrypt(fake_proposal);
|
||||||
|
let share = adv_node
|
||||||
|
.secret_key()
|
||||||
|
.decrypt_share(&fake_ciphertext)
|
||||||
|
.expect("decryption share");
|
||||||
|
// Send the share to remote nodes.
|
||||||
|
for proposer_id in 0..self.num_good + self.num_adv {
|
||||||
|
outgoing.push((
|
||||||
|
NodeUid(sender_id),
|
||||||
|
Target::All.message(
|
||||||
|
MessageContent::DecryptionShare {
|
||||||
|
proposer_id: NodeUid(proposer_id),
|
||||||
|
share: share.clone(),
|
||||||
|
}.with_epoch(*epoch),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outgoing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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_honey_badger<A>(mut network: TestNetwork<A, HoneyBadger<usize, NodeUid>>, num_txs: usize)
|
fn test_honey_badger<A>(mut network: TestNetwork<A, HoneyBadger<usize, NodeUid>>, num_txs: usize)
|
||||||
|
@ -65,7 +161,7 @@ fn new_honey_badger(netinfo: Rc<NetworkInfo<NodeUid>>) -> HoneyBadger<usize, Nod
|
||||||
fn test_honey_badger_different_sizes<A, F>(new_adversary: F, num_txs: usize)
|
fn test_honey_badger_different_sizes<A, F>(new_adversary: F, num_txs: usize)
|
||||||
where
|
where
|
||||||
A: Adversary<HoneyBadger<usize, NodeUid>>,
|
A: Adversary<HoneyBadger<usize, NodeUid>>,
|
||||||
F: Fn(usize, usize) -> A,
|
F: Fn(usize, usize, BTreeMap<NodeUid, Rc<NetworkInfo<NodeUid>>>) -> A,
|
||||||
{
|
{
|
||||||
// This returns an error in all but the first test.
|
// This returns an error in all but the first test.
|
||||||
let _ = env_logger::try_init();
|
let _ = env_logger::try_init();
|
||||||
|
@ -75,31 +171,34 @@ where
|
||||||
.chain(once(rng.gen_range(6, 10)))
|
.chain(once(rng.gen_range(6, 10)))
|
||||||
.chain(once(rng.gen_range(11, 15)));
|
.chain(once(rng.gen_range(11, 15)));
|
||||||
for size in sizes {
|
for size in sizes {
|
||||||
let num_faulty_nodes = (size - 1) / 3;
|
let num_adv_nodes = (size - 1) / 3;
|
||||||
let num_good_nodes = size - num_faulty_nodes;
|
let num_good_nodes = size - num_adv_nodes;
|
||||||
info!(
|
info!(
|
||||||
"Network size: {} good nodes, {} faulty nodes",
|
"Network size: {} good nodes, {} faulty nodes",
|
||||||
num_good_nodes, num_faulty_nodes
|
num_good_nodes, num_adv_nodes
|
||||||
);
|
|
||||||
let adversary = new_adversary(num_good_nodes, num_faulty_nodes);
|
|
||||||
let network = TestNetwork::new(
|
|
||||||
num_good_nodes,
|
|
||||||
num_faulty_nodes,
|
|
||||||
adversary,
|
|
||||||
new_honey_badger,
|
|
||||||
);
|
);
|
||||||
|
let adversary = |adv_nodes| new_adversary(num_good_nodes, num_adv_nodes, adv_nodes);
|
||||||
|
let network = TestNetwork::new(num_good_nodes, num_adv_nodes, adversary, new_honey_badger);
|
||||||
test_honey_badger(network, num_txs);
|
test_honey_badger(network, num_txs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_honey_badger_random_delivery_silent() {
|
fn test_honey_badger_random_delivery_silent() {
|
||||||
let new_adversary = |_: usize, _: usize| SilentAdversary::new(MessageScheduler::Random);
|
let new_adversary = |_: usize, _: usize, _| SilentAdversary::new(MessageScheduler::Random);
|
||||||
test_honey_badger_different_sizes(new_adversary, 10);
|
test_honey_badger_different_sizes(new_adversary, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_honey_badger_first_delivery_silent() {
|
fn test_honey_badger_first_delivery_silent() {
|
||||||
let new_adversary = |_: usize, _: usize| SilentAdversary::new(MessageScheduler::First);
|
let new_adversary = |_: usize, _: usize, _| SilentAdversary::new(MessageScheduler::First);
|
||||||
test_honey_badger_different_sizes(new_adversary, 10);
|
test_honey_badger_different_sizes(new_adversary, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_honey_badger_faulty_share() {
|
||||||
|
let new_adversary = |num_good: usize, num_adv: usize, adv_nodes| {
|
||||||
|
FaultyShareAdversary::new(num_good, num_adv, adv_nodes, MessageScheduler::Random)
|
||||||
|
};
|
||||||
|
test_honey_badger_different_sizes(new_adversary, 8);
|
||||||
|
}
|
||||||
|
|
|
@ -99,7 +99,7 @@ impl MessageScheduler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type MessageWithSender<D> = (
|
pub type MessageWithSender<D> = (
|
||||||
<D as DistAlgorithm>::NodeUid,
|
<D as DistAlgorithm>::NodeUid,
|
||||||
TargetedMessage<<D as DistAlgorithm>::Message, <D as DistAlgorithm>::NodeUid>,
|
TargetedMessage<<D as DistAlgorithm>::Message, <D as DistAlgorithm>::NodeUid>,
|
||||||
);
|
);
|
||||||
|
@ -158,9 +158,15 @@ where
|
||||||
{
|
{
|
||||||
/// Creates a new network with `good_num` good nodes, and the given `adversary` controlling
|
/// Creates a new network with `good_num` good nodes, and the given `adversary` controlling
|
||||||
/// `adv_num` nodes.
|
/// `adv_num` nodes.
|
||||||
pub fn new<F>(good_num: usize, adv_num: usize, adversary: A, new_algo: F) -> TestNetwork<A, D>
|
pub fn new<F, G>(
|
||||||
|
good_num: usize,
|
||||||
|
adv_num: usize,
|
||||||
|
adversary: G,
|
||||||
|
new_algo: F,
|
||||||
|
) -> TestNetwork<A, D>
|
||||||
where
|
where
|
||||||
F: Fn(Rc<NetworkInfo<NodeUid>>) -> D,
|
F: Fn(Rc<NetworkInfo<NodeUid>>) -> D,
|
||||||
|
G: Fn(BTreeMap<D::NodeUid, Rc<NetworkInfo<D::NodeUid>>>) -> A,
|
||||||
{
|
{
|
||||||
let mut rng = rand::thread_rng();
|
let mut rng = rand::thread_rng();
|
||||||
let sk_set = SecretKeySet::random(adv_num, &mut rng);
|
let sk_set = SecretKeySet::random(adv_num, &mut rng);
|
||||||
|
@ -189,13 +195,15 @@ where
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
let adv_nodes: BTreeMap<D::NodeUid, Rc<NetworkInfo<D::NodeUid>>> = (good_num
|
||||||
|
..(good_num + adv_num))
|
||||||
|
.map(NodeUid)
|
||||||
|
.map(new_adv_node_by_id)
|
||||||
|
.collect();
|
||||||
let mut network = TestNetwork {
|
let mut network = TestNetwork {
|
||||||
nodes: (0..good_num).map(NodeUid).map(new_node_by_id).collect(),
|
nodes: (0..good_num).map(NodeUid).map(new_node_by_id).collect(),
|
||||||
adversary,
|
adversary: adversary(adv_nodes.clone()),
|
||||||
adv_nodes: (good_num..(good_num + adv_num))
|
adv_nodes,
|
||||||
.map(NodeUid)
|
|
||||||
.map(new_adv_node_by_id)
|
|
||||||
.collect(),
|
|
||||||
};
|
};
|
||||||
let msgs = network.adversary.step();
|
let msgs = network.adversary.step();
|
||||||
for (sender_id, msg) in msgs {
|
for (sender_id, msg) in msgs {
|
||||||
|
|
Loading…
Reference in New Issue