Skip to main content

Module rng

Module rng 

Source
Expand description

RngProvider — the indirection through which Phantom Protocol obtains cryptographic randomness. Default is OsRng, which delegates to getrandom::getrandom and therefore picks up the platform’s CSPRNG on every supported target (Linux getrandom(2), macOS / iOS CCRandomGenerateBytes, Windows BCryptGenRandom, wasm32 via the js feature → crypto.getRandomValues, etc.).

Embedders can swap in their own provider by implementing this trait and threading it into the relevant _with_provider entry points (the HybridSigningKey::generate_with_provider demonstration is wired up in this commit; the rest of the crate continues to call the OsRng-using default until a follow-up sweep lifts the abstraction through every call site).

§Phase 3.8 scope (this commit)

Trait + default OsRng impl + tests. No new crate dependencies (this module uses only what already ships in Cargo.toml).

What is intentionally NOT in scope here:

  • Refactoring every existing thread_rng() / OsRng call site to thread an Arc<dyn RngProvider> through the codebase. That sweep is a follow-up.
  • A real NIST SP 800-90A DRBG (e.g., HMAC-DRBG). The trait is shaped to accept one, but the impl itself is Phase 5 (FIPS) work.
  • A hardware-RNG impl. Those are inherently target-specific and belong in a downstream HAL adapter crate, not in phantom_protocol itself.

§Slotting in alternative providers

§Hardware TRNG on embedded

On microcontrollers exposing a true-RNG peripheral (e.g., the STM32 RNG, the nRF52 RNG, RP2040 ROSC, …), the HAL crate typically exposes a blocking reader (embedded_hal::blocking::rng::Read or the rand_core::RngCore impl that newer HALs wrap it in). A downstream adapter looks roughly like:

use phantom_protocol::crypto::rng::RngProvider;
use core::sync::atomic::AtomicBool;
use spin::Mutex;          // or critical_section::Mutex on no_std-no-alloc

pub struct HwRng<R> {
    inner: Mutex<R>,
}

impl<R> HwRng<R> {
    pub fn new(peripheral: R) -> Self {
        Self { inner: Mutex::new(peripheral) }
    }
}

impl<R> RngProvider for HwRng<R>
where
    R: rand_core::RngCore + Send + 'static,
{
    fn fill_bytes(&self, dest: &mut [u8]) {
        self.inner.lock().fill_bytes(dest);
    }
}

The Mutex is needed because fill_bytes takes &self. A real HAL adapter should also surface health-test failures from the peripheral (most TRNGs have a stuck-bit / continuous-test register) rather than returning silently-biased bytes.

§NIST-approved DRBG in FIPS mode

Phase 5 will add an internal HmacDrbg (SP 800-90A § 10.1.2) keyed from getrandom at boot and re-seeded on a request / time interval per SP 800-90A § 9. The skeleton:

use phantom_protocol::crypto::rng::RngProvider;
use std::sync::Mutex;

pub struct HmacDrbg { /* V, Key, reseed_counter, ... */ }
impl HmacDrbg {
    pub fn from_entropy() -> Self { /* seed from getrandom */ todo!() }
    fn generate(&mut self, out: &mut [u8]) { /* SP 800-90A 10.1.2.5 */ todo!() }
}

pub struct FipsDrbg(Mutex<HmacDrbg>);
impl RngProvider for FipsDrbg {
    fn fill_bytes(&self, dest: &mut [u8]) {
        self.0.lock().expect("DRBG poisoned").generate(dest);
    }
}

See docs/compliance/fips-readiness.md for the larger picture.

§Deterministic test fixture

See tests::CounterRng below for a tiny in-tree example.

Structs§

OsRng
Default RngProvider — delegates to getrandom and therefore to the OS’s CSPRNG on every supported target.

Traits§

RngProvider
Source of cryptographically secure random bytes.