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#[cfg_attr(docsrs, procmacros::doc_replace(
130 "analog_pin" => gpio_for_signal!(ADC1_CH4),
131))]
132/// True Random Number Generator (TRNG)
133///
134/// The `Trng` struct represents a true random number generator that combines
135/// the randomness from the hardware RNG and an ADC. This struct provides
136/// methods to generate random numbers and fill buffers with random bytes.
137/// Due to pulling the entropy source from the ADC, it uses the associated
138/// registers, so to use TRNG we need to "occupy" the ADC peripheral.
139///
140/// To generate true random numbers, an instance of [`TrngSource`] is required. Once created, you
141/// can create [`Trng`] instances at any time, as long as the [`TrngSource`] is alive.
142///
143/// ## Example
144///
145/// ```rust, no_run
146/// # {before_snippet}
147/// # use esp_hal::peripherals::ADC1;
148/// # use esp_hal::analog::adc::{AdcConfig, Attenuation, Adc};
149/// #
150/// use esp_hal::rng::{Trng, TrngSource};
151///
152/// let mut buf = [0u8; 16];
153///
154/// // ADC is not available from now
155/// let trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1.reborrow());
156///
157/// let trng = Trng::try_new()?;
158///
159/// // Generate true random numbers
160/// trng.read(&mut buf);
161/// let true_random_number = trng.random();
162///
163/// // Downgrade to Rng to allow disabling the TrngSource
164/// let rng = trng.downgrade();
165///
166/// // Drop the true random number source. ADC is available now.
167/// core::mem::drop(trng_source);
168///
169/// let mut adc1_config = AdcConfig::new();
170/// let mut adc1_pin = adc1_config.enable_pin(peripherals.__analog_pin__, Attenuation::_11dB);
171/// let mut adc1 = Adc::new(peripherals.ADC1, adc1_config);
172/// let pin_value = adc1.read_oneshot(&mut adc1_pin)?;
173///
174/// // Now we can only generate pseudo-random numbers...
175/// rng.read(&mut buf);
176/// let pseudo_random_number = rng.random();
177///
178/// // ... but the ADC is available for use.
179/// let pin_value: u16 = adc1.read_oneshot(&mut adc1_pin)?;
180/// # {after_snippet}
181/// ```
182#[derive(Debug)]
183#[cfg_attr(feature = "defmt", derive(defmt::Format))]
184#[non_exhaustive]
185#[instability::unstable]
186pub struct Trng {
187 rng: Rng,
188}
189
190impl Clone for Trng {
191 #[inline]
192 fn clone(&self) -> Self {
193 TRNG_USERS.fetch_add(1, Ordering::Acquire);
194 Self { rng: self.rng }
195 }
196}
197
198impl Trng {
199 /// Attempts to create a new True Random Number Generator (TRNG) instance.
200 ///
201 /// This function returns a new `Trng` instance on success, or an error if the
202 /// [`TrngSource`] is not active.
203 #[inline]
204 #[instability::unstable]
205 pub fn try_new() -> Result<Self, TrngError> {
206 TRNG_USERS.fetch_add(1, Ordering::Acquire);
207 let this = Self { rng: Rng::new() };
208 if TRNG_ENABLED.load(Ordering::Acquire) == 0 {
209 // Dropping `this` reduces the TRNG_USERS count back (to 0 as it should be when TRNG
210 // is not enabled).
211 return Err(TrngError::TrngSourceNotEnabled);
212 }
213 Ok(this)
214 }
215
216 /// Returns a new, random `u32` integer.
217 #[inline]
218 #[instability::unstable]
219 pub fn random(&self) -> u32 {
220 self.rng.random()
221 }
222
223 /// Fills the provided buffer with random bytes.
224 #[inline]
225 #[instability::unstable]
226 pub fn read(&self, buffer: &mut [u8]) {
227 self.rng.read(buffer);
228 }
229
230 /// Downgrades the `Trng` instance to a `Rng` instance.
231 #[inline]
232 #[instability::unstable]
233 pub fn downgrade(self) -> Rng {
234 Rng::new()
235 }
236}
237
238impl Drop for Trng {
239 fn drop(&mut self) {
240 TRNG_USERS.fetch_sub(1, Ordering::Release);
241 }
242}
243
244/// Compatibility with `rand_core 0.6`. Documentation can be found at
245/// <https://docs.rs/rand_core/0.6.4/rand_core/trait.RngCore.html>.
246#[instability::unstable]
247impl rand_core_06::RngCore for Trng {
248 fn next_u32(&mut self) -> u32 {
249 <Rng as rand_core_06::RngCore>::next_u32(&mut self.rng)
250 }
251
252 fn next_u64(&mut self) -> u64 {
253 <Rng as rand_core_06::RngCore>::next_u64(&mut self.rng)
254 }
255
256 fn fill_bytes(&mut self, dest: &mut [u8]) {
257 <Rng as rand_core_06::RngCore>::fill_bytes(&mut self.rng, dest)
258 }
259
260 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
261 <Rng as rand_core_06::RngCore>::try_fill_bytes(&mut self.rng, dest)
262 }
263}
264
265/// Compatibility with `rand_core 0.9`. Documentation can be found at
266/// <https://docs.rs/rand_core/0.9.5/rand_core/trait.RngCore.html>.
267#[instability::unstable]
268impl rand_core_09::RngCore for Trng {
269 fn next_u32(&mut self) -> u32 {
270 <Rng as rand_core_09::RngCore>::next_u32(&mut self.rng)
271 }
272 fn next_u64(&mut self) -> u64 {
273 <Rng as rand_core_09::RngCore>::next_u64(&mut self.rng)
274 }
275 fn fill_bytes(&mut self, dest: &mut [u8]) {
276 <Rng as rand_core_09::RngCore>::fill_bytes(&mut self.rng, dest)
277 }
278}
279
280/// Compatibility with `rand_core 0.6`. Documentation can be found at
281/// <https://docs.rs/rand_core/0.6.4/rand_core/trait.CryptoRng.html>.
282#[instability::unstable]
283impl rand_core_06::CryptoRng for Trng {}
284/// Compatibility with `rand_core 0.9`. Documentation can be found at
285/// <https://docs.rs/rand_core/0.9.5/rand_core/trait.CryptoRng.html>.
286#[instability::unstable]
287impl rand_core_09::CryptoRng for Trng {}
288
289// Non-try variants are blanket-implemented when `Error = Infallible`.
290
291/// Compatibility with `rand_core 0.10`
292#[instability::unstable]
293impl rand_core_010::TryRng for Trng {
294 type Error = core::convert::Infallible;
295 fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
296 <Rng as rand_core_010::TryRng>::try_next_u32(&mut self.rng)
297 }
298 fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
299 <Rng as rand_core_010::TryRng>::try_next_u64(&mut self.rng)
300 }
301 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
302 <Rng as rand_core_010::TryRng>::try_fill_bytes(&mut self.rng, dest)
303 }
304}
305
306/// Compatibility with `rand_core 0.10`
307#[instability::unstable]
308impl rand_core_010::TryCryptoRng for Trng {}