Skip to content

Commit

Permalink
Add functions to generate random u32 and u64 values
Browse files Browse the repository at this point in the history
  • Loading branch information
newpavlov committed Nov 25, 2024
1 parent e144b1b commit 672d69f
Show file tree
Hide file tree
Showing 27 changed files with 331 additions and 91 deletions.
16 changes: 14 additions & 2 deletions src/backends.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,20 @@ cfg_if! {
mod apple_other;
pub use apple_other::*;
} else if #[cfg(all(target_arch = "wasm32", target_os = "wasi"))] {
mod wasi;
pub use wasi::*;
cfg_if! {
if #[cfg(target_env = "p1")] {
mod wasi_p1;
pub use wasi_p1::*;
} else if #[cfg(target_env = "p2")] {
mod wasi_p2;
pub use wasi_p2::*;
} else {
compile_error!(
"Unknown version of WASI (only previews 1 and 2 are supported) \
or Rust version older than 1.80 was used"
);
}
}
} else if #[cfg(target_os = "hermit")] {
mod hermit;
pub use hermit::*;
Expand Down
2 changes: 2 additions & 0 deletions src/backends/apple_other.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
let dst_ptr = dest.as_mut_ptr().cast::<c_void>();
let ret = unsafe { libc::CCRandomGenerateBytes(dst_ptr, dest.len()) };
Expand Down
2 changes: 2 additions & 0 deletions src/backends/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::mem::MaybeUninit;

pub use crate::util::{inner_u32, inner_u64};

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
extern "Rust" {
fn __getrandom_v03_custom(dest: *mut u8, len: usize) -> Result<(), Error>;
Expand Down
2 changes: 2 additions & 0 deletions src/backends/esp_idf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[cfg(not(target_os = "espidf"))]
compile_error!("`esp_idf` backend can be enabled only for ESP-IDF targets!");

Expand Down
2 changes: 2 additions & 0 deletions src/backends/fuchsia.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::mem::MaybeUninit;

pub use crate::util::{inner_u32, inner_u64};

#[link(name = "zircon")]
extern "C" {
fn zx_cprng_draw(buffer: *mut u8, length: usize);
Expand Down
2 changes: 2 additions & 0 deletions src/backends/getentropy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

Expand Down
2 changes: 2 additions & 0 deletions src/backends/getrandom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

Expand Down
4 changes: 4 additions & 0 deletions src/backends/hermit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
use crate::Error;
use core::mem::MaybeUninit;

// Note that `sys_secure_rand32` and `sys_secure_rand64` are implemented using `sys_read_entropy`:
// https://docs.rs/libhermit-rs/0.6.3/src/hermit/syscalls/entropy.rs.html#62-97
pub use crate::util::{inner_u32, inner_u64};

extern "C" {
fn sys_read_entropy(buffer: *mut u8, length: usize, flags: u32) -> isize;
}
Expand Down
2 changes: 2 additions & 0 deletions src/backends/linux_android.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::mem::MaybeUninit;

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

Expand Down
2 changes: 2 additions & 0 deletions src/backends/linux_android_with_fallback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use core::{
};
use use_file::util_libc;

pub use crate::util::{inner_u32, inner_u64};

type GetRandomFn = unsafe extern "C" fn(*mut c_void, libc::size_t, libc::c_uint) -> libc::ssize_t;

/// Sentinel value which indicates that `libc::getrandom` either not available,
Expand Down
2 changes: 2 additions & 0 deletions src/backends/linux_rustix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::{Error, MaybeUninit};
use rustix::rand::{getrandom_uninit, GetRandomFlags};

pub use crate::util::{inner_u32, inner_u64};

#[cfg(not(any(target_os = "android", target_os = "linux")))]
compile_error!("`linux_rustix` backend can be enabled only for Linux/Android targets!");

Expand Down
2 changes: 2 additions & 0 deletions src/backends/netbsd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ use core::{
sync::atomic::{AtomicPtr, Ordering},
};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

Expand Down
61 changes: 52 additions & 9 deletions src/backends/rdrand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ cfg_if! {
}
}

static RDRAND_GOOD: lazy::LazyBool = lazy::LazyBool::new();

// Recommendation from "Intel® Digital Random Number Generator (DRNG) Software
// Implementation Guide" - Section 5.2.1 and "Intel® 64 and IA-32 Architectures
// Software Developer’s Manual" - Volume 1 - Section 7.3.17.1.
Expand Down Expand Up @@ -99,15 +101,6 @@ fn is_rdrand_good() -> bool {
unsafe { self_test() }
}

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
static RDRAND_GOOD: lazy::LazyBool = lazy::LazyBool::new();
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_exact(dest) }.ok_or(Error::FAILED_RDRAND)
}

// TODO: make this function safe when we have feature(target_feature_11)
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> {
Expand All @@ -127,3 +120,53 @@ unsafe fn rdrand_exact(dest: &mut [MaybeUninit<u8>]) -> Option<()> {
}
Some(())
}

#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u32() -> Option<u32> {
rdrand().map(crate::util::truncate)
}

#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u64() -> Option<u64> {
rdrand()
}

#[cfg(target_arch = "x86")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u32() -> Option<u32> {
rdrand()
}

#[cfg(target_arch = "x86")]
#[target_feature(enable = "rdrand")]
unsafe fn rdrand_u64() -> Option<u64> {
let a = rdrand()?;
let b = rdrand()?;
Some((u64::from(a) << 32) || u64::from(b))
}

pub fn inner_u32() -> Result<u32, Error> {
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_u32() }.ok_or(Error::FAILED_RDRAND)
}

pub fn inner_u64() -> Result<u64, Error> {
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_u64() }.ok_or(Error::FAILED_RDRAND)
}

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
if !RDRAND_GOOD.unsync_init(is_rdrand_good) {
return Err(Error::NO_RDRAND);
}
// SAFETY: After this point, we know rdrand is supported.
unsafe { rdrand_exact(dest) }.ok_or(Error::FAILED_RDRAND)
}
25 changes: 24 additions & 1 deletion src/backends/rndr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
//!
//! Arm Architecture Reference Manual for A-profile architecture:
//! ARM DDI 0487K.a, ID032224, D23.2.147 RNDR, Random Number
use crate::{util::slice_as_uninit, Error};
use crate::{
util::{slice_as_uninit, truncate},
Error,
};
use core::arch::asm;
use core::mem::{size_of, MaybeUninit};

Expand Down Expand Up @@ -101,6 +104,26 @@ fn is_rndr_available() -> bool {
}
}

pub fn inner_u32() -> Result<u32, Error> {
if is_rndr_available() {
// SAFETY: after this point, we know the `rand` target feature is enabled
let res = unsafe { rndr() };
res.map(truncate).ok_or(Error::RNDR_FAILURE)
} else {
Err(Error::RNDR_NOT_AVAILABLE)
}
}

pub fn inner_u64() -> Result<u64, Error> {
if is_rndr_available() {
// SAFETY: after this point, we know the `rand` target feature is enabled
let res = unsafe { rndr() };
res.ok_or(Error::RNDR_FAILURE)
} else {
Err(Error::RNDR_NOT_AVAILABLE)
}
}

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
if is_rndr_available() {
// SAFETY: after this point, we know the `rand` target feature is enabled
Expand Down
2 changes: 2 additions & 0 deletions src/backends/solaris.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
use crate::Error;
use core::{ffi::c_void, mem::MaybeUninit};

pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
mod util_libc;

Expand Down
2 changes: 2 additions & 0 deletions src/backends/solid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use crate::Error;
use core::mem::MaybeUninit;

pub use crate::util::{inner_u32, inner_u64};

extern "C" {
pub fn SOLID_RNG_SampleRandomBytes(buffer: *mut u8, length: usize) -> i32;
}
Expand Down
3 changes: 3 additions & 0 deletions src/backends/use_file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use core::{
sync::atomic::{AtomicI32, Ordering},
};

#[cfg(not(any(target_os = "android", target_os = "linux")))]
pub use crate::util::{inner_u32, inner_u64};

#[path = "../util_libc.rs"]
pub(super) mod util_libc;

Expand Down
2 changes: 2 additions & 0 deletions src/backends/vxworks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ use core::{
#[path = "../util_libc.rs"]
mod util_libc;

pub use crate::util::{inner_u32, inner_u64};

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
static RNG_INIT: AtomicBool = AtomicBool::new(false);
while !RNG_INIT.load(Relaxed) {
Expand Down
73 changes: 0 additions & 73 deletions src/backends/wasi.rs

This file was deleted.

30 changes: 30 additions & 0 deletions src/backends/wasi_p1.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//! Implementation for WASI Preview 1
use crate::Error;
use core::mem::MaybeUninit;

pub use crate::util::{inner_u32, inner_u64};

// This linking is vendored from the wasi crate:
// https://docs.rs/wasi/0.11.0+wasi-snapshot-preview1/src/wasi/lib_generated.rs.html#2344-2350
#[link(wasm_import_module = "wasi_snapshot_preview1")]
extern "C" {
fn random_get(arg0: i32, arg1: i32) -> i32;
}

pub fn fill_inner(dest: &mut [MaybeUninit<u8>]) -> Result<(), Error> {
// Based on the wasi code:
// https://docs.rs/wasi/0.11.0+wasi-snapshot-preview1/src/wasi/lib_generated.rs.html#2046-2062
// Note that size of an allocated object can not be bigger than isize::MAX bytes.
// WASI 0.1 supports only 32-bit WASM, so casting length to `i32` is safe.
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
let ret = unsafe { random_get(dest.as_mut_ptr() as i32, dest.len() as i32) };
match ret {
0 => Ok(()),
code => {
let err = u32::try_from(code)
.map(Error::from_os_error)
.unwrap_or(Error::UNEXPECTED);
Err(err)
}
}
}
Loading

0 comments on commit 672d69f

Please sign in to comment.