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"
termcolor = "1.1.2"
clap = "3.0.0-beta.2"
tracing = "0.1.0"
tracing-subscriber = "0.2"
tracing = "0.1.22"
tracing-subscriber = "0.2.15"
hex = "0.4.2"

View File

@ -3,11 +3,14 @@ use crate::server::SimulatedServer;
use rand_distr::Pareto;
use std::io::Write;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream, WriteColor};
mod oracle;
mod parties;
mod server;
use clap::Clap;
use tracing::event;
use crate::oracle::Oracle;
use tracing::Level;
use tracing_subscriber;
use tracing_subscriber::FmtSubscriber;
@ -47,7 +50,10 @@ fn main() {
true => Level::TRACE,
_ => 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, || {
let mut rng = rand::thread_rng();
let mut server = SimulatedServer::new();
@ -55,14 +61,14 @@ fn main() {
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);
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();
{
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);
event!(
Level::INFO,
@ -101,6 +107,9 @@ fn main() {
)
.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 fuzzytags::{FuzzyPublicKey, FuzzySecretKey};
use rand::distributions::Distribution;
@ -22,24 +23,23 @@ impl SimulatedParties {
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
R: Rng,
{
let span = span!(Level::TRACE, "register_with_server");
let _enter = span.enter();
for party in self.parties.iter() {
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 detection_key = party.extract(n);
event!(Level::TRACE, "create detection key {detection_key}", detection_key = detection_key.id().as_str());
event!(Level::TRACE, "register with server");
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
D: Distribution<f64>,
R: Rng,
@ -47,31 +47,40 @@ impl SimulatedParties {
let span = span!(Level::INFO, "sample_traffic");
let _enter = span.enter();
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_public_key = self.parties.get(receiver).unwrap().public_key();
let entangle = rng.gen_bool(probs_entangled);
if entangle {
let receiver_2 = rng.gen_range(0..self.parties.len());
let receiver_public_key_2 = self.parties.get(receiver_2).unwrap().public_key();
event!(
Level::INFO,
"entangled send {party_1} {party_2}",
party_1 = receiver_public_key.id().as_str(),
party_2 = receiver_public_key_2.id().as_str()
);
if sender != receiver {
let entangle = rng.gen_bool(probs_entangled);
if entangle {
let receiver_2 = rng.gen_range(0..self.parties.len());
let receiver_public_key_2 = self.parties.get(receiver_2).unwrap().public_key();
event!(
Level::INFO,
"entangled send {party_1} {party_2}",
party_1 = receiver_public_key.id().as_str(),
party_2 = receiver_public_key_2.id().as_str()
);
for _i in 0..v {
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());
server.add_message(tag);
}
} else {
event!(Level::INFO, "regular send {party}", party = receiver_public_key.id().as_str());
for _i in 0..v {
let tag = receiver_public_key.generate_tag();
event!(Level::INFO, "message sent server {tag}", tag = tag.to_string());
server.add_message(tag);
for _i in 0..v {
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());
server.add_message(tag, &sender_public_key);
}
oracle.add_event(sender_public_key.id().clone(), receiver_public_key.id(), Some(receiver_public_key_2.id()));
} else {
event!(Level::INFO, "regular send {party}", party = receiver_public_key.id().as_str());
for _i in 0..v {
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 hashbrown::HashMap;
use tracing::event;
@ -6,9 +7,10 @@ use tracing::Level;
pub struct SimulatedServer {
keybase: Vec<(FuzzyDetectionKey, FuzzyPublicKey)>,
messages: Vec<FuzzyTag>,
messages: Vec<(FuzzyTag, FuzzyPublicKey)>,
tags_to_keys_cache: HashMap<String, Vec<FuzzyPublicKey>>,
keys_to_tags_cache: HashMap<String, Vec<FuzzyTag>>,
oracle: Oracle,
}
pub struct RoundStatistics {
@ -34,35 +36,37 @@ impl SimulatedServer {
messages: vec![],
tags_to_keys_cache: HashMap::new(),
keys_to_tags_cache: HashMap::new(),
oracle: Oracle::new(),
}
}
pub fn register_key(&mut self, detection_key: &FuzzyDetectionKey, public_key: &FuzzyPublicKey) {
self.keybase.push((detection_key.clone(), public_key.clone()));
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) {
self.messages.push(tag.clone());
pub fn add_message(&mut self, tag: FuzzyTag, sender_public_key: &FuzzyPublicKey) {
self.messages.push((tag.clone(), sender_public_key.clone()));
self.tags_to_keys_cache.insert(tag.to_string(), vec![]);
}
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() {
let span = span!(Level::TRACE, "{detection}", party = public_key.id().as_str());
let _enter = span.enter();
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());
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.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 round_stats = RoundStatistics {
num_messages: self.messages.len(),
@ -98,6 +102,6 @@ impl SimulatedServer {
party_stats.insert(pub_key.id(), p_stats);
}
(round_stats, party_stats)
(self.oracle.clone(), round_stats, party_stats)
}
}