bsv/primitives/random.rs
1//! Cryptographically secure random byte generation.
2//!
3//! Uses the `getrandom` crate for OS-provided entropy, which delegates
4//! to the appropriate platform-specific CSPRNG (e.g., /dev/urandom on
5//! Linux, SecRandomCopyBytes on macOS, BCryptGenRandom on Windows).
6
7/// Generate `len` cryptographically secure random bytes.
8///
9/// Uses the operating system's CSPRNG via the `getrandom` crate.
10/// Returns an empty Vec if `len` is 0.
11///
12/// # Panics
13///
14/// Panics if the OS random number generator fails, which should
15/// only happen in extremely unusual circumstances (e.g., very early
16/// boot on a system with no entropy sources).
17pub fn random_bytes(len: usize) -> Vec<u8> {
18 if len == 0 {
19 return Vec::new();
20 }
21 let mut buf = vec![0u8; len];
22 // SAFETY: OS CSPRNG failure is unrecoverable (no entropy source available)
23 getrandom::getrandom(&mut buf).expect("OS random number generator failed");
24 buf
25}
26
27#[cfg(test)]
28mod tests {
29 use super::*;
30
31 #[test]
32 fn test_random_bytes_correct_length() {
33 assert_eq!(random_bytes(0).len(), 0);
34 assert_eq!(random_bytes(1).len(), 1);
35 assert_eq!(random_bytes(32).len(), 32);
36 assert_eq!(random_bytes(64).len(), 64);
37 assert_eq!(random_bytes(256).len(), 256);
38 }
39
40 #[test]
41 fn test_random_bytes_empty() {
42 let result = random_bytes(0);
43 assert!(result.is_empty());
44 }
45
46 #[test]
47 fn test_random_bytes_varying_output() {
48 // Two consecutive calls should produce different output
49 // (probability of collision for 32 bytes is negligible: 2^-256)
50 let a = random_bytes(32);
51 let b = random_bytes(32);
52 assert_ne!(
53 a, b,
54 "Two random_bytes(32) calls should produce different output"
55 );
56 }
57
58 #[test]
59 fn test_random_bytes_non_zero() {
60 // 64 random bytes should not all be zero
61 // (probability: 2^-512, effectively impossible)
62 let result = random_bytes(64);
63 assert!(
64 result.iter().any(|&b| b != 0),
65 "64 random bytes should not all be zero"
66 );
67 }
68
69 #[test]
70 fn test_random_bytes_distribution() {
71 // Generate a large sample and verify it's not degenerate
72 // (all same byte value would indicate a broken RNG)
73 let result = random_bytes(1024);
74 let first = result[0];
75 let all_same = result.iter().all(|&b| b == first);
76 assert!(
77 !all_same,
78 "1024 random bytes should not all be the same value"
79 );
80 }
81}