-
Notifications
You must be signed in to change notification settings - Fork 10
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Rng: Add prng, hwrng support #54
Open
Remmirad
wants to merge
5
commits into
RIOT-OS:main
Choose a base branch
from
Remmirad:rng-support
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 2 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
use embedded_hal::blocking::rng::Read; | ||
|
||
#[derive(Debug)] | ||
#[non_exhaustive] | ||
pub enum HWRNGError {} | ||
|
||
/// Represents RIOTs hwrng module. It can be used via | ||
/// `embedded_hal`s [`embedded_hal::blocking::rng::Read`] trait. | ||
/// | ||
/// The main purpose of this module is to generate seeds for PRNGs like | ||
/// [`rand::rngs::StdRng`] or [`crate::random::Random`] (see [`crate::prng`] module). | ||
/// | ||
/// # Security | ||
/// As stated in RIOTs hwrng module-description the quality of the generated | ||
/// random data may vary drastically between boards. If you want to use this | ||
/// for e.g. cryptography make sure your current boards hwrng implementation | ||
/// provides random data with sufficient randomness. | ||
#[derive(Debug)] | ||
pub struct HWRNG; | ||
|
||
impl Read for HWRNG { | ||
type Error = HWRNGError; | ||
|
||
fn read(&mut self, buffer: &mut [u8]) -> Result<(), Self::Error> { | ||
unsafe { | ||
riot_sys::hwrng_read(buffer.as_mut_ptr() as *mut _, buffer.len() as u32); | ||
} | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
//! This module provides helper methods to setup pseudo-random-number-generators (prng's) | ||
//! by seeding them with data obtained from the [`crate::hwrng`] module. | ||
//! | ||
//! At the moment two prngs are available: [`rand::rngs::StdRng`] and [`crate::random::Random`]. | ||
//! Both of these claim to be cryptographic secure prngs. Provided of course the seeds from `hwrng` | ||
//! are secure to begin with, which drastically depends on the board used, see remarks in [`crate::hwrng`] module! | ||
|
||
|
||
use embedded_hal::prelude::_embedded_hal_blocking_rng_Read; | ||
use rand::{rngs::StdRng, SeedableRng}; | ||
|
||
use crate::{ | ||
hwrng::HWRNG, | ||
random::{Random, RandomSeed}, | ||
}; | ||
|
||
/// Seeds a [`crate::random::Random`] prng with a 32bit seed generated by [`crate::hwrng::HWRNG`]. | ||
/// | ||
/// See this modules description regarding quality of the used seeds. | ||
/// | ||
/// Be aware that there should be only one `Random` object at a time, | ||
/// since RIOT uses a global state for this internally, so creating a second object | ||
/// just results in the global state beeing overwritten and | ||
/// both objects representing practically the same prng. | ||
#[cfg(riot_module_random)] | ||
pub fn riot_prng() -> Random<32> { | ||
Random::<32>::from_seed(RandomSeed::new_from_hwrng()) | ||
} | ||
|
||
/// Seeds a [`rand::rngs::StdRng`] prng with a 32bit seed generated by [`crate::hwrng::HWRNG`]. | ||
/// | ||
/// See this modules description regarding quality of the used seeds. | ||
pub fn rand_prng() -> StdRng { | ||
let mut buffer = [0u8; 32]; | ||
|
||
HWRNG.read(&mut buffer).unwrap(); | ||
|
||
StdRng::from_seed(buffer) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
use core::mem::size_of; | ||
|
||
use embedded_hal::blocking::rng::Read; | ||
|
||
use rand::{RngCore, SeedableRng}; | ||
|
||
use crate::hwrng::HWRNG; | ||
|
||
/// Wrapper around RIOTs `random` module. | ||
/// | ||
/// ## Seedlength | ||
/// Since the module allows a dynamic seedsize | ||
/// it needs to be specified in the type. | ||
/// The `SEED_LENGTH` variable specifies the seedlength in bytes. | ||
/// **Since RIOT takes in `uint32_t` (`u32`) the length need to be divisable by 4!** | ||
/// | ||
/// ## Security | ||
/// Even though `Random` claims to be a cryptographic secure prng | ||
/// it only can be if provided sufficently random seeds! See remarks at [`crate::hwrng::HWRNG`] | ||
/// if when using it to generate seeds. | ||
/// | ||
/// ## Global state | ||
/// Be aware that there should be only one `Random` object at a time, | ||
/// since RIOT uses a global state for this internally, so creating a second object | ||
/// just results in the global state beeing overwritten and | ||
/// both objects representing practically the same prng. | ||
#[derive(Debug)] | ||
pub struct Random<const SEED_LENGTH: usize> { | ||
// Make sure this gets not manually constructed | ||
_private: (), | ||
} | ||
|
||
impl<const SEED_LENGTH: usize> RngCore for Random<SEED_LENGTH> { | ||
fn next_u32(&mut self) -> u32 { | ||
unsafe { riot_sys::random_uint32() } | ||
} | ||
|
||
fn next_u64(&mut self) -> u64 { | ||
rand_core::impls::next_u64_via_u32(self) | ||
} | ||
|
||
fn fill_bytes(&mut self, dest: &mut [u8]) { | ||
unsafe { riot_sys::random_bytes(dest.as_mut_ptr() as *mut _, dest.len() as u32) } | ||
} | ||
|
||
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand::Error> { | ||
self.fill_bytes(dest); | ||
Ok(()) | ||
} | ||
} | ||
|
||
/// A seed of length `SEED_LENGTH` inteded to be used by [`Random`]. | ||
/// | ||
/// ## Seedlength | ||
/// Since [`Random`] allows a dynamic seedsize | ||
/// it needs to be specified in the type. | ||
/// The `SEED_LENGTH` variable specifies the seedlength in bytes. | ||
/// **Since RIOT takes in `uint32_t` (`u32`) the length need to be divisable by 4!** | ||
/// | ||
/// ## Security | ||
/// This is only a container for a seed and therefore | ||
/// can not give any assurances as to the quality of the contained seed, | ||
/// which wholly depends on the method with which the contained seed was generated. | ||
#[derive(Debug)] | ||
pub struct RandomSeed<const SEED_LENGTH: usize> { | ||
seed: [u8; SEED_LENGTH], | ||
} | ||
|
||
impl<const SEED_LENGTH: usize> RandomSeed<SEED_LENGTH> { | ||
// Workaround: see https://github.com/nvzqz/static-assertions-rs/issues/40#issuecomment-1458897730 | ||
const CHECK_DIVISIBLE_BY_FOUR: () = assert!(SEED_LENGTH & 3 == 0); | ||
|
||
/// Creates an empty (zeroed) seedcontainer. | ||
/// | ||
/// This should **not** be used as a seed for anything that | ||
/// should provide any security. It is only meant to setup the buffer, | ||
/// which then can be accessed via its `buffer()` method. | ||
pub fn new_empty() -> Self { | ||
// Needed here to force the evaluation of the const | ||
let _ = Self::CHECK_DIVISIBLE_BY_FOUR; | ||
|
||
RandomSeed { | ||
seed: [0; SEED_LENGTH], | ||
} | ||
} | ||
|
||
/// Creates a [`RandomSeed`] with a seed generated by | ||
/// [`crate::hwrng::HWRNG`]. | ||
/// | ||
/// See remakrs there on the quality of the | ||
/// generated seeds which depends very much on the used board. | ||
pub fn new_from_hwrng() -> Self { | ||
let mut seed = RandomSeed::<SEED_LENGTH>::default(); | ||
|
||
HWRNG.read(seed.buffer()).unwrap(); | ||
|
||
seed | ||
} | ||
|
||
/// The internal buffer | ||
pub fn buffer(&mut self) -> &mut [u8] { | ||
&mut self.seed | ||
} | ||
} | ||
|
||
// Enforced by `rand::SeedableRng` | ||
impl<const SEED_LENGTH: usize> Default for RandomSeed<SEED_LENGTH> { | ||
fn default() -> Self { | ||
Self::new_empty() | ||
} | ||
} | ||
|
||
// Enforced by `rand::SeedableRng` | ||
impl<const SEED_LENGTH: usize> AsMut<[u8]> for RandomSeed<SEED_LENGTH> { | ||
fn as_mut(&mut self) -> &mut [u8] { | ||
&mut self.seed | ||
} | ||
} | ||
|
||
impl<const SEED_LENGTH: usize> SeedableRng for Random<SEED_LENGTH> { | ||
type Seed = RandomSeed<SEED_LENGTH>; | ||
|
||
fn from_seed(mut seed: Self::Seed) -> Self { | ||
unsafe { | ||
riot_sys::random_init_by_array( | ||
seed.seed.as_mut_ptr() as *mut u32, | ||
(seed.seed.len() / size_of::<i32>()) as i32, | ||
); | ||
} | ||
Random { _private: () } | ||
} | ||
} |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As I understand, the sensible way to use all of this is through the prng module.
Is there any good reason that the hwrng module and the random module are pub in the first place, or that RandomSeed::new_from_hwrng would be public?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes it is intended to be used through
prng
. I just left the rest public in case someone might need it e.g to seed his own prng but we could make it private to make people use the "intended" way. I do not have a strong opinion on that matter.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then please limit the public parts. Public APIs that are not used are a needless compatibility liability -- whereas the two functions that will stay pub can easily be maintained. If it turns out that any part of this is needed, it's still easy to make a few more parts pub, whereas going back on that is a breaking change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made the two modules
random
andhwrng
private