crypto_common/
generate.rs

1use hybrid_array::{Array, ArraySize};
2use rand_core::{CryptoRng, TryCryptoRng};
3
4#[cfg(feature = "getrandom")]
5use crate::RngError;
6
7/// Secure random generation.
8pub trait Generate: Sized {
9    /// Generate random key using the provided [`TryCryptoRng`].
10    fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error>;
11
12    /// Generate random key using the provided [`CryptoRng`].
13    fn from_rng<R: CryptoRng + ?Sized>(rng: &mut R) -> Self {
14        let Ok(ret) = Self::try_from_rng(rng);
15        ret
16    }
17
18    /// Randomly generate a value of this type using the system's ambient cryptographically secure
19    /// random number generator.
20    ///
21    /// # Errors
22    /// Returns [`RngError`] in the event the system's ambient RNG experiences an internal failure.
23    #[cfg(feature = "getrandom")]
24    fn try_generate() -> Result<Self, RngError> {
25        Self::try_from_rng(&mut sys_rng::SysRng)
26    }
27
28    /// Randomly generate a value of this type using the system's ambient cryptographically secure
29    /// random number generator.
30    ///
31    /// # Panics
32    /// This method will panic in the event the system's ambient RNG experiences an internal
33    /// failure.
34    ///
35    /// This shouldn't happen on most modern operating systems.
36    #[cfg(feature = "getrandom")]
37    fn generate() -> Self {
38        Self::try_generate().expect("RNG failure")
39    }
40}
41
42impl Generate for u32 {
43    #[inline]
44    fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
45        rng.try_next_u32()
46    }
47}
48
49impl Generate for u64 {
50    #[inline]
51    fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
52        rng.try_next_u64()
53    }
54}
55
56impl<const N: usize> Generate for [u8; N] {
57    #[inline]
58    fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
59        let mut ret = [0u8; N];
60        rng.try_fill_bytes(&mut ret)?;
61        Ok(ret)
62    }
63}
64
65impl<U: ArraySize> Generate for Array<u8, U> {
66    #[inline]
67    fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
68        let mut ret = Self::default();
69        rng.try_fill_bytes(&mut ret)?;
70        Ok(ret)
71    }
72}
73
74impl<U: ArraySize> Generate for Array<u32, U> {
75    #[inline]
76    fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
77        Self::try_from_fn(|_| rng.try_next_u32())
78    }
79}
80
81impl<U: ArraySize> Generate for Array<u64, U> {
82    #[inline]
83    fn try_from_rng<R: TryCryptoRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
84        Self::try_from_fn(|_| rng.try_next_u64())
85    }
86}
87
88#[cfg(feature = "getrandom")]
89pub(crate) mod sys_rng {
90    use getrandom::Error;
91    use rand_core::{TryCryptoRng, TryRngCore};
92
93    /// A [`TryRngCore`] interface over the system's preferred random number source
94    // TODO(tarcieri): replace this with `getrandom::SysRng` when `sys_rng` feature is available
95    #[derive(Clone, Copy, Debug, Default)]
96    pub struct SysRng;
97
98    impl TryRngCore for SysRng {
99        type Error = Error;
100
101        #[inline]
102        fn try_next_u32(&mut self) -> Result<u32, Error> {
103            getrandom::u32()
104        }
105
106        #[inline]
107        fn try_next_u64(&mut self) -> Result<u64, Error> {
108            getrandom::u64()
109        }
110
111        #[inline]
112        fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
113            getrandom::fill(dest)
114        }
115    }
116
117    impl TryCryptoRng for SysRng {}
118}