Give the orthogonal-access jammer its own Rayleigh channel in oma_ser_jammed, matching the convention every simulated scheme already used. Without it the closed-form curve faced a jammer at full power in every frame while the Monte Carlo curves faced a fading one, which inverted the ordering of the comparison. Measure the outsider error rate for the fixed-key and naive-refresh cases as well, and emit the two refresh tables from make_tables.py, so no cell of the paper is hand-typed.
103 lines
3.6 KiB
Python
103 lines
3.6 KiB
Python
"""Generate the LaTeX rows of the three result tables from the CSVs, so
|
|
that every table in the paper is reproducible from data/ (TIFS mandate).
|
|
Prints the tabular bodies; paste into main.tex without edits.
|
|
"""
|
|
from __future__ import annotations
|
|
import csv
|
|
import json
|
|
import math
|
|
from pathlib import Path
|
|
|
|
DATA = Path(__file__).resolve().parents[1] / "data"
|
|
|
|
NAME = {
|
|
"proposed": r"\textbf{Proposed keyed masking}",
|
|
"public_mask": "Public masks",
|
|
"perm_key": r"Global-permutation key~\cite{chen2023shuffling}",
|
|
"index_cipher": "Per-user index cipher",
|
|
"oma_plain": "OMA (no encryption)",
|
|
"random": "Random",
|
|
"hadamard": "Walsh-Hadamard",
|
|
"learned": "Learned",
|
|
"learned_reg": r"Regularized~\eqref{eq:regloss}",
|
|
}
|
|
RECEIVER = {
|
|
"legit": "Legitimate", "oma": "OMA",
|
|
"insider": "Insider", "eve": "Outsider",
|
|
}
|
|
|
|
|
|
def f3(x: str) -> str:
|
|
"""Three decimals, or an em-dash for a value that does not apply."""
|
|
try:
|
|
v = float(x)
|
|
except (TypeError, ValueError):
|
|
return "--"
|
|
return "--" if math.isnan(v) else f"{v:.3f}"
|
|
|
|
|
|
def cell(x: str, bold: bool) -> str:
|
|
s = f3(x)
|
|
if s == "--":
|
|
return "--"
|
|
return rf"$\mathbf{{{s}}}$" if bold else f"${s}$"
|
|
|
|
|
|
def compare_table():
|
|
print("% Table: scheme comparison (from sec_compare.csv)")
|
|
rows = list(csv.DictReader(open(DATA / "sec_compare.csv")))
|
|
order = ["public_mask", "perm_key", "index_cipher", "oma_plain", "proposed"]
|
|
rows.sort(key=lambda r: order.index(r["scheme"]))
|
|
for r in rows:
|
|
b = r["scheme"] == "proposed"
|
|
cells = [cell(r[k], b) for k in
|
|
("legit_ser", "eve_out", "eve_in", "jam0_ser")]
|
|
print(f"{NAME[r['scheme']]} & " + " & ".join(cells) + r" \\")
|
|
|
|
|
|
def maskfam_table():
|
|
print("% Table: key families (from sec_maskfam.csv)")
|
|
for r in csv.DictReader(open(DATA / "sec_maskfam.csv")):
|
|
cells = [cell(r[k], False) for k in
|
|
("legit_ser", "eve_ser", "eve_ones_ser", "mask_xcorr")]
|
|
print(f"{NAME[r['family']]} & " + " & ".join(cells) + r" \\")
|
|
|
|
|
|
def real_table():
|
|
print("% Table: headline recovery (from real_sec_stats.json)")
|
|
st = json.loads((DATA / "real_sec_stats.json").read_text())
|
|
rec = st["recovery"]
|
|
snrs = sorted(rec, key=float)
|
|
for key in ("legit", "oma", "insider", "eve"):
|
|
cells = " & ".join(f"${rec[s][key]:.3f}$" for s in snrs)
|
|
print(f"{RECEIVER[key]} & {cells}" + r" \\")
|
|
|
|
|
|
def refresh_tables():
|
|
print("% Table: key refresh (from refresh_summary.csv)")
|
|
for r in csv.DictReader(open(DATA / "refresh_summary.csv")):
|
|
b = r["scheme"] == "Invariant"
|
|
name = r"\textbf{Invariant}" if b else r["scheme"]
|
|
f = (lambda t: r"\mathbf{" + t + "}") if b else (lambda t: t)
|
|
print(f"{name} & ${f(format(float(r['legit']), '.3f'))}$ & "
|
|
f"${f(format(float(r['eve']), '.4f'))}$ & "
|
|
f"${f(format(float(r['entropy_bits']), '.1f'))}$~bits" + r" \\")
|
|
print()
|
|
print("% Table: known plaintext across a refresh (from refresh_kpa.csv)")
|
|
rows = {r["n_frames"]: r for r in csv.DictReader(open(DATA / "refresh_kpa.csv"))}
|
|
keep = ["2", "8", "64"]
|
|
print("Frames used by the attacker & "
|
|
+ " & ".join(f"${k}$" for k in keep) + r" \\")
|
|
for lbl, key in (("Same block", "ser_same_block"),
|
|
("Next block", "ser_next_block")):
|
|
print(f"{lbl} & "
|
|
+ " & ".join(f"${float(rows[k][key]):.3f}$" for k in keep)
|
|
+ r" \\")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
compare_table(); print()
|
|
maskfam_table(); print()
|
|
real_table(); print()
|
|
refresh_tables()
|