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