aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelipe Balbi <[email protected]>2025-12-11 11:38:56 -0800
committerFelipe Balbi <[email protected]>2025-12-11 11:38:56 -0800
commit3284620b7940e7598373ff404445858e0e7858b8 (patch)
treeaca3a3a0cd74f0730cce16838a75e0e5715ae937
parent26430facff49cf3d34bba84b4e287f57025fed4e (diff)
Replace AsyncTrng with Mode typestate
-rw-r--r--embassy-mcxa/src/trng.rs305
-rw-r--r--examples/mcxa/src/bin/trng.rs12
2 files changed, 121 insertions, 196 deletions
diff --git a/embassy-mcxa/src/trng.rs b/embassy-mcxa/src/trng.rs
index 56fe8eca2..16c759841 100644
--- a/embassy-mcxa/src/trng.rs
+++ b/embassy-mcxa/src/trng.rs
@@ -1,5 +1,7 @@
1//! True Random Number Generator 1//! True Random Number Generator
2 2
3use core::marker::PhantomData;
4
3use embassy_hal_internal::Peri; 5use embassy_hal_internal::Peri;
4use embassy_hal_internal::interrupt::InterruptExt; 6use embassy_hal_internal::interrupt::InterruptExt;
5use maitake_sync::WaitCell; 7use maitake_sync::WaitCell;
@@ -13,73 +15,39 @@ use crate::peripherals::TRNG0;
13 15
14static WAIT_CELL: WaitCell = WaitCell::new(); 16static WAIT_CELL: WaitCell = WaitCell::new();
15 17
16/// TRNG Driver 18#[allow(private_bounds)]
17pub struct Trng<'d> { 19pub trait Mode: sealed::SealedMode {}
18 _peri: Peri<'d, TRNG0>,
19}
20 20
21impl<'d> Trng<'d> { 21mod sealed {
22 /// Instantiates a new TRNG peripheral driver with 128 samples of entropy. 22 pub trait SealedMode {}
23 pub fn new_128(_peri: Peri<'d, TRNG0>) -> Self { 23}
24 Self::new_inner(
25 _peri,
26 Config {
27 sample_size: 128,
28 retry_count: 1,
29 long_run_limit_max: 29,
30 monobit_limit_max: 94,
31 monobit_limit_range: 61,
32 run_length1_limit_max: 39,
33 run_length1_limit_range: 39,
34 run_length2_limit_max: 24,
35 run_length2_limit_range: 25,
36 run_length3_limit_max: 17,
37 run_length3_limit_range: 18,
38 ..Default::default()
39 },
40 )
41 }
42 24
43 /// Instantiates a new TRNG peripheral driver with 256 samples of entropy. 25macro_rules! define_mode {
44 pub fn new_256(_peri: Peri<'d, TRNG0>) -> Self { 26 ($mode:ident) => {
45 Self::new_inner( 27 pub struct $mode;
46 _peri, 28 impl sealed::SealedMode for $mode {}
47 Config { 29 impl Mode for $mode {}
48 sample_size: 256, 30 };
49 retry_count: 1, 31}
50 long_run_limit_max: 31,
51 monobit_limit_max: 171,
52 monobit_limit_range: 86,
53 run_length1_limit_max: 63,
54 run_length1_limit_range: 56,
55 run_length2_limit_max: 38,
56 run_length2_limit_range: 38,
57 run_length3_limit_max: 25,
58 run_length3_limit_range: 26,
59 ..Default::default()
60 },
61 )
62 }
63 32
64 /// Instantiates a new TRNG peripheral driver with 512 samples of entropy. 33define_mode!(Blocking);
65 pub fn new_512(_peri: Peri<'d, TRNG0>) -> Self { 34define_mode!(Async);
66 Self::new_inner(_peri, Default::default())
67 }
68 35
69 /// Instantiates a new TRNG peripheral driver. 36/// TRNG Driver
70 /// 37pub struct Trng<'d, M: Mode> {
71 /// NOTE: this constructor makes not attempt at validating the 38 _peri: Peri<'d, TRNG0>,
72 /// parameters. If you get this wrong, the security guarantees of 39 _phantom: PhantomData<M>,
73 /// the TRNG with regards to entropy may be violated 40}
74 pub fn new_with_custom_config(_peri: Peri<'d, TRNG0>, config: Config) -> Self {
75 Self::new_inner(_peri, config)
76 }
77 41
42impl<'d, M: Mode> Trng<'d, M> {
78 fn new_inner(_peri: Peri<'d, TRNG0>, config: Config) -> Self { 43 fn new_inner(_peri: Peri<'d, TRNG0>, config: Config) -> Self {
79 _ = unsafe { enable_and_reset::<TRNG0>(&NoConfig) }; 44 _ = unsafe { enable_and_reset::<TRNG0>(&NoConfig) };
80 45
81 Self::configure(config); 46 Self::configure(config);
82 Self { _peri } 47 Self {
48 _peri,
49 _phantom: PhantomData,
50 }
83 } 51 }
84 52
85 fn configure(config: Config) { 53 fn configure(config: Config) {
@@ -241,31 +209,72 @@ impl<'d> Trng<'d> {
241 } 209 }
242} 210}
243 211
244impl Drop for Trng<'_> { 212impl<'d> Trng<'d, Blocking> {
245 fn drop(&mut self) { 213 /// Instantiates a new TRNG peripheral driver with 128 samples of entropy.
246 // wait until allowed to stop 214 pub fn new_blocking_128(_peri: Peri<'d, TRNG0>) -> Self {
247 while regs().mctl().read().tstop_ok().bit_is_clear() {} 215 Self::new_inner(
248 // stop 216 _peri,
249 Self::stop(); 217 Config {
250 // reset the TRNG 218 sample_size: 128,
251 regs().mctl().write(|w| w.rst_def().set_bit()); 219 retry_count: 1,
220 long_run_limit_max: 29,
221 monobit_limit_max: 94,
222 monobit_limit_range: 61,
223 run_length1_limit_max: 39,
224 run_length1_limit_range: 39,
225 run_length2_limit_max: 24,
226 run_length2_limit_range: 25,
227 run_length3_limit_max: 17,
228 run_length3_limit_range: 18,
229 ..Default::default()
230 },
231 )
252 } 232 }
253}
254 233
255/// TRNG Async Driver 234 /// Instantiates a new TRNG peripheral driver with 256 samples of entropy.
256pub struct AsyncTrng<'d> { 235 pub fn new_blocking_256(_peri: Peri<'d, TRNG0>) -> Self {
257 _peri: Peri<'d, TRNG0>, 236 Self::new_inner(
237 _peri,
238 Config {
239 sample_size: 256,
240 retry_count: 1,
241 long_run_limit_max: 31,
242 monobit_limit_max: 171,
243 monobit_limit_range: 86,
244 run_length1_limit_max: 63,
245 run_length1_limit_range: 56,
246 run_length2_limit_max: 38,
247 run_length2_limit_range: 38,
248 run_length3_limit_max: 25,
249 run_length3_limit_range: 26,
250 ..Default::default()
251 },
252 )
253 }
254
255 /// Instantiates a new TRNG peripheral driver with 512 samples of entropy.
256 pub fn new_blocking_512(_peri: Peri<'d, TRNG0>) -> Self {
257 Self::new_inner(_peri, Default::default())
258 }
259
260 /// Instantiates a new TRNG peripheral driver.
261 ///
262 /// NOTE: this constructor makes no attempt at validating the
263 /// parameters. If you get this wrong, the security guarantees of
264 /// the TRNG with regards to entropy may be violated
265 pub fn new_blocking_with_custom_config(_peri: Peri<'d, TRNG0>, config: Config) -> Self {
266 Self::new_inner(_peri, config)
267 }
258} 268}
259 269
260impl<'d> AsyncTrng<'d> { 270impl<'d> Trng<'d, Async> {
261 /// Instantiates a new TRNG peripheral driver with 128 samples of entropy. 271 /// Instantiates a new TRNG peripheral driver with 128 samples of entropy.
262 pub fn new_128( 272 pub fn new_128(
263 _peri: Peri<'d, TRNG0>, 273 _peri: Peri<'d, TRNG0>,
264 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd, 274 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
265 ) -> Self { 275 ) -> Self {
266 Self::new_inner( 276 let inst = Self::new_inner(
267 _peri, 277 _peri,
268 _irq,
269 Config { 278 Config {
270 sample_size: 128, 279 sample_size: 128,
271 retry_count: 1, 280 retry_count: 1,
@@ -280,7 +289,12 @@ impl<'d> AsyncTrng<'d> {
280 run_length3_limit_range: 18, 289 run_length3_limit_range: 18,
281 ..Default::default() 290 ..Default::default()
282 }, 291 },
283 ) 292 );
293 crate::pac::Interrupt::TRNG0.unpend();
294 unsafe {
295 crate::pac::Interrupt::TRNG0.enable();
296 }
297 inst
284 } 298 }
285 299
286 /// Instantiates a new TRNG peripheral driver with 256 samples of entropy. 300 /// Instantiates a new TRNG peripheral driver with 256 samples of entropy.
@@ -288,9 +302,8 @@ impl<'d> AsyncTrng<'d> {
288 _peri: Peri<'d, TRNG0>, 302 _peri: Peri<'d, TRNG0>,
289 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd, 303 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
290 ) -> Self { 304 ) -> Self {
291 Self::new_inner( 305 let inst = Self::new_inner(
292 _peri, 306 _peri,
293 _irq,
294 Config { 307 Config {
295 sample_size: 256, 308 sample_size: 256,
296 retry_count: 1, 309 retry_count: 1,
@@ -305,7 +318,12 @@ impl<'d> AsyncTrng<'d> {
305 run_length3_limit_range: 26, 318 run_length3_limit_range: 26,
306 ..Default::default() 319 ..Default::default()
307 }, 320 },
308 ) 321 );
322 crate::pac::Interrupt::TRNG0.unpend();
323 unsafe {
324 crate::pac::Interrupt::TRNG0.enable();
325 }
326 inst
309 } 327 }
310 328
311 /// Instantiates a new TRNG peripheral driver with 512 samples of entropy. 329 /// Instantiates a new TRNG peripheral driver with 512 samples of entropy.
@@ -313,12 +331,17 @@ impl<'d> AsyncTrng<'d> {
313 _peri: Peri<'d, TRNG0>, 331 _peri: Peri<'d, TRNG0>,
314 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd, 332 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
315 ) -> Self { 333 ) -> Self {
316 Self::new_inner(_peri, _irq, Default::default()) 334 let inst = Self::new_inner(_peri, Default::default());
335 crate::pac::Interrupt::TRNG0.unpend();
336 unsafe {
337 crate::pac::Interrupt::TRNG0.enable();
338 }
339 inst
317 } 340 }
318 341
319 /// Instantiates a new TRNG peripheral driver. 342 /// Instantiates a new TRNG peripheral driver.
320 /// 343 ///
321 /// NOTE: this constructor makes not attempt at validating the 344 /// NOTE: this constructor makes no attempt at validating the
322 /// parameters. If you get this wrong, the security guarantees of 345 /// parameters. If you get this wrong, the security guarantees of
323 /// the TRNG with regards to entropy may be violated 346 /// the TRNG with regards to entropy may be violated
324 pub fn new_with_custom_config( 347 pub fn new_with_custom_config(
@@ -326,24 +349,12 @@ impl<'d> AsyncTrng<'d> {
326 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd, 349 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
327 config: Config, 350 config: Config,
328 ) -> Self { 351 ) -> Self {
329 Self::new_inner(_peri, _irq, config) 352 let inst = Self::new_inner(_peri, config);
330 }
331
332 fn new_inner(
333 _peri: Peri<'d, TRNG0>,
334 _irq: impl crate::interrupt::typelevel::Binding<typelevel::TRNG0, InterruptHandler> + 'd,
335 config: Config,
336 ) -> Self {
337 _ = unsafe { enable_and_reset::<TRNG0>(&NoConfig) };
338
339 Trng::configure(config);
340
341 crate::pac::Interrupt::TRNG0.unpend(); 353 crate::pac::Interrupt::TRNG0.unpend();
342 unsafe { 354 unsafe {
343 crate::pac::Interrupt::TRNG0.enable(); 355 crate::pac::Interrupt::TRNG0.enable();
344 } 356 }
345 357 inst
346 Self { _peri }
347 } 358 }
348 359
349 fn enable_ints() { 360 fn enable_ints() {
@@ -377,88 +388,39 @@ impl<'d> AsyncTrng<'d> {
377 return Ok(()); // nothing to fill 388 return Ok(()); // nothing to fill
378 } 389 }
379 390
380 Trng::start();
381 for chunk in buf.chunks_mut(32) { 391 for chunk in buf.chunks_mut(32) {
382 Self::wait_for_generation().await?; 392 Self::wait_for_generation().await?;
383 Trng::fill_chunk(chunk); 393 Self::fill_chunk(chunk);
384 } 394 }
385 Trng::stop();
386 395
387 Ok(()) 396 Ok(())
388 } 397 }
389 398
390 /// Return a random u32, async version. 399 /// Return a random u32, async version.
391 pub async fn async_next_u32(&mut self) -> Result<u32, Error> { 400 pub async fn async_next_u32(&mut self) -> Result<u32, Error> {
392 Trng::start();
393 Self::wait_for_generation().await?; 401 Self::wait_for_generation().await?;
394 // New random bytes are generated only after reading ENT7 402 // New random bytes are generated only after reading ENT7
395 let result = regs().ent(7).read().bits(); 403 Ok(regs().ent(7).read().bits())
396 Trng::stop();
397
398 Ok(result)
399 } 404 }
400 405
401 /// Return a random u64, async version. 406 /// Return a random u64, async version.
402 pub async fn async_next_u64(&mut self) -> Result<u64, Error> { 407 pub async fn async_next_u64(&mut self) -> Result<u64, Error> {
403 Trng::start();
404 Self::wait_for_generation().await?; 408 Self::wait_for_generation().await?;
405 409
406 let mut result = u64::from(regs().ent(6).read().bits()) << 32; 410 let mut result = u64::from(regs().ent(6).read().bits()) << 32;
407 // New random bytes are generated only after reading ENT7 411 // New random bytes are generated only after reading ENT7
408 result |= u64::from(regs().ent(7).read().bits()); 412 result |= u64::from(regs().ent(7).read().bits());
409 413
410 Trng::stop();
411
412 Ok(result) 414 Ok(result)
413 } 415 }
414
415 // Blocking API
416
417 /// Fill the buffer with random bytes, blocking version.
418 pub fn blocking_fill_bytes(&mut self, buf: &mut [u8]) {
419 if buf.is_empty() {
420 return; // nothing to fill
421 }
422
423 Trng::start();
424 for chunk in buf.chunks_mut(32) {
425 Trng::blocking_wait_for_generation();
426 Trng::fill_chunk(chunk);
427 }
428 Trng::stop();
429 }
430
431 /// Return a random u32, blocking version.
432 pub fn blocking_next_u32(&mut self) -> u32 {
433 Trng::start();
434 Trng::blocking_wait_for_generation();
435 let result = regs().ent(0).read().bits();
436
437 // New random bytes are generated only after reading ENT7
438 let _ = regs().ent(7).read().bits();
439 Trng::stop();
440
441 result
442 }
443
444 /// Return a random u64, blocking version.
445 pub fn blocking_next_u64(&mut self) -> u64 {
446 Trng::start();
447 Trng::blocking_wait_for_generation();
448
449 let mut result = u64::from(regs().ent(0).read().bits()) << 32;
450 result |= u64::from(regs().ent(1).read().bits());
451
452 // New random bytes are generated only after reading ENT7
453 let _ = regs().ent(7).read().bits();
454 Trng::stop();
455
456 result
457 }
458} 416}
459 417
460impl Drop for AsyncTrng<'_> { 418impl<M: Mode> Drop for Trng<'_, M> {
461 fn drop(&mut self) { 419 fn drop(&mut self) {
420 // wait until allowed to stop
421 while regs().mctl().read().tstop_ok().bit_is_clear() {}
422 // stop
423 Self::stop();
462 // reset the TRNG 424 // reset the TRNG
463 regs().mctl().write(|w| w.rst_def().set_bit()); 425 regs().mctl().write(|w| w.rst_def().set_bit());
464 } 426 }
@@ -678,44 +640,7 @@ impl From<OscMode> for TrngEntCtl {
678 } 640 }
679} 641}
680 642
681impl<'d> rand_core_06::RngCore for Trng<'d> { 643impl<'d, M: Mode> rand_core_06::RngCore for Trng<'d, M> {
682 fn next_u32(&mut self) -> u32 {
683 self.blocking_next_u32()
684 }
685
686 fn next_u64(&mut self) -> u64 {
687 self.blocking_next_u64()
688 }
689
690 fn fill_bytes(&mut self, dest: &mut [u8]) {
691 self.blocking_fill_bytes(dest);
692 }
693
694 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
695 self.blocking_fill_bytes(dest);
696 Ok(())
697 }
698}
699
700impl<'d> rand_core_06::CryptoRng for Trng<'d> {}
701
702impl<'d> rand_core_09::RngCore for Trng<'d> {
703 fn next_u32(&mut self) -> u32 {
704 self.blocking_next_u32()
705 }
706
707 fn next_u64(&mut self) -> u64 {
708 self.blocking_next_u64()
709 }
710
711 fn fill_bytes(&mut self, dest: &mut [u8]) {
712 self.blocking_fill_bytes(dest);
713 }
714}
715
716impl<'d> rand_core_09::CryptoRng for Trng<'d> {}
717
718impl<'d> rand_core_06::RngCore for AsyncTrng<'d> {
719 fn next_u32(&mut self) -> u32 { 644 fn next_u32(&mut self) -> u32 {
720 self.blocking_next_u32() 645 self.blocking_next_u32()
721 } 646 }
@@ -734,9 +659,9 @@ impl<'d> rand_core_06::RngCore for AsyncTrng<'d> {
734 } 659 }
735} 660}
736 661
737impl<'d> rand_core_06::CryptoRng for AsyncTrng<'d> {} 662impl<'d, M: Mode> rand_core_06::CryptoRng for Trng<'d, M> {}
738 663
739impl<'d> rand_core_09::RngCore for AsyncTrng<'d> { 664impl<'d, M: Mode> rand_core_09::RngCore for Trng<'d, M> {
740 fn next_u32(&mut self) -> u32 { 665 fn next_u32(&mut self) -> u32 {
741 self.blocking_next_u32() 666 self.blocking_next_u32()
742 } 667 }
@@ -750,4 +675,4 @@ impl<'d> rand_core_09::RngCore for AsyncTrng<'d> {
750 } 675 }
751} 676}
752 677
753impl<'d> rand_core_09::CryptoRng for AsyncTrng<'d> {} 678impl<'d, M: Mode> rand_core_09::CryptoRng for Trng<'d, M> {}
diff --git a/examples/mcxa/src/bin/trng.rs b/examples/mcxa/src/bin/trng.rs
index bdd1f1041..5f6e2408c 100644
--- a/examples/mcxa/src/bin/trng.rs
+++ b/examples/mcxa/src/bin/trng.rs
@@ -4,7 +4,7 @@
4use embassy_executor::Spawner; 4use embassy_executor::Spawner;
5use hal::bind_interrupts; 5use hal::bind_interrupts;
6use hal::config::Config; 6use hal::config::Config;
7use hal::trng::{self, AsyncTrng, InterruptHandler, Trng}; 7use hal::trng::{self, InterruptHandler, Trng};
8use rand_core::RngCore; 8use rand_core::RngCore;
9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _}; 9use {defmt_rtt as _, embassy_mcxa as hal, panic_probe as _};
10 10
@@ -21,26 +21,26 @@ async fn main(_spawner: Spawner) {
21 21
22 defmt::info!("TRNG example"); 22 defmt::info!("TRNG example");
23 23
24 let mut trng = Trng::new_128(p.TRNG0.reborrow()); 24 let mut trng = Trng::new_blocking_128(p.TRNG0.reborrow());
25 let rand = trng.blocking_next_u32(); 25 let rand = trng.blocking_next_u32();
26 defmt::info!("128-bit {}", rand); 26 defmt::info!("128-bit {}", rand);
27 27
28 drop(trng); 28 drop(trng);
29 29
30 let mut trng = Trng::new_256(p.TRNG0.reborrow()); 30 let mut trng = Trng::new_blocking_256(p.TRNG0.reborrow());
31 let rand = trng.blocking_next_u32(); 31 let rand = trng.blocking_next_u32();
32 defmt::info!("256-bit {}", rand); 32 defmt::info!("256-bit {}", rand);
33 33
34 drop(trng); 34 drop(trng);
35 35
36 let mut trng = Trng::new_512(p.TRNG0.reborrow()); 36 let mut trng = Trng::new_blocking_512(p.TRNG0.reborrow());
37 let rand = trng.blocking_next_u32(); 37 let rand = trng.blocking_next_u32();
38 defmt::info!("512-bit {}", rand); 38 defmt::info!("512-bit {}", rand);
39 39
40 drop(trng); 40 drop(trng);
41 41
42 let config = trng::Config::default(); 42 let config = trng::Config::default();
43 let mut trng = Trng::new_with_custom_config(p.TRNG0.reborrow(), config); 43 let mut trng = Trng::new_blocking_with_custom_config(p.TRNG0.reborrow(), config);
44 44
45 defmt::info!("========== BLOCKING =========="); 45 defmt::info!("========== BLOCKING ==========");
46 46
@@ -75,7 +75,7 @@ async fn main(_spawner: Spawner) {
75 75
76 defmt::info!("========== ASYNC =========="); 76 defmt::info!("========== ASYNC ==========");
77 77
78 let mut trng = AsyncTrng::new_with_custom_config(p.TRNG0.reborrow(), Irqs, config); 78 let mut trng = Trng::new_with_custom_config(p.TRNG0.reborrow(), Irqs, config);
79 79
80 defmt::info!("Generate 10 u32"); 80 defmt::info!("Generate 10 u32");
81 for _ in 0..10 { 81 for _ in 0..10 {