Covariance attack at the main configuration, stored to data/
The ciphertext-only check trained its own L=16 model and printed only a verdict; it now attacks the main configuration and writes data/cov_attack.csv, which the manuscript cites.
This commit is contained in:
@@ -18,16 +18,18 @@ Procedure, using nothing the threat model keeps secret:
|
||||
6. report the recovered-entry fraction and the eavesdropper SER, both
|
||||
WITHOUT ever using a known index
|
||||
|
||||
Run under WSL. Prints a verdict; writes nothing to data/.
|
||||
Run under WSL. Writes data/cov_attack.csv so the manuscript sentence
|
||||
it supports is traceable to a stored artifact.
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import itertools
|
||||
import math
|
||||
from pathlib import Path
|
||||
import numpy as np
|
||||
import torch
|
||||
|
||||
from sse_lib import rayleigh_gain, DEVICE
|
||||
from exp_full import get_model, hadamard, eval_ser_eve
|
||||
from exp_full import main_model, hadamard, eval_ser_eve
|
||||
|
||||
|
||||
def collect_frames(m, n, snr_db, seed):
|
||||
@@ -94,18 +96,25 @@ def attack(m, snr_db, n_frames, seed):
|
||||
|
||||
|
||||
def main():
|
||||
U, L = 4, 16
|
||||
K0 = torch.tensor(hadamard(L)[1:U + 1], dtype=torch.float32)
|
||||
m = get_model(iters=4000, freeze_W=K0)
|
||||
import csv
|
||||
m = main_model()
|
||||
m.eval()
|
||||
chance = 1.0 - (1.0 / m.vu) ** m.P
|
||||
print(f"chance SER = {chance:.5f}, legitimate reference ~0.276")
|
||||
print(f"chance SER = {chance:.5f} at the main configuration")
|
||||
print("ciphertext-only (NO known plaintext):")
|
||||
rows = []
|
||||
for snr in (10.0, 20.0):
|
||||
for nf in (300, 1000, 10000):
|
||||
frac, ser = attack(m, snr, nf, seed=1234 + nf)
|
||||
rows.append((snr, nf, "%.4f" % frac, "%.4f" % ser))
|
||||
print(f" {snr:4.0f} dB N={nf:6d} "
|
||||
f"key-entry recovery={frac:.3f} eve SER={ser:.4f}")
|
||||
out = Path(__file__).resolve().parents[1] / "data" / "cov_attack.csv"
|
||||
with open(out, "w", newline="") as f:
|
||||
w = csv.writer(f)
|
||||
w.writerow(["snr_db", "n_frames", "entry_recovery", "eve_ser"])
|
||||
w.writerows(rows)
|
||||
print("[csv]", out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@@ -34,10 +34,10 @@ FIG.mkdir(exist_ok=True)
|
||||
plt.rcParams.update({
|
||||
"font.family": "serif",
|
||||
"font.serif": ["DejaVu Serif", "Times New Roman"],
|
||||
# The manuscript includes each result figure at 0.70 of a 3.455 in
|
||||
# column while the canvas is 3.15 in, a printed scale of 0.768. Every
|
||||
# The manuscript includes each result figure at 0.62 of a 3.455 in
|
||||
# column while the canvas is 3.15 in, a printed scale of 0.680. Every
|
||||
# size below is therefore pre-divided by that scale so the PRINTED
|
||||
# sizes are 9 pt labels, 8 pt ticks and a 6.6 pt legend. Change the
|
||||
# sizes are 8 pt labels, 7 pt ticks and a 5.5 pt legend. Change the
|
||||
# include width and these must change with it.
|
||||
"font.size": 10.4,
|
||||
"axes.labelsize": 10.4,
|
||||
@@ -50,7 +50,7 @@ plt.rcParams.update({
|
||||
"grid.alpha": 0.6,
|
||||
"lines.linewidth": 1.5,
|
||||
"lines.markersize": 5.2,
|
||||
"figure.figsize": (3.15, 2.36),
|
||||
"figure.figsize": (3.15, 2.25), # shorter canvas: same printed width and font size, less page height
|
||||
"pdf.fonttype": 42,
|
||||
})
|
||||
AXES_RECT = dict(left=0.205, right=0.970, top=0.955, bottom=0.215)
|
||||
@@ -283,7 +283,7 @@ def fig_snr():
|
||||
ax.set_xlim(min(x), max(x))
|
||||
# most of a decade below the data leaves the lower-left genuinely
|
||||
# empty, which is what gives the four-entry legend a clear berth
|
||||
ax.set_ylim(bottom=8e-4)
|
||||
ax.set_ylim(bottom=2e-4)
|
||||
place_legend(ax)
|
||||
save(fig, "fig_sec_snr")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user