Skip to main content

osom_lib_entropy/std/
mod.rs

1//! Holds the implementation of the standard entropy generator, based
2//! on the operating system's available entropy sources.
3
4mod fill_impl;
5
6use core::{convert::Infallible, marker::PhantomData};
7
8use osom_lib_reprc::macros::reprc;
9use osom_lib_try_clone::TryClone;
10
11use crate::traits::{EntropyConcreteGenerator, EntropyGenerator};
12
13/// An enum for handling various failures of entropy generation.
14#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
15#[reprc]
16#[repr(u8)]
17pub enum StdEntropyError {
18    /// Kernel returned an error.
19    GenericKernelError = 0,
20
21    /// The current platform is not supported.
22    UnsupportedPlatform = 1,
23}
24
25impl TryClone for StdEntropyError {
26    type Error = Infallible;
27    fn try_clone(&self) -> Result<Self, Self::Error> {
28        Ok(*self)
29    }
30}
31
32osom_lib_macros::unreachable_from_infallible!(StdEntropyError);
33
34impl core::fmt::Display for StdEntropyError {
35    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
36        write!(
37            f,
38            "StdEntropyError::{}",
39            match self {
40                StdEntropyError::GenericKernelError => "GenericKernelError",
41                StdEntropyError::UnsupportedPlatform => "UnsupportedPlatform",
42            }
43        )
44    }
45}
46
47/// The standard entropy generator. It uses various os available
48/// operations to generate entropy:
49///
50/// * `macos` <- it utilizes `getentropy` syscall
51/// * `linux` <- it utilizes `getrandom` syscall
52/// * `windows` <- it utilizes `ProcessPrng` syscall
53/// * Other platforms are unsupported and attempting to use the generator will
54///   result in a [`StdEntropyError::UnsupportedPlatform`] error.
55#[derive(Debug, Default, PartialEq, Eq, Hash, Clone, Copy)]
56#[reprc]
57#[repr(transparent)]
58#[must_use]
59pub struct StdEntropyGenerator {
60    _phantom: PhantomData<()>,
61}
62
63impl TryClone for StdEntropyGenerator {
64    type Error = Infallible;
65    fn try_clone(&self) -> Result<Self, Self::Error> {
66        Ok(*self)
67    }
68}
69
70impl StdEntropyGenerator {
71    /// Creates a new instance of [`StdEntropyGenerator`]. This
72    /// method is basically free.
73    #[inline(always)]
74    pub const fn new() -> Self {
75        Self { _phantom: PhantomData }
76    }
77}
78
79impl EntropyGenerator for StdEntropyGenerator {
80    type Error = StdEntropyError;
81
82    unsafe fn fill_raw(&mut self, buffer_ptr: *mut u8, buffer_len: usize) -> Result<(), Self::Error> {
83        fill_impl::fill(buffer_ptr, buffer_len)
84    }
85}
86
87#[inline]
88fn generate_random_t<T: Copy, TGen: EntropyGenerator>(gene: &mut TGen) -> Result<T, TGen::Error> {
89    let mut item = core::mem::MaybeUninit::<T>::uninit();
90    let item_ptr = item.as_mut_ptr();
91    let slice = unsafe { core::slice::from_raw_parts_mut(item_ptr.cast::<u8>(), size_of::<T>()) };
92    gene.fill(slice)?;
93    Ok(unsafe { item.assume_init() })
94}
95
96impl<const N: usize> EntropyConcreteGenerator<StdEntropyGenerator> for [u8; N] {
97    #[inline(always)]
98    fn generate(generator: &mut StdEntropyGenerator) -> Result<Self, StdEntropyError> {
99        if N == 0 {
100            return Ok([0u8; N]);
101        }
102        generate_random_t(generator)
103    }
104}
105
106macro_rules! concrete {
107    ( $t: ty ) => {
108        impl EntropyConcreteGenerator<StdEntropyGenerator> for $t {
109            #[inline(always)]
110            fn generate(generator: &mut StdEntropyGenerator) -> Result<Self, StdEntropyError>
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);