Module pool

Module pool 

Source
Expand description

Persisted entropy pool: a flash-seeded, hash-ratcheted CSPRNG.

The pool exists for platforms whose hardware entropy source is not always available — on the ESP32 the TRNG is only trustworthy while the RF subsystem is up, which used to chain the RNG’s lifetime to the BLE controller’s. A seed stored in flash breaks that chain: the pool is cryptographically strong from the first instruction of boot, and the hardware source becomes something it harvests when available rather than something it dies without.

§The seed-file protocol (Fortuna’s, with a lazy write)

  1. Read the stored seed S and build the pool with EntropyPool::from_seed. The working key is HKDF(S, salt) with per-boot salt (chip id, reset reason) — flash never holds the working key, and a flash image taken later reveals nothing about this session’s outputs.
  2. Before the first draw, write next_seed to flash and, once the write is confirmed, call seed_committed.
  3. Draw. draw refuses until step 2 has happened — that ordering is the whole crash-safety story. A boot that dies before the commit replays a working key that never emitted a byte, which is harmless; a boot that dies after it ratchets forward next time. No boot counter is needed.

The write is deliberately lazy: nothing touches flash until something actually wants randomness, so a reboot loop that dies before its first draw costs zero flash cycles.

§Mixing

mix folds harvested entropy into the working key whenever a hardware source happens to be live. Mixing is what heals a compromised or cloned seed file, so callers should persist a fresh next_seed afterwards — but mixing never invalidates the commit, because replay safety comes from the boot-time ratchet, not from the stored seed tracking the live key.

§Construction

Everything is HKDF-SHA256 over the platform’s Sha256Provider; there is no stream cipher because every consumer wants a small seed or nonce, not a keystream. Each draw ratchets the working key one-way, so compromising the pool later reveals nothing already emitted. Domain separation comes from distinct info strings plus the caller’s label as HKDF salt.

Structs§

DrawBeforeCommit
A draw was attempted before the next seed was committed to storage.
EntropyPool
The pool: a 32-byte working key that only ever moves forward.