Merge pull request #82 from poanetwork/vk-test-decryption-shares

An adversary sending faulty decryption shares
This commit is contained in:
Andreas Fackler 2018-06-26 09:06:33 +02:00 committed by GitHub
commit b3b3994ec1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 144 additions and 33 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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