-
Notifications
You must be signed in to change notification settings - Fork 239
RngCore::fill_bytes is infallible; hardware RNG failure cannot be surfaced — TryCryptoRng is the fix and needs to be the primary recommended path #2364
Description
Repo: RustCrypto/traits (affects rand_core)
Labels: api-design, rand, hardware, fips
Background
rand_core::RngCore::fill_bytes(&mut self, dest: &mut [u8]) returns ().
For a software PRNG (ChaCha20, DRBG backed by a software seed), this is
fine — filling bytes from a seeded generator cannot fail.
For a hardware entropy source, failure is a normal operational condition,
not a programmer error:
- The hardware may not be ready (power-on self-test still running).
- The entropy pool may be temporarily exhausted (valid in some designs).
- The hardware may report a fault that must be handled — this is precisely what
FIPS 140-3's Continuous Random Bit Generator (CRBG) test is designed to
detect.
rand_core 0.9 added TryCryptoRng with a fallible try_fill_bytes to
address exactly this. We have adopted it, and it solves the problem for our
crate.
What remains
The issue is adoption and discoverability:
1. TryCryptoRng is not the documented primary interface for hardware RNG
backends. The rand_core documentation and ecosystem treat it as an
advanced feature. A developer writing a new hardware entropy driver will reach
for RngCore first and implement fill_bytes with a panic or a silent
discard of errors, because that is what the documentation implies.
2. Key generation APIs still take impl CryptoRng, not impl TryCryptoRng.
For example:
// In signature crates:
pub fn generate(rng: &mut impl CryptoRng) -> Self;
// In KeyInit:
pub fn generate(rng: &mut impl CryptoRng) -> Self;A hardware RNG backend correctly implements TryCryptoRng but has no
CryptoRng blanket impl (or the blanket impl panics on failure, defeating the
purpose). Key generation from a hardware source that can fail cannot propagate
errors through these APIs.
In our codebase (discovered while implementing wolfcrypt, a RustCrypto backend wrapping wolfCrypt — a FIPS 140-3 validated C cryptographic library with hardware dispatch via WOLF_CRYPTO_CB):
Our WolfRng type implements TryCryptoRng. The fill_bytes implementation
is forced to assert! because RngCore::fill_bytes returns (), and the code
comment explicitly documents why:
"RNG failure is unrecoverable" as a direct consequence of the trait signature
What we are asking for
-
Document
TryCryptoRngas the required interface for hardware entropy
sources, not just an optional extra. A hardware RNG backend that
implements onlyRngCore::fill_byteswith a panic is not a correct
implementation; this should be stated clearly. -
Audit key generation entry points —
KeyInit::generate,
SigningKey::generate, and similar — and addTryCryptoRng-accepting
variants so that hardware entropy sources can propagate failures through key
generation without panicking. -
Apply the same
Try*pattern todigest::UpdateandMac(see
companion Issue 9) to complete the hardware-dispatch story: if entropy,
hashing, and MACing can all fail and propagate errors, a hardware-backed
crypto pipeline becomes first-class.
Prior art
rand_core0.9:TryCryptoRng/try_fill_bytes— already shipped; this
is exactly the right design.embedded-hal1.0: fallibletype Erroron all peripheral traits, including
RNG.embedded-hal-async: async + fallible, showing the pattern composes with
async hardware dispatch.