]> git.proxmox.com Git - rustc.git/blame - src/librand/reseeding.rs
New upstream version 1.22.1+dfsg1
[rustc.git] / src / librand / reseeding.rs
CommitLineData
1a4d82fc
JJ
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
32a655c1 14use core::fmt;
1a4d82fc 15use {Rng, SeedableRng};
1a4d82fc
JJ
16
17/// How many bytes of entropy the underling RNG is allowed to generate
18/// before it is reseeded.
c34b1796 19const DEFAULT_GENERATION_THRESHOLD: usize = 32 * 1024;
1a4d82fc
JJ
20
21/// A wrapper around any RNG which reseeds the underlying RNG after it
22/// has generated a certain number of random bytes.
23pub struct ReseedingRng<R, Rsdr> {
24 rng: R,
c34b1796
AL
25 generation_threshold: usize,
26 bytes_generated: usize,
3b2f2976 27 /// Controls the behavior when reseeding the RNG.
1a4d82fc
JJ
28 pub reseeder: Rsdr,
29}
30
31impl<R: Rng, Rsdr: Reseeder<R>> ReseedingRng<R, Rsdr> {
32 /// Create a new `ReseedingRng` with the given parameters.
33 ///
34 /// # Arguments
35 ///
36 /// * `rng`: the random number generator to use.
37 /// * `generation_threshold`: the number of bytes of entropy at which to reseed the RNG.
38 /// * `reseeder`: the reseeding object to use.
b039eaaf 39 pub fn new(rng: R, generation_threshold: usize, reseeder: Rsdr) -> ReseedingRng<R, Rsdr> {
1a4d82fc 40 ReseedingRng {
3b2f2976
XL
41 rng,
42 generation_threshold,
1a4d82fc 43 bytes_generated: 0,
3b2f2976 44 reseeder,
1a4d82fc
JJ
45 }
46 }
47
48 /// Reseed the internal RNG if the number of bytes that have been
49 /// generated exceed the threshold.
50 pub fn reseed_if_necessary(&mut self) {
51 if self.bytes_generated >= self.generation_threshold {
52 self.reseeder.reseed(&mut self.rng);
53 self.bytes_generated = 0;
54 }
55 }
56}
57
1a4d82fc
JJ
58impl<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
78impl<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
3157f602
XL
86/// Create a new `ReseedingRng` from the given reseeder and
87/// seed. This uses a default value for `generation_threshold`.
1a4d82fc
JJ
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,
b039eaaf 93 reseeder: rsdr,
1a4d82fc
JJ
94 }
95 }
96}
97
32a655c1
SL
98impl<R: fmt::Debug, Rsdr: fmt::Debug> fmt::Debug for ReseedingRng<R, Rsdr> {
99 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
100 f.debug_struct("ReseedingRng")
101 .field("rng", &self.rng)
102 .field("generation_threshold", &self.generation_threshold)
103 .field("bytes_generated", &self.bytes_generated)
104 .field("reseeder", &self.reseeder)
105 .finish()
106 }
107}
108
1a4d82fc 109/// Something that can be used to reseed an RNG via `ReseedingRng`.
1a4d82fc
JJ
110pub trait Reseeder<R> {
111 /// Reseed the given RNG.
112 fn reseed(&mut self, rng: &mut R);
113}
114
115/// Reseed an RNG using a `Default` instance. This reseeds by
116/// replacing the RNG with the result of a `Default::default` call.
32a655c1 117#[derive(Copy, Clone, Debug)]
c34b1796 118pub struct ReseedWithDefault;
1a4d82fc
JJ
119
120impl<R: Rng + Default> Reseeder<R> for ReseedWithDefault {
121 fn reseed(&mut self, rng: &mut R) {
122 *rng = Default::default();
123 }
124}
85aaf69f 125#[stable(feature = "rust1", since = "1.0.0")]
1a4d82fc 126impl Default for ReseedWithDefault {
9e0c209e 127 /// Creates an instance of `ReseedWithDefault`.
b039eaaf
SL
128 fn default() -> ReseedWithDefault {
129 ReseedWithDefault
130 }
1a4d82fc
JJ
131}
132
133#[cfg(test)]
d9579d0f 134mod tests {
1a4d82fc
JJ
135 use std::prelude::v1::*;
136
3157f602
XL
137 use super::{ReseedWithDefault, ReseedingRng};
138 use {Rng, SeedableRng};
1a4d82fc
JJ
139
140 struct Counter {
b039eaaf 141 i: u32,
1a4d82fc
JJ
142 }
143
144 impl Rng for Counter {
145 fn next_u32(&mut self) -> u32 {
146 self.i += 1;
147 // very random
148 self.i - 1
149 }
150 }
151 impl Default for Counter {
c30ab7b3 152 /// Constructs a `Counter` with initial value zero.
1a4d82fc
JJ
153 fn default() -> Counter {
154 Counter { i: 0 }
155 }
156 }
157 impl SeedableRng<u32> for Counter {
158 fn reseed(&mut self, seed: u32) {
159 self.i = seed;
160 }
161 fn from_seed(seed: u32) -> Counter {
162 Counter { i: seed }
163 }
164 }
165 type MyRng = ReseedingRng<Counter, ReseedWithDefault>;
166
167 #[test]
168 fn test_reseeding() {
b039eaaf 169 let mut rs = ReseedingRng::new(Counter { i: 0 }, 400, ReseedWithDefault);
1a4d82fc
JJ
170
171 let mut i = 0;
85aaf69f 172 for _ in 0..1000 {
1a4d82fc
JJ
173 assert_eq!(rs.next_u32(), i % 100);
174 i += 1;
175 }
176 }
177
178 #[test]
179 fn test_rng_seeded() {
180 let mut ra: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
181 let mut rb: MyRng = SeedableRng::from_seed((ReseedWithDefault, 2));
3157f602 182 assert!(ra.gen_ascii_chars()
c30ab7b3
SL
183 .take(100)
184 .eq(rb.gen_ascii_chars().take(100)));
1a4d82fc
JJ
185 }
186
187 #[test]
188 fn test_rng_reseed() {
189 let mut r: MyRng = SeedableRng::from_seed((ReseedWithDefault, 3));
190 let string1: String = r.gen_ascii_chars().take(100).collect();
191
192 r.reseed((ReseedWithDefault, 3));
193
194 let string2: String = r.gen_ascii_chars().take(100).collect();
195 assert_eq!(string1, string2);
196 }
197
c34b1796 198 const FILL_BYTES_V_LEN: usize = 13579;
1a4d82fc
JJ
199 #[test]
200 fn test_rng_fill_bytes() {
c1a9b12d 201 let mut v = vec![0; FILL_BYTES_V_LEN];
85aaf69f 202 ::test::rng().fill_bytes(&mut v);
1a4d82fc
JJ
203
204 // Sanity test: if we've gotten here, `fill_bytes` has not infinitely
205 // recursed.
206 assert_eq!(v.len(), FILL_BYTES_V_LEN);
207
208 // To test that `fill_bytes` actually did something, check that the
209 // average of `v` is not 0.
210 let mut sum = 0.0;
85aaf69f 211 for &x in &v {
1a4d82fc
JJ
212 sum += x as f64;
213 }
214 assert!(sum / v.len() as f64 != 0.0);
215 }
216}