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}