test: jitter defense + injection taxonomy (44/44)
This commit is contained in:
parent
66e745d33d
commit
90e279868a
|
|
@ -1116,3 +1116,64 @@ def test_injection_attacker_invisible():
|
|||
max_attacker = max(scores.get(a, 0) for a in ["target", "other1", "other2"])
|
||||
assert attacker_echo < max_attacker * 0.5, \
|
||||
f"Attacker should be relatively invisible: echo={attacker_echo:.2f} vs max agent={max_attacker:.2f}"
|
||||
|
||||
|
||||
def test_jitter_defense_recovers_from_injection():
|
||||
"""
|
||||
Jitter defense: adding ±N seconds of random noise to timestamps
|
||||
recovers most of the target's echo from a targeted injection attack.
|
||||
|
||||
Without jitter: target echo = 0 (100% kill).
|
||||
With ±10s jitter: target echo ≈ baseline (statistically).
|
||||
|
||||
Discovered 2026-07-28: binary phase transition at Δt=0 means
|
||||
a ±10s jitter window randomizes whether attacker arrives before/after.
|
||||
Over 30 rounds, statistical averaging recovers ~90%+ of baseline.
|
||||
"""
|
||||
import random
|
||||
random.seed(42)
|
||||
|
||||
target_concepts = [f"x{i}" for i in range(5)]
|
||||
msgs = []
|
||||
target_times = []
|
||||
|
||||
# Build corpus: target introduces, 3 agents echo
|
||||
for r in range(30):
|
||||
t = float(r * 200)
|
||||
tc = target_concepts[r % 5]
|
||||
target_ts = t + random.randint(10, 60)
|
||||
target_times.append((t, target_ts, tc))
|
||||
msgs.append({"from_id": "target", "to_id": "_all",
|
||||
"timestamp": target_ts, "concepts": [tc]})
|
||||
for agent in ["a", "b", "c"]:
|
||||
msgs.append({"from_id": agent, "to_id": "_all",
|
||||
"timestamp": target_ts + random.randint(30, 90),
|
||||
"concepts": [tc, f"{agent}_{r % 5}"]})
|
||||
|
||||
baseline = score_echo(msgs, snapshot_idf=True)
|
||||
target_base = baseline.get("target", 0)
|
||||
assert target_base > 0
|
||||
|
||||
# Inject attacker 5s before target
|
||||
injected = list(msgs)
|
||||
for _, target_ts, tc in target_times:
|
||||
injected.append({"from_id": "atk", "to_id": "_all",
|
||||
"timestamp": target_ts - 5,
|
||||
"concepts": [tc]})
|
||||
|
||||
# Without jitter: total kill
|
||||
no_jitter = score_echo(injected, snapshot_idf=True)
|
||||
assert no_jitter.get("target", 0) == 0, "Without jitter, target should be killed"
|
||||
|
||||
# With ±10s jitter: run multiple trials, average should recover >50%
|
||||
recoveries = []
|
||||
for trial in range(30):
|
||||
random.seed(trial + 200)
|
||||
jittered = score_echo(injected, snapshot_idf=True, jitter_seconds=10)
|
||||
t_echo = jittered.get("target", 0)
|
||||
if target_base > 0:
|
||||
recoveries.append(t_echo / target_base)
|
||||
|
||||
mean_recovery = sum(recoveries) / len(recoveries)
|
||||
assert mean_recovery > 0.5, \
|
||||
f"Jitter defense should recover >50% of baseline: got {mean_recovery:.0%}"
|
||||
|
|
|
|||
Loading…
Reference in New Issue