Skip to content

esp32_rng

The ESP32’s hardware random number generator.

One register. Each read returns a fresh 32-bit value.

This matters more than the API does, because reading the register and assuming the result is unpredictable is a security bug that looks exactly like working code.

The RNG harvests entropy from the RF subsystem’s thermal noise and, failing that, from an internal fast oscillator sampled against the slower RTC clock. Espressif’s own guidance is that the output is only suitable for cryptographic use when the WiFi or Bluetooth radio is running. FlintOS does not bring up the radio (see #36), so on this kernel today:

  • Fine for a random backoff, a jittered retry, a test seed, a nonce whose only requirement is “usually different”.
  • Not fine for a key, a token, or anything an attacker benefits from guessing.

The distinction is deliberately not hidden behind a comforting name. [read_u32] says what it does; nothing here is called secure_random.

Register from the ESP32 TRM chapter 24 and esp-idf’s esp_random(), which reads the same address.

fn fill(buf: &mut [u8])

Fill buf with random bytes.

Safe: reads the generator as [read_u32] does. See the module docs on entropy quality.

fn fill_from<impl FnMut() -> u32>(next: impl FnMut, buf: &mut [u8])

Fill buf from an arbitrary 32-bit source.

Split out from [fill] so the chunking can be tested on a host. The register read cannot be, but the part that actually goes wrong — the tail shorter than a word — can, and does in most hand-written versions of this.

fn read_u32() -> u32

One 32-bit value from the hardware generator.

Safe: a side-effect-free read of a fixed, always-mapped register that needs nothing enabled or owned. See the module docs before trusting the value with a secret — that is a quality concern, not a soundness one.

const RNG_DATA_REG: u32;

WDEV_RND_REG. Reads return a new value each time; there is nothing to configure and nothing to enable.