From 7dc003456dcf3ed5bb0a56263dfa9d43d6586f55 Mon Sep 17 00:00:00 2001 From: Youngjoon Lee <5462944+youngjoon-lee@users.noreply.github.com> Date: Fri, 31 May 2024 21:07:47 +0900 Subject: [PATCH] plots, but not expected --- mixnet/v2/sim/analysis.py | 62 +++++++++++++++++++++++++++++++++--- mixnet/v2/sim/measurement.py | 10 +++++- mixnet/v2/sim/p2p.py | 9 ++++-- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/mixnet/v2/sim/analysis.py b/mixnet/v2/sim/analysis.py index b93db8e..e043df1 100644 --- a/mixnet/v2/sim/analysis.py +++ b/mixnet/v2/sim/analysis.py @@ -2,9 +2,11 @@ import random from collections import defaultdict, Counter from typing import TYPE_CHECKING +import numpy as np import pandas as pd import seaborn from matplotlib import pyplot as plt +import scipy.stats as stats from adversary import NodeState from config import Config @@ -174,6 +176,7 @@ class Analysis: - there is no message to track back within a reasonable time window - enough hops have been traversed """ + all_results = [] window = len(self.sim.p2p.adversary.msgs_in_node_per_window) - 1 while window >= 0: items = self.sim.p2p.adversary.msgs_in_node_per_window[window].items() @@ -181,10 +184,61 @@ class Analysis: if len(actual_receivers) == 0: window -= 1 continue - receiver = random.choice(actual_receivers) - nodes_per_hop = self.timing_attack_with(receiver, window) - self.print_nodes_per_hop(nodes_per_hop, window) - window -= len(nodes_per_hop) + + results = [] + max_hops = 0 + for receiver in actual_receivers: + nodes_per_hop = self.timing_attack_with(receiver, window) + self.print_nodes_per_hop(nodes_per_hop, window) + results.append(nodes_per_hop) + max_hops = max(max_hops, len(nodes_per_hop)) + window -= max_hops + all_results.extend(results) + + suspected_senders = Counter() + for result in all_results: + print(Counter({node.id: count for node, count in result[-1].items()})) + suspected_senders.update(result[-1]) + suspected_senders = ({node.id: count for node, count in suspected_senders.items()}) + print(f"suspected nodes count: {len(suspected_senders)}") + + # Extract keys and values from the Counter + keys = list(suspected_senders.keys()) + values = list(suspected_senders.values()) + # Create the bar plot + plt.figure(figsize=(12, 8)) + plt.bar(keys, values) + plt.xlabel('Node ID') + plt.ylabel('Counts') + plt.title('Suspected Sender Counts') + plt.show() + + # Create the bar plot for original sender counts + original_senders = ({node.id: count for node, count in self.sim.p2p.measurement.original_senders.items()}) + plt.figure(figsize=(12, 8)) + plt.bar(list(original_senders.keys()), list(original_senders.values())) + plt.xlabel('Node ID') + plt.ylabel('Counts') + plt.title('Original Sender Counts') + plt.show() + + # Calculate the mean and standard deviation of the counts + mean = np.mean(values) + std_dev = np.std(values) + # Plot the histogram of the values + plt.figure(figsize=(12, 8)) + plt.hist(values, bins=30, density=True, alpha=0.6, color='g', label='Counts Histogram') + # Plot the normal distribution curve + xmin, xmax = plt.xlim() + x = np.linspace(xmin, xmax, 100) + p = stats.norm.pdf(x, mean, std_dev) + plt.plot(x, p, 'k', linewidth=2, label='Normal Distribution') + title = "Fit results: mean = %.2f, std_dev = %.2f" % (mean, std_dev) + plt.title(title) + plt.xlabel('Counts') + plt.ylabel('Density') + plt.legend() + plt.show() def timing_attack_with(self, starting_node: "Node", starting_window: int): _, senders = self.sim.p2p.adversary.msgs_in_node_per_window[starting_window][starting_node] diff --git a/mixnet/v2/sim/measurement.py b/mixnet/v2/sim/measurement.py index b5cf642..bb462be 100644 --- a/mixnet/v2/sim/measurement.py +++ b/mixnet/v2/sim/measurement.py @@ -1,4 +1,4 @@ -from collections import defaultdict +from collections import defaultdict, Counter from typing import TYPE_CHECKING import pandas as pd @@ -15,12 +15,20 @@ class Measurement: def __init__(self, env: simpy.Environment, config: Config): self.env = env self.config = config + self.original_senders = Counter() self.egress_bandwidth_per_time = [] self.ingress_bandwidth_per_time = [] self.message_hops = defaultdict(int) # dict[msg_hash, hops] self.env.process(self._update_bandwidth_window()) + def set_nodes(self, nodes: list["Node"]): + for node in nodes: + self.original_senders[node] = 0 + + def count_original_sender(self, sender: "Node"): + self.original_senders[sender] += 1 + def measure_egress(self, node: "Node", msg: SphinxPacket | bytes): self.egress_bandwidth_per_time[-1][node] += len(msg) diff --git a/mixnet/v2/sim/p2p.py b/mixnet/v2/sim/p2p.py index 79ddddf..d72ee3a 100644 --- a/mixnet/v2/sim/p2p.py +++ b/mixnet/v2/sim/p2p.py @@ -27,6 +27,7 @@ class P2P(ABC): def set_nodes(self, nodes: list["Node"]): self.nodes = nodes + self.measurement.set_nodes(nodes) def get_nodes(self, n: int) -> list["Node"]: return random.sample(self.nodes, n) @@ -40,6 +41,9 @@ class P2P(ABC): yield self.env.timeout(0) def send(self, msg: SphinxPacket | bytes, hops: int, sender: "Node", receiver: "Node", is_first_of_msg: bool): + if hops == 0: + self.measurement.count_original_sender(sender) + if is_first_of_msg: self.adversary.inspect_message_size(msg) self.adversary.observe_sending_node(sender, receiver) @@ -128,9 +132,8 @@ class GossipP2P(P2P): msg_hash = hashlib.sha256(bytes(msg)).digest() if msg_hash not in self.message_cache[receiver]: self.message_cache[receiver][msg_hash] = sender - hops += 1 - self.measurement.update_message_hops(msg_hash, hops) - # Receive and gossip self.env.process(receiver.receive_message(msg)) + hops += 1 + self.measurement.update_message_hops(msg_hash, hops) self.env.process(self.broadcast(receiver, msg, hops))