//! random -- print random bytes from the kernel's entropy source. //! //! random 16 random bytes as hex (a fresh 128-bit id) //! random -n 32 32 bytes as hex //! random -d 6 [N] roll N dice with 6 sides (default 1 die) //! //! The bytes come from the `getrandom` system call (Linux number 318), //! which the kernel fills from the virtio-rng device, i.e. from the host's //! /dev/urandom. /dev/random and /dev/urandom read the same source. #![no_std] #![no_main] #[macro_use] #[path = "../../../rbrt/ulib.rs"] mod ulib; use ulib::*; fn main() -> i64 { match (arg(1), arg(2), arg(3)) { (None, ..) => hex(16), (Some("-n"), Some(n), None) => match n.parse::() { Ok(n) if n <= 4096 => hex(n), _ => usage(), }, (Some("-d"), Some(sides), count) => { let sides = sides.parse::().unwrap_or(0); let count = count.map_or(Some(1), |c| c.parse::().ok()).unwrap_or(0); if sides < 2 || count == 0 || count > 100 { return usage(); } for i in 0..count { print!("{}{}", if i > 0 { " " } else { "" }, roll(sides)); } println!(); 0 } _ => usage(), } } /// Print `n` random bytes as hex digits. fn hex(n: usize) -> i64 { let mut buf = [0u8; 4096]; let r = getrandom(&mut buf[..n]); if r < 0 { eprintln!("random: getrandom: {}", strerror(r)); return 1; } for b in &buf[..n] { print!("{:02x}", b); } println!(); 0 } /// A fair number in 1..=sides. Plain `x % sides` would favour small /// numbers slightly, so throw away the values from the uneven top part. fn roll(sides: u64) -> u64 { let limit = u64::MAX - u64::MAX % sides; loop { let mut b = [0u8; 8]; getrandom(&mut b); let x = u64::from_le_bytes(b); if x < limit { return x % sides + 1; } } } fn usage() -> i64 { eprintln!("usage: random | random -n BYTES (max 4096) | random -d SIDES [COUNT]"); 2 }