docs(10): correct F-10a's own overstatement — x3dh sites are identifiers, not key material

The F-10a scope correction committed hours earlier asserted semantics its
evidence did not support. The KEY-05 planner caught it against the code:

- mesh/x3dh.rs:100/:114 are u32 prekey IDENTIFIERS (spk_id, otk_id), not key
  agreement material. The X25519 secrets come from
  crypto::generate_x25519_ephemeral() at :99/:113 and were never in scope.
- session.rs's 16 raw matches read as 16 production token sites; #[cfg(test)]
  begins at :470, so it is 4 production + 12 test.
- wallet/bdhke.rs is 2 production of 4 (#[cfg(test)] at :143) — and those two
  ARE genuine key material: generate_secret() :133 and
  random_blinding_factor() :139.

The Medium rating still holds, on narrower grounds: bdhke's two production
sites plus storage_crypto.rs:39's AEAD nonce. It no longer rests on x3dh.

Struck rather than silently rewritten. F-10 was corrected on the grounds that
understatement misleads the next reader; overstatement does the same, and this
table managed both within a day.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
archipelago
2026-08-02 07:30:43 -04:00
co-authored by Claude Opus 5
parent dba3a30af9
commit 90ce4bcc46
3 changed files with 32 additions and 12 deletions
+3 -2
View File
@@ -110,8 +110,9 @@ those are marked ✅ below with the commit that did it, so we stop re-litigating
- [ ] **Crate-wide CSPRNG enforcement — a defaulted RNG cannot be inherited anywhere**
(entropy audit **R-16 / F-10a**, Medium) — tracked as **KEY-05 in Phase 10**, so plan
and execute it there rather than as a standalone item. `session.rs` (16 sites),
`pine_ha.rs` (6), `wallet/bdhke.rs` (4**ecash key material**), `mesh/x3dh.rs` (2 —
**key-agreement material**), `storage_crypto.rs` (1 — **AEAD nonce**), +10 more files.
`pine_ha.rs` (6), `wallet/bdhke.rs` (2 prod — **Cashu proof secret + blinding factor,
genuine key material**), `storage_crypto.rs` (1 — **AEAD nonce**), `mesh/x3dh.rs` (2 —
prekey *identifiers*, **not** key material — corrected 2026-08-02), +10 more files.
Nothing is broken today (`rand::random()`/`thread_rng()` are ChaCha12 from
`getrandom(2)`), but it is the T1 shape that produced the COLDCARD defect, now with key
material in the blast radius. Five layers: sealed allowlist trait at key-gen seams;
+28 -9
View File
@@ -157,7 +157,7 @@ action of the "your seed may be predictable, migrate now" kind is warranted —
| F-08 | **Low** | 24-word master mnemonic persisted in browser `sessionStorage` during onboarding | `neode-ui/src/views/OnboardingSeedGenerate.vue:330` |
| F-09 | **Low** | Modulo bias in TOTP backup-code generation | `core/archipelago/src/totp.rs:305` |
| F-10 | **Low****see F-10a** | Container `generated_secrets` use `thread_rng()` rather than an explicit `OsRng` (same T1 shape as F-02, smaller blast radius) | `core/archipelago/src/container/secrets.rs:92`, `:101` |
| F-10a | **Medium** | **Scope correction to F-10 (2026-08-02):** the defaulted-RNG surface is crate-wide — **41 call sites across 15 files**, not 2 — and includes ecash and X3DH key material | `core/archipelago/src/session.rs` (16), `wallet/bdhke.rs` (4), `mesh/x3dh.rs` (2), `storage_crypto.rs`, +11 more — full table in §F-10a |
| F-10a | **Medium** | **Scope correction to F-10 (2026-08-02):** the defaulted-RNG surface is crate-wide — **41 raw matches across 15 files**, not 2 — and includes ecash key material and an AEAD nonce | `core/archipelago/src/wallet/bdhke.rs:133`,`:139` (Cashu secret + blinding factor), `storage_crypto.rs:39` (nonce), `session.rs` (4 prod), +12 more files — full table in §F-10a |
| F-11 | **Informational** | `Math.random()` inside a seed-handling view (benign — UX challenge selection only) | `neode-ui/src/views/OnboardingSeedVerify.vue:159` |
| F-12 | **Informational** | Identical default OS credentials on every flashed node | `image-recipe/archipelago-scripts/install-to-disk.sh:205` |
| F-13 | **High** | BIP-84 account **private** key is imported into Bitcoin Core's wallet, duplicating the spending key outside the encrypted envelope | `core/archipelago/src/api/rpc/bitcoin.rs:203`, `:229-231` |
@@ -502,10 +502,10 @@ already-remediated F-02 file, leaving **41 matches across 15 files**:
| File | Matches | Generates |
|---|---|---|
| `core/archipelago/src/session.rs` | 16 | session tokens |
| `core/archipelago/src/session.rs` | 16 **4 prod + 12 test** | session tokens (`#[cfg(test)]` begins `:470`) |
| `core/archipelago/src/api/rpc/package/pine_ha.rs` | 6 | app credentials |
| `core/archipelago/src/wallet/bdhke.rs` | 4 | **Cashu blinded-key-exchange values — key material** |
| `core/archipelago/src/mesh/x3dh.rs` | 2 | **X3DH key agreement — key material** |
| `core/archipelago/src/wallet/bdhke.rs` | 4 **2 prod + 2 test** | **Cashu proof secret (`generate_secret`, `:133`) and blinding factor (`random_blinding_factor`, `:139`) — genuine key material** (`#[cfg(test)]` begins `:143`) |
| `core/archipelago/src/mesh/x3dh.rs` | 2 | ~~X3DH key agreement — key material~~ **CORRECTED: `u32` prekey *identifiers*** (`spk_id` `:100`, `otk_id` `:114`). The X25519 secrets come from `crypto::generate_x25519_ephemeral()` at `:99`/`:113` and are **not** in this table |
| `core/archipelago/src/container/secrets.rs` | 2 | `generated_secrets` (the original F-10) |
| `core/archipelago/src/api/rpc/package/install.rs` | 2 | install-time secrets |
| `core/archipelago/src/storage_crypto.rs` | 1 | **ChaCha20-Poly1305 nonce — reuse breaks the AEAD** |
@@ -519,16 +519,35 @@ already-remediated F-02 file, leaving **41 matches across 15 files**:
| `core/archipelago/src/api/rpc/auth.rs` | 1 | auth-path material |
**Per-site production-vs-test classification is deliberately NOT asserted here** — it is the
first task of the remediation, not an assumption of this correction. The counts above are raw
matches.
first task of the remediation (KEY-05 Task 1), not an assumption of this correction. The counts
above are raw matches.
> **Self-correction, 2026-08-02 (same day, before any KEY-05 work began).** The first version of
> this table asserted semantics in its right-hand column that two entries did not support, and
> the KEY-05 planner caught it against the code. Both are fixed inline above, struck rather than
> silently rewritten:
> - **`mesh/x3dh.rs` was wrong.** Called "X3DH key agreement — key material"; the two sites are
> `u32` prekey *identifiers*. The X25519 secrets are drawn elsewhere and were never in scope.
> - **`session.rs` was misleading.** 16 raw matches read as 16 production token sites; it is 4
> production and 12 test.
>
> **The Medium rating still holds, on narrower grounds.** It now rests on `wallet/bdhke.rs`'s two
> production sites (the Cashu proof secret and the blinding factor — a predictable blinding
> factor breaks the ecash unlinkability guarantee and is genuinely key material) and on
> `storage_crypto.rs:39`'s AEAD nonce. It does **not** rest on x3dh. Recorded because the
> correction to F-10 was made on the grounds that understatement misleads the next reader —
> overstatement does exactly the same, and this table did both within one day.
**Assessment.** Unchanged from F-10 in kind: `rand::random()` and `thread_rng()` are backed by
ChaCha12 seeded from `getrandom(2)` on `rand 0.8.5`, so **nothing in this table is broken
today**. What changes is the *blast radius* of the T1 structural objection. F-10 rated this Low
on the basis of "per-app credentials rather than the master key hierarchy". That justification
does not survive the true scope: `wallet/bdhke.rs` and `mesh/x3dh.rs` generate key material, and
`storage_crypto.rs:39` draws an AEAD nonce, where a silent rebinding to a non-cryptographic PRNG
would be catastrophic rather than merely undesirable. Re-rated **Medium**.
does not survive the true scope: `wallet/bdhke.rs:133`/`:139` generate the Cashu proof secret and
blinding factor — genuine key material, where a predictable blinding factor breaks ecash
unlinkability — and `storage_crypto.rs:39` draws an AEAD nonce, where a silent rebinding to a
non-cryptographic PRNG would be catastrophic rather than merely undesirable. Re-rated **Medium**
on those two grounds. (An earlier version of this sentence also cited `mesh/x3dh.rs`; that was
incorrect and is struck in the table above — those sites are prekey identifiers.)
**Why the original audit missed it.** F-10 was reached by tracing the *manifest secrets* path
(secret class 4). No step enumerated defaulted-RNG use across the whole crate independently of