Skip to main content

esp_hal/rng/
trng.rs

1//! TRNG implementation.
2
3use portable_atomic::{AtomicUsize, Ordering};
4
5static TRNG_ENABLED: AtomicUsize = AtomicUsize::new(0);
6static TRNG_USERS: AtomicUsize = AtomicUsize::new(0);
7
8use super::Rng;
9use crate::peripherals::{ADC1, RNG};
10
11/// Ensures random numbers are cryptographically secure.
12#[instability::unstable]
13pub struct TrngSource<'d> {
14    _rng: RNG<'d>,
15    _adc: ADC1<'d>,
16}
17
18impl<'d> TrngSource<'d> {
19    /// Enables the SAR ADC entropy source.
20    // TODO: this is not final. A single ADC channel should be sufficient.
21    #[instability::unstable]
22    pub fn new(_rng: RNG<'d>, _adc: ADC1<'d>) -> Self {
23        crate::soc::trng::ensure_randomness();
24        unsafe { Self::increase_entropy_source_counter() }
25        Self { _rng, _adc }
26    }
27
28    /// Increases the internal entropy source counter.
29    ///
30    /// # Panics
31    ///
32    /// This function panics if the internal counter overflows.
33    ///
34    /// # Safety
35    ///
36    /// This function must only be called after a new entropy source has been enabled.
37    #[instability::unstable]
38    pub unsafe fn increase_entropy_source_counter() {
39        if TRNG_ENABLED.fetch_add(1, Ordering::Relaxed) == usize::MAX {
40            panic!("TrngSource enable overflowed");
41        }
42    }
43
44    /// Decreases the internal entropy source counter.
45    ///
46    /// This function should only be called **before** disabling an entropy source (such as the
47    /// radio).
48    ///
49    /// This function should only be called as many times as
50    /// [`TrngSource::increase_entropy_source_counter`] was called.
51    ///
52    /// # Panics
53    ///
54    /// This function panics if the internal counter underflows. Dropping the `TrngSource` will
55    /// panic if this function is called more times than
56    /// [`TrngSource::increase_entropy_source_counter`].
57    #[instability::unstable]
58    pub fn decrease_entropy_source_counter(_private: crate::private::Internal) {
59        match TRNG_ENABLED.fetch_sub(1, Ordering::Relaxed) {
60            0 => panic!("TrngSource is not active"),
61
62            1 => assert!(
63                TRNG_USERS.load(Ordering::Acquire) == 0,
64                "TRNG cannot be disabled while it's in use"
65            ),
66
67            _ => {}
68        }
69    }
70
71    /// Returns whether the TRNG is currently enabled.
72    ///
73    /// Note that entropy sources can be disabled at any time.
74    #[instability::unstable]
75    pub fn is_enabled() -> bool {
76        TRNG_ENABLED.load(Ordering::Relaxed) > 0
77    }
78
79    /// Attempts to disable the TRNG.
80    ///
81    /// This function returns `Err(TrngSource)` if there are TRNG users.
82    ///
83    /// # Panics
84    ///
85    /// This function panics if the TRNG is not enabled (i.e. it has been disabled by calling
86    /// [`TrngSource::decrease_entropy_source_counter`] incorrectly).
87    #[instability::unstable]
88    pub fn try_disable(self) -> Result<(), Self> {
89        if TRNG_ENABLED
90            .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |enabled| {
91                assert!(enabled > 0, "TrngSource is not active");
92                if TRNG_USERS.load(Ordering::Acquire) > 0 {
93                    return None;
94                }
95
96                Some(enabled - 1)
97            })
98            .is_err()
99        {
100            // The TRNG is in use.
101            return Err(self);
102        }
103
104        core::mem::forget(self);
105        Ok(())
106    }
107}
108
109impl Drop for TrngSource<'_> {
110    fn drop(&mut self) {
111        Self::decrease_entropy_source_counter(crate::private::Internal);
112        crate::soc::trng::revert_trng();
113    }
114}
115
116/// Errors returned when constructing a [`Trng`].
117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
118#[cfg_attr(feature = "defmt", derive(defmt::Format))]
119#[non_exhaustive]
120#[instability::unstable]
121pub enum TrngError {
122    /// The [`TrngSource`] is not enabled.
123    ///
124    /// This error is returned by [`Trng::try_new`] when the RNG is not configured
125    /// to generate true random numbers.
126    TrngSourceNotEnabled,
127}
128
129/// True Random Number Generator (TRNG)
130///
131/// The `Trng` struct represents a true random number generator that combines
132/// the randomness from the hardware RNG and an ADC. This struct provides
133/// methods to generate random numbers and fill buffers with random bytes.
134/// Due to pulling the entropy source from the ADC, it uses the associated
135/// registers, so to use TRNG we need to "occupy" the ADC peripheral.
136///
137/// To generate true random numbers, an instance of [`TrngSource`] is required. Once created, you
138/// can create [`Trng`] instances at any time, as long as the [`TrngSource`] is alive.
139#[cfg_attr(docsrs, procmacros::doc_replace(
140    "analog_pin" => {
141        cfg(esp32) => "GPIO32",
142        _ => "GPIO3"
143    }
144))]
145/// ## Example
146///
147/// ```rust, no_run
148/// # {before_snippet}
149/// # use esp_hal::peripherals::ADC1;
150/// # use esp_hal::analog::adc::{AdcConfig, Attenuation, Adc};
151/// #
152/// use esp_hal::rng::{Trng, TrngSource};
153///
154/// let mut buf = [0u8; 16];
155///
156/// // ADC is not available from now
157/// let trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1.reborrow());
158///
159/// let trng = Trng::try_new()?;
160///
161/// // Generate true random numbers
162/// trng.read(&mut buf);
163/// let true_random_number = trng.random();
164///
165/// // Downgrade to Rng to allow disabling the TrngSource
166/// let rng = trng.downgrade();
167///
168/// // Drop the true random number source. ADC is available now.
169/// core::mem::drop(trng_source);
170///
171/// let mut adc1_config = AdcConfig::new();
172/// let mut adc1_pin = adc1_config.enable_pin(peripherals.__analog_pin__, Attenuation::_11dB);
173/// let mut adc1 = Adc::new(peripherals.ADC1, adc1_config);
174/// let pin_value = adc1.read_oneshot(&mut adc1_pin)?;
175///
176/// // Now we can only generate pseudo-random numbers...
177/// rng.read(&mut buf);
178/// let pseudo_random_number = rng.random();
179///
180/// // ... but the ADC is available for use.
181/// let pin_value: u16 = adc1.read_oneshot(&mut adc1_pin)?;
182/// # {after_snippet}
183/// ```
184#[derive(Default, Debug)]
185#[cfg_attr(feature = "defmt", derive(defmt::Format))]
186#[non_exhaustive]
187#[instability::unstable]
188pub struct Trng {
189    rng: Rng,
190}
191
192impl Clone for Trng {
193    #[inline]
194    fn clone(&self) -> Self {
195        TRNG_USERS.fetch_add(1, Ordering::Acquire);
196        Self { rng: self.rng }
197    }
198}
199
200impl Trng {
201    /// Attempts to create a new True Random Number Generator (TRNG) instance.
202    ///
203    /// This function returns a new `Trng` instance on success, or an error if the
204    /// [`TrngSource`] is not active.
205    #[inline]
206    #[instability::unstable]
207    pub fn try_new() -> Result<Self, TrngError> {
208        TRNG_USERS.fetch_add(1, Ordering::Acquire);
209        let this = Self { rng: Rng::new() };
210        if TRNG_ENABLED.load(Ordering::Acquire) == 0 {
211            // Dropping `this` reduces the TRNG_USERS count back (to 0 as it should be when TRNG
212            // is not enabled).
213            return Err(TrngError::TrngSourceNotEnabled);
214        }
215        Ok(this)
216    }
217
218    /// Returns a new, random `u32` integer.
219    #[inline]
220    #[instability::unstable]
221    pub fn random(&self) -> u32 {
222        self.rng.random()
223    }
224
225    /// Fills the provided buffer with random bytes.
226    #[inline]
227    #[instability::unstable]
228    pub fn read(&self, buffer: &mut [u8]) {
229        self.rng.read(buffer);
230    }
231
232    /// Downgrades the `Trng` instance to a `Rng` instance.
233    #[inline]
234    #[instability::unstable]
235    pub fn downgrade(self) -> Rng {
236        Rng::new()
237    }
238}
239
240impl Drop for Trng {
241    fn drop(&mut self) {
242        TRNG_USERS.fetch_sub(1, Ordering::Release);
243    }
244}
245
246/// Compatibility with `rand_core 0.6`. Documentation can be found at
247/// <https://docs.rs/rand_core/0.6.4/rand_core/trait.RngCore.html>.
248#[instability::unstable]
249impl rand_core_06::RngCore for Trng {
250    fn next_u32(&mut self) -> u32 {
251        <Rng as rand_core_06::RngCore>::next_u32(&mut self.rng)
252    }
253
254    fn next_u64(&mut self) -> u64 {
255        <Rng as rand_core_06::RngCore>::next_u64(&mut self.rng)
256    }
257
258    fn fill_bytes(&mut self, dest: &mut [u8]) {
259        <Rng as rand_core_06::RngCore>::fill_bytes(&mut self.rng, dest)
260    }
261
262    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
263        <Rng as rand_core_06::RngCore>::try_fill_bytes(&mut self.rng, dest)
264    }
265}
266
267/// Compatibility with `rand_core 0.9`. Documentation can be found at
268/// <https://docs.rs/rand_core/0.9.5/rand_core/trait.RngCore.html>.
269#[instability::unstable]
270impl rand_core_09::RngCore for Trng {
271    fn next_u32(&mut self) -> u32 {
272        <Rng as rand_core_09::RngCore>::next_u32(&mut self.rng)
273    }
274    fn next_u64(&mut self) -> u64 {
275        <Rng as rand_core_09::RngCore>::next_u64(&mut self.rng)
276    }
277    fn fill_bytes(&mut self, dest: &mut [u8]) {
278        <Rng as rand_core_09::RngCore>::fill_bytes(&mut self.rng, dest)
279    }
280}
281
282/// Compatibility with `rand_core 0.6`. Documentation can be found at
283/// <https://docs.rs/rand_core/0.6.4/rand_core/trait.CryptoRng.html>.
284#[instability::unstable]
285impl rand_core_06::CryptoRng for Trng {}
286/// Compatibility with `rand_core 0.9`. Documentation can be found at
287/// <https://docs.rs/rand_core/0.9.5/rand_core/trait.CryptoRng.html>.
288#[instability::unstable]
289impl rand_core_09::CryptoRng for Trng {}
290
291// Non-try variants are blanket-implemented when `Error = Infallible`.
292
293/// Compatibility with `rand_core 0.10`
294#[instability::unstable]
295impl rand_core_010::TryRng for Trng {
296    type Error = core::convert::Infallible;
297    fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
298        <Rng as rand_core_010::TryRng>::try_next_u32(&mut self.rng)
299    }
300    fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
301        <Rng as rand_core_010::TryRng>::try_next_u64(&mut self.rng)
302    }
303    fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
304        <Rng as rand_core_010::TryRng>::try_fill_bytes(&mut self.rng, dest)
305    }
306}
307
308/// Compatibility with `rand_core 0.10`
309#[instability::unstable]
310impl rand_core_010::TryCryptoRng for Trng {}