1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// ---------------- [ File: bitcoin-random/src/sanity.rs ]
crate::ix!();
/**
| Check that OS randomness is available
| and returning the requested number
| of bytes.
|
*/
pub fn random_sanity_check() -> bool {
let mut start: u64 = get_performance_counter().try_into().unwrap();
/*
| This does not measure the quality of
| randomness, but it does test that
| GetOSRand() overwrites all 32 bytes
| of the output given a maximum number
| of tries.
|
*/
const MAX_TRIES: i32 = 1024;
let mut data: [u8; NUM_OS_RANDOM_BYTES as usize] = [0; NUM_OS_RANDOM_BYTES as usize];
/*
| Tracks which bytes have been overwritten
| at least once
|
*/
let mut overwritten: [bool; NUM_OS_RANDOM_BYTES as usize] = [false; NUM_OS_RANDOM_BYTES as usize];
let mut num_overwritten: i32 = 0;
let mut tries: i32 = 0;
/*
| Loop until all bytes have been overwritten
| at least once, or max number tries reached
|
*/
loop {
unsafe {
libc::memset(
data.as_mut_ptr() as *mut c_void,
0,
NUM_OS_RANDOM_BYTES as usize
);
}
get_os_rand(data.as_mut_ptr());
for x in 0..NUM_OS_RANDOM_BYTES {
overwritten[x as usize] |= data[x as usize] != 0;
}
num_overwritten = 0;
for x in 0..NUM_OS_RANDOM_BYTES {
if overwritten[x as usize] {
num_overwritten += 1;
}
}
tries += 1;
let onward: bool = num_overwritten < NUM_OS_RANDOM_BYTES && tries < MAX_TRIES;
if !onward {
break;
}
}
if num_overwritten != NUM_OS_RANDOM_BYTES {
/*
| If this failed, bailed out after too
| many tries
|
*/
return false;
}
/*
| Check that GetPerformanceCounter
| increases at least during a GetOSRand()
| call + 1ms sleep.
|
*/
std::thread::sleep(ONE_MILLISECOND.try_into().unwrap());
let mut stop: u64 = get_performance_counter().try_into().unwrap();
if stop == start {
return false;
}
/*
| We called GetPerformanceCounter.
| Use it as entropy.
|
*/
let mut to_add: Sha512 = Sha512::default();
to_add.write(&mut start as *mut u64 as *mut u8, size_of_val(&start));
to_add.write(&mut stop as *mut u64 as *mut u8, size_of_val(&stop));
G_RNG.lock().mix_extract(&mut [], 0, to_add, false);
true
}
#[cfg(test)]
mod sanity_spec {
use super::*;
#[traced_test]
fn random_sanity_check_passes() {
assert!(random_sanity_check(), "OS RNG sanity check failed on this system");
}
}