From 55f0f675544a7f1018f2069d1b7bf5c06fae401b Mon Sep 17 00:00:00 2001 From: Youngjoon Lee <5462944+youngjoon-lee@users.noreply.github.com> Date: Mon, 27 May 2024 18:20:59 +0900 Subject: [PATCH] improve advesary: io_window_moving_interval --- mixnet/v2/sim/adversary.py | 24 ++++++++++++++++++------ mixnet/v2/sim/analysis.py | 28 ++++++++++++++-------------- mixnet/v2/sim/config.py | 10 +++++++--- mixnet/v2/sim/config.yaml | 7 +++++-- 4 files changed, 44 insertions(+), 25 deletions(-) diff --git a/mixnet/v2/sim/adversary.py b/mixnet/v2/sim/adversary.py index f8bd74f..f4f5c68 100644 --- a/mixnet/v2/sim/adversary.py +++ b/mixnet/v2/sim/adversary.py @@ -1,7 +1,7 @@ from __future__ import annotations import math -from collections import defaultdict +from collections import defaultdict, deque from enum import Enum from typing import TYPE_CHECKING @@ -21,7 +21,8 @@ class Adversary: self.config = config self.message_sizes = [] self.senders_around_interval = defaultdict(int) - self.mixed_msgs_per_window = [] + self.msgs_in_node_per_window = [] # [] + self.cur_window_per_node = defaultdict(lambda: deque()) # : int is + or -. # self.node_states = defaultdict(dict) self.env.process(self.update_observation_window()) @@ -30,12 +31,12 @@ class Adversary: self.message_sizes.append(len(msg)) def observe_receiving_node(self, node: "Node"): - self.mixed_msgs_per_window[-1][node] += 1 + self.cur_window_per_node[node].append((self.env.now, 1)) # if node not in self.node_states[self.env.now]: # self.node_states[self.env.now][node] = NodeState.RECEIVING def observe_sending_node(self, node: "Node"): - self.mixed_msgs_per_window[-1][node] -= 1 + self.cur_window_per_node[node].append((self.env.now, -1)) if self.is_around_message_interval(self.env.now): self.senders_around_interval[node] += 1 # self.node_states[self.env.now][node] = NodeState.SENDING @@ -46,8 +47,19 @@ class Adversary: def update_observation_window(self): while True: - self.mixed_msgs_per_window.append(defaultdict(int)) - yield self.env.timeout(self.config.adversary.io_observation_window) + yield self.env.timeout(self.config.adversary.io_window_moving_interval) + + self.msgs_in_node_per_window.append(defaultdict(int)) # + for node, queue in self.cur_window_per_node.items(): + msg_cnt = 0.0 + # Pop old events that are out of the new window, and accumulate msg_cnt + while queue and queue[0][0] < self.env.now - self.config.adversary.io_window_size: + _, delta = queue.popleft() + msg_cnt += delta + # Iterate remaining events that will remain in the new window, and accumulate msg_cnt + for _, delta in queue: + msg_cnt += delta + self.msgs_in_node_per_window[-1][node] = msg_cnt class NodeState(Enum): diff --git a/mixnet/v2/sim/analysis.py b/mixnet/v2/sim/analysis.py index 91a4226..860fef1 100644 --- a/mixnet/v2/sim/analysis.py +++ b/mixnet/v2/sim/analysis.py @@ -16,8 +16,7 @@ class Analysis: message_size_df = self.message_size_distribution() self.bandwidth(message_size_df) self.messages_emitted_around_interval() - if self.config.mixnet.is_mixing_on(): - self.mixed_messages_per_node_over_time() + self.messages_in_node_over_time() # self.node_states() def bandwidth(self, message_size_df: pd.DataFrame): @@ -88,24 +87,25 @@ class Analysis: plt.legend(title="expected") plt.show() - def mixed_messages_per_node_over_time(self): + def messages_in_node_over_time(self): dataframes = [] - for mixed_msgs_per_node in self.sim.p2p.adversary.mixed_msgs_per_window: - df = pd.DataFrame([(node.id, cnt) for node, cnt in mixed_msgs_per_node.items()], - columns=["node_id", "msg_count"]) - dataframes.append(df) - observation_times = range(len(dataframes)) - df = pd.concat([df.assign(Time=time) for df, time in zip(dataframes, observation_times)], ignore_index=True) - df = df.pivot(index="Time", columns="node_id", values="msg_count") + for i, msgs_in_node in enumerate(self.sim.p2p.adversary.msgs_in_node_per_window): + time = i * self.config.adversary.io_window_moving_interval + df = pd.DataFrame([(time, node.id, cnt) for node, cnt in msgs_in_node.items()], + columns=["time", "node_id", "msg_count"]) + if not df.empty: + dataframes.append(df) + df = pd.concat(dataframes, ignore_index=True) + df_pivot = df.pivot(index="time", columns="node_id", values="msg_count") plt.figure(figsize=(12, 6)) - for column in df.columns: - plt.plot(df.index, df[column], marker="o", label=column) - plt.title("Mixed messages in each mix over time") + for column in df_pivot.columns: + plt.plot(df_pivot.index, df_pivot[column], marker=None, label=column) + plt.title("Messages in each node over time") plt.xlabel("Time") plt.ylabel("Msg Count") plt.ylim(bottom=0) - plt.legend(title="Node ID") plt.grid(True) + plt.tight_layout() plt.show() def node_states(self): diff --git a/mixnet/v2/sim/config.py b/mixnet/v2/sim/config.py index b3ea439..d3672f1 100644 --- a/mixnet/v2/sim/config.py +++ b/mixnet/v2/sim/config.py @@ -131,8 +131,12 @@ class MeasurementConfig: @dataclass class AdversaryConfig: - # A discrete time window for the adversary to observe inputs and outputs of a certain node - io_observation_window: int + # A time window for the adversary to observe inputs and outputs of each node + io_window_size: float + # A moving interval of the time window for the adversary to observe inputs and outputs of each node + # This must be smaller or equal to io_window_size. + io_window_moving_interval: float def validate(self): - assert self.io_observation_window >= 1 + assert self.io_window_size > 0 + assert 0 < self.io_window_moving_interval <= self.io_window_size diff --git a/mixnet/v2/sim/config.yaml b/mixnet/v2/sim/config.yaml index 3f37821..27126c3 100644 --- a/mixnet/v2/sim/config.yaml +++ b/mixnet/v2/sim/config.yaml @@ -38,5 +38,8 @@ measurement: sim_time_per_second: 1 adversary: - # A discrete time window for the adversary to observe inputs and outputs of a certain node - io_observation_window: 1 \ No newline at end of file + # A time window for the adversary to observe inputs and outputs of each node + io_window_size: 0.20 + # A moving interval of the time window for the adversary to observe inputs and outputs of each node + # This must be smaller or equal to io_window_size. + io_window_moving_interval: 0.10 \ No newline at end of file