esp-hal icon indicating copy to clipboard operation
esp-hal copied to clipboard

Feature: correct TRNG mechanism

Open playfulFence opened this issue 9 months ago • 1 comments

Thank you for your contribution!

We appreciate the time and effort you've put into this pull request. To help us review it efficiently, please ensure you've gone through the following checklist:

Submission Checklist 📝

  • [x] I have updated existing examples or added new ones (if applicable).
  • [x] My changes were added to the CHANGELOG.md in the proper section.\

Pull Request Details 📖

Description

Based on what's discussed in #1499 and previous related issues, created a TRNG struct, which takes RNG peripheral and ADC instance. Working on using ADC peripheral instead of instance, this will be draft until it's done

Testing

#![no_std]
#![no_main]

use esp_backtrace as _;
use esp_hal::{prelude::*, rng::Trng,
    analog::adc::{AdcConfig, Attenuation, ADC},
    clock::ClockControl,
    delay::Delay,
    gpio::IO,
    peripherals::{Peripherals, ADC1}};

use esp_println::println;

#[entry]
fn main() -> ! {
    let peripherals = Peripherals::take();
    let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);

    let analog_pin = io.pins.gpio3.into_analog();
    let mut adc1_config = AdcConfig::new();
    let mut adc1_pin = adc1_config.enable_pin(analog_pin, Attenuation::Attenuation11dB);
    let mut adc1 = ADC::<ADC1>::new(peripherals.ADC1, adc1_config);
    let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap();
    
    let mut trng = Trng::new(peripherals.RNG, &mut adc1);
    
    let (mut rng, adc1) = trng.downgrade();
    
    // Fill a buffer with random bytes:
    let mut buf = [0u8; 16];
    // trng.read(&mut buf);
    println!("Random bytes: {:?}", buf);

    loop {
        println!("Random u32:   {}", rng.random());
        let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap();
        println!("ADC reading = {}", pin_value);
    }
}

playfulFence avatar May 05 '24 13:05 playfulFence

I guess Trng should implement https://docs.rs/rand_core/0.6.4/rand_core/trait.CryptoRngCore.html not just CryptRng

Would deserve some docs (but I see this is draft so you probably already thought about that)

bjoernQ avatar May 06 '24 06:05 bjoernQ

According to rand_core docs: CryptoRngCore An extension trait that is automatically implemented for any type implementing RngCore and CryptoRng.

playfulFence avatar May 10 '24 16:05 playfulFence

According to rand_core docs: CryptoRngCore An extension trait that is automatically implemented for any type implementing RngCore and CryptoRng.

But RngCore isn't implemented? Maybe the diff looks weird for me

bjoernQ avatar May 10 '24 16:05 bjoernQ

Oh, I did it, but maybe it's lost in another branch 😄. Will double check when I'm near my PC again.

playfulFence avatar May 10 '24 16:05 playfulFence

Looks good! Thanks for your continuous effort here. I think we should address the comment about the example code but otherwise looks good to me

bjoernQ avatar Jul 01 '24 06:07 bjoernQ

I tested on hardware and with ADC example changed to this:

//! Connect a potentiometer to an IO pin and see the read values change when
//! rotating the shaft.
//!
//! Alternatively, you could also connect the IO pin to GND or 3V3 to see the
//! maximum and minimum raw values read.

//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3

#![no_std]
#![no_main]

use esp_backtrace as _;
use esp_hal::{
    analog::adc::{Adc, AdcConfig, Attenuation},
    clock::ClockControl,
    delay::Delay,
    gpio::Io,
    peripherals::Peripherals,
    prelude::*,
    rng::Trng,
    system::SystemControl,
};
use esp_println::println;

#[entry]
fn main() -> ! {
    let peripherals = Peripherals::take();
    let system = SystemControl::new(peripherals.SYSTEM);
    let clocks = ClockControl::boot_defaults(system.clock_control).freeze();

    let io = Io::new(peripherals.GPIO, peripherals.IO_MUX);
    cfg_if::cfg_if! {
        if #[cfg(feature = "esp32")] {
            let analog_pin = io.pins.gpio32;
        } else if #[cfg(any(feature = "esp32s2", feature = "esp32s3"))] {
            let analog_pin = io.pins.gpio3;
        } else {
            let analog_pin = io.pins.gpio2;
        }
    }

    let mut adc = peripherals.ADC1;
    let mut trng = esp_hal::rng::Trng::new(peripherals.RNG, &mut adc);
    let mut buff = [0u8; 32];
    trng.read(&mut buff);
    println!("{:?}", buff);
    core::mem::drop(trng);

    // Create ADC instances
    let mut adc1_config = AdcConfig::new();
    let mut adc1_pin = adc1_config.enable_pin(analog_pin, Attenuation::Attenuation11dB);
    let mut adc1 = Adc::new(&mut adc, adc1_config);

    let delay = Delay::new(&clocks);

    loop {
        let pin_value: u16 = nb::block!(adc1.read_oneshot(&mut adc1_pin)).unwrap();
        println!("ADC reading = {}", pin_value);
        delay.delay_millis(1500);
    }
}

The C6 reads 0 once and then dies. Looks good on all other targets for me

bjoernQ avatar Jul 01 '24 14:07 bjoernQ

The C6 reads 0 once and then dies. Looks good on all other targets for me.

After some tests, it turned out that there's a same issue in esp-idf as well. I've created an issue there already: https://github.com/espressif/esp-idf/issues/14124

playfulFence avatar Jul 02 '24 13:07 playfulFence

All the limitations for esp32c6 are temporary since at this moment user cannot use ADC after TRNG is dropped (see https://github.com/espressif/esp-idf/issues/14124)

playfulFence avatar Jul 02 '24 13:07 playfulFence

We probably should document that calling core::mem:drop on Trng on ESP32-C6 will result in ADC1 being still unusable for now

bjoernQ avatar Jul 04 '24 08:07 bjoernQ