Skip to main content

osom_lib_entropy_cprng/
cprng_entropy.rs

1//! Holds the implementation of the CPRNG entropy generator.
2
3use core::convert::Infallible;
4
5use osom_lib_entropy::{
6    std::StdEntropyGenerator,
7    traits::{EntropyConcreteGenerator, EntropyGenerator},
8};
9use osom_lib_prng::traits::{CryptographicallySecure, PRNGenerator, Seedable};
10use osom_lib_reprc::macros::reprc;
11use osom_lib_try_clone::TryClone;
12
13/// Represents a generic entropy generator, which generates randomness
14/// from a cryptographically secure PRNG, but is seed from the actual
15/// OS entropy.
16#[reprc]
17#[repr(transparent)]
18#[derive(Clone)]
19pub struct CPRNGEntropy<TPrng>
20where
21    TPrng: PRNGenerator + CryptographicallySecure + Seedable<u128>,
22{
23    cprng: TPrng,
24}
25
26impl<TPrng> TryClone for CPRNGEntropy<TPrng>
27where
28    TPrng: PRNGenerator + CryptographicallySecure + Seedable<u128> + TryClone,
29{
30    type Error = <TPrng as TryClone>::Error;
31
32    fn try_clone(&self) -> Result<Self, Self::Error> {
33        let cprng = self.cprng.try_clone()?;
34        Ok(Self { cprng })
35    }
36}
37
38impl<TPrng> CPRNGEntropy<TPrng>
39where
40    TPrng: PRNGenerator + CryptographicallySecure + Seedable<u128>,
41{
42    /// Creates a new instance of [`CPRNGEntropy`]
43    ///
44    /// # Errors
45    ///
46    /// These get propagated from [`StdEntropyGenerator`] when
47    /// generating a new seed fails.
48    pub fn new() -> Result<Self, <StdEntropyGenerator as EntropyGenerator>::Error> {
49        let mut entropy = StdEntropyGenerator::new();
50        let seed = entropy.generate::<u128>()?;
51        let cprng = TPrng::with_seed(seed);
52        Ok(Self { cprng })
53    }
54
55    /// Generates a new random item.
56    #[allow(clippy::missing_panics_doc)]
57    #[inline(always)]
58    pub fn generate<T: EntropyConcreteGenerator<CPRNGEntropy<TPrng>>>(&mut self) -> T {
59        // We explicitly specify the type here, so that unwrap() actually is valid.
60        // This is a safeguard against potential future modifications to Error type.
61        let result: Result<T, Infallible> = <Self as EntropyGenerator>::generate::<T>(self);
62        result.unwrap()
63    }
64}
65
66impl<TPrng> EntropyGenerator for CPRNGEntropy<TPrng>
67where
68    TPrng: PRNGenerator + CryptographicallySecure + Seedable<u128>,
69{
70    /// [`CPRNGEntropy`] cannot fail at randomness generation.
71    type Error = Infallible;
72
73    unsafe fn fill_raw(&mut self, buffer_ptr: *mut u8, buffer_len: usize) -> Result<(), Infallible> {
74        unsafe {
75            self.cprng.fill_raw(buffer_ptr, buffer_len);
76        }
77        Ok(())
78    }
79}
80
81#[inline]
82fn generate_random_t<T: Copy, TGen: EntropyGenerator>(gene: &mut TGen) -> Result<T, TGen::Error> {
83    let mut item = core::mem::MaybeUninit::<T>::uninit();
84    let item_ptr = item.as_mut_ptr();
85    let slice = unsafe { core::slice::from_raw_parts_mut(item_ptr.cast::<u8>(), size_of::<T>()) };
86    gene.fill(slice)?;
87    Ok(unsafe { item.assume_init() })
88}
89
90impl<const N: usize, TPrng> EntropyConcreteGenerator<CPRNGEntropy<TPrng>> for [u8; N]
91where
92    TPrng: PRNGenerator + CryptographicallySecure + Seedable<u128>,
93{
94    #[inline(always)]
95    fn generate(generator: &mut CPRNGEntropy<TPrng>) -> Result<Self, <CPRNGEntropy<TPrng> as EntropyGenerator>::Error> {
96        if N == 0 {
97            return Ok([0u8; N]);
98        }
99        generate_random_t(generator)
100    }
101}
102
103macro_rules! concrete {
104    ( $t: ty ) => {
105        impl<TPrng> EntropyConcreteGenerator<CPRNGEntropy<TPrng>> for $t
106        where
107            TPrng: PRNGenerator + CryptographicallySecure + Seedable<u128>
108        {
109            #[inline(always)]
110            fn generate(generator: &mut CPRNGEntropy<TPrng>) -> Result<Self, <CPRNGEntropy<TPrng> as EntropyGenerator>::Error>
111            {
112                generate_random_t(generator)
113            }
114        }
115    };
116    ( $t: ty, $($ts:ty),* $(,)?) => {
117        concrete!($t);
118        concrete!($($ts),*);
119    };
120}
121
122concrete!(i16, u16, i32, u32, i64, u64, i128, u128, usize, isize);