Skip to content

Commit

Permalink
random: Add module
Browse files Browse the repository at this point in the history
This provides an RNG similar to rand_core's OsRng, provided suitable
RIOT modules are enabled.
  • Loading branch information
chrysn committed Nov 23, 2023
1 parent 0cf9a84 commit 028196d
Show file tree
Hide file tree
Showing 3 changed files with 69 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ bare-metal = "1"
cstr = "^0.2.11"

heapless = "^0.7"
rand_core_06 = { package = "rand_core", version = "^0.6" }

# For nimble UUID parsing and some debug implementations
hex = { version = "^0.4.3", default-features = false }
Expand Down
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,8 @@ pub mod gnrc_util;
pub mod i2c;
#[cfg(riot_module_core_msg)]
pub mod msg;
#[cfg(riot_module_random)]
pub mod random;

#[cfg(riot_module_periph_spi)]
pub mod spi;
Expand Down
66 changes: 66 additions & 0 deletions src/random.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//! RIOT's system random number generator
/// The global random number generator available in RIOT
///
/// Actual functionality is available through its implementation of [rand_core_06::RngCore]. It
/// implements [rand_core_06::CryptoRng] if the RIOT module `prng_shaxprng` is present. (If more
/// CSPRNGs are implemented in RIOT, the list around this implementation needs to be extended).
///
/// Note that this *is* copy (unlike what RngCore recommends) -- because the state is not in here
/// but global (as is their own OsRng).
#[derive(Copy, Clone, Debug)]
pub struct Random(());

impl Random {
/// Access the system random number generator
#[cfg(riot_module_auto_init_random)]
fn new() -> Self {
Random(())
}

/// Seed and start the random number generator
///
/// While technically not unsound, this is marked unsafe as it may overwrite existing good RNG
/// state.
///
/// This is not going through the the [rand_core_06::SeedableRng] trait because that would
/// require per-RNG seedability.
unsafe fn new_with_seed(seed: u32) -> Self {
riot_sys::random_init(seed);
Random(())
}
}

#[cfg(riot_module_auto_init_random)]
impl Default for Random {
fn default() -> Self {
Self::new()
}
}

impl rand_core_06::RngCore for Random {
fn next_u32(&mut self) -> u32 {
// unsafe: C API makes no requirements, and the type ensures it's seeded
unsafe { riot_sys::random_uint32() }
}

fn next_u64(&mut self) -> u64 {
let mut result = core::mem::MaybeUninit::uninit();
// unsafe: C API makes no requirements, and the type ensures it's seeded
unsafe { riot_sys::random_bytes(result.as_mut_ptr() as _, 8) };
// unsafe: We had it written, and every state is inhabited
unsafe { result.assume_init() }
}

fn fill_bytes(&mut self, dest: &mut [u8]) {
// unsafe: C API makes no requirements, and the type ensures it's seeded
unsafe { riot_sys::random_bytes(dest.as_mut_ptr() as _, dest.len() as _) };
}

fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rand_core_06::Error> {
Ok(self.fill_bytes(dest))
}
}

#[cfg(riot_module_prng_shaxprng)]
impl rand_core_06::CryptoRng for Random {}

0 comments on commit 028196d

Please sign in to comment.