reports/blend/pd: section 3.10, cover traffic

Written from configs/cover-traffic.yaml: the rate swept over three decades against
three release delays, each timeline paired with the epoch emission budget.

The finding that shapes the section is that mixing never happens. At one message
per second a relay holds 0.0014 messages and never more than two; even 256x the
rate reaches only 0.39, matching Little law exactly. So the anonymity set is
entirely blending -- the broadcasts a relay saw between releases -- which follows
rate*(2M+1)/3, twice the mean hold. Measured within ~1% over most of the range.

That makes delay the cheap lever: both knobs enter linearly, but bandwidth is paid
on every link while delay is paid once per hop. An anonymity set of 100 costs 42.9
msg/s at a 3s delay and 4.9 msg/s at 30s.

The quota ceiling is the hard edge. A node proposals must fit its emission budget,
capping stake at ln(1-q)/ln(1-f) of INFERRED stake -- about 0.1% at the baseline
rate once Poisson fluctuation is allowed for. A 9.5% holder overruns by ~65x and
is distinguishable by emission count alone, before any path is captured.

Two existing sections needed correcting as a result. 3.6-3.7: with cover traffic
running, catching an emission is not catching a block, and the large stakers those
sections analyse sit one to two orders of magnitude above the quota ceiling, so
their binding exposure is the quota rather than the cascade. 5: the timing-
correlation adversary was deferred for want of cover traffic and is now unblocked.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Marcin Pawlowski 2026-08-06 12:14:45 +02:00 committed by Marcin Pawlowski
parent 8a3a43b366
commit a93311013b
No known key found for this signature in database
8 changed files with 67 additions and 5 deletions

View File

@ -14,6 +14,7 @@ A peering degree of **68** is the operating sweet spot across the sizes teste
| blend-path length | **set from the anonymity target**: `blend_hops ≥ ln ε / ln f_adv` to hold whole-path capture ≤ ε | the degree-independent anonymity lever; costs ~1.52.7 s latency (degree-dependent) and a `(1u)` reliability factor per hop (§3.4, §3.2, §3.5) |
| operating churn | pick the degree from the churn to be survived: **`u_c = 1 1/(degree 1)`** (degree 6 → 80 %, degree 8 → 86 %) | site percolation of the responsive sub-graph (§3.5) |
| messaging redundancy | **R = 1 unless reliability demands more** — each extra copy multiplies *both* delivery and capture by `1(1x)^R` | redundancy is reliability and exposure in one dial; it cuts time-to-link ≈ R× (§3.8) |
| cover-traffic rate | **buy the anonymity set with delay before bandwidth** — both enter linearly, but delay is paid once per hop | `blending = rate·(2M+1)/3`; the rate also sets the stake ceiling `s_max` (§3.10) |
A node's exposure is not only *whether* it is deanonymized but *how soon*: if each 30 s slot one node emits with probability equal to its stake, the time to link an emitter is `≈ 30 s · ln(1/(1α)) / (stake · f_adv^blend_hops)`**inversely proportional to its stake** — so high-stake nodes are identified in days and the smallest holders effectively never (§3.6). The same event stream lets an adversary *estimate* a node's stake, but pinning it below ~0.1 % takes over a decade and below ~0.01 % centuries (§3.7).
@ -40,6 +41,8 @@ A node's exposure is not only *whether* it is deanonymized but *how soon*: if ea
7. **Correlated outages are the *milder* failure for the live network, not the harsher one.** When failures cluster by AS or region — and peering is regional enough that a failure domain is also a connectivity domain — whole neighbourhoods vanish and every surviving neighbourhood stays whole. Live coverage then holds at 1.000 through 80 % churn, at every degree tested, and the percolation threshold of finding 4 never appears; at degree 4 and 70 % churn, scattered failure annihilates the network (coverage 0.001, delivery 0.000) while the same number of clustered failures still delivers 30 % of messages. The cost is that dead domains become unreachable islands rather than offline nodes among live peers, so coverage *of all nodes* falls instead. The uncorrelated threshold of finding 4 is therefore the conservative case for the operating network (§3.9).
8. **Cover traffic buys uniform emission counts, and almost nothing else for free.** Every node emits equally often whether or not it produces blocks, which hides block production in the emission *count*. But per-relay **mixing never happens** — at one message per second a relay holds 0.0014 messages, and even 256× the rate only reaches 0.39 — so the anonymity set is entirely **blending**, the broadcasts a relay saw between releases, which is `rate·(2M+1)/3`. Delay is the cheap lever: an anonymity set of 100 costs 42.9 msg/s at a 3 s release delay but 4.9 msg/s at 30 s. And the guarantee has a hard edge: a node's proposals must fit its emission quota, capping stake at `α_max = ln(1q)/ln(1f)` of *inferred* stake — about 0.1 % at the baseline rate, so a 9.5 % holder overruns by ~65× and is distinguishable by emission count alone (§3.10).
**The tension, in one line.** Axes 1, 2-eclipse, and 4 all want *more* degree; axis 2-observation and axis 3-full-deanonymization want *less*. Because whole-path deanonymization (axis 3) depends only on the blend-path length, the resolution is to raise the degree to where speed, eclipse, and churn saturate (68) and to control anonymity independently through the number of blend hops. Messaging redundancy (finding 6) does not escape the trade — it moves reliability and anonymity together, never apart — and time itself is an axis: exposure is a rate, and a high-stake node accumulates it fastest (finding 5).
*Method note: the peer graph is a deterministic, exactly d-regular matching-union reconstructible from one seed; the adversary observation/eclipse counts and both deanonymization rates are computed in closed form, so they carry no sampling error at any N; propagation delays are Monte-Carlo over random senders (1 000 rounds × 8 topologies = 8 000 rounds per cell; see §5 for the resulting error bars). Delays fold a geographic link base (15200 ms), an exponential transport jitter, and a per-node processing lag ({10, 50, 100} ms); mixing is the residual wait to a relay's next free-running release on a Uniform{0…3}-second clock.*
@ -57,7 +60,9 @@ A node's exposure is not only *whether* it is deanonymized but *how soon*: if ea
**Messaging redundancy.** A sender may emit `redundancy = R` copies of a message over `R` *independent* blend cascades, each drawing its own relays. A node receives whichever copy reaches it first, so the round's arrival times are the element-wise minimum over the cascades that survived: the message is delivered if **any** cascade completes, its coverage is the union of their reached sets, and its full delay is the last node's *earliest* arrival. `R = 1` is the plain single-cascade model, to which this reduces exactly.
**Emission cadence and linking.** For the time-based results, traffic is modelled as: every 30 s slot exactly one node network-wide emits, chosen with probability proportional to its stake — so a node holding stake fraction `s` emits with probability `s` per slot. A node is **linked** the first time one of its emissions is *fully deanonymized*, which requires that node to be linkable at all (to have ≥ 1 adversarial peer; the rest are structurally beyond this attack). Counting the linked emissions over time additionally *estimates* the node's stake, since they arrive at a rate proportional to it.
**Cover traffic.** Each node schedules emissions on uniformly-chosen slots at rate `cover_rate_mult / N` per second, so the default rate puts one emission per second on the whole network. Winning the block lottery consumes the next scheduled cover, keeping every node's emission count identical whether or not it produces blocks. Cover and block messages travel the same cascade over independently drawn paths and both end in a broadcast, so they are indistinguishable in transit. Each node's release clock is shared by every message passing through it, which is what lets messages meet at a relay (§3.10).
**Emission cadence and linking.** For the time-based results of §3.6§3.7, traffic is modelled as: every 30 s slot exactly one node network-wide emits, chosen with probability proportional to its stake — so a node holding stake fraction `s` emits with probability `s` per slot. A node is **linked** the first time one of its emissions is *fully deanonymized*, which requires that node to be linkable at all (to have ≥ 1 adversarial peer; the rest are structurally beyond this attack). Counting the linked emissions over time additionally *estimates* the node's stake, since they arrive at a rate proportional to it.
**Adversary.** A fraction `f_adv` of nodes are adversarial, placed either at random (average case) or by a greedy worst-case strategy (the security *envelope*, characterized at N ≤ 10⁵). An honest node is **observed** if it has ≥ 1 adversarial peer and **eclipsed** if *all* its peers are adversarial; both are counted exactly by one sparse reduction over the graph.
@ -204,7 +209,9 @@ At `f_adv = 0.2`, `blend_hops = 3`, degree 8 (`q = 0.2³ = 0.008`):
| 0.005 % | 602 d (1.6 yr) | 1 999 d (5.5 yr) | 3 998 d (11.0 yr) |
| 0.001 % | 3 008 d (8.2 yr) | 9 994 d (27.4 yr) | 19 988 d (54.8 yr) |
Every 10× drop in stake multiplies the time by 10, and raising the confidence from α = 0.5 to 0.99 costs a fixed factor `ln(1/0.01)/ln 2 ≈ 6.6` at any stake. A large staker is deanonymized within days; the smallest holders are, for practical purposes, never linked — and lengthening the blend path multiplies `q` down by `f_adv` per hop, stretching every entry in the table by `1/f_adv` (25× per two hops at `f_adv = 0.2`). This is the anonymity value of both a small stake and a long path, expressed as time (**Fig 16**).
Every 10× drop in stake multiplies the time by 10, and raising the confidence from α = 0.5 to 0.99 costs a fixed factor `ln(1/0.01)/ln 2 ≈ 6.6` at any stake.
**Two corrections from §3.10, both of which matter here.** First, with cover traffic running, catching an emission is *not* the same as catching a block: only about one emission in `block_interval × cover_rate` is a proposal, so linking a node to a message identifies the **node**, not the fact that it produced a block. The times above are therefore times to link an *identity*; attributing a *proposal* takes correspondingly longer. Second, the large stakers this table is most interested in cannot be emission-uniform at all — the quota ceiling at the baseline rate is ~0.1 % of stake (§3.10), so the 5 % and 1 % rows sit one to two orders of magnitude above it. Such a node is distinguishable by how often it emits, without any path being captured. **For the head of the stake distribution, the binding exposure is the emission quota, not the cascade.** A large staker is deanonymized within days; the smallest holders are, for practical purposes, never linked — and lengthening the blend path multiplies `q` down by `f_adv` per hop, stretching every entry in the table by `1/f_adv` (25× per two hops at `f_adv = 0.2`). This is the anonymity value of both a small stake and a long path, expressed as time (**Fig 16**).
![Fig 16 — time to link vs stake](report-figures/16_time_to_link_vs_stake.png)
*Fig 16 — Time to link an emitter vs its stake fraction, one line per confidence α (log-log; `f_adv = 0.2`, `blend_hops = 3`, degree 8; linkable fraction 0.83). The parallel lines are the `T ∝ 1/stake` law; only the 83 % of nodes with an adversarial peer are on it at all.*
@ -297,6 +304,60 @@ Two consequences for the rest of the report. First, **§3.5's `u_c = 1 1/(de
![Fig 22 — correlated vs uniform churn](report-figures/22_churn_correlated_vs_uniform.png)
*Fig 22 — Correlated (AS/region) outages against uniform churn at matched churn (N = 20 000, degree 8, 1 hop, 40 domains, 75 % locality). Solid = coverage of the live network, dashed = coverage of all nodes. Regional churn holds the live network at 1.000 throughout while stranding the dead domains; uniform churn keeps the dead reachable but takes the whole network down with it.*
<a id="s3-10"></a>
### 3.10 Cover traffic — what it buys, and what it costs
Everything above treats a message as a lone event. A deployed Blend network also emits **cover traffic**: every node picks emission slots uniformly at random at rate `cover_rate_mult / N` per slot, so the default rate puts one emission per second on the whole network. Winning the block lottery consumes the next scheduled cover, so **every node emits the same number of times per epoch whether or not it produces blocks** — the emission *count* carries no signal. That uniformity is the property cover traffic exists to buy, and it turns out to be both narrower and more expensive than it looks.
Two quantities have to be kept apart, because they behave completely differently.
**Mixing** is how many messages a relay holds at once. **Blending** is how many broadcasts it has *seen* between two consecutive releases. Since every broadcast reaches every node, an observer watching a relay release cannot tell which of the messages it had seen was the one forwarded — so blending, not mixing, is the anonymity set. Measured at N = 20 000, degree 8, 3 hops:
| `max_blend_delay` | blending | mixing (mean / max) | mean hold |
|---|---|---|---|
| 3 s | 2.4 | **0.0014** / 1 | 1.18 s |
| 10 s | 7.1 | 0.0041 / 1.8 | 3.49 s |
| 30 s | 19.8 | 0.0120 / 2 | 10.14 s |
**At the specified rate there is no mixing at all.** A relay holds 0.0014 messages on average and never more than two — one message per second spread over twenty thousand nodes simply never collides. Anything the design gains here it gains through blending. And this is not a low-rate artefact: pushing the rate up by **256×** only lifts mean occupancy to 0.39 (max 9), exactly as Little's law requires (`256 × 3 × 10.17 / 20 000`). **Per-relay mixing is unreachable at any rate a real network would pay for**, so the anonymity set is entirely the traffic a relay has watched go by.
Blending itself follows a clean law. Intervals sampled *at a release* are size-biased — a longer gap is likelier to have caught an arrival — so the set is
**`blending = rate × (2·max_blend_delay + 1) / 3`**
which is exactly twice the mean hold, not `rate × M/2` as a naive reading gives. Measured across three decades of rate and three delays it holds to ~1 % over most of the range and ~7 % at the extreme (**Fig 23**):
| rate (msg/s) | M = 3 | M = 10 | M = 30 |
|---|---|---|---|
| 1 | 2.4 | 7.1 | 19.8 |
| 16 | 37.2 | 110.9 | 316.2 |
| 256 | 593 | 1 744 | 4 832 |
The practical consequence is that **delay is a far cheaper lever than bandwidth**. Both enter linearly, but bandwidth is paid by every node on every link while delay is paid once per hop. An anonymity set of 100 costs 42.9 msg/s at `M = 3` but only 4.9 msg/s at `M = 30` — a ninefold traffic saving for a hop that takes ~10 s instead of ~1.2 s (§3.1 prices that latency). Cover traffic between block proposals is `rate × block_interval` — about 30 messages at the baseline, one of which is cancelled by the block itself.
**The quota bounds stake concentration.** The uniform-emission guarantee holds only while a node's proposals fit inside its budget. A node's lottery weight is its stake relative to the **inferred** total `D̂` — that is the denominator the threshold is derived from — so with quota `q = cover_rate_mult/N` per slot the bind is exact:
**`α_max = ln(1 q) / ln(1 f)`**, and in true stake **`s_max = (D̂/D) · α_max`**
The familiar `q/f` is a small-`q` approximation that runs 1.7 % high and therefore *overstates* the tolerable stake. Measured over a full epoch against heavy-tailed stake, the ceiling scales with the cover rate and the measured breakpoint tracks the prediction:
| rate | quota/epoch | `s_max` predicted | 99 %-safe | measured breakpoint |
|---|---|---|---|---|
| 1 | 32.4 | 0.147 % | 0.096 % | 0.122 0.168 % |
| 16 | 518 | 2.36 % | 2.13 % | 2.03 2.58 % |
| 64 | 2 074 | 9.45 % | 8.98 % | 5.96 9.54 % |
| 256 | 8 294 | 38.0 % | 37.0 % | nobody overran |
At the baseline rate that ceiling is **0.147 % of inferred stake — about 0.1 % once Poisson fluctuation is allowed for** (a node sitting on the mean bind overruns in half of all epochs). With realistic stake concentration 99.7 % of nodes comply, but the head does not: **a 9.5 % holder wins some 65× its allowance** and cannot hide inside a uniform emission count at any delay. This reaches back into §3.6§3.7, whose 5 % and 1 % stakers sit one to two orders of magnitude above the ceiling — *those* nodes are distinguishable by emission count alone, before any path is captured. Raising the cover rate is the only remedy, and it buys headroom linearly: 64× the traffic to admit a 9.5 % staker (**Fig 24**).
Because `s_max` is expressed against `D̂`, an estimator that runs low tightens the true-stake ceiling in exact proportion — `D̂/D` is an input here, taken from the consensus-side study rather than assumed, and deflating it to 0.64 measurably pushes more nodes over their quota. **The two systems are coupled: stake-inference accuracy propagates directly into who can remain emission-uniform.**
![Fig 23 — anonymity set vs cover rate and delay](report-figures/23_blending_vs_rate_and_delay.png)
*Fig 23 — Blending against cover rate, one line per release delay (log-log, N = 20 000). Dashed = `rate·(2M+1)/3`. Both knobs enter linearly, but delay is bought once per hop while rate is paid on every link.*
![Fig 24 — the emission-quota stake ceiling](report-figures/24_quota_stake_ceiling.png)
*Fig 24 — The most stake a node can hold and still emit like everyone else, against cover rate: predicted ceiling, the 99 %-safe ceiling, the measured transition band, and the largest staker actually present.*
---
<a id="s4"></a>
@ -317,7 +378,7 @@ Two consequences for the rest of the report. First, **§3.5's `u_c = 1 1/(de
<a id="s5"></a>
## 5. Validity and caveats
- **Structural adversary; timing correlation is the next study, and is blocked on cover traffic.** The adversary is modelled as controlling *nodes* and their peerings: it observes messages traversing relays it owns (deanonymization) and honest nodes it peers (observation). It does **not** perform timing or traffic-analysis correlation across honest relays. That is not an oversight but a sequencing constraint — a timing adversary is only meaningful against a network that emits **cover traffic**, which the Blend design calls for and this simulator does not yet generate. Modelling cover traffic and then the timing-correlation adversary against it is the natural next step; until then a timing attack here would face an unrealistically bare traffic pattern and its results would not transfer. An adversary that adaptively targets the transport path of a *specific* known sender is likewise outside the current model.
- **Structural adversary; timing correlation is the next study, and is blocked on cover traffic.** The adversary is modelled as controlling *nodes* and their peerings: it observes messages traversing relays it owns (deanonymization) and honest nodes it peers (observation). It does **not** perform timing or traffic-analysis correlation across honest relays. That is not an oversight but a sequencing constraint — a timing adversary is only meaningful against a network that emits **cover traffic**. With §3.10 that prerequisite is now in place, so the timing study is unblocked and is the next piece of work rather than a deferred one. It has a specific target: distinguishing a *relayed* message from a *blended* one by when it leaves a relay, and deciding between adding random jitter to the release and holding messages to a clock tick so they leave alongside blended traffic. §3.10 already supplies the reason to expect that comparison to be sharp — a relay holds 0.0014 messages on average, so a release almost never coincides with another, and timing carries essentially no cover of its own. An adversary that adaptively targets the transport path of a *specific* known sender is likewise outside the current model.
- **Churn is modelled both ways; adversarial churn is not.** §3.5 removes nodes independently and §3.9 removes whole AS/region failure domains, at matched churn — and the correlated case turns out to be *gentler* on the live network, so the uncorrelated threshold is the conservative one. What remains outside the model is **adversarially placed** churn: an attacker who chooses which nodes to silence (a cut set rather than a random or clustered set) would be worse than either, and the worst-case placement machinery used for the adversary in §3.3 has no counterpart here. Regional churn also assumes equal-sized domains; real AS sizes are heavy-tailed, so a single dominant provider failing would remove a larger, less uniform slice than modelled.
- **Exactly d-regular topology — by design, not by simplification.** Every node has exactly the same number of peers because the protocol requires it: the peer graph is derived by every node from one global seed, so the degree is a protocol constant rather than an emergent property. This is the topology the deployed network will have, so the results are not an idealisation of some heavier-tailed reality — a degree *distribution* would be a different protocol, not a more realistic model of this one.
- **Sampled propagation, exact structure — and what each is worth.** Only the propagation quantities are sampled: they are Monte-Carlo over **1 000 rounds × 8 independent topologies = 8 000 rounds per cell**, which puts the standard error at **≤ 0.009 on every delivery rate**, **≤ 0.001 on every coverage figure** (bar the critical cell below), and **≤ 0.04 s on every full-delay mean** (the redundancy study uses 1 200 × 8 = 9 600 rounds per cell, SEM ≤ 0.006, and the churn-threshold study 800 × 8 = 6 400). That is a digit finer than the tables quote, so the reported two-decimal rates and 0.1-second delays are resolved rather than sampling noise; error bars were computed across topologies, which captures graph-to-graph variation as well as round-to-round. Everything else — the graph invariants, the observation and eclipse counts, both deanonymization rates, and therefore all of §3.6§3.8's derived times — is closed-form and carries **no sampling error at all** at any N. The worst-case adversary placement is a greedy envelope characterized at N ≤ 10⁵.
@ -331,7 +392,7 @@ Two consequences for the rest of the report. First, **§3.5's `u_c = 1 1/(de
<a id="s6"></a>
## 6. Reproducibility
The simulator, configs, and analytic checks live in [`tools/simulators/blend/pd`](../../../tools/simulators/blend/pd). From that directory: `make install`, then `make sweep` runs the main grid (`configs/default.yaml`: N up to 10⁵, degree 316, 15 blend hops, `f_adv` up to 0.5, unresponsive fractions to 0.5, all three placement modes, 8 topology seeds) into `runs/<timestamp>_default/`, writing three tables — `propagation.parquet`, `adversary.parquet`, and `deanon.parquet` — and rendering the figures. `make sweep-fullscale` extends the exact metrics to 10⁶ nodes. The messaging-redundancy study (§3.8) and the linkability figures come from `configs/redundancy.yaml` (`python -m pd.sweep --config configs/redundancy.yaml`), which sweeps `redundancy` ∈ {1, 2, 3, 4} alongside the churn and adversary grids; the churn-threshold study (§3.5, Fig 20) comes from `configs/percolation.yaml`, which walks the unresponsive fraction to 0.9 so each degree's collapse can be located against `u_c = 1 1/(degree 1)`; and the correlated-outage study (§3.9, Fig 22) from `configs/correlated-churn.yaml` (`make correlated-churn`), which partitions the network into failure domains and runs both churn modes on the same topologies. `make sweep-fullscale` produces the 10⁶ scaling check described in §5. Round counts in all three configs are set for statistical resolution, not speed — see the sampling-error note in §5. `make verify` runs the analytic anchors (d-regularity; `observed ≈ 1 (1 f)^degree`; `eclipsed ≈ f^degree`; delivery `≈ (1 u)^blend_hops`; both deanonymization rates against a direct Monte-Carlo of the same draw; and — check 6 — `deanon_R` / `delivery_R = 1 (1 x)^R` for R independent cascades and the time-to-link geometric law), and `make test` the unit suite (`test_linkability.py` covers the time-to-link and stake formulae). The time-to-link and stake-inference curves are computed by `pd.linkability` from these exact rates.
The simulator, configs, and analytic checks live in [`tools/simulators/blend/pd`](../../../tools/simulators/blend/pd). From that directory: `make install`, then `make sweep` runs the main grid (`configs/default.yaml`: N up to 10⁵, degree 316, 15 blend hops, `f_adv` up to 0.5, unresponsive fractions to 0.5, all three placement modes, 8 topology seeds) into `runs/<timestamp>_default/`, writing three tables — `propagation.parquet`, `adversary.parquet`, and `deanon.parquet` — and rendering the figures. `make sweep-fullscale` extends the exact metrics to 10⁶ nodes. The messaging-redundancy study (§3.8) and the linkability figures come from `configs/redundancy.yaml` (`python -m pd.sweep --config configs/redundancy.yaml`), which sweeps `redundancy` ∈ {1, 2, 3, 4} alongside the churn and adversary grids; the churn-threshold study (§3.5, Fig 20) comes from `configs/percolation.yaml`, which walks the unresponsive fraction to 0.9 so each degree's collapse can be located against `u_c = 1 1/(degree 1)`; and the correlated-outage study (§3.9, Fig 22) from `configs/correlated-churn.yaml` (`make correlated-churn`), which partitions the network into failure domains and runs both churn modes on the same topologies. `make sweep-fullscale` produces the 10⁶ scaling check described in §5; and the cover-traffic study (§3.10, Figs 2324) comes from `configs/cover-traffic.yaml`, which sweeps the emission rate over three decades against three release delays and pairs each timeline with the epoch-scale emission budget. Round counts in all three configs are set for statistical resolution, not speed — see the sampling-error note in §5. `make verify` runs the analytic anchors (d-regularity; `observed ≈ 1 (1 f)^degree`; `eclipsed ≈ f^degree`; delivery `≈ (1 u)^blend_hops`; both deanonymization rates against a direct Monte-Carlo of the same draw; and — check 6 — `deanon_R` / `delivery_R = 1 (1 x)^R` for R independent cascades and the time-to-link geometric law), and `make test` the unit suite (`test_linkability.py` covers the time-to-link and stake formulae). The time-to-link and stake-inference curves are computed by `pd.linkability` from these exact rates.
The figures of record for this report are the copies checked in under [`report-figures/`](report-figures); the simulator does not commit its own generated figures. To regenerate: run the sweeps above, then copy `runs/<…>/figures/*.png` into `report-figures/`.
@ -339,4 +400,4 @@ The **evidence** is checked in too: [`data/`](data) holds the sweep outputs behi
## Figures
All twenty-two rendered figures are versioned in [`report-figures/`](report-figures): `01``03` propagation delay (vs degree, vs path length, vs N); `04``09` adversary observation and eclipse (vs `f_adv`, vs degree, and heatmaps); `10``11` reliability under churn (delivery and coverage); `12``15` deanonymization (whole-path and full, vs path length, `f_adv`, and degree); `16``18` linkability over time (time to link vs stake, with redundancy, and time to learn stake vs threshold); `19` the redundancy reliability-vs-anonymity trade-off in probability and `21` the same trade in delivery-vs-time-to-link; `20` the churn-percolation threshold; `22` correlated versus uniform outages. Sixteen of the twenty-two are embedded above; the other six (`04``06`, `09`, `11`, `13`) are alternative cuts of data already shown — for instance 11 and 20 both plot coverage against churn, and 20 supersedes 11 by walking the churn past every degree's threshold.
All twenty-four rendered figures are versioned in [`report-figures/`](report-figures): `01``03` propagation delay (vs degree, vs path length, vs N); `04``09` adversary observation and eclipse (vs `f_adv`, vs degree, and heatmaps); `10``11` reliability under churn (delivery and coverage); `12``15` deanonymization (whole-path and full, vs path length, `f_adv`, and degree); `16``18` linkability over time (time to link vs stake, with redundancy, and time to learn stake vs threshold); `19` the redundancy reliability-vs-anonymity trade-off in probability and `21` the same trade in delivery-vs-time-to-link; `20` the churn-percolation threshold; `22` correlated versus uniform outages; `23``24` cover traffic (the anonymity set against rate and delay, and the emission-quota stake ceiling). Eighteen of the twenty-four are embedded above; the other six (`04``06`, `09`, `11`, `13`) are alternative cuts of data already shown — for instance 11 and 20 both plot coverage against churn, and 20 supersedes 11 by walking the churn past every degree's threshold.

View File

@ -14,6 +14,7 @@ Each run directory holds the three tables the simulator writes: `propagation.par
| `percolation/` | `configs/percolation.yaml` | 800 × 8 = **6 400/cell** | §3.5 — the churn threshold `u_c = 1 1/(degree 1)` |
| `correlated-churn/` | `configs/correlated-churn.yaml` | 800 × 8 = **6 400/cell** | §3.9 — correlated AS/region outages vs uniform churn |
| `fullscale/` | `configs/fullscale.yaml` | 64 × 3 = **192/cell** | §5 — the 10⁶ scaling check (deliberately lighter; not a source of headline numbers) |
| `cover-traffic/` | `configs/cover-traffic.yaml` | 900 s timeline × 4 seeds | §3.10 — blending, mixing, and the emission-quota stake ceiling. Carries a fourth table, `traffic.parquet` |
The linkability results (§3.6§3.7) and both deanonymization rates are closed forms over these
tables rather than separate measurements, so they have no run of their own — `pd.linkability`

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB