1use crate::std_facade::{Arc, String, ToOwned, Vec};
11use core::result::Result;
12use core::{fmt, str, u8, convert::TryInto};
13use crate::test_runner::{config, RngSeed};
14use rand::{self, Rng, RngCore, SeedableRng};
15use rand_chacha::ChaChaRng;
16use rand_xorshift::XorShiftRng;
17
18#[derive(Clone, Copy, Debug, PartialEq, Eq)]
24pub enum RngAlgorithm {
25 XorShift,
34 ChaCha,
39 PassThrough,
52 Recorder,
61 #[allow(missing_docs)]
62 #[doc(hidden)]
63 _NonExhaustive,
64}
65
66impl Default for RngAlgorithm {
67 fn default() -> Self {
68 RngAlgorithm::ChaCha
69 }
70}
71
72impl RngAlgorithm {
73 pub(crate) fn persistence_key(self) -> &'static str {
74 match self {
75 RngAlgorithm::XorShift => "xs",
76 RngAlgorithm::ChaCha => "cc",
77 RngAlgorithm::PassThrough => "pt",
78 RngAlgorithm::Recorder => "rc",
79 RngAlgorithm::_NonExhaustive => unreachable!(),
80 }
81 }
82
83 pub(crate) fn from_persistence_key(k: &str) -> Option<Self> {
84 match k {
85 "xs" => Some(RngAlgorithm::XorShift),
86 "cc" => Some(RngAlgorithm::ChaCha),
87 "pt" => Some(RngAlgorithm::PassThrough),
88 "rc" => Some(RngAlgorithm::Recorder),
89 _ => None,
90 }
91 }
92}
93
94impl str::FromStr for RngAlgorithm {
97 type Err = ();
98 fn from_str(s: &str) -> Result<Self, ()> {
99 RngAlgorithm::from_persistence_key(s).ok_or(())
100 }
101}
102impl fmt::Display for RngAlgorithm {
103 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
104 write!(f, "{}", self.persistence_key())
105 }
106}
107
108#[derive(Clone, Debug)]
110pub struct TestRng {
111 rng: TestRngImpl,
112}
113
114#[derive(Clone, Debug)]
115enum TestRngImpl {
116 XorShift(XorShiftRng),
117 ChaCha(ChaChaRng),
118 PassThrough {
119 off: usize,
120 end: usize,
121 data: Arc<[u8]>,
122 },
123 Recorder {
124 rng: ChaChaRng,
125 record: Vec<u8>,
126 },
127}
128
129impl RngCore for TestRng {
130 fn next_u32(&mut self) -> u32 {
131 match &mut self.rng {
132 TestRngImpl::XorShift(rng) => rng.next_u32(),
133 TestRngImpl::ChaCha(rng) => rng.next_u32(),
134 TestRngImpl::PassThrough { .. } => {
135 let mut buf = [0; 4];
136 self.fill_bytes(&mut buf[..]);
137 u32::from_le_bytes(buf)
138 }
139 TestRngImpl::Recorder { rng, record } => {
140 let read = rng.next_u32();
141 record.extend_from_slice(&read.to_le_bytes());
142 read
143 }
144 }
145 }
146
147 fn next_u64(&mut self) -> u64 {
148 match &mut self.rng {
149 TestRngImpl::XorShift(rng) => rng.next_u64(),
150 TestRngImpl::ChaCha(rng) => rng.next_u64(),
151 TestRngImpl::PassThrough { .. } => {
152 let mut buf = [0; 8];
153 self.fill_bytes(&mut buf[..]);
154 u64::from_le_bytes(buf)
155 }
156 TestRngImpl::Recorder { rng, record } => {
157 let read = rng.next_u64();
158 record.extend_from_slice(&read.to_le_bytes());
159 read
160 }
161 }
162 }
163
164 fn fill_bytes(&mut self, dest: &mut [u8]) {
165 match &mut self.rng {
166 TestRngImpl::XorShift(rng) => rng.fill_bytes(dest),
167 TestRngImpl::ChaCha(rng) => rng.fill_bytes(dest),
168 TestRngImpl::PassThrough { off, end, data } => {
169 let bytes_to_copy = dest.len().min(*end - *off);
170 dest[.. bytes_to_copy].copy_from_slice(&data[*off .. *off + bytes_to_copy]);
171 *off += bytes_to_copy;
172 for i in bytes_to_copy .. dest.len() {
173 dest[i] = 0;
174 }
175 }
176 TestRngImpl::Recorder { rng, record } => {
177 rng.fill_bytes(dest);
178 record.extend_from_slice(dest);
179 }
180 }
181 }
182}
183
184#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
185pub(crate) enum Seed {
186 XorShift([u8; 16]),
187 ChaCha([u8; 32]),
188 PassThrough(Option<(usize, usize)>, Arc<[u8]>),
189 Recorder([u8; 32]),
190}
191
192impl Seed {
193 pub(crate) fn from_bytes(algorithm: RngAlgorithm, seed: &[u8]) -> Self {
194 match algorithm {
195 RngAlgorithm::XorShift => {
196 assert_eq!(16, seed.len(), "XorShift requires a 16-byte seed");
197 let mut buf = [0; 16];
198 buf.copy_from_slice(seed);
199 Seed::XorShift(buf)
200 }
201
202 RngAlgorithm::ChaCha => {
203 assert_eq!(32, seed.len(), "ChaCha requires a 32-byte seed");
204 let mut buf = [0; 32];
205 buf.copy_from_slice(seed);
206 Seed::ChaCha(buf)
207 }
208
209 RngAlgorithm::PassThrough => Seed::PassThrough(None, seed.into()),
210
211 RngAlgorithm::Recorder => {
212 assert_eq!(32, seed.len(), "Recorder requires a 32-byte seed");
213 let mut buf = [0; 32];
214 buf.copy_from_slice(seed);
215 Seed::Recorder(buf)
216 }
217
218 RngAlgorithm::_NonExhaustive => unreachable!(),
219 }
220 }
221
222 pub(crate) fn from_persistence(string: &str) -> Option<Seed> {
223 fn from_base16(dst: &mut [u8], src: &str) -> Option<()> {
224 if dst.len() * 2 != src.len() {
225 return None;
226 }
227
228 for (dst_byte, src_pair) in
229 dst.into_iter().zip(src.as_bytes().chunks(2))
230 {
231 *dst_byte =
232 u8::from_str_radix(str::from_utf8(src_pair).ok()?, 16)
233 .ok()?;
234 }
235
236 Some(())
237 }
238
239 let parts =
240 string.trim().split(char::is_whitespace).collect::<Vec<_>>();
241 RngAlgorithm::from_persistence_key(&parts[0]).and_then(
242 |alg| match alg {
243 RngAlgorithm::XorShift => {
244 if 5 != parts.len() {
245 return None;
246 }
247
248 let mut dwords = [0u32; 4];
249 for (dword, part) in
250 (&mut dwords[..]).into_iter().zip(&parts[1..])
251 {
252 *dword = part.parse().ok()?;
253 }
254
255 let mut seed = [0u8; 16];
256 for (chunk, dword) in seed.chunks_mut(4).zip(dwords) {
257 chunk.copy_from_slice(&dword.to_le_bytes());
258 }
259 Some(Seed::XorShift(seed))
260 }
261
262 RngAlgorithm::ChaCha => {
263 if 2 != parts.len() {
264 return None;
265 }
266
267 let mut seed = [0u8; 32];
268 from_base16(&mut seed, &parts[1])?;
269 Some(Seed::ChaCha(seed))
270 }
271
272 RngAlgorithm::PassThrough => {
273 if 1 == parts.len() {
274 return Some(Seed::PassThrough(None, vec![].into()));
275 }
276
277 if 2 != parts.len() {
278 return None;
279 }
280
281 let mut seed = vec![0u8; parts[1].len() / 2];
282 from_base16(&mut seed, &parts[1])?;
283 Some(Seed::PassThrough(None, seed.into()))
284 }
285
286 RngAlgorithm::Recorder => {
287 if 2 != parts.len() {
288 return None;
289 }
290
291 let mut seed = [0u8; 32];
292 from_base16(&mut seed, &parts[1])?;
293 Some(Seed::Recorder(seed))
294 }
295
296 RngAlgorithm::_NonExhaustive => unreachable!(),
297 },
298 )
299 }
300
301 pub(crate) fn to_persistence(&self) -> String {
302 fn to_base16(dst: &mut String, src: &[u8]) {
303 for byte in src {
304 dst.push_str(&format!("{:02x}", byte));
305 }
306 }
307
308 match *self {
309 Seed::XorShift(ref seed) => {
310 let dwords = [
311 u32::from_le_bytes(seed[0..4].try_into().unwrap()),
312 u32::from_le_bytes(seed[4..8].try_into().unwrap()),
313 u32::from_le_bytes(seed[8..12].try_into().unwrap()),
314 u32::from_le_bytes(seed[12..16].try_into().unwrap()),
315 ];
316 format!(
317 "{} {} {} {} {}",
318 RngAlgorithm::XorShift.persistence_key(),
319 dwords[0],
320 dwords[1],
321 dwords[2],
322 dwords[3]
323 )
324 }
325
326 Seed::ChaCha(ref seed) => {
327 let mut string =
328 RngAlgorithm::ChaCha.persistence_key().to_owned();
329 string.push(' ');
330 to_base16(&mut string, seed);
331 string
332 }
333
334 Seed::PassThrough(bounds, ref data) => {
335 let data =
336 bounds.map_or(&data[..], |(start, end)| &data[start..end]);
337 let mut string =
338 RngAlgorithm::PassThrough.persistence_key().to_owned();
339 string.push(' ');
340 to_base16(&mut string, data);
341 string
342 }
343
344 Seed::Recorder(ref seed) => {
345 let mut string =
346 RngAlgorithm::Recorder.persistence_key().to_owned();
347 string.push(' ');
348 to_base16(&mut string, seed);
349 string
350 }
351 }
352 }
353}
354
355impl TestRng {
356 pub fn from_seed(algorithm: RngAlgorithm, seed: &[u8]) -> Self {
366 TestRng::from_seed_internal(Seed::from_bytes(algorithm, seed))
367 }
368
369 pub fn bytes_used(&self) -> Vec<u8> {
376 match self.rng {
377 TestRngImpl::Recorder { ref record, .. } => record.clone(),
378 _ => panic!("bytes_used() called on non-Recorder RNG"),
379 }
380 }
381
382 pub(crate) fn default_rng(seed: config::RngSeed, algorithm: RngAlgorithm) -> Self {
384 #[cfg(feature = "std")]
385 {
386 Self {
387 rng: match algorithm {
388 RngAlgorithm::XorShift => {
389 let rng = match seed {
390 RngSeed::Random => XorShiftRng::from_os_rng(),
391 RngSeed::Fixed(seed) => XorShiftRng::seed_from_u64(seed),
392 };
393 TestRngImpl::XorShift(rng)
394 }
395 RngAlgorithm::ChaCha => {
396 let rng = match seed {
397 RngSeed::Random => ChaChaRng::from_os_rng(),
398 RngSeed::Fixed(seed) => ChaChaRng::seed_from_u64(seed),
399 };
400 TestRngImpl::ChaCha(rng)
401 }
402 RngAlgorithm::PassThrough => {
403 panic!("cannot create default instance of PassThrough")
404 }
405 RngAlgorithm::Recorder => {
406 let rng = match seed {
407 RngSeed::Random => ChaChaRng::from_os_rng(),
408 RngSeed::Fixed(seed) => ChaChaRng::seed_from_u64(seed),
409 };
410 TestRngImpl::Recorder {rng, record: Vec::new()}
411 },
412 RngAlgorithm::_NonExhaustive => unreachable!(),
413 },
414 }
415 }
416 #[cfg(all(
417 not(feature = "std"),
418 any(target_arch = "x86", target_arch = "x86_64"),
419 feature = "hardware-rng"
420 ))]
421 {
422 return Self::hardware_rng(algorithm);
423 }
424 #[cfg(not(feature = "std"))]
425 {
426 return Self::deterministic_rng(algorithm);
427 }
428 }
429
430 const SEED_FOR_XOR_SHIFT: [u8; 16] = [
431 0xf4, 0x16, 0x16, 0x48, 0xc3, 0xac, 0x77, 0xac, 0x72, 0x20, 0x0b, 0xea,
432 0x99, 0x67, 0x2d, 0x6d,
433 ];
434
435 const SEED_FOR_CHA_CHA: [u8; 32] = [
436 0xf4, 0x16, 0x16, 0x48, 0xc3, 0xac, 0x77, 0xac, 0x72, 0x20, 0x0b, 0xea,
437 0x99, 0x67, 0x2d, 0x6d, 0xca, 0x9f, 0x76, 0xaf, 0x1b, 0x09, 0x73, 0xa0,
438 0x59, 0x22, 0x6d, 0xc5, 0x46, 0x39, 0x1c, 0x4a,
439 ];
440
441 #[cfg(all(
448 not(feature = "std"),
449 any(target_arch = "x86", target_arch = "x86_64"),
450 feature = "hardware-rng"
451 ))]
452 pub fn hardware_rng(algorithm: RngAlgorithm) -> Self {
453 use x86::random::{rdrand_slice, RdRand};
454
455 Self::from_seed_internal(match algorithm {
456 RngAlgorithm::XorShift => {
457 let mut seed: [u8; 16] = TestRng::SEED_FOR_XOR_SHIFT;
459 unsafe {
460 let r = rdrand_slice(&mut seed);
461 debug_assert!(r, "hardware_rng should only be called on machines with support for rdrand");
462 }
463 Seed::XorShift(seed)
464 }
465 RngAlgorithm::ChaCha => {
466 let mut seed: [u8; 32] = TestRng::SEED_FOR_CHA_CHA;
468 unsafe {
469 let r = rdrand_slice(&mut seed);
470 debug_assert!(r, "hardware_rng should only be called on machines with support for rdrand");
471 }
472 Seed::ChaCha(seed)
473 }
474 RngAlgorithm::PassThrough => {
475 panic!("deterministic RNG not available for PassThrough")
476 }
477 RngAlgorithm::Recorder => {
478 let mut seed: [u8; 32] = TestRng::SEED_FOR_CHA_CHA;
480 unsafe {
481 let r = rdrand_slice(&mut seed);
482 debug_assert!(r, "hardware_rng should only be called on machines with support for rdrand");
483 }
484 Seed::Recorder(seed)
485 }
486 RngAlgorithm::_NonExhaustive => unreachable!(),
487 })
488 }
489
490 pub fn deterministic_rng(algorithm: RngAlgorithm) -> Self {
505 Self::from_seed_internal(match algorithm {
506 RngAlgorithm::XorShift => {
507 Seed::XorShift(TestRng::SEED_FOR_XOR_SHIFT)
508 }
509 RngAlgorithm::ChaCha => Seed::ChaCha(TestRng::SEED_FOR_CHA_CHA),
510 RngAlgorithm::PassThrough => {
511 panic!("deterministic RNG not available for PassThrough")
512 }
513 RngAlgorithm::Recorder => Seed::Recorder(TestRng::SEED_FOR_CHA_CHA),
514 RngAlgorithm::_NonExhaustive => unreachable!(),
515 })
516 }
517
518 pub(crate) fn gen_rng(&mut self) -> Self {
521 Self::from_seed_internal(self.new_rng_seed())
522 }
523
524 pub(crate) fn set_seed(&mut self, seed: Seed) {
526 *self = Self::from_seed_internal(seed);
527 }
528
529 pub(crate) fn gen_get_seed(&mut self) -> Seed {
532 let seed = self.new_rng_seed();
533 self.set_seed(seed.clone());
534 seed
535 }
536
537 pub(crate) fn new_rng_seed(&mut self) -> Seed {
539 match self.rng {
540 TestRngImpl::XorShift(ref mut rng) => {
541 let mut seed = rng.random::<[u8; 16]>();
542
543 for word in seed.chunks_mut(4) {
547 word[3] ^= 0xde;
548 word[2] ^= 0xad;
549 word[1] ^= 0xbe;
550 word[0] ^= 0xef;
551 }
552
553 Seed::XorShift(seed)
554 }
555
556 TestRngImpl::ChaCha(ref mut rng) => Seed::ChaCha(rng.random()),
557
558 TestRngImpl::PassThrough {
559 ref mut off,
560 ref mut end,
561 ref data,
562 } => {
563 let len = *end - *off;
564 let child_start = *off + len / 2;
565 let child_end = *off + len;
566 *end = child_start;
567 Seed::PassThrough(
568 Some((child_start, child_end)),
569 Arc::clone(data),
570 )
571 }
572
573 TestRngImpl::Recorder { ref mut rng, .. } => {
574 Seed::Recorder(rng.random())
575 }
576 }
577 }
578
579 fn from_seed_internal(seed: Seed) -> Self {
581 Self {
582 rng: match seed {
583 Seed::XorShift(seed) => {
584 TestRngImpl::XorShift(XorShiftRng::from_seed(seed))
585 }
586
587 Seed::ChaCha(seed) => {
588 TestRngImpl::ChaCha(ChaChaRng::from_seed(seed))
589 }
590
591 Seed::PassThrough(bounds, data) => {
592 let (start, end) = bounds.unwrap_or((0, data.len()));
593 TestRngImpl::PassThrough {
594 off: start,
595 end,
596 data,
597 }
598 }
599
600 Seed::Recorder(seed) => TestRngImpl::Recorder {
601 rng: ChaChaRng::from_seed(seed),
602 record: Vec::new(),
603 },
604 },
605 }
606 }
607}
608
609#[cfg(test)]
610mod test {
611 use crate::std_facade::Vec;
612
613 use rand::{Rng, RngCore};
614
615 use super::{RngAlgorithm, Seed, TestRng};
616 use crate::arbitrary::any;
617 use crate::strategy::*;
618
619 proptest! {
620 #[test]
621 fn gen_parse_seeds(
622 seed in prop_oneof![
623 any::<[u8;16]>().prop_map(Seed::XorShift),
624 any::<[u8;32]>().prop_map(Seed::ChaCha),
625 any::<Vec<u8>>().prop_map(|data| Seed::PassThrough(None, data.into())),
626 any::<[u8;32]>().prop_map(Seed::Recorder),
627 ])
628 {
629 assert_eq!(seed, Seed::from_persistence(&seed.to_persistence()).unwrap());
630 }
631
632 #[test]
633 fn rngs_dont_clone_self_on_genrng(
634 seed in prop_oneof![
635 any::<[u8;16]>().prop_map(Seed::XorShift),
636 any::<[u8;32]>().prop_map(Seed::ChaCha),
637 Just(()).prop_perturb(|_, mut rng| {
638 let mut buf = vec![0u8; 2048];
639 rng.fill_bytes(&mut buf);
640 Seed::PassThrough(None, buf.into())
641 }),
642 any::<[u8;32]>().prop_map(Seed::Recorder),
643 ])
644 {
645 type Value = [u8;32];
646 let orig = TestRng::from_seed_internal(seed);
647
648 {
649 let mut rng1 = orig.clone();
650 let mut rng2 = rng1.gen_rng();
651 assert_ne!(rng1.random::<Value>(), rng2.random::<Value>());
652 }
653
654 {
655 let mut rng1 = orig.clone();
656 let mut rng2 = rng1.gen_rng();
657 let mut rng3 = rng1.gen_rng();
658 let mut rng4 = rng2.gen_rng();
659 let a = rng1.random::<Value>();
660 let b = rng2.random::<Value>();
661 let c = rng3.random::<Value>();
662 let d = rng4.random::<Value>();
663 assert_ne!(a, b);
664 assert_ne!(a, c);
665 assert_ne!(a, d);
666 assert_ne!(b, c);
667 assert_ne!(b, d);
668 assert_ne!(c, d);
669 }
670 }
671 }
672
673 #[test]
674 fn passthrough_rng_behaves_properly() {
675 let mut rng = TestRng::from_seed(
676 RngAlgorithm::PassThrough,
677 &[
678 0xDE, 0xC0, 0x12, 0x34, 0x56, 0x78, 0xFE, 0xCA, 0xEF, 0xBE,
679 0xAD, 0xDE, 0x01, 0x02, 0x03,
680 ],
681 );
682
683 assert_eq!(0x3412C0DE, rng.next_u32());
684 assert_eq!(0xDEADBEEFCAFE7856, rng.next_u64());
685
686 let mut buf = [0u8; 4];
687 rng.fill_bytes(&mut buf[0..4]);
688 assert_eq!([1, 2, 3, 0], buf);
689 rng.fill_bytes(&mut buf[0..4]);
690 assert_eq!([0, 0, 0, 0], buf);
691 }
692}