nanorand/
entropy.rs
1#[cfg(all(target_vendor = "apple", not(feature = "getrandom")))]
2pub use darwin::entropy as system;
3#[cfg(all(
4 any(target_os = "linux", target_os = "android"),
5 not(feature = "getrandom")
6))]
7pub use linux::entropy as system;
8#[cfg(all(windows, not(target_vendor = "uwp"), not(feature = "getrandom")))]
9pub use windows::entropy as system;
10#[cfg(all(windows, target_vendor = "uwp", not(feature = "getrandom")))]
11pub use windows_uwp::entropy as system;
12
13#[cfg(all(
14 any(target_os = "linux", target_os = "android"),
15 not(feature = "getrandom")
16))]
17pub mod linux;
19
20#[cfg(all(target_vendor = "apple", not(feature = "getrandom")))]
21pub mod darwin;
23
24#[cfg(all(windows, target_vendor = "uwp", not(feature = "getrandom")))]
25pub mod windows_uwp;
27
28#[cfg(all(windows, not(target_vendor = "uwp"), not(feature = "getrandom")))]
29pub mod windows;
31
32#[cfg(feature = "getrandom")]
33pub fn system(out: &mut [u8]) {
36 match getrandom::getrandom(out) {
37 Ok(_) => (),
38 Err(_) => backup(out),
39 }
40}
41
42#[cfg(not(any(
44 feature = "getrandom",
45 target_os = "linux",
46 target_os = "android",
47 target_vendor = "apple",
48 windows
49)))]
50pub fn system(out: &mut [u8]) {
51 backup_entropy(out);
52}
53
54#[cfg(feature = "rdseed")]
55#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
56fn stupid_rdseed_hack() -> Option<u64> {
57 #[cfg(target_arch = "x86")]
58 use core::arch::x86::_rdseed64_step as rdseed;
59 #[cfg(target_arch = "x86_64")]
60 use core::arch::x86_64::_rdseed64_step as rdseed;
61 let mut x = 0;
62 for _ in 0..10 {
63 if 0 != unsafe { rdseed(&mut x) } {
64 return Some(x);
65 }
66 }
67 None
68}
69
70#[cfg(all(feature = "rdseed", any(target_arch = "x86", target_arch = "x86_64")))]
71pub fn rdseed(out: &mut [u8]) -> Option<usize> {
77 if !std::is_x86_feature_detected!("rdseed") {
78 return None;
79 }
80 let amt = out.len();
81 let mut bytes_pulled: usize = 0;
82
83 let rdseed_amt = ((amt + core::mem::size_of::<u64>() - 1) / core::mem::size_of::<u64>()).max(0);
84 for n in 0..rdseed_amt {
85 let seed = match stupid_rdseed_hack() {
86 Some(s) => s,
87 None => return Some(bytes_pulled),
88 };
89 let x = seed.to_ne_bytes();
90 bytes_pulled += x.len();
91 x.iter()
92 .enumerate()
93 .for_each(|(i, val)| out[(core::mem::size_of::<u64>() * n) + i] = *val);
94 }
95 Some(bytes_pulled)
96}
97
98#[cfg(any(
100 not(feature = "rdseed"),
101 not(any(target_arch = "x86", target_arch = "x86_64"))
102))]
103pub fn rdseed(_out: &mut [u8]) -> Option<usize> {
104 None
105}
106
107#[cfg(feature = "std")]
108pub fn backup(out: &mut [u8]) {
116 if let Some(amt) = rdseed(out) {
117 if amt >= out.len() {
118 return;
119 }
120 };
121
122 panic!("Failed to source sufficient entropy!")
123}
124
125#[cfg(not(feature = "std"))]
126pub fn backup_entropy(_: &mut [u8]) {
128 panic!("Failed to source any entropy!")
129}