aescrypt_rs/crypto/
rng.rs

1// src/crypto/rng.rs
2//! Ultra-high-performance secure randomness for fixed-size secrets
3//!
4//! Adds `T::random()` to every `fixed_alias!` type (Aes256Key, Iv16, RingBuffer64, …)
5//! using a thread-local `OsRng` → first call ~80 µs, every subsequent call < 80 ns.
6//!
7//! This is the fastest safe design possible in modern Rust.
8
9use rand::{rngs::OsRng, TryRngCore};
10use secure_gate::Fixed;
11use std::cell::RefCell;
12
13/// Extension trait – gives `.random()` to all fixed-size secret types
14pub trait SecureRandomExt {
15    /// Generate a cryptographically secure random instance of this type
16    fn random() -> Self;
17}
18
19// Thread-local OsRng wrapped in RefCell so we can mutably borrow it
20thread_local! {
21    static RNG: RefCell<OsRng> = const { RefCell::new(OsRng) };
22}
23
24/// Blanket impl – every `Fixed<[u8; N]>` (i.e. every `fixed_alias!` type) gets `.random()`
25impl<const N: usize> SecureRandomExt for Fixed<[u8; N]> {
26    #[inline(always)]
27    fn random() -> Self {
28        RNG.with(|rng_cell| {
29            let mut rng = rng_cell.borrow_mut();
30            let mut bytes = [0u8; N];
31            let _ = rng.try_fill_bytes(&mut bytes); // RngCore::fill_bytes is the correct, infallible method
32            Fixed::new(bytes)
33        })
34    }
35}
36
37// ---------------------------------------------------------------------------
38// Optional manual RNG type (almost never needed – just use T::random())
39// ---------------------------------------------------------------------------
40
41#[derive(Debug, Clone)]
42pub struct SecureRng(OsRng);
43
44impl SecureRng {
45    #[inline(always)]
46    pub fn new() -> Self {
47        Self(OsRng)
48    }
49
50    #[inline(always)]
51    pub fn fill<T>(&mut self, dest: &mut T)
52    where
53        T: AsMut<[u8]>,
54    {
55        let _ = self.0.try_fill_bytes(dest.as_mut());
56    }
57}
58
59impl Default for SecureRng {
60    #[inline(always)]
61    fn default() -> Self {
62        Self::new()
63    }
64}