Skip to main content

dryoc/
rng.rs

1//! Random bytes come from the operating system through
2//! [`getrandom`](https://docs.rs/getrandom), which does not need `std`. On
3//! targets without a supported system source, such as bare-metal
4//! `thumbv7em-none-eabihf` or `aarch64-unknown-none`, the application must
5//! provide a
6//! [getrandom custom backend](https://docs.rs/getrandom/latest/getrandom/#custom-backend).
7
8#[cfg(feature = "alloc")]
9use alloc::vec::Vec;
10
11/// Provides random data up to `len` from the OS's random number generator.
12///
13/// # Panics
14///
15/// Panics if the operating system's random number generator fails.
16#[cfg(feature = "alloc")]
17#[must_use]
18pub fn randombytes_buf(len: usize) -> Vec<u8> {
19    let mut r: Vec<u8> = vec![0; len];
20    copy_randombytes(r.as_mut_slice());
21
22    r
23}
24
25/// Provides random data up to length of `data` from the OS's random number
26/// generator.
27///
28/// # Panics
29///
30/// Panics if the operating system's random number generator fails.
31pub fn copy_randombytes(dest: &mut [u8]) {
32    fill_from(getrandom::fill, dest)
33}
34
35/// Fills `dest` with `fill`, panicking on failure. The shared body of the
36/// public entry points; takes the source as a parameter so tests can
37/// substitute a failing one.
38fn fill_from<E: core::fmt::Debug>(fill: impl FnOnce(&mut [u8]) -> Result<(), E>, dest: &mut [u8]) {
39    fill(dest).expect("failed to fill random bytes");
40}
41
42#[cfg(test)]
43mod tests {
44    use super::*;
45
46    #[test]
47    #[cfg(feature = "alloc")]
48    fn randombytes_buf_returns_requested_length_and_fresh_data() {
49        assert!(randombytes_buf(0).is_empty());
50
51        let first = randombytes_buf(32);
52        let second = randombytes_buf(32);
53        assert_eq!(first.len(), 32);
54        assert_ne!(first, second, "two 32-byte draws collided");
55    }
56
57    #[test]
58    fn copy_randombytes_fills_exactly_the_destination() {
59        let mut buf = [0u8; 64];
60        copy_randombytes(&mut buf[16..48]);
61
62        assert_eq!(&buf[..16], &[0; 16]);
63        assert_eq!(&buf[48..], &[0; 16]);
64        assert_ne!(&buf[16..48], &[0; 32]);
65
66        copy_randombytes(&mut buf[..0]);
67        assert_eq!(&buf[..16], &[0; 16]);
68    }
69
70    #[test]
71    #[should_panic]
72    fn os_rng_failure_panics_instead_of_leaving_zeroes() {
73        let mut dest = [0u8; 8];
74        fill_from(|_: &mut [u8]| Err("no entropy"), &mut dest);
75    }
76}