Audit round: fair OMA reference, dense grids, covariance-attack checks

Resource-match the OMA reference in the key-length sweep (oma_ser_keylen),
which gives it the L/16 combining gain the longer frame allows. The
proposal now passes a resource-matched OMA by 1.27x at L=64 rather than
the 4.3x reported against a fixed-d reference.

Densify the JSR, sensitivity, and brute-force grids so the curves are
smooth, give the index cipher its channel floor instead of error-free
reception, and add the permutation-key known-plaintext attack
(exp_permkpa) so Fig. 7 carries a conventional linear scheme.

Add check_cov_attack.py and check_cov_ceiling.py: a referee raised a
ciphertext-only second-order attack; the exact-population test shows the
received covariance leaks only a sparse rank-deficient subset of the key
Gram and leaves the eavesdropper at the random-guess level.

Dump verify_math.csv, move the superseded V=256 pilot CSVs to data/pilot.
This commit is contained in:
KiHoLee
2026-08-16 23:48:39 +09:00
parent fbbad154b2
commit 3529ab1918
28 changed files with 755 additions and 123 deletions
+5 -3
View File
@@ -28,8 +28,10 @@ code/
schemes, key families, scheme comparison, attack difficulty
exp_kpa.py stage H: known-plaintext attack on the key
exp_refresh.py stage K: the key-refresh layer, invariance group
exp_permkpa.py permutation-key known-plaintext attack (Fig. 7)
check_cov_*.py ciphertext-only covariance-attack checks (referee M1)
exp_real_sec.py stage G: real BERT WordPiece token streams
verify_math.py closed-form checks V1-V5 against Monte Carlo, PASS/FAIL
verify_math.py closed-form checks V1-V5, PASS/FAIL and verify_math.csv
replot_security.py every result figure, from data/ to fig/
make_tables.py LaTeX rows of every result table, from data/
feasibility_security.py early CPU-sized study, kept for the record
@@ -66,10 +68,10 @@ files.
|---|---|---|
| Fig. 2 SER against SNR | `exp_full.stage_A` | `sec_snr.csv` |
| Fig. 3 key length | `exp_full.stage_B` | `sec_keylen.csv` |
| Fig. 4 jamming | `exp_full.stage_L` | `sec_jam_cmp.csv`, `sec_jam.csv` |
| Fig. 4 jamming (4 schemes) | `exp_full.stage_L` | `sec_jam_cmp.csv`, `sec_jam.csv` |
| Fig. 5 key sensitivity | `exp_full.stage_I` | `sec_sens_cmp.csv` |
| Fig. 6 brute-force search | `exp_full.stage_J` | `sec_brute_cmp.csv`, `sec_brute.csv` |
| Fig. 7 known-plaintext attack | `exp_kpa` | `kpa.csv` |
| Fig. 7 known-plaintext attack | `exp_kpa`, `exp_permkpa` | `kpa.csv`, `pkpa.csv` |
| Fig. 8 real token streams | `exp_real_sec` | `real_sec_ter.csv` |
| Scheme comparison table | `exp_full.stage_E` | `sec_compare.csv` |
| Key family table | `exp_full.stage_D` | `sec_maskfam.csv`, `sec_regjam.csv` |
+112
View File
@@ -0,0 +1,112 @@
"""Independent check of the ciphertext-only second-order attack (audit M1).
Claim under test: an eavesdropper who observes only received frames (no
known indices) can estimate the key Gram matrix M^T M from the sample
covariance, because per period
E[y_k y_l] = (1/c^2) * E[h^2] * C_kl * (M^T M)_kl,
where C_kl = (1/Vu) sum_i b_{i,k} b_{i,l} is the PUBLIC codebook column
correlation and the noise touches only the diagonal.
Procedure, using nothing the threat model keeps secret:
1. collect N received frames y_n = h_n * (1/c) sum_u e_{s_u} ⊙ m_u + noise
2. form the per-period sample second moment S_kl = mean_n y_{n,k} y_{n,l}
3. divide the off-diagonal by C_kl (public) to get G_hat ≈ M^T M
4. set the diagonal of G_hat to U (unit-modulus keys)
5. factor G_hat = M_hat^T M_hat (rank U), then for Walsh-Hadamard keys
round to ±1 and search the 2^U U! signed permutations, keeping the
M_hat that best decodes a handful of the collected frames
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/.
"""
from __future__ import annotations
import itertools
import math
import numpy as np
import torch
from sse_lib import rayleigh_gain, DEVICE
from exp_full import get_model, hadamard, eval_ser_eve
def collect_frames(m, n, snr_db, seed):
"""Received frames and the true indices (indices kept only for scoring)."""
g = torch.Generator().manual_seed(seed)
Bn = m.unit_codebook()
true_m = m.masks()
c = m.c
sigma = math.sqrt(1.0 / (m.d * 10.0 ** (snr_db / 10.0)))
digits = torch.randint(m.vu, (n, m.users, m.P), generator=g).to(DEVICE)
e = Bn[digits] / math.sqrt(m.P) # (n,U,P,L)
y = (e * true_m[None, :, None, :]).sum(dim=1) / c # (n,P,L)
h = rayleigh_gain((n,), device=DEVICE)
y = h[:, None, None] * y + sigma * torch.randn(n, m.P, m.L, device=DEVICE)
return y, digits, Bn, true_m
def codebook_corr(Bn):
"""Public column correlation C_kl = (1/Vu) sum_i b_ik b_il."""
return (Bn.T @ Bn) / Bn.shape[0] # (L,L)
def attack(m, snr_db, n_frames, seed):
y, digits, Bn, true_m = collect_frames(m, n_frames, snr_db, seed)
U, L = m.users, m.L
yf = y.reshape(-1, L) # pool all periods
S = (yf.T @ yf) / yf.shape[0] # (L,L) 2nd moment
C = codebook_corr(Bn) # public
G = torch.zeros(L, L, device=DEVICE)
mask = C.abs() > 1e-3
G[mask] = S[mask] / C[mask] # ≈ (1/c^2) M^T M
scale = float(torch.diagonal(G)[mask.diagonal()].mean()) / U
G = G / max(scale, 1e-9) # normalize so diag≈U
G.fill_diagonal_(float(U)) # unit-modulus keys
# symmetric rank-U factor
G = 0.5 * (G + G.T)
evals, evecs = torch.linalg.eigh(G)
idx = torch.argsort(evals, descending=True)[:U]
root = evecs[:, idx] * evals[idx].clamp_min(0).sqrt()
Mhat0 = root.T # (U,L), up to U×U orth
# for WH keys, snap to ±1 and search signed row permutations
cand = torch.sign(Mhat0)
cand[cand == 0] = 1.0
best = None
best_ser = 1.0
val = torch.arange(min(2000, n_frames))
for perm in itertools.permutations(range(U)):
for signs in itertools.product([1.0, -1.0], repeat=U):
Mh = (cand[list(perm)] *
torch.tensor(signs, device=DEVICE)[:, None])
ser = eval_ser_eve(m, Mh.cpu(), [snr_db], frames=20_000,
seed=13)[0]
if ser < best_ser:
best_ser, best = ser, Mh
# recovered-entry fraction against the true keys (best sign-aligned)
tm = torch.sign(true_m).to(DEVICE)
frac = 0.0
for perm in itertools.permutations(range(U)):
for signs in itertools.product([1.0, -1.0], repeat=U):
Mh = (best[list(perm)] *
torch.tensor(signs, device=DEVICE)[:, None])
frac = max(frac, float((Mh == tm).float().mean()))
return frac, best_ser
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)
m.eval()
chance = 1.0 - (1.0 / m.vu) ** m.P
print(f"chance SER = {chance:.5f}, legitimate reference ~0.276")
print("ciphertext-only (NO known plaintext):")
for snr in (10.0, 20.0):
for nf in (300, 1000, 10000):
frac, ser = attack(m, snr, nf, seed=1234 + nf)
print(f" {snr:4.0f} dB N={nf:6d} "
f"key-entry recovery={frac:.3f} eve SER={ser:.4f}")
if __name__ == "__main__":
main()
+82
View File
@@ -0,0 +1,82 @@
"""Decisive noiseless population test of the covariance attack (audit M1).
If the second-order statistics leak the key Gram, they leak it best in
the noiseless infinite-sample limit. This computes the EXACT per-period
second moment E[y_k y_l] over the uniform index distribution with no
channel and no noise, then runs the same recovery, and asks whether the
keys come out. If they do not come out even here, no finite noisy attack
can do better and the leak is not exploitable against this codebook.
"""
from __future__ import annotations
import itertools
import math
import numpy as np
import torch
from sse_lib import DEVICE
from exp_full import get_model, hadamard, eval_ser_eve
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)
m.eval()
Bn = m.unit_codebook().to(DEVICE) # (Vu,L)
true_m = m.masks().to(DEVICE) # (U,L)
c = m.c
# exact population second moment of one period, indices uniform
# y_k = (1/c) sum_u e_{s_u,k} m_{u,k}, s_u iid uniform over Vu
mu = Bn.mean(0) # codebook column mean
R = (Bn.T @ Bn) / Bn.shape[0] # E[e_k e_l], (L,L)
G_true = true_m.T @ true_m # (L,L) key Gram, the target
# E[y_k y_l] = (1/c^2)[ R_kl (M^TM)_kl + (mu_k mu_l)(rowsum_k rowsum_l
# - diag correction) ]; assemble exactly
rs = true_m.sum(0) # sum_u m_{u,k}
cross = torch.outer(rs, rs) - G_true # sum_{u!=v} m_uk m_vl
S = (R * G_true + torch.outer(mu, mu) * cross) / (c * c)
print(f"codebook column mean |mu|_max = {mu.abs().max():.4f}")
offdiag = R - torch.diag(torch.diagonal(R))
print(f"codebook R off-diagonal: max|R_kl| = {offdiag.abs().max():.4f}, "
f"mean|R_kl| = {offdiag.abs().mean():.4f}")
# recover G from S using the public R (exactly the attack)
C = R
keep = C.abs() > 1e-2
Ghat = torch.zeros(L, L, device=DEVICE)
Ghat[keep] = S[keep] * (c * c) / C[keep]
# how well does the off-diagonal of Ghat match the true key Gram?
od = ~torch.eye(L, dtype=torch.bool, device=DEVICE)
usable = keep & od
if usable.any():
err = (Ghat[usable] - G_true[usable]).abs().mean()
rng = G_true[od].abs().mean()
print(f"usable off-diagonal entries: {int(usable.sum())} of {L*(L-1)}")
print(f"recovered-Gram error on usable entries: {err:.4f} "
f"(true off-diag scale {rng:.4f})")
else:
print("no usable off-diagonal entries: R is diagonal, zero leak")
# try to factor and decode from the exact-population Ghat
Ghat[~keep] = 0.0
Ghat.fill_diagonal_(float(U))
Ghat = 0.5 * (Ghat + Ghat.T)
ev, evec = torch.linalg.eigh(Ghat)
idx = torch.argsort(ev, descending=True)[:U]
root = (evec[:, idx] * ev[idx].clamp_min(0).sqrt()).T
cand = torch.sign(root)
cand[cand == 0] = 1.0
best = 1.0
for perm in itertools.permutations(range(U)):
for sg in itertools.product([1.0, -1.0], repeat=U):
Mh = cand[list(perm)] * torch.tensor(sg, device=DEVICE)[:, None]
best = min(best, eval_ser_eve(m, Mh.cpu(), [10.0],
frames=20_000, seed=13)[0])
print(f"best eavesdropper SER from EXACT population covariance: {best:.4f}")
print("chance 0.99998, legitimate ~0.276")
if __name__ == "__main__":
main()
+77 -13
View File
@@ -152,7 +152,7 @@ def get_model(P=4, vu=16, d=64, U=4, iters=4000, seed=1, freeze_W=None, tag=""):
def stage_A():
print("[A] security vs SNR (V=65536) ...")
m = get_model(iters=4000)
snr = [0.0, 4.0, 8.0, 12.0, 16.0, 20.0]
snr = [float(v) for v in range(0, 21, 2)]
frames = 800_000
legit = eval_ser_sse(m, snr, frames=frames)
ew = eve_wrong_mask(m.users, m.L, seed=20260813).to(DEVICE)
@@ -209,18 +209,46 @@ def get_model_reg(P=4, vu=16, d=64, U=4, iters=4000, seed=1):
return m
def oma_ser_keylen(L, snr_db, bits=16, n_grid=200_000):
"""Resource-matched OMA reference for the key-length sweep.
The OMA user owns d/U = L exclusive real dimensions for its 16 index
bits at the same per-dimension SNR. For L >= 16 the best use of the
allocation is antipodal signaling on 16 dimensions with the frame
energy concentrated on them, an energy gain of L/16 per bit. For
L < 16 the user must pack 16/L bits per dimension, a 2^(16/L)-ary
pulse-amplitude constellation, defined when 16/L is an integer and
reported as nan otherwise.
"""
import numpy as np
if L >= bits:
return oma_ser([snr_db + 10.0 * math.log10(L / bits)], bits=bits)[0]
if bits % L:
return float("nan")
M = 2 ** (bits // L)
x = (np.arange(n_grid) + 0.5) / n_grid
h = np.sqrt(-np.log(1.0 - x))
g = 10.0 ** (snr_db / 10.0)
arg = np.clip(h * math.sqrt(6.0 * g / (M * M - 1.0)), 0, 38)
q = (1.0 - 1.0 / M) * np.array([math.erfc(v / math.sqrt(2.0))
for v in arg])
q = np.clip(q, 0.0, 1.0)
return float(np.mean(1.0 - (1.0 - q) ** L))
def stage_B():
print("[B] key length (dense grid so the curve is smooth) ...")
oma10 = oma_ser([10.0], bits=16)[0]
rows = []
for d in [16, 24, 32, 48, 64, 96, 128, 192, 256]:
for d in [16, 24, 32, 40, 48, 56, 64, 80, 96, 128, 192, 256]:
m = get_model(d=d, iters=4000)
lg = eval_ser_sse(m, [10.0], frames=500_000)[0]
ew = eve_wrong_mask(m.users, m.L, seed=20260813).to(DEVICE)
ev = eval_ser_eve(m, ew, [10.0], frames=500_000)[0]
xc = mean_abs_xcorr(m.masks().detach())
rows.append((m.L, d, lg, ev, xc, oma10))
print(f" L={m.L:4d} legit={lg:.2e} eve={ev:.3f} xcorr={xc:.4f}")
oma = oma_ser_keylen(m.L, 10.0)
rows.append((m.L, d, lg, ev, xc, oma))
print(f" L={m.L:4d} legit={lg:.2e} eve={ev:.3f} xcorr={xc:.4f} "
f"oma={oma:.4f}")
write_csv(DATA / "sec_keylen.csv",
["L", "d", "legit_ser", "eve_ser", "mask_xcorr", "oma"], rows)
@@ -548,8 +576,10 @@ def stage_I():
between the guessed and the true mask. For the permutation scheme it
is the fraction of positions the guessed permutation places
correctly. For the index cipher it is the fraction of pad bits the
attacker knows, whose error rate is the closed form
1 - 2^{-(1-f) log2 V} because the unknown bits are uniform.
attacker knows. Its error rate is the closed form
1 - (1-p_ch) 2^{-(1-f) log2 V}, the probability of decoding the
ciphered index over the channel times the probability that the
unknown pad bits, which stay uniform, are all guessed right.
"""
print("[I] key sensitivity across schemes ...")
m = get_model(iters=4000)
@@ -563,8 +593,12 @@ def stage_I():
perms = gperm[None].repeat(m.users, 1)
# a marker grid comparable to the other result figures, with the
# spacing tightened only where the curves fall
fracs = [0.0, 0.2, 0.4, 0.6, 0.75, 0.85, 0.9, 0.94, 0.97, 1.0]
fracs = [0.0, 0.2, 0.4, 0.6, 0.75, 0.85, 0.9, 0.92, 0.94, 0.955,
0.97, 0.985, 1.0]
bits = math.log2(m.V)
# the channel success of a public-mask receiver, which the cipher
# cannot exceed even with the full pad
lg1 = eval_scheme(m, 10.0, 200_000)
rows = []
for f in fracs:
acc_m = []
@@ -585,7 +619,7 @@ def stage_I():
perms, eve_perms=pperms,
seed=777 + 13 * t))
ser_perm = sum(acc) / len(acc)
ser_pad = 1.0 - 2.0 ** (-(1.0 - f) * bits)
ser_pad = 1.0 - (1.0 - lg1) * 2.0 ** (-(1.0 - f) * bits)
rows.append((f, ser_mask, ser_perm, ser_pad))
print(f" f={f:.3f} mask={ser_mask:.4f} perm={ser_perm:.4f} "
f"pad={ser_pad:.4f}")
@@ -602,7 +636,8 @@ def stage_J():
one that places the most positions correctly, map the resulting
fraction through the same sensitivity curve.
Index cipher: K random pads out of the 2^{log2 V} possible pads, so
the attacker succeeds with probability K/V on each symbol.
the attacker holds the right pad with probability K/V and still has
to decode the ciphered index over the channel.
"""
print("[J] brute-force search across schemes ...")
import numpy as np
@@ -612,7 +647,11 @@ def stage_J():
perm_arr = np.array([float(r["ser_perm"]) for r in cmp_rows])
d, L, V = 64, 16, 65536
ks = [1, 10, 100, 1_000, 10_000, 100_000, 1_000_000]
# channel floor of the cipher receiver, read from the stage-I curve
# at a fully known pad so both figures share one source
lg1 = 1.0 - (1.0 - float(cmp_rows[-1]["ser_pad"]))
ks = [1, 3, 10, 30, 100, 300, 1_000, 3_000, 10_000, 30_000, 65_536,
100_000, 300_000, 1_000_000]
rng = np.random.default_rng(2026)
trials = 400
rows = []
@@ -629,7 +668,7 @@ def stage_J():
best_frac[t] = rng.binomial(d, 1.0 / d, size=K).max() / d
ser_mask = float(np.mean(np.interp(best_kappa, f_arr, mask_arr)))
ser_perm = float(np.mean(np.interp(best_frac, f_arr, perm_arr)))
ser_pad = 1.0 - min(1.0, K / V)
ser_pad = 1.0 - min(1.0, K / V) * (1.0 - lg1)
rows.append((K, ser_mask, ser_perm, ser_pad,
float(best_kappa.mean()), float(best_frac.mean())))
print(f" K={K:8d} mask={ser_mask:.4f} perm={ser_perm:.4f} "
@@ -692,7 +731,7 @@ def stage_L():
d = m.P * m.L
gp = torch.Generator().manual_seed(11)
perms = torch.randperm(d, generator=gp)[None].repeat(m.users, 1)
jsr = [-10.0, -5.0, 0.0, 5.0, 10.0, 15.0, 20.0]
jsr = [float(v) for v in range(-10, 21, 2)]
oma = oma_ser_jammed(10.0, jsr, bits=int(math.log2(m.V)), U=m.users)
rows = []
for i, j in enumerate(jsr):
@@ -705,6 +744,31 @@ def stage_L():
write_csv(DATA / "sec_jam_cmp.csv",
["jsr_db", "blind", "matched", "perm_blind", "oma_targeted"],
rows)
stage_L_gap(rows)
def stage_L_gap(rows):
"""Store the blind-vs-matched power gap as a raw artifact.
For every error level both curves reach, the gap is the extra JSR the
blind jammer needs to inflict it. Both curves are interpolated on the
dense grid, so the quoted range comes from a stored file rather than
from a hand interpolation.
"""
import numpy as np
j = np.array([r[0] for r in rows])
blind = np.array([r[1] for r in rows])
matched = np.array([r[2] for r in rows])
lo = max(blind.min(), matched.min())
hi = min(blind.max(), matched.max())
ser = np.linspace(lo, hi, 200)
jb = np.interp(ser, blind, j)
jm = np.interp(ser, matched, j)
gap = jb - jm
write_csv(DATA / "sec_jam_gap.csv", ["ser", "gap_db"],
list(zip(ser.tolist(), gap.tolist())))
print(f" gap: {gap.min():.2f} to {gap.max():.2f} dB "
f"over SER {lo:.3f} to {hi:.3f}")
def main():
+99
View File
@@ -0,0 +1,99 @@
"""Known-plaintext attack on the global-permutation key (run under WSL).
The permutation scheme keeps the masks public and protects the frame
with one secret permutation of the d entries shared by all users. Like
the keyed masking, the protection is linear, so an attacker that knows
the indices a few frames carried can recover the secret. This stage
measures how many known frames the recovery needs, mirroring the grid
of exp_kpa.py so the two curves share one figure.
Attack: with N known frames the attacker knows the pre-permutation
signal x_n and observes y_n = h_n * perm(x_n) + noise at the collection
SNR. The cross-correlation matrix C[i, j] = sum_n y_n[i] x_n[j] peaks at
j = perm(i) because h_n > 0, so the permutation is the assignment that
maximizes the total correlation, solved by the Hungarian method. The
recovered permutation then decodes user 1 at 10 dB, the convention of
exp_kpa.py.
Writes data/pkpa.csv. Fixed seeds: permutation 11 (the stage-I secret),
collection 909.
"""
from __future__ import annotations
import math
import numpy as np
import torch
from sse_lib import write_csv, set_seed, DATA, DEVICE
from exp_full import get_model, eval_scheme_permuted_eve, rayleigh_gain
try:
from scipy.optimize import linear_sum_assignment
except ImportError: # greedy fallback
def linear_sum_assignment(cost):
c = cost.copy()
n = c.shape[0]
rows = np.empty(n, dtype=int)
cols = np.empty(n, dtype=int)
for k in range(n):
i, j = np.unravel_index(np.argmin(c), c.shape)
rows[k], cols[k] = i, j
c[i, :] = np.inf
c[:, j] = np.inf
order = np.argsort(rows)
return rows[order], cols[order]
COLLECT_DB = 20.0
DECODE_DB = 10.0
TRIALS = 20
EVAL_FRAMES = 100_000
def main():
m = get_model(iters=4000) # training needs grad
m.eval()
_run(m)
@torch.no_grad()
def _run(m):
d = m.P * m.L
Bn = m.unit_codebook()
true_m = m.masks()
c = m.c
gp = torch.Generator().manual_seed(11)
gperm = torch.randperm(d, generator=gp)
perms = gperm[None].repeat(m.users, 1)
sigma = math.sqrt(1.0 / (d * 10.0 ** (COLLECT_DB / 10.0)))
print(f"[P] permutation known-plaintext, collect {COLLECT_DB:.0f} dB, "
f"decode {DECODE_DB:.0f} dB ...")
rows = []
for nf in [1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 24, 32, 48, 64]:
fr, sr = [], []
for t in range(TRIALS):
g = torch.Generator().manual_seed(909 + 1000 * t + nf)
digits = torch.randint(m.vu, (nf, m.users, m.P), generator=g)
e = Bn[digits.to(DEVICE)] / math.sqrt(m.P)
x = (e * true_m[None, :, None, :]).sum(dim=1) / c # (nf,P,L)
xf = x.reshape(nf, d)
h = rayleigh_gain((nf,), device=DEVICE)
noise = sigma * torch.randn(nf, d, device=DEVICE)
yf = h[:, None] * xf[:, gperm.to(DEVICE)] + noise
C = (yf.T @ xf).cpu().numpy() # (d,d)
_, est = linear_sum_assignment(-C)
est_t = torch.tensor(est, dtype=torch.long)
fr.append(float((est_t == gperm).float().mean()))
sr.append(eval_scheme_permuted_eve(
m, DECODE_DB, EVAL_FRAMES, perms,
eve_perms=est_t[None].repeat(m.users, 1),
seed=777 + 31 * t))
frac = sum(fr) / len(fr)
ser = sum(sr) / len(sr)
rows.append((nf, frac, ser))
print(f" N={nf:3d} frac={frac:.4f} eve={ser:.4f}")
write_csv(DATA / "pkpa.csv", ["n_frames", "perm_frac", "eve_ser"], rows)
print("[done] pkpa.csv")
if __name__ == "__main__":
main()
+3 -3
View File
@@ -166,7 +166,7 @@ def main():
print("[Q1] Eve no-mask SER:", [f"{v:.3g}" for v in eve_n])
print(f"[Q1] chance frame SER = {chance_frame:.4f}")
write_csv(DATA / "feas_q1_eavesdrop.csv",
write_csv(DATA / "pilot" / "feas_q1_eavesdrop.csv",
["snr_db", "legit", "eve_wrong", "eve_none", "eve_avg", "chance"],
[(s, legit[i], eve_w[i], eve_n[i], eve_a[i], chance_frame)
for i, s in enumerate(snr_eval)])
@@ -187,7 +187,7 @@ def main():
xc = mean_abs_cross_corr(mdl.masks().detach().cpu())
q2_rows.append((mdl.L, d, lg, ev, xc))
print(f" L={mdl.L:4d} legit={lg:.3g} eve={ev:.3g} |xcorr|={xc:.3f}")
write_csv(DATA / "feas_q2_keyentropy.csv",
write_csv(DATA / "pilot" / "feas_q2_keyentropy.csv",
["L", "d", "legit_ser", "eve_ser", "mask_xcorr"], q2_rows)
# Q3: jamming robustness at SNR=10 dB
@@ -197,7 +197,7 @@ def main():
jam_rd = eval_ser_jam(model, 10.0, jsr, frames=300_000, mode="random")
print("[Q3] aligned-jammer SER:", [f"{v:.3g}" for v in jam_al])
print("[Q3] random-jammer SER:", [f"{v:.3g}" for v in jam_rd])
write_csv(DATA / "feas_q3_jamming.csv",
write_csv(DATA / "pilot" / "feas_q3_jamming.csv",
["jsr_db", "ser_aligned", "ser_random"],
[(j, jam_al[i], jam_rd[i]) for i, j in enumerate(jsr)])
+70 -67
View File
@@ -3,20 +3,22 @@ from ../data/*.csv and writes paper-ready PDFs to ../fig/. No experiment
is rerun. All result plots share one canvas and axes rectangle (8:6 box).
Label dictionary is fixed here and copied verbatim into tables and prose.
fig_sec_snr.pdf : legitimate and outsider SER vs SNR (Fig. 2)
fig_sec_snr.pdf : legitimate and eavesdropper SER vs SNR (Fig. 2)
fig_sec_keylen.pdf : SER vs key length L (Fig. 3)
fig_sec_jam.pdf : target-user SER vs JSR, four schemes (Fig. 4)
fig_sec_sens.pdf : outsider SER vs fraction of key held (Fig. 5)
fig_sec_brute.pdf : outsider SER vs number of key guesses (Fig. 6)
fig_sec_kpa.pdf : outsider SER vs known-plaintext frames (Fig. 7)
fig_sec_sens.pdf : eavesdropper SER vs fraction of key held (Fig. 5)
fig_sec_brute.pdf : eavesdropper SER vs number of key guesses (Fig. 6)
fig_sec_kpa.pdf : eavesdropper SER vs known-plaintext frames (Fig. 7)
fig_sec_real.pdf : token error rate on real streams (Fig. 8)
fig_sec_brute_rho.pdf is also emitted as a diagnostic and is not used in
the paper.
Curves that coincide by construction are drawn deliberately layered, the
lower one wide and semi-transparent and the upper one narrow with open
markers, so every legend entry has a visible curve.
"""
from __future__ import annotations
from pathlib import Path
import csv
import math
import matplotlib
matplotlib.use("Agg")
@@ -32,7 +34,7 @@ plt.rcParams.update({
"font.serif": ["DejaVu Serif", "Times New Roman"],
"font.size": 9,
"axes.labelsize": 9,
"legend.fontsize": 6.6,
"legend.fontsize": 7.4,
"xtick.labelsize": 8,
"ytick.labelsize": 8,
"axes.grid": True,
@@ -57,13 +59,20 @@ C_PUB = "#16a085"
LBL = {
"legit": "Legitimate",
"oma": "OMA",
"eve_pub": "Eve, public masks",
"eve_key": "Eve, wrong key",
"eve_pub": "Eavesdropper, public masks",
"eve_key": "Eavesdropper, wrong key",
"chance": "Random guess",
"jam_m": "Matched jammer (public masks)",
"jam_b": "Blind jammer (proposed)",
"nojam": "No jammer",
"mask": "Keyed masking",
"perm": "Permutation key",
"pad": "Index cipher",
"insider": "Insider",
"outsider": "Outsider",
}
# deliberate-layering style for the LOWER of two coinciding curves
UNDER = dict(lw=2.6, ms=7, alpha=0.85)
# and for the curve riding on top of it
OVER = dict(lw=1.2, ms=4.5, mfc="none")
def load(name):
@@ -106,10 +115,11 @@ def fig_snr():
r = load("sec_snr.csv")
x = col(r, "snr_db")
fig, ax = plt.subplots()
# legitimate and OMA coincide by construction; layered deliberately
ax.semilogy(x, col(r, "legit"), color=C_LEGIT, marker="o", ls="-",
label=LBL["legit"])
label=LBL["legit"], **UNDER)
ax.semilogy(x, col(r, "oma"), color=C_OMA, marker="^", ls=":",
label=LBL["oma"])
label=LBL["oma"], **OVER)
ax.semilogy(x, col(r, "eve_public"), color=C_PUB, marker="v",
ls="none", markersize=5.2, markerfacecolor="none",
label=LBL["eve_pub"])
@@ -125,13 +135,17 @@ def fig_snr():
def fig_keylen():
"""The OMA reference is the resource-matched one of oma_ser_keylen,
which is undefined at key lengths where 16/L is not an integer; those
rows carry nan and are skipped."""
r = load("sec_keylen.csv")
x = col(r, "L", int)
fig, ax = plt.subplots()
ax.semilogy(x, col(r, "legit_ser"), color=C_LEGIT, marker="o", ls="-",
label=LBL["legit"])
ax.semilogy(x, col(r, "oma"), color=C_OMA, marker="^", ls=":",
label=LBL["oma"])
op = [(l, v) for l, v in zip(x, col(r, "oma")) if not math.isnan(v)]
ax.semilogy([p[0] for p in op], [p[1] for p in op], color=C_OMA,
marker="^", ls=":", label=LBL["oma"])
ax.semilogy(x, col(r, "eve_ser"), color=C_EVE, marker="s", ls="--",
label=LBL["eve_key"])
ax.set_xlabel("Key length $L$")
@@ -144,47 +158,47 @@ def fig_keylen():
def fig_jam():
"""Target-user SER against JSR for four schemes. A linear axis is
used because the range spans less than one decade, where a log axis
would print wide minor tick labels that crowd out the y label."""
would print wide minor tick labels that crowd out the y label. The
no-jammer reference is annotated on the line rather than listed in
the legend, so the legend never covers it."""
r = load("sec_jam_cmp.csv")
x = col(r, "jsr_db")
me = max(1, len(x) // 8)
fig, ax = plt.subplots()
ax.plot(x, col(r, "oma_targeted"), color=C_PUB, marker="^", ls=":",
label="OMA, targeted")
ax.plot(x, col(r, "matched"), color=C_MATCH, marker="P", ls="--",
label="Public masks, matched")
# the two blind curves agree to 0.0015, so the proposed one is drawn
# first and wide and the permutation key rides on top with open
# markers, otherwise one legend entry would have no visible curve
ax.plot(x, col(r, "blind"), color=C_LEGIT, marker="o", ls="-", lw=2.6,
ms=7, alpha=0.85, label="Proposed, blind")
markevery=me, label=LBL["mask"] + ", matched")
ax.plot(x, col(r, "oma_targeted"), color=C_PUB, marker="^", ls=":",
markevery=me, label=LBL["oma"] + ", targeted")
# the two blind curves agree to 0.0015; deliberate layering
ax.plot(x, col(r, "blind"), color=C_LEGIT, marker="o", ls="-",
markevery=me, label=LBL["mask"] + ", blind", **UNDER)
ax.plot(x, col(r, "perm_blind"), color=C_EVE, marker="s", ls="-.",
lw=1.2, ms=4.5, mfc="none", label="Permutation key, blind")
markevery=me, label=LBL["perm"] + ", blind", **OVER)
nojam = float(load("sec_jam.csv")[0]["nojam"])
ax.axhline(nojam, color=C_OMA, ls=(0, (1, 3)), lw=0.9,
label=LBL["nojam"])
ax.axhline(nojam, color=C_OMA, ls=(0, (1, 3)), lw=0.9)
ax.text(max(x) - 0.6, nojam + 0.02, LBL["nojam"], ha="right",
va="bottom", fontsize=7.4, color="#555555")
ax.set_xlabel("JSR (dB)")
ax.set_ylabel("SER")
ax.set_xlim(min(x), max(x))
ax.set_ylim(0.2, 1.02)
ax.legend(loc="lower right")
ax.legend(loc="center right", bbox_to_anchor=(0.985, 0.47))
save(fig, "fig_sec_jam")
def fig_sens():
"""Key sensitivity of three schemes on one axis, the fraction of the
key the attacker holds. For keyed masking that fraction is the mask
correlation, for the permutation scheme the fraction of positions
placed correctly, for the index cipher the fraction of pad bits
known."""
key the attacker holds. All three ride the random-guess level over
most of the range, so the flat region is deliberately layered."""
r = load("sec_sens_cmp.csv")
x = col(r, "frac")
fig, ax = plt.subplots()
ax.plot(x, col(r, "ser_mask"), color=C_LEGIT, marker="o", ls="-",
label="Keyed masking")
label=LBL["mask"], **UNDER)
ax.plot(x, col(r, "ser_perm"), color=C_EVE, marker="s", ls="--",
label="Permutation key")
label=LBL["perm"], **OVER)
ax.plot(x, col(r, "ser_pad"), color=C_PUB, marker="v", ls="-.",
label="Index cipher")
lw=1.2, ms=4.5, mfc="none", label=LBL["pad"])
chance = 1.0 - (1.0 / 16.0) ** 4
ax.axhline(chance, color=C_CH, ls=":", lw=0.9, label=LBL["chance"])
ax.set_xlabel("Fraction of the key recovered")
@@ -200,54 +214,35 @@ def fig_brute():
r = load("sec_brute_cmp.csv")
x = col(r, "K")
fig, ax = plt.subplots()
ax.semilogx(x, col(r, "ser_mask"), color=C_LEGIT, marker="o", ls="-",
label="Keyed masking")
ax.semilogx(x, col(r, "ser_perm"), color=C_EVE, marker="s", ls="--",
label="Permutation key")
label=LBL["perm"], **UNDER)
ax.semilogx(x, col(r, "ser_pad"), color=C_PUB, marker="v", ls="-.",
label="Index cipher")
label=LBL["pad"], **OVER)
ax.semilogx(x, col(r, "ser_mask"), color=C_LEGIT, marker="o", ls="-",
label=LBL["mask"])
kl = load("sec_keylen.csv")
legit = float([q for q in kl if int(q["L"]) == 16][0]["legit_ser"])
ax.axhline(legit, color=C_OMA, ls=":", lw=0.9, label=LBL["legit"])
ax.set_xlabel("Number of key guesses $K$")
ax.set_ylabel("Eavesdropper SER")
ax.set_ylim(-0.03, 1.05)
ax.legend(loc="center left")
ax.set_ylim(0.2, 1.05)
ax.legend(loc="lower left")
save(fig, "fig_sec_brute")
def fig_brute_rho():
"""Best key correlation a search of size K reaches, per key length.
This is a property of the key space alone."""
r = load("sec_brute.csv")
fig, ax = plt.subplots()
sty = {8: ("#c0392b", "o"), 16: ("#2c5fa8", "s"),
32: ("#16a085", "v"), 64: ("#8e44ad", "P")}
for Lp, (c, mk) in sty.items():
rows = [row for row in r if int(row["L"]) == Lp]
ax.semilogx([float(x["K"]) for x in rows],
[float(x["best_rho"]) for x in rows],
color=c, marker=mk, ls="-", label=f"$L={Lp}$")
ax.axhline(0.96, color=C_CH, ls="-.", lw=0.9, label="Break threshold")
ax.set_xlabel("Number of key guesses $K$")
ax.set_ylabel(r"Best key correlation $\kappa$")
ax.set_ylim(0, 1.05)
ax.legend(loc="upper left")
save(fig, "fig_sec_brute_rho")
def fig_real():
r = load("real_sec_ter.csv")
x = col(r, "snr_db")
fig, ax = plt.subplots()
# legitimate/OMA and insider/outsider coincide pairwise; layered
ax.semilogy(x, col(r, "ter_legit"), color=C_LEGIT, marker="o", ls="-",
label=LBL["legit"])
label=LBL["legit"], **UNDER)
ax.semilogy(x, col(r, "ter_oma"), color=C_OMA, marker="^", ls=":",
label=LBL["oma"])
label=LBL["oma"], **OVER)
ax.semilogy(x, col(r, "ter_insider"), color=C_PUB, marker="v", ls="-.",
label="Insider")
lw=2.6, alpha=0.85, ms=7, label=LBL["insider"])
ax.semilogy(x, col(r, "ter_eve"), color=C_EVE, marker="s", ls="--",
label=LBL["eve_key"])
label=LBL["outsider"], **OVER)
ax.set_xlabel("SNR (dB)")
ax.set_ylabel("TER")
ax.set_xlim(min(x), max(x))
@@ -256,6 +251,9 @@ def fig_real():
def fig_kpa():
"""Known-plaintext recovery of the keyed masks at three collection
SNRs, with the permutation key under the same attack as the linear
comparison scheme."""
r = load("kpa.csv")
fig, ax = plt.subplots()
sty = {0.0: ("#c0392b", "o"), 10.0: ("#2c5fa8", "s"),
@@ -265,7 +263,13 @@ def fig_kpa():
n = [float(row["n_frames"]) for row in rows]
ser = [float(row["eve_ser"]) for row in rows]
ax.semilogx(n, ser, color=c, marker=mk, ls="-",
label=f"{int(snr)} dB")
label=LBL["mask"] + f", {int(snr)} dB")
try:
p = load("pkpa.csv")
ax.semilogx(col(p, "n_frames"), col(p, "eve_ser"), color=C_MATCH,
marker="P", ls="--", label=LBL["perm"] + ", 20 dB")
except FileNotFoundError:
print("[skip] pkpa.csv not present yet")
# legitimate reference measured with the SAME estimator as the
# eavesdropper curves, namely the four-user average of eval_ser_sse
# at L=16, taken from sec_keylen.csv rather than from the user-1
@@ -287,7 +291,6 @@ def main():
try:
fig_sens()
fig_brute()
fig_brute_rho()
except FileNotFoundError:
print("[skip] attack-difficulty CSVs not present yet")
try:
+14
View File
@@ -33,9 +33,13 @@ def masks(U, d, rng):
return M / np.linalg.norm(M, axis=1, keepdims=True) * np.sqrt(d)
ROWS = [] # (tag, claim, emp, err, tol, verdict)
def report(tag, claim, emp, tol, extra=""):
err = abs(claim - emp)
ok = err <= tol
ROWS.append((tag, claim, emp, err, tol, "PASS" if ok else "FAIL"))
print(f"[{'PASS' if ok else 'FAIL'}] {tag}: claim={claim:.5g} "
f"emp={emp:.5g} |err|={err:.2g} tol={tol:g} {extra}")
return ok
@@ -195,6 +199,16 @@ def main():
}
print("\nsummary:", {k: ("PASS" if v else "FAIL") for k, v in results.items()})
print("ALL PASS" if all(results.values()) else "SOME FAILED")
# stored artifact so every quoted verification number has a raw file
import csv as _csv
from pathlib import Path as _Path
data = _Path(__file__).resolve().parents[1] / "data"
with open(data / "verify_math.csv", "w", newline="") as f:
w = _csv.writer(f)
w.writerow(["check", "claim", "empirical", "abs_err", "tol",
"verdict"])
w.writerows(ROWS)
print("[csv]", data / "verify_math.csv")
if __name__ == "__main__":
+3
View File
@@ -0,0 +1,3 @@
Superseded CPU-sized pilot run (V=256) from feasibility_security.py.
Kept for the record; every quoted number in the paper comes from the
full-scale CSVs one level up or from verify_math.csv.
+15
View File
@@ -0,0 +1,15 @@
n_frames,perm_frac,eve_ser
1,0.20234375,0.998977
2,0.7140625,0.7107255
3,0.91484375,0.4172725
4,0.94921875,0.324415
5,0.9515625,0.340107
6,0.94765625,0.3034795
8,0.95625,0.303056
10,0.95546875,0.3027505
12,0.94921875,0.3028
16,0.9546875,0.3036285
24,0.94921875,0.303151
32,0.95234375,0.302631
48,0.95,0.3030415
64,0.9515625,0.3025125
1 n_frames perm_frac eve_ser
2 1 0.20234375 0.998977
3 2 0.7140625 0.7107255
4 3 0.91484375 0.4172725
5 4 0.94921875 0.324415
6 5 0.9515625 0.340107
7 6 0.94765625 0.3034795
8 8 0.95625 0.303056
9 10 0.95546875 0.3027505
10 12 0.94921875 0.3028
11 16 0.9546875 0.3036285
12 24 0.94921875 0.303151
13 32 0.95234375 0.302631
14 48 0.95 0.3030415
15 64 0.9515625 0.3025125
+14 -7
View File
@@ -1,8 +1,15 @@
K,ser_mask,ser_perm,ser_pad,best_kappa,best_frac
1,0.9993678262,0.9999544349,0.9999847412,0.1909643153,0.0160546875
10,0.9948030015,0.9999095052,0.9998474121,0.4626973216,0.041015625
100,0.9825717055,0.9998648567,0.9984741211,0.6342127242,0.0658203125
1000,0.9568330187,0.9998315989,0.9847412109,0.7432459045,0.084296875
10000,0.909109588,0.9997988333,0.8474121094,0.8165387856,0.1025
100000,0.8435049061,0.9997690911,0,0.8680494354,0.1190234375
1000000,0.7503523409,0.9997409661,0,0.905556646,0.1346484375
1,0.9993527855,0.9999542171,0.9999893771,0.1909643153,0.0160546875
3,0.9977393447,0.9999284847,0.9999681312,0.3326517476,0.0281640625
10,0.9952796283,0.9998968587,0.9998937706,0.450762326,0.043046875
30,0.9895360243,0.9998741146,0.9996813118,0.5560672497,0.05375
100,0.9834025595,0.9998495442,0.998937706,0.6290900875,0.0653125
300,0.9728417994,0.9998307015,0.996813118,0.688703621,0.0741796875
1000,0.9568452325,0.9998081233,0.9893770599,0.7427389508,0.0848046875
3000,0.9366731394,0.9997877864,0.9681311798,0.7822538913,0.094375
10000,0.9075372546,0.9997705208,0.8937705994,0.8169040678,0.1025
30000,0.8818766363,0.9997525081,0.6813117981,0.8434367197,0.1109765625
65536,0.8592861449,0.9997413851,0.303815,0.8592030095,0.1162109375
100000,0.8443657504,0.9997355745,0.303815,0.8678447033,0.1189453125
300000,0.802269081,0.9997181429,0.303815,0.8874619916,0.1271484375
1000000,0.7622180175,0.9997021224,0.303815,0.9034448904,0.1346875
1 K ser_mask ser_perm ser_pad best_kappa best_frac
2 1 0.9993678262 0.9993527855 0.9999544349 0.9999542171 0.9999847412 0.9999893771 0.1909643153 0.0160546875
3 10 3 0.9948030015 0.9977393447 0.9999095052 0.9999284847 0.9998474121 0.9999681312 0.4626973216 0.3326517476 0.041015625 0.0281640625
4 100 10 0.9825717055 0.9952796283 0.9998648567 0.9998968587 0.9984741211 0.9998937706 0.6342127242 0.450762326 0.0658203125 0.043046875
5 1000 30 0.9568330187 0.9895360243 0.9998315989 0.9998741146 0.9847412109 0.9996813118 0.7432459045 0.5560672497 0.084296875 0.05375
6 10000 100 0.909109588 0.9834025595 0.9997988333 0.9998495442 0.8474121094 0.998937706 0.8165387856 0.6290900875 0.1025 0.0653125
7 100000 300 0.8435049061 0.9728417994 0.9997690911 0.9998307015 0 0.996813118 0.8680494354 0.688703621 0.1190234375 0.0741796875
8 1000000 1000 0.7503523409 0.9568452325 0.9997409661 0.9998081233 0 0.9893770599 0.905556646 0.7427389508 0.1346484375 0.0848046875
9 3000 0.9366731394 0.9997877864 0.9681311798 0.7822538913 0.094375
10 10000 0.9075372546 0.9997705208 0.8937705994 0.8169040678 0.1025
11 30000 0.8818766363 0.9997525081 0.6813117981 0.8434367197 0.1109765625
12 65536 0.8592861449 0.9997413851 0.303815 0.8592030095 0.1162109375
13 100000 0.8443657504 0.9997355745 0.303815 0.8678447033 0.1189453125
14 300000 0.802269081 0.9997181429 0.303815 0.8874619916 0.1271484375
15 1000000 0.7622180175 0.9997021224 0.303815 0.9034448904 0.1346875
+15 -6
View File
@@ -1,8 +1,17 @@
jsr_db,blind,matched,perm_blind,oma_targeted
-10,0.4691233333,0.7203966667,0.4694833333,0.6401244609
-5,0.6347966667,0.87413,0.6333466667,0.8146859285
0,0.80602,0.95331,0.8066566667,0.9237966241
5,0.9194566667,0.98428,0.9189733333,0.9727474174
10,0.9703833333,0.99481,0.97034,0.9908905586
15,0.9903833333,0.9983633333,0.9900733333,0.9970319887
20,0.9967733333,0.9995166667,0.9968766667,0.9990359654
-8,0.52954,0.7906333333,0.5275833333,0.7152454705
-6,0.5965433333,0.8503566667,0.59758,0.7840240868
-4,0.6703433333,0.8956333333,0.6699733333,0.8424432091
-2,0.7420833333,0.9283666667,0.7431533333,0.8888838836
0,0.8070433333,0.9532066667,0.8059933333,0.9237966241
2,0.8593066667,0.96942,0.85862,0.9488822017
4,0.9014266667,0.9805533333,0.9025733333,0.9662811712
6,0.9327633333,0.9872533333,0.9318466667,0.9780307416
8,0.9549433333,0.9917766667,0.9550866667,0.9858109157
10,0.9699833333,0.99508,0.9707366667,0.9908905586
12,0.98118,0.9966966667,0.9804366667,0.9941743502
14,0.9872866667,0.9979833333,0.9879066667,0.9962827887
16,0.9922966667,0.99871,0.9921133333,0.9976304229
18,0.9948766667,0.9992,0.99484,0.9984893291
20,0.99685,0.9994833333,0.9969366667,0.9990359654
1 jsr_db blind matched perm_blind oma_targeted
2 -10 0.4691233333 0.7203966667 0.4694833333 0.6401244609
3 -5 -8 0.6347966667 0.52954 0.87413 0.7906333333 0.6333466667 0.5275833333 0.8146859285 0.7152454705
4 0 -6 0.80602 0.5965433333 0.95331 0.8503566667 0.8066566667 0.59758 0.9237966241 0.7840240868
5 5 -4 0.9194566667 0.6703433333 0.98428 0.8956333333 0.9189733333 0.6699733333 0.9727474174 0.8424432091
6 10 -2 0.9703833333 0.7420833333 0.99481 0.9283666667 0.97034 0.7431533333 0.9908905586 0.8888838836
7 15 0 0.9903833333 0.8070433333 0.9983633333 0.9532066667 0.9900733333 0.8059933333 0.9970319887 0.9237966241
8 20 2 0.9967733333 0.8593066667 0.9995166667 0.96942 0.9968766667 0.85862 0.9990359654 0.9488822017
9 4 0.9014266667 0.9805533333 0.9025733333 0.9662811712
10 6 0.9327633333 0.9872533333 0.9318466667 0.9780307416
11 8 0.9549433333 0.9917766667 0.9550866667 0.9858109157
12 10 0.9699833333 0.99508 0.9707366667 0.9908905586
13 12 0.98118 0.9966966667 0.9804366667 0.9941743502
14 14 0.9872866667 0.9979833333 0.9879066667 0.9962827887
15 16 0.9922966667 0.99871 0.9921133333 0.9976304229
16 18 0.9948766667 0.9992 0.99484 0.9984893291
17 20 0.99685 0.9994833333 0.9969366667 0.9990359654
+201
View File
@@ -0,0 +1,201 @@
ser,gap_db
0.7203966667,7.395409349
0.7217858794,7.394580398
0.7231750921,7.393751447
0.7245643049,7.392922496
0.7259535176,7.392093545
0.7273427303,7.391264594
0.728731943,7.390435644
0.7301211558,7.389606693
0.7315103685,7.388777742
0.7328995812,7.387948791
0.734288794,7.38711984
0.7356780067,7.386290889
0.7370672194,7.385461939
0.7384564322,7.384632988
0.7398456449,7.383804037
0.7412348576,7.382975086
0.7426240704,7.383719533
0.7440132831,7.386932812
0.7454024958,7.390146092
0.7467917085,7.393359371
0.7481809213,7.39657265
0.749570134,7.39978593
0.7509593467,7.402999209
0.7523485595,7.406212489
0.7537377722,7.409425768
0.7551269849,7.412639048
0.7565161977,7.415852327
0.7579054104,7.419065607
0.7592946231,7.422278886
0.7606838358,7.425492166
0.7620730486,7.428705445
0.7634622613,7.431918725
0.764851474,7.435132004
0.7662406868,7.438345284
0.7676298995,7.441558563
0.7690191122,7.444771843
0.770408325,7.447985122
0.7717975377,7.451198402
0.7731867504,7.454411681
0.7745759631,7.457624961
0.7759651759,7.46083824
0.7773543886,7.46405152
0.7787436013,7.467264799
0.7801328141,7.470478079
0.7815220268,7.473691358
0.7829112395,7.476904638
0.7843004523,7.480117917
0.785689665,7.483331197
0.7870788777,7.486544476
0.7884680905,7.489757756
0.7898573032,7.492971035
0.7912465159,7.493110679
0.7926357286,7.4893604
0.7940249414,7.485610121
0.7954141541,7.481859841
0.7968033668,7.478109562
0.7981925796,7.474359282
0.7995817923,7.470609003
0.800971005,7.466858724
0.8023602178,7.463108444
0.8037494305,7.459358165
0.8051386432,7.455607885
0.8065278559,7.451857606
0.8079170687,7.454642491
0.8093062814,7.461282924
0.8106954941,7.467923358
0.8120847069,7.474563791
0.8134739196,7.481204225
0.8148631323,7.487844658
0.8162523451,7.494485092
0.8176415578,7.501125525
0.8190307705,7.507765959
0.8204199832,7.514406392
0.821809196,7.521046826
0.8231984087,7.527687259
0.8245876214,7.534327693
0.8259768342,7.540968126
0.8273660469,7.54760856
0.8287552596,7.554248993
0.8301444724,7.560889427
0.8315336851,7.567529861
0.8329228978,7.574170294
0.8343121106,7.580810728
0.8357013233,7.587451161
0.837090536,7.594091595
0.8384797487,7.600732028
0.8398689615,7.607372462
0.8412581742,7.614012895
0.8426473869,7.620653329
0.8440365997,7.627293762
0.8454258124,7.633934196
0.8468150251,7.640574629
0.8482042379,7.647215063
0.8495934506,7.653855496
0.8509826633,7.653807084
0.852371876,7.645603621
0.8537610888,7.637400158
0.8551503015,7.629196695
0.8565395142,7.620993232
0.857928727,7.612789769
0.8593179397,7.604690194
0.8607071524,7.609289208
0.8620963652,7.613888221
0.8634855779,7.618487234
0.8648747906,7.623086248
0.8662640034,7.627685261
0.8676532161,7.632284274
0.8690424288,7.636883288
0.8704316415,7.641482301
0.8718208543,7.646081314
0.873210067,7.650680328
0.8745992797,7.655279341
0.8759884925,7.659878354
0.8773777052,7.664477367
0.8787669179,7.669076381
0.8801561307,7.673675394
0.8815453434,7.678274407
0.8829345561,7.682873421
0.8843237688,7.687472434
0.8857129816,7.692071447
0.8871021943,7.696670461
0.888491407,7.701269474
0.8898806198,7.705868487
0.8912698325,7.7104675
0.8926590452,7.715066514
0.894048258,7.719665527
0.8954374707,7.72426454
0.8968266834,7.708663797
0.8982158961,7.689747699
0.8996051089,7.670831601
0.9009943216,7.651915503
0.9023835343,7.648634256
0.9037727471,7.652417362
0.9051619598,7.656200468
0.9065511725,7.659983574
0.9079403853,7.66376668
0.909329598,7.667549785
0.9107188107,7.671332891
0.9121080235,7.675115997
0.9134972362,7.678899103
0.9148864489,7.682682209
0.9162756616,7.686465314
0.9176648744,7.69024842
0.9190540871,7.694031526
0.9204432998,7.697814632
0.9218325126,7.701597738
0.9232217253,7.705380843
0.924610938,7.709163949
0.9260001508,7.712947055
0.9273893635,7.716730161
0.9287785762,7.712515836
0.9301677889,7.68932668
0.9315570017,7.666137524
0.9329462144,7.647766978
0.9343354271,7.661181255
0.9357246399,7.674595531
0.9371138526,7.688009808
0.9385030653,7.701424084
0.9398922781,7.714838361
0.9412814908,7.728252637
0.9426707035,7.741666914
0.9440599162,7.75508119
0.945449129,7.768495467
0.9468383417,7.781909743
0.9482275544,7.79532402
0.9496167672,7.808738296
0.9510059799,7.822152572
0.9523951926,7.835566849
0.9537844054,7.82423082
0.9551736181,7.787989163
0.9565628308,7.801358196
0.9579520436,7.814727229
0.9593412563,7.828096263
0.960730469,7.841465296
0.9621196817,7.85483433
0.9635088945,7.868203363
0.9648981072,7.881572397
0.9662873199,7.89494143
0.9676765327,7.908310464
0.9690657454,7.921679497
0.9704549581,7.898323164
0.9718441709,7.896911546
0.9732333836,7.895499928
0.9746225963,7.894088311
0.976011809,7.892676693
0.9774010218,7.891265075
0.9787902345,7.889853457
0.9801794472,7.888441839
0.98156866,7.824207805
0.9829578727,7.864499773
0.9843470854,7.904791741
0.9857362982,7.945083709
0.9871255109,7.985375677
0.9885147236,7.932516304
0.9899039363,7.872849328
0.9912931491,7.813182351
0.9926823618,7.750636227
0.9940715745,7.986447804
0.9954607873,8.12093709
0.99685,7.761658031
1 ser gap_db
2 0.7203966667 7.395409349
3 0.7217858794 7.394580398
4 0.7231750921 7.393751447
5 0.7245643049 7.392922496
6 0.7259535176 7.392093545
7 0.7273427303 7.391264594
8 0.728731943 7.390435644
9 0.7301211558 7.389606693
10 0.7315103685 7.388777742
11 0.7328995812 7.387948791
12 0.734288794 7.38711984
13 0.7356780067 7.386290889
14 0.7370672194 7.385461939
15 0.7384564322 7.384632988
16 0.7398456449 7.383804037
17 0.7412348576 7.382975086
18 0.7426240704 7.383719533
19 0.7440132831 7.386932812
20 0.7454024958 7.390146092
21 0.7467917085 7.393359371
22 0.7481809213 7.39657265
23 0.749570134 7.39978593
24 0.7509593467 7.402999209
25 0.7523485595 7.406212489
26 0.7537377722 7.409425768
27 0.7551269849 7.412639048
28 0.7565161977 7.415852327
29 0.7579054104 7.419065607
30 0.7592946231 7.422278886
31 0.7606838358 7.425492166
32 0.7620730486 7.428705445
33 0.7634622613 7.431918725
34 0.764851474 7.435132004
35 0.7662406868 7.438345284
36 0.7676298995 7.441558563
37 0.7690191122 7.444771843
38 0.770408325 7.447985122
39 0.7717975377 7.451198402
40 0.7731867504 7.454411681
41 0.7745759631 7.457624961
42 0.7759651759 7.46083824
43 0.7773543886 7.46405152
44 0.7787436013 7.467264799
45 0.7801328141 7.470478079
46 0.7815220268 7.473691358
47 0.7829112395 7.476904638
48 0.7843004523 7.480117917
49 0.785689665 7.483331197
50 0.7870788777 7.486544476
51 0.7884680905 7.489757756
52 0.7898573032 7.492971035
53 0.7912465159 7.493110679
54 0.7926357286 7.4893604
55 0.7940249414 7.485610121
56 0.7954141541 7.481859841
57 0.7968033668 7.478109562
58 0.7981925796 7.474359282
59 0.7995817923 7.470609003
60 0.800971005 7.466858724
61 0.8023602178 7.463108444
62 0.8037494305 7.459358165
63 0.8051386432 7.455607885
64 0.8065278559 7.451857606
65 0.8079170687 7.454642491
66 0.8093062814 7.461282924
67 0.8106954941 7.467923358
68 0.8120847069 7.474563791
69 0.8134739196 7.481204225
70 0.8148631323 7.487844658
71 0.8162523451 7.494485092
72 0.8176415578 7.501125525
73 0.8190307705 7.507765959
74 0.8204199832 7.514406392
75 0.821809196 7.521046826
76 0.8231984087 7.527687259
77 0.8245876214 7.534327693
78 0.8259768342 7.540968126
79 0.8273660469 7.54760856
80 0.8287552596 7.554248993
81 0.8301444724 7.560889427
82 0.8315336851 7.567529861
83 0.8329228978 7.574170294
84 0.8343121106 7.580810728
85 0.8357013233 7.587451161
86 0.837090536 7.594091595
87 0.8384797487 7.600732028
88 0.8398689615 7.607372462
89 0.8412581742 7.614012895
90 0.8426473869 7.620653329
91 0.8440365997 7.627293762
92 0.8454258124 7.633934196
93 0.8468150251 7.640574629
94 0.8482042379 7.647215063
95 0.8495934506 7.653855496
96 0.8509826633 7.653807084
97 0.852371876 7.645603621
98 0.8537610888 7.637400158
99 0.8551503015 7.629196695
100 0.8565395142 7.620993232
101 0.857928727 7.612789769
102 0.8593179397 7.604690194
103 0.8607071524 7.609289208
104 0.8620963652 7.613888221
105 0.8634855779 7.618487234
106 0.8648747906 7.623086248
107 0.8662640034 7.627685261
108 0.8676532161 7.632284274
109 0.8690424288 7.636883288
110 0.8704316415 7.641482301
111 0.8718208543 7.646081314
112 0.873210067 7.650680328
113 0.8745992797 7.655279341
114 0.8759884925 7.659878354
115 0.8773777052 7.664477367
116 0.8787669179 7.669076381
117 0.8801561307 7.673675394
118 0.8815453434 7.678274407
119 0.8829345561 7.682873421
120 0.8843237688 7.687472434
121 0.8857129816 7.692071447
122 0.8871021943 7.696670461
123 0.888491407 7.701269474
124 0.8898806198 7.705868487
125 0.8912698325 7.7104675
126 0.8926590452 7.715066514
127 0.894048258 7.719665527
128 0.8954374707 7.72426454
129 0.8968266834 7.708663797
130 0.8982158961 7.689747699
131 0.8996051089 7.670831601
132 0.9009943216 7.651915503
133 0.9023835343 7.648634256
134 0.9037727471 7.652417362
135 0.9051619598 7.656200468
136 0.9065511725 7.659983574
137 0.9079403853 7.66376668
138 0.909329598 7.667549785
139 0.9107188107 7.671332891
140 0.9121080235 7.675115997
141 0.9134972362 7.678899103
142 0.9148864489 7.682682209
143 0.9162756616 7.686465314
144 0.9176648744 7.69024842
145 0.9190540871 7.694031526
146 0.9204432998 7.697814632
147 0.9218325126 7.701597738
148 0.9232217253 7.705380843
149 0.924610938 7.709163949
150 0.9260001508 7.712947055
151 0.9273893635 7.716730161
152 0.9287785762 7.712515836
153 0.9301677889 7.68932668
154 0.9315570017 7.666137524
155 0.9329462144 7.647766978
156 0.9343354271 7.661181255
157 0.9357246399 7.674595531
158 0.9371138526 7.688009808
159 0.9385030653 7.701424084
160 0.9398922781 7.714838361
161 0.9412814908 7.728252637
162 0.9426707035 7.741666914
163 0.9440599162 7.75508119
164 0.945449129 7.768495467
165 0.9468383417 7.781909743
166 0.9482275544 7.79532402
167 0.9496167672 7.808738296
168 0.9510059799 7.822152572
169 0.9523951926 7.835566849
170 0.9537844054 7.82423082
171 0.9551736181 7.787989163
172 0.9565628308 7.801358196
173 0.9579520436 7.814727229
174 0.9593412563 7.828096263
175 0.960730469 7.841465296
176 0.9621196817 7.85483433
177 0.9635088945 7.868203363
178 0.9648981072 7.881572397
179 0.9662873199 7.89494143
180 0.9676765327 7.908310464
181 0.9690657454 7.921679497
182 0.9704549581 7.898323164
183 0.9718441709 7.896911546
184 0.9732333836 7.895499928
185 0.9746225963 7.894088311
186 0.976011809 7.892676693
187 0.9774010218 7.891265075
188 0.9787902345 7.889853457
189 0.9801794472 7.888441839
190 0.98156866 7.824207805
191 0.9829578727 7.864499773
192 0.9843470854 7.904791741
193 0.9857362982 7.945083709
194 0.9871255109 7.985375677
195 0.9885147236 7.932516304
196 0.9899039363 7.872849328
197 0.9912931491 7.813182351
198 0.9926823618 7.750636227
199 0.9940715745 7.986447804
200 0.9954607873 8.12093709
201 0.99685 7.761658031
+11 -8
View File
@@ -1,10 +1,13 @@
L,d,legit_ser,eve_ser,mask_xcorr,oma
4,16,0.9997925,0.999963,0.01188752614,0.2747696909
6,24,0.9921175,0.9996935,0.09415384382,0.2747696909
8,32,0.9297855,0.999972,0.007307400461,0.2747696909
12,48,0.416604,0.999781,0.005153660662,0.2747696909
4,16,0.9997925,0.999963,0.01188752614,0.961963405
6,24,0.9921175,0.9996935,0.09415384382,nan
8,32,0.9297855,0.999972,0.007307400461,0.4769767714
10,40,0.6965535,0.9999585,0.006223429926,nan
12,48,0.416604,0.999781,0.005153660662,nan
14,56,0.3323575,0.999695,0.005685989745,nan
16,64,0.2762895,0.9999285,0.007116591092,0.2747696909
24,96,0.1829615,0.999975,0.002973971656,0.2747696909
32,128,0.131901,0.9998895,0.005575809628,0.2747696909
48,192,0.090206,0.999845,0.005743456539,0.2747696909
64,256,0.0635265,0.9997915,0.006678360514,0.2747696909
20,80,0.2076175,0.9996245,0.003162040841,0.2289444229
24,96,0.1829615,0.999975,0.002973971656,0.1961714033
32,128,0.131901,0.9998895,0.005575809628,0.1524639978
48,192,0.090206,0.999845,0.005743456539,0.1054308944
64,256,0.0635265,0.9997915,0.006678360514,0.08056383667
1 L d legit_ser eve_ser mask_xcorr oma
2 4 16 0.9997925 0.999963 0.01188752614 0.2747696909 0.961963405
3 6 24 0.9921175 0.9996935 0.09415384382 0.2747696909 nan
4 8 32 0.9297855 0.999972 0.007307400461 0.2747696909 0.4769767714
5 12 10 48 40 0.416604 0.6965535 0.999781 0.9999585 0.005153660662 0.006223429926 0.2747696909 nan
6 12 48 0.416604 0.999781 0.005153660662 nan
7 14 56 0.3323575 0.999695 0.005685989745 nan
8 16 64 0.2762895 0.9999285 0.007116591092 0.2747696909
9 24 20 96 80 0.1829615 0.2076175 0.999975 0.9996245 0.002973971656 0.003162040841 0.2747696909 0.2289444229
10 32 24 128 96 0.131901 0.1829615 0.9998895 0.999975 0.005575809628 0.002973971656 0.2747696909 0.1961714033
11 48 32 192 128 0.090206 0.131901 0.999845 0.9998895 0.005743456539 0.005575809628 0.2747696909 0.1524639978
12 64 48 256 192 0.0635265 0.090206 0.9997915 0.999845 0.006678360514 0.005743456539 0.2747696909 0.1054308944
13 64 256 0.0635265 0.9997915 0.006678360514 0.08056383667
+13 -10
View File
@@ -1,11 +1,14 @@
frac,ser_mask,ser_perm,ser_pad
0,0.99998375,0.9999833333,0.9999847412
0.2,0.9997954167,0.9996233333,0.999859778
0.4,0.9985329167,0.9949383333,0.9987114181
0.6,0.99153625,0.9540933333,0.9881584643
0.75,0.9644704167,0.880335,0.9375
0.85,0.88742875,0.7279433333,0.8105354292
0.9,0.7780379167,0.5716733333,0.6701230223
0.94,0.6256225,0.4316466667,0.4859430867
0.97,0.43810125,0.3708666667,0.283022376
1,0.2756983333,0.3021566667,0
0,0.9999779167,0.9999883333,0.9999893771
0.2,0.9997833333,0.9995633333,0.9999023796
0.4,0.9984945833,0.9950233333,0.9991029086
0.6,0.9915358333,0.9543866667,0.9917561005
0.75,0.9643629167,0.8802716667,0.9564884375
0.85,0.8872583333,0.727755,0.8680976078
0.9,0.7787070833,0.5709983333,0.7703445963
0.92,0.7202866667,0.502115,0.7133141438
0.94,0.6145370833,0.4848966667,0.6421212878
0.955,0.52254125,0.4416266667,0.5773478672
0.97,0.4333570833,0.3520316667,0.5008509328
0.985,0.3505958333,0.30335,0.4105086147
1,0.2758220833,0.303165,0.303815
1 frac ser_mask ser_perm ser_pad
2 0 0.99998375 0.9999779167 0.9999833333 0.9999883333 0.9999847412 0.9999893771
3 0.2 0.9997954167 0.9997833333 0.9996233333 0.9995633333 0.999859778 0.9999023796
4 0.4 0.9985329167 0.9984945833 0.9949383333 0.9950233333 0.9987114181 0.9991029086
5 0.6 0.99153625 0.9915358333 0.9540933333 0.9543866667 0.9881584643 0.9917561005
6 0.75 0.9644704167 0.9643629167 0.880335 0.8802716667 0.9375 0.9564884375
7 0.85 0.88742875 0.8872583333 0.7279433333 0.727755 0.8105354292 0.8680976078
8 0.9 0.7780379167 0.7787070833 0.5716733333 0.5709983333 0.6701230223 0.7703445963
9 0.94 0.92 0.6256225 0.7202866667 0.4316466667 0.502115 0.4859430867 0.7133141438
10 0.97 0.94 0.43810125 0.6145370833 0.3708666667 0.4848966667 0.283022376 0.6421212878
11 1 0.955 0.2756983333 0.52254125 0.3021566667 0.4416266667 0 0.5773478672
12 0.97 0.4333570833 0.3520316667 0.5008509328
13 0.985 0.3505958333 0.30335 0.4105086147
14 1 0.2758220833 0.303165 0.303815
+11 -6
View File
@@ -1,7 +1,12 @@
snr_db,legit,eve_wrong,eve_none,eve_public,oma,chance
0,0.8944596875,0.9999515625,0.999990625,0.8943865625,0.8933480658,0.9999847412
4,0.66980875,0.9999575,0.99998625,0.670624375,0.6686275787,0.9999847412
8,0.39054875,0.9999425,0.9999865625,0.3902384375,0.3892153151,0.9999847412
12,0.1880821875,0.9999284375,0.9999890625,0.1877565625,0.1870712987,0.9999847412
16,0.0811665625,0.9999203125,0.9999875,0.081488125,0.08092517452,0.9999847412
20,0.033519375,0.999921875,0.999988125,0.0334946875,0.03334949917,0.9999847412
0,0.8944596875,0.9999621875,0.999988125,0.8945528125,0.8933480658,0.9999847412
2,0.79877875,0.9999559375,0.999986875,0.798940625,0.7973276257,0.9999847412
4,0.6697890625,0.9999446875,0.99998625,0.6702265625,0.6686275787,0.9999847412
6,0.5269903125,0.999944375,0.99999125,0.5272609375,0.525415822,0.9999847412
8,0.39087,0.9999415625,0.999988125,0.39062875,0.3892153151,0.9999847412
10,0.2760796875,0.9999296875,0.999986875,0.2753090625,0.2747696909,0.9999847412
12,0.1876809375,0.9999203125,0.9999884375,0.1878209375,0.1870712987,0.9999847412
14,0.1250471875,0.999920625,0.9999896875,0.12470875,0.1241256148,0.9999847412
16,0.0812634375,0.9999153125,0.999985625,0.08121,0.08092517452,0.9999847412
18,0.05243375,0.9999090625,0.9999865625,0.0526228125,0.05214810026,0.9999847412
20,0.0335228125,0.9999196875,0.999988125,0.033636875,0.03334949917,0.9999847412
1 snr_db legit eve_wrong eve_none eve_public oma chance
2 0 0.8944596875 0.9999515625 0.9999621875 0.999990625 0.999988125 0.8943865625 0.8945528125 0.8933480658 0.9999847412
3 4 2 0.66980875 0.79877875 0.9999575 0.9999559375 0.99998625 0.999986875 0.670624375 0.798940625 0.6686275787 0.7973276257 0.9999847412
4 8 4 0.39054875 0.6697890625 0.9999425 0.9999446875 0.9999865625 0.99998625 0.3902384375 0.6702265625 0.3892153151 0.6686275787 0.9999847412
5 12 6 0.1880821875 0.5269903125 0.9999284375 0.999944375 0.9999890625 0.99999125 0.1877565625 0.5272609375 0.1870712987 0.525415822 0.9999847412
6 16 8 0.0811665625 0.39087 0.9999203125 0.9999415625 0.9999875 0.999988125 0.081488125 0.39062875 0.08092517452 0.3892153151 0.9999847412
7 20 10 0.033519375 0.2760796875 0.999921875 0.9999296875 0.999988125 0.999986875 0.0334946875 0.2753090625 0.03334949917 0.2747696909 0.9999847412
8 12 0.1876809375 0.9999203125 0.9999884375 0.1878209375 0.1870712987 0.9999847412
9 14 0.1250471875 0.999920625 0.9999896875 0.12470875 0.1241256148 0.9999847412
10 16 0.0812634375 0.9999153125 0.999985625 0.08121 0.08092517452 0.9999847412
11 18 0.05243375 0.9999090625 0.9999865625 0.0526228125 0.05214810026 0.9999847412
12 20 0.0335228125 0.9999196875 0.999988125 0.033636875 0.03334949917 0.9999847412
+10
View File
@@ -0,0 +1,10 @@
check,claim,empirical,abs_err,tol,verdict
V1 legit self-alignment,1.0,0.9994724071424732,0.000527592857526793,0.02,PASS
V2a eve mean advantage,0.0,0.0006469982936097643,0.0006469982936097643,0.003,PASS
V2b eve SER @ 0dB,0.99609375,0.995,0.0010937500000000044,0.015,PASS
V2b eve SER @ 10dB,0.99609375,0.9888333333333333,0.007260416666666658,0.015,PASS
V2b eve SER @ 20dB,0.99609375,0.9881666666666666,0.007927083333333362,0.015,PASS
V2b eve SER @ 80dB,0.99609375,0.9896666666666667,0.0064270833333333055,0.015,PASS
V3b random mask E|corr|,0.09973557010035818,0.10187042771408686,0.002134857613728683,0.009973557010035819,PASS
V4a blind jammer projection mean,0.0,0.00026396107284673695,0.00026396107284673695,0.003,PASS
V4b blind jammer projection variance,0.01558576233568703,0.015476787953278994,0.00010897438240803532,0.0007792881167843516,PASS
1 check claim empirical abs_err tol verdict
2 V1 legit self-alignment 1.0 0.9994724071424732 0.000527592857526793 0.02 PASS
3 V2a eve mean advantage 0.0 0.0006469982936097643 0.0006469982936097643 0.003 PASS
4 V2b eve SER @ 0dB 0.99609375 0.995 0.0010937500000000044 0.015 PASS
5 V2b eve SER @ 10dB 0.99609375 0.9888333333333333 0.007260416666666658 0.015 PASS
6 V2b eve SER @ 20dB 0.99609375 0.9881666666666666 0.007927083333333362 0.015 PASS
7 V2b eve SER @ 80dB 0.99609375 0.9896666666666667 0.0064270833333333055 0.015 PASS
8 V3b random mask E|corr| 0.09973557010035818 0.10187042771408686 0.002134857613728683 0.009973557010035819 PASS
9 V4a blind jammer projection mean 0.0 0.00026396107284673695 0.00026396107284673695 0.003 PASS
10 V4b blind jammer projection variance 0.01558576233568703 0.015476787953278994 0.00010897438240803532 0.0007792881167843516 PASS
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.