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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use rand_core::{RngCore, CryptoRng, Error, impls};
use {OsRng, JitterRng};
#[derive(Debug)]
pub struct EntropyRng {
rng: EntropySource,
}
#[derive(Debug)]
enum EntropySource {
Os(OsRng),
Jitter(JitterRng),
None,
}
impl EntropyRng {
pub fn new() -> Self {
EntropyRng { rng: EntropySource::None }
}
}
impl RngCore for EntropyRng {
fn next_u32(&mut self) -> u32 {
impls::next_u32_via_fill(self)
}
fn next_u64(&mut self) -> u64 {
impls::next_u64_via_fill(self)
}
fn fill_bytes(&mut self, dest: &mut [u8]) {
self.try_fill_bytes(dest).unwrap_or_else(|err|
panic!("all entropy sources failed; first error: {}", err))
}
fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
fn try_os_new(dest: &mut [u8]) -> Result<OsRng, Error>
{
let mut rng = OsRng::new()?;
rng.try_fill_bytes(dest)?;
Ok(rng)
}
fn try_jitter_new(dest: &mut [u8]) -> Result<JitterRng, Error>
{
let mut rng = JitterRng::new()?;
rng.try_fill_bytes(dest)?;
Ok(rng)
}
let mut switch_rng = None;
match self.rng {
EntropySource::None => {
let os_rng_result = try_os_new(dest);
match os_rng_result {
Ok(os_rng) => {
debug!("EntropyRng: using OsRng");
switch_rng = Some(EntropySource::Os(os_rng));
}
Err(os_rng_error) => {
warn!("EntropyRng: OsRng failed [falling back to JitterRng]: {}",
os_rng_error);
match try_jitter_new(dest) {
Ok(jitter_rng) => {
debug!("EntropyRng: using JitterRng");
switch_rng = Some(EntropySource::Jitter(jitter_rng));
}
Err(_jitter_error) => {
warn!("EntropyRng: JitterRng failed: {}",
_jitter_error);
return Err(os_rng_error);
}
}
}
}
}
EntropySource::Os(ref mut rng) => {
let os_rng_result = rng.try_fill_bytes(dest);
if let Err(os_rng_error) = os_rng_result {
warn!("EntropyRng: OsRng failed [falling back to JitterRng]: {}",
os_rng_error);
match try_jitter_new(dest) {
Ok(jitter_rng) => {
debug!("EntropyRng: using JitterRng");
switch_rng = Some(EntropySource::Jitter(jitter_rng));
}
Err(_jitter_error) => {
warn!("EntropyRng: JitterRng failed: {}",
_jitter_error);
return Err(os_rng_error);
}
}
}
}
EntropySource::Jitter(ref mut rng) => {
if let Ok(os_rng) = try_os_new(dest) {
debug!("EntropyRng: using OsRng");
switch_rng = Some(EntropySource::Os(os_rng));
} else {
return rng.try_fill_bytes(dest);
}
}
}
if let Some(rng) = switch_rng {
self.rng = rng;
}
Ok(())
}
}
impl CryptoRng for EntropyRng {}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_entropy() {
let mut rng = EntropyRng::new();
let n = (rng.next_u32() ^ rng.next_u32()).count_ones();
assert!(n >= 2);
}
}