Files
archy/core
archipelagoandClaude Opus 5 09a1f7621c feat(10-06): name every entropy source and guard key draws (KEY-05 a/d)
Closes F-10a. Nothing here fixes a present defect: on the pinned rand
0.8.5, rand::random() and thread_rng() both resolve to a ChaCha12 CSPRNG
seeded from getrandom(2). What they lack is a STATED backend — it is
fixed by dependency and build configuration rather than by the calling
code, with no compile error if that changes. That is the structural
shape behind the 2026-07-30 COLDCARD entropy defect, and here the blast
radius includes Cashu blinded-key-exchange values, X3DH prekey material,
session bearer tokens and a ChaCha20-Poly1305 nonce.

Layer (a) — every production key, nonce and token draw now names
rand::rngs::OsRng at its own call site. The mnemonic seam is bound to
entropy::KeyGenRng, a SEALED allowlist whose supertrait lives in a
private module, so the set of RNGs that can drive the master key
hierarchy is exactly what one file says it is. This retires the false
promise at seed.rs:656: rand::CryptoRng is a marker with no
compiler-checked content, and the crate now contains zero impls of it.

Layer (d) — key material and AEAD nonces of >=12 bytes run a
degenerate-entropy predicate that refuses all-zero, all-identical and
wrapping +/-1 counter draws. Nothing heuristic: no entropy estimator, no
chi-squared. Each of the three shapes has a false-positive probability
computable in closed form (3 * 2^-88 at 12 bytes, 3 * 2^-248 at 32), and
a predicate whose false-positive rate cannot be computed cannot be
argued safe on a key-generation path. There is deliberately no retry — a
retry would paper over the broken RNG this exists to surface.

Layer (e) — the kernel-CSPRNG readiness verdict at master-seed
generation is now durable (backlog R-09). It was previously computed,
logged and thrown away, so a node could never answer after the fact
whether its keys were born from a seeded pool. The record holds a schema
version, timestamp, verdict and event name — no entropy, no key bytes.

Formats and wire shapes are proven unchanged rather than asserted:
storage_crypto and the credential store each open a HARDCODED
pre-migration ciphertext vector (a same-process round trip would pass
even if the envelope had changed), the vector was produced by an
independent RFC 8439 implementation so it pins the documented
nonce||ciphertext format rather than this implementation's output, and
the x3dh prekey bundle and bdhke values keep their field set and order.

totp.rs migrates its SOURCE only: the % charset.len() reduction and the
32-char charset are untouched. The bias there is presently zero (32
divides 256) and fixing the latent bias is R-12, which stays deferred.

Verified: cargo build clean; cargo test -p archipelago 1068 passed,
2 failed. Both failures are container::boot_reconciler timing tests
(second_pass_fires_after_interval, shutdown_terminates_loop) in a file
this change does not touch — pre-existing, not caused here.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-02 16:27:34 -04:00
..
2026-01-24 22:59:20 +00:00
2026-01-24 22:59:20 +00:00