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()/OsRngcall site to thread anArc<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_protocolitself.
§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 togetrandomand therefore to the OS’s CSPRNG on every supported target.
Traits§
- RngProvider
- Source of cryptographically secure random bytes.