Lines
85.71 %
Functions
100 %
//! TRNG implementation.
use portable_atomic::{AtomicUsize, Ordering};
static TRNG_ENABLED: AtomicUsize = AtomicUsize::new(0);
static TRNG_USERS: AtomicUsize = AtomicUsize::new(0);
use super::Rng;
use crate::peripherals::{ADC1, RNG};
/// Ensures random numbers are cryptographically secure.
#[instability::unstable]
pub struct TrngSource<'d> {
_rng: RNG<'d>,
_adc: ADC1<'d>,
}
impl<'d> TrngSource<'d> {
/// Enables the SAR ADC entropy source.
// TODO: this is not final. A single ADC channel should be sufficient.
pub fn new(_rng: RNG<'d>, _adc: ADC1<'d>) -> Self {
crate::soc::trng::ensure_randomness();
unsafe { Self::increase_entropy_source_counter() }
Self { _rng, _adc }
/// Increases the internal entropy source counter.
///
/// # Panics
/// Panics if the internal counter overflows.
/// # Safety
/// Must only be called after a new entropy source has been enabled.
pub unsafe fn increase_entropy_source_counter() {
if TRNG_ENABLED.fetch_add(1, Ordering::Relaxed) == usize::MAX {
panic!("TrngSource enable overflowed");
/// Decreases the internal entropy source counter.
/// Should only be called **before** disabling an entropy source (such as the
/// radio).
/// Should only be called as many times as
/// [`TrngSource::increase_entropy_source_counter`] was called.
/// Panics if the internal counter underflows. Dropping the `TrngSource` panics
/// if this method is called more times than
/// [`TrngSource::increase_entropy_source_counter`].
pub fn decrease_entropy_source_counter(_private: crate::private::Internal) {
match TRNG_ENABLED.fetch_sub(1, Ordering::Relaxed) {
0 => panic!("TrngSource is not active"),
1 => assert!(
TRNG_USERS.load(Ordering::Acquire) == 0,
"TRNG cannot be disabled while it's in use"
),
_ => {}
/// Returns whether the TRNG is currently enabled.
/// Entropy sources can be disabled at any time.
pub fn is_enabled() -> bool {
TRNG_ENABLED.load(Ordering::Relaxed) > 0
/// Attempts to disable the TRNG.
/// Panics if the TRNG is not enabled (i.e. it has been disabled by calling
/// [`TrngSource::decrease_entropy_source_counter`] incorrectly).
/// # Errors
/// [`TrngSource`] when there are TRNG users.
pub fn try_disable(self) -> Result<(), Self> {
if TRNG_ENABLED
.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |enabled| {
assert!(enabled > 0, "TrngSource is not active");
if TRNG_USERS.load(Ordering::Acquire) > 0 {
return None;
Some(enabled - 1)
})
.is_err()
{
// The TRNG is in use.
return Err(self);
core::mem::forget(self);
Ok(())
impl Drop for TrngSource<'_> {
fn drop(&mut self) {
Self::decrease_entropy_source_counter(crate::private::Internal);
crate::soc::trng::revert_trng();
/// Errors returned when constructing a [`Trng`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "defmt", derive(defmt::Format))]
#[non_exhaustive]
pub enum TrngError {
/// The [`TrngSource`] is not enabled.
/// Returned by [`Trng::try_new`] when the RNG is not configured to generate
/// true random numbers.
TrngSourceNotEnabled,
#[cfg_attr(docsrs, procmacros::doc_replace(
"analog_pin" => gpio_for_signal!(ADC1_CH3),
))]
/// True Random Number Generator (TRNG)
/// The `Trng` struct represents a true random number generator that combines randomness from the
/// hardware RNG and an ADC. Provides methods to generate random numbers and fill buffers with
/// random bytes. Because entropy is sourced from the ADC, the associated registers are used and
/// the ADC peripheral must be occupied.
/// To generate true random numbers, an instance of [`TrngSource`] is required. Once created,
/// [`Trng`] instances can be created at any time, as long as the [`TrngSource`] is alive
/// # Examples
/// ```rust, no_run
/// # {before_snippet}
/// # use esp_hal::peripherals::ADC1;
/// # use esp_hal::analog::adc::{AdcConfig, Attenuation, Adc};
/// #
/// use esp_hal::rng::{Trng, TrngSource};
/// let mut buf = [0u8; 16];
/// // ADC is not available from now
/// let trng_source = TrngSource::new(peripherals.RNG, peripherals.ADC1.reborrow());
/// let trng = Trng::try_new()?;
/// // Generate true random numbers
/// trng.read(&mut buf);
/// let true_random_number = trng.random();
/// // Downgrade to Rng to allow disabling the TrngSource
/// let rng = trng.downgrade();
/// // Drop the true random number source. ADC is available now.
/// core::mem::drop(trng_source);
/// let mut adc1_config = AdcConfig::new();
/// let mut adc1_pin = adc1_config.enable_pin(peripherals.__analog_pin__, Attenuation::_11dB);
/// let mut adc1 = Adc::new(peripherals.ADC1, adc1_config);
/// let pin_value = adc1.read_oneshot(&mut adc1_pin)?;
/// // Now we can only generate pseudo-random numbers...
/// rng.read(&mut buf);
/// let pseudo_random_number = rng.random();
/// // ... but the ADC is available for use.
/// let pin_value: u16 = adc1.read_oneshot(&mut adc1_pin)?;
/// # {after_snippet}
/// ```
#[derive(Debug)]
pub struct Trng {
rng: Rng,
impl Clone for Trng {
#[inline]
fn clone(&self) -> Self {
TRNG_USERS.fetch_add(1, Ordering::Acquire);
Self { rng: self.rng }
impl Trng {
/// Creates a new True Random Number Generator (TRNG) instance.
/// [`TrngError::TrngSourceNotEnabled`] when the [`TrngSource`] is not active.
pub fn try_new() -> Result<Self, TrngError> {
let this = Self { rng: Rng::new() };
if TRNG_ENABLED.load(Ordering::Acquire) == 0 {
// Dropping `this` reduces the TRNG_USERS count back (to 0 as it should be when TRNG
// is not enabled).
return Err(TrngError::TrngSourceNotEnabled);
Ok(this)
/// Returns a new, random `u32` integer.
pub fn random(&self) -> u32 {
self.rng.random()
/// Fills the provided buffer with random bytes.
pub fn read(&self, buffer: &mut [u8]) {
self.rng.read(buffer);
/// Downgrades the `Trng` instance to a `Rng` instance.
pub fn downgrade(self) -> Rng {
Rng::new()
impl Drop for Trng {
TRNG_USERS.fetch_sub(1, Ordering::Release);
/// Compatibility with `rand_core 0.6`. Documentation can be found at
/// <https://docs.rs/rand_core/0.6.4/rand_core/trait.RngCore.html>.
impl rand_core_06::RngCore for Trng {
fn next_u32(&mut self) -> u32 {
<Rng as rand_core_06::RngCore>::next_u32(&mut self.rng)
fn next_u64(&mut self) -> u64 {
<Rng as rand_core_06::RngCore>::next_u64(&mut self.rng)
fn fill_bytes(&mut self, dest: &mut [u8]) {
<Rng as rand_core_06::RngCore>::fill_bytes(&mut self.rng, dest)
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
<Rng as rand_core_06::RngCore>::try_fill_bytes(&mut self.rng, dest)
/// Compatibility with `rand_core 0.9`. Documentation can be found at
/// <https://docs.rs/rand_core/0.9.5/rand_core/trait.RngCore.html>.
impl rand_core_09::RngCore for Trng {
<Rng as rand_core_09::RngCore>::next_u32(&mut self.rng)
<Rng as rand_core_09::RngCore>::next_u64(&mut self.rng)
<Rng as rand_core_09::RngCore>::fill_bytes(&mut self.rng, dest)
/// <https://docs.rs/rand_core/0.6.4/rand_core/trait.CryptoRng.html>.
impl rand_core_06::CryptoRng for Trng {}
/// <https://docs.rs/rand_core/0.9.5/rand_core/trait.CryptoRng.html>.
impl rand_core_09::CryptoRng for Trng {}
// Non-try variants are blanket-implemented when `Error = Infallible`.
/// Compatibility with `rand_core 0.10`
impl rand_core_010::TryRng for Trng {
type Error = core::convert::Infallible;
fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
<Rng as rand_core_010::TryRng>::try_next_u32(&mut self.rng)
fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
<Rng as rand_core_010::TryRng>::try_next_u64(&mut self.rng)
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
<Rng as rand_core_010::TryRng>::try_fill_bytes(&mut self.rng, dest)
impl rand_core_010::TryCryptoRng for Trng {}