Add Oracle and graphviz output

This commit is contained in:
Sarah Jamie Lewis 2021-02-03 05:05:59 -08:00
parent 7ac7eaa193
commit e681e35054
5 changed files with 138 additions and 39 deletions

View File

@ -13,5 +13,6 @@ rand_distr = "0.4.0"
hashbrown = "0.9.1" hashbrown = "0.9.1"
termcolor = "1.1.2" termcolor = "1.1.2"
clap = "3.0.0-beta.2" clap = "3.0.0-beta.2"
tracing = "0.1.0" tracing = "0.1.22"
tracing-subscriber = "0.2" tracing-subscriber = "0.2.15"
hex = "0.4.2"

View File

@ -3,11 +3,14 @@ use crate::server::SimulatedServer;
use rand_distr::Pareto; use rand_distr::Pareto;
use std::io::Write; use std::io::Write;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor}; use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
mod oracle;
mod parties; mod parties;
mod server; mod server;
use clap::Clap; use clap::Clap;
use tracing::event; use tracing::event;
use crate::oracle::Oracle;
use tracing::Level; use tracing::Level;
use tracing_subscriber; use tracing_subscriber;
use tracing_subscriber::FmtSubscriber; use tracing_subscriber::FmtSubscriber;
@ -47,7 +50,10 @@ fn main() {
true => Level::TRACE, true => Level::TRACE,
_ => Level::INFO, _ => Level::INFO,
}; };
let subscriber = FmtSubscriber::builder().with_max_level(level).finish();
let mut oracle = Oracle::new();
let subscriber = FmtSubscriber::default();
tracing::subscriber::with_default(subscriber, || { tracing::subscriber::with_default(subscriber, || {
let mut rng = rand::thread_rng(); let mut rng = rand::thread_rng();
let mut server = SimulatedServer::new(); let mut server = SimulatedServer::new();
@ -55,14 +61,14 @@ fn main() {
let simulated_parties = SimulatedParties::new_simulation(opts.num_parties, opts.gamma); let simulated_parties = SimulatedParties::new_simulation(opts.num_parties, opts.gamma);
{ {
event!(Level::INFO, "Generating {} Parties and registering them with the server", opts.num_parties); event!(Level::INFO, "Generating {} Parties and registering them with the server", opts.num_parties);
simulated_parties.register_with_server(&mut server, &mut rng, opts.min_p, opts.max_p); simulated_parties.register_with_server(&mut server, &mut rng, opts.min_p, opts.max_p, &mut oracle);
} }
let pareto = Pareto::new(1.0, 1.0).unwrap(); let pareto = Pareto::new(1.0, 1.0).unwrap();
{ {
event!(Level::INFO, "Simulating message sends using {} samples from a pareto distribution...", opts.samples_per_round); event!(Level::INFO, "Simulating message sends using {} samples from a pareto distribution...", opts.samples_per_round);
(0..opts.samples_per_round).for_each(|_i| simulated_parties.sample_traffic(&mut server, &mut rng, pareto, opts.prob_entangled)); (0..opts.samples_per_round).for_each(|_i| simulated_parties.sample_traffic(&mut server, &mut rng, pareto, opts.prob_entangled, &mut oracle));
} }
{ {
@ -71,7 +77,7 @@ fn main() {
} }
{ {
let (round_stats, party_stats) = server.statistics(); let (server_oracle, round_stats, party_stats) = server.statistics();
let if_uniform = (round_stats.num_messages as f64) / (round_stats.num_registered_parties as f64); let if_uniform = (round_stats.num_messages as f64) / (round_stats.num_registered_parties as f64);
event!( event!(
Level::INFO, Level::INFO,
@ -101,6 +107,9 @@ fn main() {
) )
.unwrap(); .unwrap();
} }
server_oracle.compile_to_dot("server_event.dot", true);
} }
}); });
oracle.compile_to_dot("actual_events.dot", false);
} }

76
src/oracle.rs Normal file
View File

@ -0,0 +1,76 @@
// todo would be neat to just make this a subscriber of the tracing log, but there doesn't
// seem to be a nice way for that API to do what we want.. so until then...
use rand::{thread_rng, Rng};
use std::fs::File;
use std::io::Write;
#[derive(Clone)]
pub struct Event {
sender: String,
intended_receiver: String,
entangled_receiver: Option<String>,
}
#[derive(Clone)]
pub struct Oracle {
parties: Vec<String>,
actual_events: Vec<Event>,
}
impl Oracle {
pub fn new() -> Oracle {
Oracle {
parties: vec![],
actual_events: vec![],
}
}
pub fn register_party(&mut self, party: String) {
self.parties.push(party);
}
pub fn add_event(&mut self, sender: String, intended_receiver: String, entangled_receiver: Option<String>) {
self.actual_events.push(Event {
sender,
intended_receiver,
entangled_receiver,
});
}
pub fn compile_to_dot(&self, filename: &str, strict: bool) {
let mut output = File::create(filename).unwrap();
if strict {
write!(output, "strict ");
}
write!(output, "digraph {{\n");
write!(
output,
r#"K=2.5;
repulsiveforce=0.1;
overlap=true;
splines = true;
dpi=400;
penwidth = 0.8;
"#
);
for party in self.parties.iter() {
let r = hex::decode(party).unwrap()[0];
let g = hex::decode(party).unwrap()[1];
let b = hex::decode(party).unwrap()[2];
writeln!(output, "\"{}\" [shape=point, color=\"#{:x}{:x}{:x}\"]", party, r, g, b);
}
for event in self.actual_events.iter() {
writeln!(output, "\"{}\" -> \"{}\" [arrowhead=none]", event.sender, event.intended_receiver);
match &event.entangled_receiver {
Some(entangled_receiver) => {
writeln!(output, "\"{}\" -> \"{}\" [arrowhead=none,style=dashed]", event.sender, entangled_receiver);
}
_ => {}
};
}
write!(output, "}}");
}
}

View File

@ -1,3 +1,4 @@
use crate::oracle::Oracle;
use crate::server::SimulatedServer; use crate::server::SimulatedServer;
use fuzzytags::{FuzzyPublicKey, FuzzySecretKey}; use fuzzytags::{FuzzyPublicKey, FuzzySecretKey};
use rand::distributions::Distribution; use rand::distributions::Distribution;
@ -22,24 +23,23 @@ impl SimulatedParties {
SimulatedParties { gamma, parties } SimulatedParties { gamma, parties }
} }
pub fn register_with_server<R>(&self, server: &mut SimulatedServer, rng: &mut R, min_p: usize, max_p: usize) pub fn register_with_server<R>(&self, server: &mut SimulatedServer, rng: &mut R, min_p: usize, max_p: usize, oracle: &mut Oracle)
where where
R: Rng, R: Rng,
{ {
let span = span!(Level::TRACE, "register_with_server");
let _enter = span.enter();
for party in self.parties.iter() { for party in self.parties.iter() {
let n = rng.gen_range(min_p..max_p); let n = rng.gen_range(min_p..max_p);
let span = span!(Level::TRACE, "{register}", party = party.public_key().id().as_str()); let span = span!(Level::INFO, "register", party = party.public_key().id().as_str());
let _enter = span.enter(); let _enter = span.enter();
let detection_key = party.extract(n); let detection_key = party.extract(n);
event!(Level::TRACE, "create detection key {detection_key}", detection_key = detection_key.id().as_str()); event!(Level::TRACE, "create detection key {detection_key}", detection_key = detection_key.id().as_str());
event!(Level::TRACE, "register with server"); event!(Level::TRACE, "register with server");
server.register_key(&detection_key, &party.public_key()); server.register_key(&detection_key, &party.public_key());
oracle.register_party(party.public_key().id());
} }
} }
pub fn sample_traffic<R, D>(&self, server: &mut SimulatedServer, rng: &mut R, distribution: D, probs_entangled: f64) pub fn sample_traffic<R, D>(&self, server: &mut SimulatedServer, rng: &mut R, distribution: D, probs_entangled: f64, oracle: &mut Oracle)
where where
D: Distribution<f64>, D: Distribution<f64>,
R: Rng, R: Rng,
@ -47,31 +47,40 @@ impl SimulatedParties {
let span = span!(Level::INFO, "sample_traffic"); let span = span!(Level::INFO, "sample_traffic");
let _enter = span.enter(); let _enter = span.enter();
let v = distribution.sample(rng).to_u16().unwrap(); let v = distribution.sample(rng).to_u16().unwrap();
let sender = rng.gen_range(0..self.parties.len());
let sender_public_key = self.parties.get(sender).unwrap().public_key();
let receiver = rng.gen_range(0..self.parties.len()); let receiver = rng.gen_range(0..self.parties.len());
let receiver_public_key = self.parties.get(receiver).unwrap().public_key(); let receiver_public_key = self.parties.get(receiver).unwrap().public_key();
let entangle = rng.gen_bool(probs_entangled); if sender != receiver {
if entangle { let entangle = rng.gen_bool(probs_entangled);
let receiver_2 = rng.gen_range(0..self.parties.len()); if entangle {
let receiver_public_key_2 = self.parties.get(receiver_2).unwrap().public_key(); let receiver_2 = rng.gen_range(0..self.parties.len());
event!( let receiver_public_key_2 = self.parties.get(receiver_2).unwrap().public_key();
Level::INFO, event!(
"entangled send {party_1} {party_2}", Level::INFO,
party_1 = receiver_public_key.id().as_str(), "entangled send {party_1} {party_2}",
party_2 = receiver_public_key_2.id().as_str() party_1 = receiver_public_key.id().as_str(),
); party_2 = receiver_public_key_2.id().as_str()
);
for _i in 0..v { for _i in 0..v {
let tag = FuzzyPublicKey::generate_entangled_tag(vec![receiver_public_key.clone(), receiver_public_key_2.clone()], self.gamma); let tag = FuzzyPublicKey::generate_entangled_tag(vec![receiver_public_key.clone(), receiver_public_key_2.clone()], self.gamma);
event!(Level::TRACE, "message sent to server {tag}", tag = tag.to_string()); event!(Level::TRACE, "message sent to server {tag}", tag = tag.to_string());
server.add_message(tag); server.add_message(tag, &sender_public_key);
} }
} else {
event!(Level::INFO, "regular send {party}", party = receiver_public_key.id().as_str()); oracle.add_event(sender_public_key.id().clone(), receiver_public_key.id(), Some(receiver_public_key_2.id()));
for _i in 0..v { } else {
let tag = receiver_public_key.generate_tag(); event!(Level::INFO, "regular send {party}", party = receiver_public_key.id().as_str());
event!(Level::INFO, "message sent server {tag}", tag = tag.to_string()); for _i in 0..v {
server.add_message(tag); let tag = receiver_public_key.generate_tag();
event!(Level::INFO, "message sent server {tag}", tag = tag.to_string());
server.add_message(tag, &sender_public_key);
}
oracle.add_event(sender_public_key.id().clone(), receiver_public_key.id(), None);
} }
} }
} }

View File

@ -1,3 +1,4 @@
use crate::oracle::Oracle;
use fuzzytags::{FuzzyDetectionKey, FuzzyPublicKey, FuzzyTag}; use fuzzytags::{FuzzyDetectionKey, FuzzyPublicKey, FuzzyTag};
use hashbrown::HashMap; use hashbrown::HashMap;
use tracing::event; use tracing::event;
@ -6,9 +7,10 @@ use tracing::Level;
pub struct SimulatedServer { pub struct SimulatedServer {
keybase: Vec<(FuzzyDetectionKey, FuzzyPublicKey)>, keybase: Vec<(FuzzyDetectionKey, FuzzyPublicKey)>,
messages: Vec<FuzzyTag>, messages: Vec<(FuzzyTag, FuzzyPublicKey)>,
tags_to_keys_cache: HashMap<String, Vec<FuzzyPublicKey>>, tags_to_keys_cache: HashMap<String, Vec<FuzzyPublicKey>>,
keys_to_tags_cache: HashMap<String, Vec<FuzzyTag>>, keys_to_tags_cache: HashMap<String, Vec<FuzzyTag>>,
oracle: Oracle,
} }
pub struct RoundStatistics { pub struct RoundStatistics {
@ -34,35 +36,37 @@ impl SimulatedServer {
messages: vec![], messages: vec![],
tags_to_keys_cache: HashMap::new(), tags_to_keys_cache: HashMap::new(),
keys_to_tags_cache: HashMap::new(), keys_to_tags_cache: HashMap::new(),
oracle: Oracle::new(),
} }
} }
pub fn register_key(&mut self, detection_key: &FuzzyDetectionKey, public_key: &FuzzyPublicKey) { pub fn register_key(&mut self, detection_key: &FuzzyDetectionKey, public_key: &FuzzyPublicKey) {
self.keybase.push((detection_key.clone(), public_key.clone())); self.keybase.push((detection_key.clone(), public_key.clone()));
self.keys_to_tags_cache.insert(public_key.id(), vec![]); self.keys_to_tags_cache.insert(public_key.id(), vec![]);
self.oracle.register_party(public_key.id());
} }
pub fn add_message(&mut self, tag: FuzzyTag) { pub fn add_message(&mut self, tag: FuzzyTag, sender_public_key: &FuzzyPublicKey) {
self.messages.push(tag.clone()); self.messages.push((tag.clone(), sender_public_key.clone()));
self.tags_to_keys_cache.insert(tag.to_string(), vec![]); self.tags_to_keys_cache.insert(tag.to_string(), vec![]);
} }
pub fn test_messages(&mut self) { pub fn test_messages(&mut self) {
for message in self.messages.iter() { for (message, sender) in self.messages.iter() {
for (detection_key, public_key) in self.keybase.iter() { for (detection_key, public_key) in self.keybase.iter() {
let span = span!(Level::TRACE, "{detection}", party = public_key.id().as_str()); let span = span!(Level::TRACE, "{detection}", party = public_key.id().as_str());
let _enter = span.enter(); let _enter = span.enter();
if detection_key.test_tag(message) { if detection_key.test_tag(message) {
event!(Level::TRACE, "Matched detection key for {key} to tag {tag} ", key = public_key.id(), tag = message.to_string()); event!(Level::TRACE, "Matched detection key for {key} to tag {tag} ", key = public_key.id(), tag = message.to_string());
self.tags_to_keys_cache.get_mut(message.to_string().as_str()).unwrap().push((*public_key).clone()); self.tags_to_keys_cache.get_mut(message.to_string().as_str()).unwrap().push((*public_key).clone());
self.keys_to_tags_cache.get_mut(public_key.id().as_str()).unwrap().push((*message).clone()); self.keys_to_tags_cache.get_mut(public_key.id().as_str()).unwrap().push((*message).clone());
self.oracle.add_event(sender.id(), public_key.id(), None);
} }
} }
} }
} }
pub fn statistics(&self) -> (RoundStatistics, HashMap<String, PartyStatistics>) { pub fn statistics(&self) -> (Oracle, RoundStatistics, HashMap<String, PartyStatistics>) {
let mut party_stats = HashMap::new(); let mut party_stats = HashMap::new();
let round_stats = RoundStatistics { let round_stats = RoundStatistics {
num_messages: self.messages.len(), num_messages: self.messages.len(),
@ -98,6 +102,6 @@ impl SimulatedServer {
party_stats.insert(pub_key.id(), p_stats); party_stats.insert(pub_key.id(), p_stats);
} }
(round_stats, party_stats) (self.oracle.clone(), round_stats, party_stats)
} }
} }