1
//! TRNG implementation.
2

            
3
use portable_atomic::{AtomicUsize, Ordering};
4

            
5
static TRNG_ENABLED: AtomicUsize = AtomicUsize::new(0);
6
static TRNG_USERS: AtomicUsize = AtomicUsize::new(0);
7

            
8
use super::Rng;
9
use crate::peripherals::{ADC1, RNG};
10

            
11
/// Ensures random numbers are cryptographically secure.
12
#[instability::unstable]
13
pub struct TrngSource<'d> {
14
    _rng: RNG<'d>,
15
    _adc: ADC1<'d>,
16
}
17

            
18
impl<'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
12
    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
12
    }
27

            
28
    /// Increases the internal entropy source counter.
29
    ///
30
    /// # Panics
31
    ///
32
    /// Panics if the internal counter overflows.
33
    ///
34
    /// # Safety
35
    ///
36
    /// Must only be called after a new entropy source has been enabled.
37
    #[instability::unstable]
38
    pub unsafe fn increase_entropy_source_counter() {
39
15
        if TRNG_ENABLED.fetch_add(1, Ordering::Relaxed) == usize::MAX {
40
            panic!("TrngSource enable overflowed");
41
        }
42
4
    }
43

            
44
    /// Decreases the internal entropy source counter.
45
    ///
46
    /// Should only be called **before** disabling an entropy source (such as the
47
    /// radio).
48
    ///
49
    /// Should only be called as many times as
50
    /// [`TrngSource::increase_entropy_source_counter`] was called.
51
    ///
52
    /// # Panics
53
    ///
54
    /// Panics if the internal counter underflows. Dropping the `TrngSource` panics
55
    /// if this method is called more times than
56
    /// [`TrngSource::increase_entropy_source_counter`].
57
    #[instability::unstable]
58
3
    pub fn decrease_entropy_source_counter(_private: crate::private::Internal) {
59
15
        match TRNG_ENABLED.fetch_sub(1, Ordering::Relaxed) {
60
            0 => panic!("TrngSource is not active"),
61

            
62
1
            1 => assert!(
63
14
                TRNG_USERS.load(Ordering::Acquire) == 0,
64
                "TRNG cannot be disabled while it's in use"
65
            ),
66

            
67
            _ => {}
68
        }
69
3
    }
70

            
71
    /// Returns whether the TRNG is currently enabled.
72
    ///
73
    /// 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
    /// # Panics
82
    ///
83
    /// Panics if the TRNG is not enabled (i.e. it has been disabled by calling
84
    /// [`TrngSource::decrease_entropy_source_counter`] incorrectly).
85
    ///
86
    /// # Errors
87
    ///
88
    /// [`TrngSource`] when there are TRNG users.
89
    #[instability::unstable]
90
1
    pub fn try_disable(self) -> Result<(), Self> {
91
        if TRNG_ENABLED
92
            .fetch_update(Ordering::Relaxed, Ordering::Relaxed, |enabled| {
93
1
                assert!(enabled > 0, "TrngSource is not active");
94
1
                if TRNG_USERS.load(Ordering::Acquire) > 0 {
95
                    return None;
96
                }
97

            
98
                Some(enabled - 1)
99
            })
100
            .is_err()
101
        {
102
            // The TRNG is in use.
103
            return Err(self);
104
        }
105

            
106
        core::mem::forget(self);
107
        Ok(())
108
1
    }
109
}
110

            
111
impl Drop for TrngSource<'_> {
112
12
    fn drop(&mut self) {
113
        Self::decrease_entropy_source_counter(crate::private::Internal);
114
        crate::soc::trng::revert_trng();
115
11
    }
116
}
117

            
118
/// Errors returned when constructing a [`Trng`].
119
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
120
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
121
#[non_exhaustive]
122
#[instability::unstable]
123
pub enum TrngError {
124
    /// The [`TrngSource`] is not enabled.
125
    ///
126
    /// Returned by [`Trng::try_new`] when the RNG is not configured to generate
127
    /// true random numbers.
128
    TrngSourceNotEnabled,
129
}
130

            
131
#[cfg_attr(docsrs, procmacros::doc_replace(
132
    "analog_pin" => gpio_for_signal!(ADC1_CH3),
133
))]
134
/// True Random Number Generator (TRNG)
135
///
136
/// The `Trng` struct represents a true random number generator that combines randomness from the
137
/// hardware RNG and an ADC. Provides methods to generate random numbers and fill buffers with
138
/// random bytes. Because entropy is sourced from the ADC, the associated registers are used and
139
/// the ADC peripheral must be occupied.
140
///
141
/// To generate true random numbers, an instance of [`TrngSource`] is required. Once created,
142
/// [`Trng`] instances can be created at any time, as long as the [`TrngSource`] is alive
143
///
144
/// # Examples
145
///
146
/// ```rust, no_run
147
/// # {before_snippet}
148
/// # use esp_hal::peripherals::ADC1;
149
/// # use esp_hal::analog::adc::{AdcConfig, Attenuation, Adc};
150
/// #
151
/// use esp_hal::rng::{Trng, TrngSource};
152
///
153
/// let mut buf = [0u8; 16];
154
///
155
/// // ADC is not available from now
156
/// let trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1.reborrow());
157
///
158
/// let trng = Trng::try_new()?;
159
///
160
/// // Generate true random numbers
161
/// trng.read(&mut buf);
162
/// let true_random_number = trng.random();
163
///
164
/// // Downgrade to Rng to allow disabling the TrngSource
165
/// let rng = trng.downgrade();
166
///
167
/// // Drop the true random number source. ADC is available now.
168
/// core::mem::drop(trng_source);
169
///
170
/// let mut adc1_config = AdcConfig::new();
171
/// let mut adc1_pin = adc1_config.enable_pin(peripherals.__analog_pin__, Attenuation::_11dB);
172
/// let mut adc1 = Adc::new(peripherals.ADC1, adc1_config);
173
/// let pin_value = adc1.read_oneshot(&mut adc1_pin)?;
174
///
175
/// // Now we can only generate pseudo-random numbers...
176
/// rng.read(&mut buf);
177
/// let pseudo_random_number = rng.random();
178
///
179
/// // ... but the ADC is available for use.
180
/// let pin_value: u16 = adc1.read_oneshot(&mut adc1_pin)?;
181
/// # {after_snippet}
182
/// ```
183
#[derive(Debug)]
184
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
185
#[non_exhaustive]
186
#[instability::unstable]
187
pub struct Trng {
188
    rng: Rng,
189
}
190

            
191
impl Clone for Trng {
192
    #[inline]
193
    fn clone(&self) -> Self {
194
        TRNG_USERS.fetch_add(1, Ordering::Acquire);
195
        Self { rng: self.rng }
196
    }
197
}
198

            
199
impl Trng {
200
    /// Creates a new True Random Number Generator (TRNG) instance.
201
    ///
202
    /// # Errors
203
    ///
204
    /// [`TrngError::TrngSourceNotEnabled`] when the [`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
1
        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

            
240
impl Drop for Trng {
241
4
    fn drop(&mut self) {
242
        TRNG_USERS.fetch_sub(1, Ordering::Release);
243
4
    }
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]
249
impl 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]
270
impl 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]
285
impl 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]
289
impl 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]
295
impl 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]
310
impl rand_core_010::TryCryptoRng for Trng {}