Skip to main content

imxrt_hal/chip/drivers/
trng.rs

1//! True random number generator.
2//!
3//! Provides basic support for the True Random Number Generator. The TRNG generates truly random
4//! data and is intended for use as a generator of entropy.
5//!
6//! The TRNG is fairly slow - 15 minutes to an hour to generate 1 megabyte - so it probably
7//! should only be used to generate a relatively small amount of entropy for a cryptographic
8//! algorithm. Occasionally retrieving entropy from it won't necessarily need to block, as
9//! this driver retrieves 512 bits at a time.
10//!
11//! # Example
12//!
13//! Enable the TRNG clock gate, wait to generate random data.
14//!
15//! ```no_run
16//! use core::task::Poll;
17//! use imxrt_hal as hal;
18//! use imxrt_ral as ral;
19//!
20//! # || -> Option<()> {
21//! let mut ccm = unsafe { ral::ccm::CCM::instance() };
22//! hal::ccm::clock_gate::trng().set(&mut ccm, hal::ccm::clock_gate::ON);
23//!
24//! let mut trng = hal::trng::Trng::new(
25//!     unsafe { ral::trng::TRNG::instance() },
26//!     hal::trng::SampleMode::default(),
27//!     hal::trng::RetryCount::default(),
28//! );
29//!
30//! let random_data = loop {
31//!     if let Poll::Ready(result) = trng.next_u32() {
32//!         break result.ok()?;
33//!     }
34//! };
35//! # Some(()) }();
36//! ```
37
38use core::fmt;
39use core::task::{Poll, ready};
40
41use crate::ral::trng;
42use crate::ral::{modify_reg, read_reg, write_reg};
43
44/// TRNG sampling mode
45#[cfg_attr(feature = "defmt", derive(defmt::Format))]
46#[derive(Copy, Clone, Debug, PartialEq, Eq)]
47#[repr(u32)]
48pub enum SampleMode {
49    /// von Neumann data in both entropy shifter and statistical checks. Approximately 4x slower
50    /// than the other modes.
51    VonNeumann = trng::MCTL::SAMP_MODE::RW::SAMP_MODE_0,
52    /// Raw data in both entropy shifter and statistical checks. Likely lower quality than the
53    /// other two modes.
54    Raw = trng::MCTL::SAMP_MODE::RW::SAMP_MODE_1,
55    /// von Neumann data in entropy shifter, raw data in statistical checks
56    VonNeumannRaw = trng::MCTL::SAMP_MODE::RW::SAMP_MODE_2,
57}
58
59impl Default for SampleMode {
60    /// Returns `VonNeumannRaw`.
61    fn default() -> Self {
62        // "Set sample mode of the TRNG ring oscillator to Von Neumann, for better random data.
63        // It is optional." <- SDK, explaining why they set sample mode to 0 (VN)
64        // Teensyduino uses VNRaw, the reason appears to be this post:
65        // https://forum.pjrc.com/threads/54711-Teensy-4-0-First-Beta-Test?p=195000&viewfull=1#post195000
66        // VNRaw appears to produce equivalent quality output and is ~4x faster than VN.
67        // As such, VonNeumannRaw is the default SampleMode here.
68        Self::VonNeumannRaw
69    }
70}
71
72/// The true random number generator.
73pub struct Trng {
74    reg: trng::TRNG,
75    block: [u32; 16],
76    index: usize,
77}
78
79impl fmt::Debug for Trng {
80    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
81        f.debug_struct("TRNG")
82            .field("block", &self.block)
83            .field("index", &self.index)
84            .finish()
85    }
86}
87
88#[cfg(feature = "defmt")]
89impl defmt::Format for Trng {
90    fn format(&self, f: defmt::Formatter) {
91        defmt::write!(f, "Trng {{ block: {}, index: {} }}", self.block, self.index)
92    }
93}
94
95/// The number of retry attempts.
96///
97/// Describes the number of times to retry
98/// after a test failure before an error is declared. Valid
99/// range `1..=15`. The default retry count is the largest
100/// possible value.
101#[cfg_attr(feature = "defmt", derive(defmt::Format))]
102#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103pub struct RetryCount(u32);
104
105impl RetryCount {
106    /// The default reset count.
107    pub const DEFAULT: u32 = 15;
108
109    /// Create a new retry count.
110    ///
111    /// Returns `None` if `retry_count` is not in the half-closed range
112    /// `1..=15`.
113    pub fn new(retry_count: u32) -> Option<Self> {
114        (1..=15)
115            .contains(&retry_count)
116            .then_some(RetryCount(retry_count))
117    }
118}
119
120impl Default for RetryCount {
121    fn default() -> Self {
122        RetryCount(Self::DEFAULT)
123    }
124}
125
126impl Trng {
127    /// Create a TRNG given a sampling mode and retry count.
128    ///
129    /// To select the default sampling mode and retry counts, use `Default::default()`.
130    pub fn new(reg: trng::TRNG, sample_mode: SampleMode, retry_count: RetryCount) -> Self {
131        // Not supported: locking TRNG to prevent programmability.
132        // A number of things here are likely configurable if you have access to the SRM.
133        // Without it only limited configuration is safe. Garbage configs lead to endless errors.
134
135        modify_reg!(trng, reg, MCTL, PRGM: 1);
136        modify_reg!(trng, reg, MCTL, RST_DEF: 1);
137        // enter program mode and reset to defaults
138        // it isn't clear what defaults it actually sets, so let's set the tests manually
139
140        // All these values are sourced only from the #defines in the MCUXpresso TRNG driver for the
141        // IMXRT1062. The doc comments contain both typos and completely wrong values.
142
143        write_reg!(trng, reg, SCMISC, RTY_CT: retry_count.0, LRUN_MAX: 34); // _RUN_MAX_LIMIT
144
145        // Note: The SDK uses _MAX and _MIN for values, but the registers use the max value and a
146        // range. The SDK _MIN values are expressed as (max - range), making it easy to ensure
147        // that these values are correct.
148        write_reg!(trng, reg, SCML, MONO_MAX: 1384, MONO_RNG: 268); // _MONOBIT_
149        write_reg!(trng, reg, SCR1L, RUN1_MAX: 405, RUN1_RNG: 178); // _RUNBIT1_
150        write_reg!(trng, reg, SCR2L, RUN2_MAX: 220, RUN2_RNG: 122); // _RUNBIT2_
151        write_reg!(trng, reg, SCR3L, RUN3_MAX: 125, RUN3_RNG: 88); // _RUNBIT3_
152        write_reg!(trng, reg, SCR4L, RUN4_MAX: 75, RUN4_RNG: 64); // _RUNBIT4_
153        write_reg!(trng, reg, SCR5L, RUN5_MAX: 47, RUN5_RNG: 46); // _RUNBIT5_
154        write_reg!(trng, reg, SCR6PL, RUN6P_MAX: 47, RUN6P_RNG: 46); // _RUNBIT6PLUS_
155
156        write_reg!(trng, reg, PKRMAX, PKR_MAX: 26912); // _POKER_MAXIMUM
157        write_reg!(trng, reg, PKRRNG, PKR_RNG: 2467);
158
159        write_reg!(trng, reg, FRQMAX, FRQ_MAX: 25600); // _FREQUENCY_MAXIMUM
160        write_reg!(trng, reg, FRQMIN, FRQ_MIN: 1600); // _FREQUENCY_MINIMUM
161
162        write_reg!(trng, reg, SDCTL, SAMP_SIZE: 2500, ENT_DLY: 3200); // _SAMPLE_SIZE, _ENTROPY_DELAY
163        write_reg!(trng, reg, SBLIM, SB_LIM: 63); // _SPARSE_BIT_LIMIT
164
165        // set sample mode, exit program mode
166        modify_reg!(trng, reg, MCTL, SAMP_MODE: sample_mode as u32);
167        modify_reg!(trng, reg, MCTL, PRGM: 0);
168        // for 1015, 1021, maybe other non i.MX chips: set TRNG_ACC to 1 here
169        read_reg!(trng, reg, ENT[15]);
170        // reading ENT15 triggers new entropy generation
171
172        Self {
173            reg,
174            block: [0; 16],
175            index: 16, // equal to len, to trigger immediate retrieval
176        }
177    }
178
179    /// Return the next randomly-generated `u32`. May need to retrieve another block of random numbers.
180    ///
181    /// Returns `Poll::Pending` if we're not ready to read entropy; try again. See the module-level
182    /// example for how to block.
183    pub fn next_u32(&mut self) -> Poll<Result<u32, Error>> {
184        ready!(self.retrieve_if_needed())?;
185        let data = self.block[self.index];
186        self.index += 1;
187        Poll::Ready(Ok(data))
188    }
189
190    /// Retrieve another block of random numbers if we've used them all up.
191    fn retrieve_if_needed(&mut self) -> Poll<Result<(), Error>> {
192        if self.index >= self.block.len() {
193            ready!(self.retrieve())?;
194            self.index = 0;
195        }
196        Poll::Ready(Ok(()))
197    }
198
199    /// Retrieve another block of random numbers.
200    fn retrieve(&mut self) -> Poll<Result<(), Error>> {
201        let mctl = read_reg!(trng, self.reg, MCTL);
202        if (mctl & trng::MCTL::ERR::mask) != 0 {
203            let flags = self.get_error_flags();
204            write_reg!(trng, self.reg, MCTL, mctl); // write reg back to clear error
205            return Poll::Ready(Err(Error(flags)));
206        }
207        if (mctl & trng::MCTL::ENT_VAL::mask) == 0 {
208            return Poll::Pending; // not ready to read entropy
209        }
210        for idx in 0..self.reg.ENT.len() {
211            self.block[idx] = read_reg!(trng, self.reg, ENT[idx]);
212        }
213
214        read_reg!(trng, self.reg, ENT[0]);
215        // SDK (fsl_trng.c):
216        //     Dummy read. Defect workaround.
217        //     TRNG could not clear ENT_VAL flag automatically, application
218        //     had to do a dummy reading operation for anyone TRNG register
219        //     to clear it firstly, then to read the RTENT0 to RTENT15 again
220        // This appears unnecessary on the 1062? done anyway in case it's necessary for another chip
221        Poll::Ready(Ok(()))
222    }
223
224    /// Retrieve all known error flags.
225    fn get_error_flags(&self) -> ErrorFlags {
226        let status = read_reg!(trng, self.reg, STATUS) & 0xFFFF;
227        // all the error flags in STATUS are in the low 16 bits
228        let mut flags = ErrorFlags::from_bits_truncate(status);
229        flags.set(
230            ErrorFlags::FCT_FAIL,
231            read_reg!(trng, self.reg, MCTL, FCT_FAIL) == 1,
232        );
233        flags
234    }
235
236    /// Release the TRNG in a disabled state.
237    ///
238    /// This preserves any previously set retry count, sample mode,
239    /// and peripheral settings. However, the register block is returned
240    /// in a disabled state.
241    pub fn release_disabled(self) -> trng::TRNG {
242        modify_reg!(trng, self.reg, MCTL, PRGM: 1);
243        while read_reg!(trng, self.reg, MCTL, TSTOP_OK) == 0 {
244            core::hint::spin_loop();
245        }
246        self.reg
247    }
248}
249
250/// A TRNG error occurred, such as a statistical test failing.
251#[cfg_attr(feature = "defmt", derive(defmt::Format))]
252#[derive(Copy, Clone, Debug, PartialEq, Eq)]
253pub struct Error(pub ErrorFlags);
254
255bitflags::bitflags! {
256    /// Specific errors that may occur during entropy generation
257    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
258    pub struct ErrorFlags : u32 {
259        // STATUS register starts here (automatically set from bits)
260        /// 1-bit run sampling 0s test failed
261        const TF1BR0 = 1 << 0;
262        /// 1-bit run sampling 1s test failed
263        const TF1BR1 = 1 << 1;
264        /// 2-bit run sampling 0s test failed
265        const TF2BR0 = 1 << 2;
266        /// 2-bit run sampling 1s test failed
267        const TF2BR1 = 1 << 3;
268        /// 3-bit run sampling 0s test failed
269        const TF3BR0 = 1 << 4;
270        /// 3-bit run sampling 1s test failed
271        const TF3BR1 = 1 << 5;
272        /// 4-bit run sampling 0s test failed
273        const TF4BR0 = 1 << 6;
274        /// 4-bit run sampling 1s test failed
275        const TF4BR1 = 1 << 7;
276        /// 5-bit run sampling 0s test failed
277        const TF5BR0 = 1 << 8;
278        /// 5-bit run sampling 1s test failed
279        const TF5BR1 = 1 << 9;
280        /// 6-plus-bit run sampling 0s test failed
281        const TF6PBR0 = 1 << 10;
282        /// 6-plus-bit run sampling 1s test failed
283        const TF6PBR1 = 1 << 11;
284        /// Sparse bit test failed
285        const TFSB = 1 << 12;
286        /// Long run test failed
287        const TFLR = 1 << 13;
288        /// Poker test failed
289        const TFP = 1 << 14;
290        /// Mono bit test failed
291        const TFMB = 1 << 15;
292        // MCTL register starts here (set manually)
293        /// Count taken during entropy generation was outside the defined range of FRQ_MIN to FRQ_MAX
294        const FCT_FAIL = 1 << 16;
295    }
296}
297
298#[cfg(feature = "defmt")]
299impl defmt::Format for ErrorFlags {
300    fn format(&self, f: defmt::Formatter) {
301        defmt::write!(f, "ErrorFlags({=u32:#x})", self.bits());
302    }
303}
304
305impl fmt::Display for Error {
306    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
307        write!(f, "An error occurred in the TRNG module")
308    }
309}
310
311#[cfg(test)]
312mod tests {
313    use super::RetryCount;
314
315    #[test]
316    fn retry_count() {
317        assert!(RetryCount::new(0).is_none());
318        for count in 1..16 {
319            assert!(RetryCount::new(count).is_some());
320        }
321        assert!(RetryCount::new(16).is_none());
322    }
323}