Architecture
ActiveOverview
Two Rust crates. The first holds the threat model, the geometry, the estimator and the detector, and has no dependencies at all. The second adds real ephemeris: it loads two-line element sets, propagates them with SGP4, and converts the result into the local frame the first crate estimates in.
The split is the main architectural decision. It exists so the central claim — that a uniform timing offset produces zero displacement — can be verified on any machine with a Rust toolchain, with no crates to resolve, no network, and no version drift. Everything that needs the outside world is quarantined in the second crate.
Components
| Component | Responsibility | Implementation | Artifact |
|---|---|---|---|
geometry | ENU frame, line-of-sight, geometry matrix , HDOP, Cramér–Rao resolution | threat-model/src/geometry.rs | CODE-001 |
adversary | Classes A3 to A6 behind a trait, plus an honest baseline | threat-model/src/adversary.rs | CODE-001 |
estimator | Gauss–Newton solve for | threat-model/src/estimator.rs | CODE-001 |
detector | Density-based relay detection, per-cell quota, terminal-count bound | threat-model/src/detector.rs | CODE-001 |
rng | Seeded xorshift64* with Box–Muller | threat-model/src/rng.rs | CODE-001 |
linalg | 3×3 inverse and least squares | threat-model/src/linalg.rs | CODE-001 |
constellation | Walker-delta fallback, dependency-free | threat-model/src/constellation.rs | CODE-001 |
ephemeris | TLE loading, SGP4, TEME→ECEF→ENU, visibility, diverse selection | ephemeris/src/lib.rs | CODE-002 |
Artifact identifiers are provisional; the code is not yet registered under artifacts.
Interfaces
| Between | Contract | Format | Failure mode |
|---|---|---|---|
ephemeris → threat-model | Vec<Satellite> in the site’s local ENU frame, position and velocity in metres | In-process | Fewer than three satellites: estimator returns Underdetermined rather than a wrong fix |
| Adversary → detector | Vec<Session>, each a set of pseudoranges plus ground truth for scoring | In-process | Ground truth is never visible to the detector, only to the scorer |
| Evaluation → paper | Eight CSVs | CSV | Only eval-relay.csv is consumed automatically, by pgfplots at LaTeX compile time |
| CelesTrak → archive | Three-line TLE | Text | Rate-limited with HTTP 403 and a plain-text body; archived rather than fetched at run time |
The last row is deliberate. Nothing fetches at run time, so a result is reproducible from the repository alone.
Technology choices
| Decision | Chosen | Rejected | Reason |
|---|---|---|---|
| Core crate dependencies | None | nalgebra for linear algebra | Three unknowns means a hand-rolled 3×3 inverse is clearer and removes the last barrier to reproducing the central theorem |
| Randomness | Hand-rolled xorshift64* + Box–Muller | rand crate | A seed must reproduce identical noise across machines and across dependency updates. A crate bump could silently change results |
| Propagator | sgp4 crate | Hand-rolled SGP4 | SGP4 is intricate and getting it subtly wrong would invalidate everything downstream. Validated against a known reference before use |
| Element set | CelesTrak supplemental GP, archived | Live fetch at run time | Reproducibility. Also CelesTrak rate-limits, so a live fetch is not reliable |
| Constellation model | Real TLEs | Walker-delta from published shell parameters | Used the Walker model while CelesTrak was unreachable; replaced it as soon as real elements were available. Retained as a dependency-free fallback |
| Link selection | select_diverse, greedy max-min angular separation | Six highest-elevation satellites | 2.7× better median HDOP. High satellites cluster near zenith and leave ill-conditioned |
| Relay detection | Density over a neighbourhood | Fixed grid of pitch | The grid fragments a real cluster: 45 of 200 relayed identities in the modal cell |
| Figure generation | pgfplots reading CSV at compile time | Exported image | A figure that reads its own data cannot silently disagree with it |
Reproducibility
Every component that produces a reported number lives in one repository at a known commit. A run is fully determined by three things: the archived element set, the seed, and the source constants. There is no wall-clock dependence and no network access at run time.
| Component | Repository | Pin |
|---|---|---|
threat-model | und-phd/fall26 | 12dbcc9 |
ephemeris | und-phd/fall26 | 12dbcc9 |
| Element set (primary) | ephemeris/data/starlink-supplemental-20260829.tle | 10,734 elements, median epoch 2026-08-29 21:17:42 UTC |
| Element set (cross-check) | ephemeris/data/starlink-gp-20260830.tle | 10,731 elements, median epoch 2026-08-30 06:08:36 UTC |
| Seed | — | 20271002 |
Operating instructions are in SIMULATION.md at the repository root.