]> git.proxmox.com Git - rustc.git/blob - src/librand/reseeding.rs
New upstream version 1.14.0+dfsg1
[rustc.git] / src / librand / reseeding.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! A wrapper around another RNG that reseeds it after it
12 //! generates a certain number of random bytes.
13
14 use {Rng, SeedableRng};
15
16 /// How many bytes of entropy the underling RNG is allowed to generate
17 /// before it is reseeded.
18 const DEFAULT_GENERATION_THRESHOLD: usize = 32 * 1024;
19
20 /// A wrapper around any RNG which reseeds the underlying RNG after it
21 /// has generated a certain number of random bytes.
22 pub struct ReseedingRng<R, Rsdr> {
23 rng: R,
24 generation_threshold: usize,
25 bytes_generated: usize,
26 /// Controls the behaviour when reseeding the RNG.
27 pub reseeder: Rsdr,
28 }
29
30 impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
31 /// Create a new `ReseedingRng` with the given parameters.
32 ///
33 /// # Arguments
34 ///
35 /// * `rng`: the random number generator to use.
36 /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
37 /// * `reseeder`: the reseeding object to use.
38 pub fn new(rng: R, generation_threshold: usize, reseeder: Rsdr) -> ReseedingRng<R, Rsdr> {
39 ReseedingRng {
40 rng: rng,
41 generation_threshold: generation_threshold,
42 bytes_generated: 0,
43 reseeder: reseeder,
44 }
45 }
46
47 /// Reseed the internal RNG if the number of bytes that have been
48 /// generated exceed the threshold.
49 pub fn reseed_if_necessary(&mut self) {
50 if self.bytes_generated >= self.generation_threshold {
51 self.reseeder.reseed(&mut self.rng);
52 self.bytes_generated = 0;
53 }
54 }
55 }
56
57
58 impl<R: Rng, Rsdr: Reseeder<R>> Rng for ReseedingRng<R, Rsdr> {
59 fn next_u32(&mut self) -> u32 {
60 self.reseed_if_necessary();
61 self.bytes_generated += 4;
62 self.rng.next_u32()
63 }
64
65 fn next_u64(&mut self) -> u64 {
66 self.reseed_if_necessary();
67 self.bytes_generated += 8;
68 self.rng.next_u64()
69 }
70
71 fn fill_bytes(&mut self, dest: &mut [u8]) {
72 self.reseed_if_necessary();
73 self.bytes_generated += dest.len();
74 self.rng.fill_bytes(dest)
75 }
76 }
77
78 impl<S, R: SeedableRng<S>, Rsdr: Reseeder<R> + Default>
79 SeedableRng<(Rsdr, S)> for ReseedingRng<R, Rsdr> {
80 fn reseed(&mut self, (rsdr, seed): (Rsdr, S)) {
81 self.rng.reseed(seed);
82 self.reseeder = rsdr;
83 self.bytes_generated = 0;
84 }
85
86 /// Create a new `ReseedingRng` from the given reseeder and
87 /// seed. This uses a default value for `generation_threshold`.
88 fn from_seed((rsdr, seed): (Rsdr, S)) -> ReseedingRng<R, Rsdr> {
89 ReseedingRng {
90 rng: SeedableRng::from_seed(seed),
91 generation_threshold: DEFAULT_GENERATION_THRESHOLD,
92 bytes_generated: 0,
93 reseeder: rsdr,
94 }
95 }
96 }
97
98 /// Something that can be used to reseed an RNG via `ReseedingRng`.
99 pub trait Reseeder<R> {
100 /// Reseed the given RNG.
101 fn reseed(&mut self, rng: &mut R);
102 }
103
104 /// Reseed an RNG using a `Default` instance. This reseeds by
105 /// replacing the RNG with the result of a `Default::default` call.
106 #[derive(Copy, Clone)]
107 pub struct ReseedWithDefault;
108
109 impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
110 fn reseed(&mut self, rng: &mut R) {
111 *rng = Default::default();
112 }
113 }
114 #[stable(feature = "rust1", since = "1.0.0")]
115 impl Default for ReseedWithDefault {
116 /// Creates an instance of `ReseedWithDefault`.
117 fn default() -> ReseedWithDefault {
118 ReseedWithDefault
119 }
120 }
121
122 #[cfg(test)]
123 mod tests {
124 use std::prelude::v1::*;
125
126 use super::{ReseedWithDefault, ReseedingRng};
127 use {Rng, SeedableRng};
128
129 struct Counter {
130 i: u32,
131 }
132
133 impl Rng for Counter {
134 fn next_u32(&mut self) -> u32 {
135 self.i += 1;
136 // very random
137 self.i - 1
138 }
139 }
140 impl Default for Counter {
141 /// Constructs a `Counter` with initial value zero.
142 fn default() -> Counter {
143 Counter { i: 0 }
144 }
145 }
146 impl SeedableRng<u32> for Counter {
147 fn reseed(&mut self, seed: u32) {
148 self.i = seed;
149 }
150 fn from_seed(seed: u32) -> Counter {
151 Counter { i: seed }
152 }
153 }
154 type MyRng = ReseedingRng<Counter, ReseedWithDefault>;
155
156 #[test]
157 fn test_reseeding() {
158 let mut rs = ReseedingRng::new(Counter { i: 0 }, 400, ReseedWithDefault);
159
160 let mut i = 0;
161 for _ in 0..1000 {
162 assert_eq!(rs.next_u32(), i % 100);
163 i += 1;
164 }
165 }
166
167 #[test]
168 fn test_rng_seeded() {
169 let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
170 let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
171 assert!(ra.gen_ascii_chars()
172 .take(100)
173 .eq(rb.gen_ascii_chars().take(100)));
174 }
175
176 #[test]
177 fn test_rng_reseed() {
178 let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
179 let string1: String = r.gen_ascii_chars().take(100).collect();
180
181 r.reseed((ReseedWithDefault, 3));
182
183 let string2: String = r.gen_ascii_chars().take(100).collect();
184 assert_eq!(string1, string2);
185 }
186
187 const FILL_BYTES_V_LEN: usize = 13579;
188 #[test]
189 fn test_rng_fill_bytes() {
190 let mut v = vec![0; FILL_BYTES_V_LEN];
191 ::test::rng().fill_bytes(&mut v);
192
193 // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
194 // recursed.
195 assert_eq!(v.len(), FILL_BYTES_V_LEN);
196
197 // To test that `fill_bytes` actually did something, check that the
198 // average of `v` is not 0.
199 let mut sum = 0.0;
200 for &x in &v {
201 sum += x as f64;
202 }
203 assert!(sum / v.len() as f64 != 0.0);
204 }
205 }