From 25d6463c233ca879487c2665c5fb6ccc4a4b8e52 Mon Sep 17 00:00:00 2001 From: Marcin Pawlowski Date: Wed, 5 Aug 2026 14:50:41 +0200 Subject: [PATCH] Check in the evidence behind the pd report The simulator gitignores its runs/ directory, so every table and figure in reports/blend/pd rested on data that existed only on one machine. This adds the sweep outputs of record under reports/blend/pd/data -- one directory per study, 1 MB total -- so any number can be checked against its source, or challenged, without re-running hours of compute. report_numbers.py comes with them: run it and it prints every value the report quotes together with its across-topology standard error, straight from these parquets. It reproduces the report tables exactly. Kept: default (8000 rounds/cell), redundancy (9600), percolation (6400), correlated-churn (6400), fullscale (192, the deliberately lighter 1e6 check). Omitted: the smoke runs, and an earlier 144-rounds/cell redundancy grid whose sampling error produced a non-monotonic delivery curve -- superseded, and the reason the kept grid samples 9600. Co-Authored-By: Claude Opus 5 (1M context) --- reports/blend/pd/README.md | 2 + reports/blend/pd/data/README.md | 43 ++++++ .../data/correlated-churn/adversary.parquet | Bin 0 -> 9539 bytes .../pd/data/correlated-churn/deanon.parquet | Bin 0 -> 8832 bytes .../data/correlated-churn/propagation.parquet | Bin 0 -> 72898 bytes .../blend/pd/data/default/adversary.parquet | Bin 0 -> 143761 bytes reports/blend/pd/data/default/deanon.parquet | Bin 0 -> 240845 bytes .../blend/pd/data/default/propagation.parquet | Bin 0 -> 317959 bytes .../blend/pd/data/fullscale/adversary.parquet | Bin 0 -> 17275 bytes .../blend/pd/data/fullscale/deanon.parquet | Bin 0 -> 13483 bytes .../pd/data/fullscale/propagation.parquet | Bin 0 -> 27594 bytes .../pd/data/percolation/adversary.parquet | Bin 0 -> 10279 bytes .../blend/pd/data/percolation/deanon.parquet | Bin 0 -> 9048 bytes .../pd/data/percolation/propagation.parquet | Bin 0 -> 47553 bytes .../pd/data/redundancy/adversary.parquet | Bin 0 -> 15396 bytes .../blend/pd/data/redundancy/deanon.parquet | Bin 0 -> 26725 bytes .../pd/data/redundancy/propagation.parquet | Bin 0 -> 68417 bytes reports/blend/pd/data/report_numbers.py | 131 ++++++++++++++++++ 18 files changed, 176 insertions(+) create mode 100644 reports/blend/pd/data/README.md create mode 100644 reports/blend/pd/data/correlated-churn/adversary.parquet create mode 100644 reports/blend/pd/data/correlated-churn/deanon.parquet create mode 100644 reports/blend/pd/data/correlated-churn/propagation.parquet create mode 100644 reports/blend/pd/data/default/adversary.parquet create mode 100644 reports/blend/pd/data/default/deanon.parquet create mode 100644 reports/blend/pd/data/default/propagation.parquet create mode 100644 reports/blend/pd/data/fullscale/adversary.parquet create mode 100644 reports/blend/pd/data/fullscale/deanon.parquet create mode 100644 reports/blend/pd/data/fullscale/propagation.parquet create mode 100644 reports/blend/pd/data/percolation/adversary.parquet create mode 100644 reports/blend/pd/data/percolation/deanon.parquet create mode 100644 reports/blend/pd/data/percolation/propagation.parquet create mode 100644 reports/blend/pd/data/redundancy/adversary.parquet create mode 100644 reports/blend/pd/data/redundancy/deanon.parquet create mode 100644 reports/blend/pd/data/redundancy/propagation.parquet create mode 100644 reports/blend/pd/data/report_numbers.py diff --git a/reports/blend/pd/README.md b/reports/blend/pd/README.md index ceb9784..b2204ca 100644 --- a/reports/blend/pd/README.md +++ b/reports/blend/pd/README.md @@ -335,6 +335,8 @@ The simulator, configs, and analytic checks live in [`tools/simulators/blend/pd` 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/`. +The **evidence** is checked in too: [`data/`](data) holds the sweep outputs behind every table and figure, one directory per study, with [`data/report_numbers.py`](data/report_numbers.py) regenerating every quoted value together with its standard error directly from them. Any number in this report can therefore be checked against its source without re-running the sweeps — see [`data/README.md`](data/README.md) for what each run is and how it was sampled. + ## 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. diff --git a/reports/blend/pd/data/README.md b/reports/blend/pd/data/README.md new file mode 100644 index 0000000..20b0f1f --- /dev/null +++ b/reports/blend/pd/data/README.md @@ -0,0 +1,43 @@ +# Evidence of record + +The sweep outputs behind every number in [the report](../README.md). The simulator does not commit +its own `runs/` directory — these are the copies of record, kept so that any figure or table can be +re-derived, or challenged, without re-running hours of compute. + +Each run directory holds the three tables the simulator writes: `propagation.parquet`, +`adversary.parquet` and `deanon.parquet`. + +| directory | config | sampling | backs | +|---|---|---|---| +| `default/` | `configs/default.yaml` | 1 000 rounds × 8 seeds = **8 000/cell** | §3.1–§3.5 — delay, observation, eclipse, deanonymization, delivery, coverage | +| `redundancy/` | `configs/redundancy.yaml` | 1 200 × 8 = **9 600/cell** | §3.8 — messaging redundancy R = 1…4 | +| `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) | + +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` +derives them and `make verify` checks them against Monte-Carlo. + +## Regenerating the report's numbers + +``` +python report_numbers.py +``` + +prints every quoted value with its across-topology standard error, straight from the parquets here. +That is the fastest way to check a table in the report against its evidence. It takes optional +paths (`report_numbers.py `) if you want to point it at fresh +runs instead. + +## Regenerating the data itself + +From [`tools/simulators/blend/pd`](../../../../tools/simulators/blend/pd): `make sweep`, +`make redundancy`, `make percolation`, `make correlated-churn`, `make sweep-fullscale`. Results +land in that simulator's `runs/_