1use chacha20::ChaCha20Rng;
11use crate::std_facade::{Arc, String, ToOwned, Vec};
12use core::convert::{Infallible, TryInto};
13use core::result::Result;
14use core::{fmt, str, u8};
15use crate::test_runner::config;
16use rand::{Rng, RngExt, SeedableRng, TryRng};
17#[cfg(feature = "std")]
18use rand::rand_core::UnwrapErr;
19#[cfg(feature = "std")]
20use rand::rngs::SysRng;
21use rand_xorshift::XorShiftRng;
22
23#[derive(Clone, Copy, Debug, PartialEq, Eq)]
29pub enum RngAlgorithm {
30 XorShift,
39 ChaCha,
44 PassThrough,
57 Recorder,
66 #[allow(missing_docs)]
67 #[doc(hidden)]
68 _NonExhaustive,
69}
70
71impl Default for RngAlgorithm {
72 fn default() -> Self {
73 RngAlgorithm::ChaCha
74 }
75}
76
77impl RngAlgorithm {
78 pub(crate) fn persistence_key(self) -> &'static str {
79 match self {
80 RngAlgorithm::XorShift => "xs",
81 RngAlgorithm::ChaCha => "cc",
82 RngAlgorithm::PassThrough => "pt",
83 RngAlgorithm::Recorder => "rc",
84 RngAlgorithm::_NonExhaustive => unreachable!(),
85 }
86 }
87
88 pub(crate) fn from_persistence_key(k: &str) -> Option<Self> {
89 match k {
90 "xs" => Some(RngAlgorithm::XorShift),
91 "cc" => Some(RngAlgorithm::ChaCha),
92 "pt" => Some(RngAlgorithm::PassThrough),
93 "rc" => Some(RngAlgorithm::Recorder),
94 _ => None,
95 }
96 }
97}
98
99impl str::FromStr for RngAlgorithm {
102 type Err = ();
103 fn from_str(s: &str) -> Result<Self, ()> {
104 RngAlgorithm::from_persistence_key(s).ok_or(())
105 }
106}
107impl fmt::Display for RngAlgorithm {
108 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
109 write!(f, "{}", self.persistence_key())
110 }
111}
112
113#[derive(Clone, Debug)]
115pub struct TestRng {
116 rng: TestRngImpl,
117}
118
119#[derive(Debug)]
120enum TestRngImpl {
121 XorShift(XorShiftRng),
122 ChaCha(ChaCha20Rng),
123 PassThrough {
124 off: usize,
125 end: usize,
126 data: Arc<[u8]>,
127 },
128 Recorder {
129 rng: ChaCha20Rng,
130 record: Vec<u8>,
131 },
132}
133
134impl Clone for TestRngImpl {
136 fn clone(&self) -> Self {
137 match self {
138 Self::XorShift(rng) => Self::XorShift(rng.clone()),
139 Self::ChaCha(rng) => Self::ChaCha(clone_chacha20_rng(rng)),
140 Self::PassThrough { off, end, data } => Self::PassThrough { off: off.clone(), end: end.clone(), data: data.clone() },
141 Self::Recorder { rng, record } => Self::Recorder { rng: clone_chacha20_rng(rng), record: record.clone() },
142 }
143 }
144}
145
146fn clone_chacha20_rng(rng: &ChaCha20Rng) -> ChaCha20Rng {
147 let seed = rng.get_seed();
148 let stream = rng.get_stream();
149 let word_offset = rng.get_word_pos();
150
151 let mut rng_clone = ChaCha20Rng::from_seed(seed);
152 rng_clone.set_stream(stream);
153 rng_clone.set_word_pos(word_offset);
154
155 rng_clone
156}
157
158#[cfg(feature = "std")]
159fn from_sys_rng<R: SeedableRng>() -> R {
160 let mut rng = UnwrapErr(SysRng);
161 R::from_rng(&mut rng)
162}
163
164impl TestRng {
165 fn next_u32_inner(&mut self) -> u32 {
166 match &mut self.rng {
167 TestRngImpl::XorShift(rng) => rng.next_u32(),
168 TestRngImpl::ChaCha(rng) => rng.next_u32(),
169 TestRngImpl::PassThrough { .. } => {
170 let mut buf = [0; 4];
171 self.fill_bytes_inner(&mut buf[..]);
172 u32::from_le_bytes(buf)
173 }
174 TestRngImpl::Recorder { rng, record } => {
175 let read = rng.next_u32();
176 record.extend_from_slice(&read.to_le_bytes());
177 read
178 }
179 }
180 }
181
182 fn next_u64_inner(&mut self) -> u64 {
183 match &mut self.rng {
184 TestRngImpl::XorShift(rng) => rng.next_u64(),
185 TestRngImpl::ChaCha(rng) => rng.next_u64(),
186 TestRngImpl::PassThrough { .. } => {
187 let mut buf = [0; 8];
188 self.fill_bytes_inner(&mut buf[..]);
189 u64::from_le_bytes(buf)
190 }
191 TestRngImpl::Recorder { rng, record } => {
192 let read = rng.next_u64();
193 record.extend_from_slice(&read.to_le_bytes());
194 read
195 }
196 }
197 }
198
199 fn fill_bytes_inner(&mut self, dest: &mut [u8]) {
200 match &mut self.rng {
201 TestRngImpl::XorShift(rng) => rng.fill_bytes(dest),
202 TestRngImpl::ChaCha(rng) => rng.fill_bytes(dest),
203 TestRngImpl::PassThrough { off, end, data } => {
204 let bytes_to_copy = dest.len().min(*end - *off);
205 dest[.. bytes_to_copy].copy_from_slice(&data[*off .. *off + bytes_to_copy]);
206 *off += bytes_to_copy;
207 for i in bytes_to_copy .. dest.len() {
208 dest[i] = 0;
209 }
210 }
211 TestRngImpl::Recorder { rng, record } => {
212 rng.fill_bytes(dest);
213 record.extend_from_slice(dest);
214 }
215 }
216 }
217}
218
219impl TryRng for TestRng {
220 type Error = Infallible;
221
222 fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
223 Ok(self.next_u32_inner())
224 }
225
226 fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
227 Ok(self.next_u64_inner())
228 }
229
230 fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Self::Error> {
231 self.fill_bytes_inner(dest);
232 Ok(())
233 }
234}
235
236#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
237pub(crate) enum Seed {
238 XorShift([u8; 16]),
239 ChaCha([u8; 32]),
240 PassThrough(Option<(usize, usize)>, Arc<[u8]>),
241 Recorder([u8; 32]),
242}
243
244impl Seed {
245 pub(crate) fn from_bytes(algorithm: RngAlgorithm, seed: &[u8]) -> Self {
246 match algorithm {
247 RngAlgorithm::XorShift => {
248 assert_eq!(16, seed.len(), "XorShift requires a 16-byte seed");
249 let mut buf = [0; 16];
250 buf.copy_from_slice(seed);
251 Seed::XorShift(buf)
252 }
253
254 RngAlgorithm::ChaCha => {
255 assert_eq!(32, seed.len(), "ChaCha requires a 32-byte seed");
256 let mut buf = [0; 32];
257 buf.copy_from_slice(seed);
258 Seed::ChaCha(buf)
259 }
260
261 RngAlgorithm::PassThrough => Seed::PassThrough(None, seed.into()),
262
263 RngAlgorithm::Recorder => {
264 assert_eq!(32, seed.len(), "Recorder requires a 32-byte seed");
265 let mut buf = [0; 32];
266 buf.copy_from_slice(seed);
267 Seed::Recorder(buf)
268 }
269
270 RngAlgorithm::_NonExhaustive => unreachable!(),
271 }
272 }
273
274 pub(crate) fn from_persistence(string: &str) -> Option<Seed> {
275 fn from_base16(dst: &mut [u8], src: &str) -> Option<()> {
276 if dst.len() * 2 != src.len() {
277 return None;
278 }
279
280 for (dst_byte, src_pair) in
281 dst.into_iter().zip(src.as_bytes().chunks(2))
282 {
283 *dst_byte =
284 u8::from_str_radix(str::from_utf8(src_pair).ok()?, 16)
285 .ok()?;
286 }
287
288 Some(())
289 }
290
291 let parts =
292 string.trim().split(char::is_whitespace).collect::<Vec<_>>();
293 RngAlgorithm::from_persistence_key(&parts[0]).and_then(
294 |alg| match alg {
295 RngAlgorithm::XorShift => {
296 if 5 != parts.len() {
297 return None;
298 }
299
300 let mut dwords = [0u32; 4];
301 for (dword, part) in
302 (&mut dwords[..]).into_iter().zip(&parts[1..])
303 {
304 *dword = part.parse().ok()?;
305 }
306
307 let mut seed = [0u8; 16];
308 for (chunk, dword) in seed.chunks_mut(4).zip(dwords) {
309 chunk.copy_from_slice(&dword.to_le_bytes());
310 }
311 Some(Seed::XorShift(seed))
312 }
313
314 RngAlgorithm::ChaCha => {
315 if 2 != parts.len() {
316 return None;
317 }
318
319 let mut seed = [0u8; 32];
320 from_base16(&mut seed, &parts[1])?;
321 Some(Seed::ChaCha(seed))
322 }
323
324 RngAlgorithm::PassThrough => {
325 if 1 == parts.len() {
326 return Some(Seed::PassThrough(None, vec![].into()));
327 }
328
329 if 2 != parts.len() {
330 return None;
331 }
332
333 let mut seed = vec![0u8; parts[1].len() / 2];
334 from_base16(&mut seed, &parts[1])?;
335 Some(Seed::PassThrough(None, seed.into()))
336 }
337
338 RngAlgorithm::Recorder => {
339 if 2 != parts.len() {
340 return None;
341 }
342
343 let mut seed = [0u8; 32];
344 from_base16(&mut seed, &parts[1])?;
345 Some(Seed::Recorder(seed))
346 }
347
348 RngAlgorithm::_NonExhaustive => unreachable!(),
349 },
350 )
351 }
352
353 pub(crate) fn to_persistence(&self) -> String {
354 fn to_base16(dst: &mut String, src: &[u8]) {
355 for byte in src {
356 dst.push_str(&format!("{:02x}", byte));
357 }
358 }
359
360 match *self {
361 Seed::XorShift(ref seed) => {
362 let dwords = [
363 u32::from_le_bytes(seed[0..4].try_into().unwrap()),
364 u32::from_le_bytes(seed[4..8].try_into().unwrap()),
365 u32::from_le_bytes(seed[8..12].try_into().unwrap()),
366 u32::from_le_bytes(seed[12..16].try_into().unwrap()),
367 ];
368 format!(
369 "{} {} {} {} {}",
370 RngAlgorithm::XorShift.persistence_key(),
371 dwords[0],
372 dwords[1],
373 dwords[2],
374 dwords[3]
375 )
376 }
377
378 Seed::ChaCha(ref seed) => {
379 let mut string =
380 RngAlgorithm::ChaCha.persistence_key().to_owned();
381 string.push(' ');
382 to_base16(&mut string, seed);
383 string
384 }
385
386 Seed::PassThrough(bounds, ref data) => {
387 let data =
388 bounds.map_or(&data[..], |(start, end)| &data[start..end]);
389 let mut string =
390 RngAlgorithm::PassThrough.persistence_key().to_owned();
391 string.push(' ');
392 to_base16(&mut string, data);
393 string
394 }
395
396 Seed::Recorder(ref seed) => {
397 let mut string =
398 RngAlgorithm::Recorder.persistence_key().to_owned();
399 string.push(' ');
400 to_base16(&mut string, seed);
401 string
402 }
403 }
404 }
405}
406
407impl TestRng {
408 pub fn from_seed(algorithm: RngAlgorithm, seed: &[u8]) -> Self {
418 TestRng::from_seed_internal(Seed::from_bytes(algorithm, seed))
419 }
420
421 pub fn bytes_used(&self) -> Vec<u8> {
428 match self.rng {
429 TestRngImpl::Recorder { ref record, .. } => record.clone(),
430 _ => panic!("bytes_used() called on non-Recorder RNG"),
431 }
432 }
433
434 pub(crate) fn default_rng(seed: config::RngSeed, algorithm: RngAlgorithm) -> Self {
436 #[cfg(feature = "std")]
437 {
438 Self {
439 rng: match algorithm {
440 RngAlgorithm::XorShift => {
441 let rng = match seed {
442 config::RngSeed::Random => from_sys_rng::<XorShiftRng>(),
443 config::RngSeed::Fixed(seed) => XorShiftRng::seed_from_u64(seed),
444 };
445 TestRngImpl::XorShift(rng)
446 }
447 RngAlgorithm::ChaCha => {
448 let rng = match seed {
449 config::RngSeed::Random => from_sys_rng::<ChaCha20Rng>(),
450 config::RngSeed::Fixed(seed) => ChaCha20Rng::seed_from_u64(seed),
451 };
452 TestRngImpl::ChaCha(rng)
453 }
454 RngAlgorithm::PassThrough => {
455 panic!("cannot create default instance of PassThrough")
456 }
457 RngAlgorithm::Recorder => {
458 let rng = match seed {
459 config::RngSeed::Random => from_sys_rng::<ChaCha20Rng>(),
460 config::RngSeed::Fixed(seed) => ChaCha20Rng::seed_from_u64(seed),
461 };
462 TestRngImpl::Recorder {rng, record: Vec::new()}
463 },
464 RngAlgorithm::_NonExhaustive => unreachable!(),
465 },
466 }
467 }
468 #[cfg(all(
469 not(feature = "std"),
470 any(target_arch = "x86", target_arch = "x86_64"),
471 feature = "hardware-rng"
472 ))]
473 {
474 return Self::hardware_rng(algorithm);
475 }
476 #[cfg(not(feature = "std"))]
477 {
478 return Self::deterministic_rng(algorithm);
479 }
480 }
481
482 const SEED_FOR_XOR_SHIFT: [u8; 16] = [
483 0xf4, 0x16, 0x16, 0x48, 0xc3, 0xac, 0x77, 0xac, 0x72, 0x20, 0x0b, 0xea,
484 0x99, 0x67, 0x2d, 0x6d,
485 ];
486
487 const SEED_FOR_CHA_CHA: [u8; 32] = [
488 0xf4, 0x16, 0x16, 0x48, 0xc3, 0xac, 0x77, 0xac, 0x72, 0x20, 0x0b, 0xea,
489 0x99, 0x67, 0x2d, 0x6d, 0xca, 0x9f, 0x76, 0xaf, 0x1b, 0x09, 0x73, 0xa0,
490 0x59, 0x22, 0x6d, 0xc5, 0x46, 0x39, 0x1c, 0x4a,
491 ];
492
493 #[cfg(all(
500 not(feature = "std"),
501 any(target_arch = "x86", target_arch = "x86_64"),
502 feature = "hardware-rng"
503 ))]
504 pub fn hardware_rng(algorithm: RngAlgorithm) -> Self {
505 use x86::random::{rdrand_slice, RdRand};
506 assert!(core_detect::is_x86_feature_detected!("rdrand"));
507
508 Self::from_seed_internal(match algorithm {
509 RngAlgorithm::XorShift => {
510 let mut seed: [u8; 16] = TestRng::SEED_FOR_XOR_SHIFT;
512 unsafe {
514 let r = rdrand_slice(&mut seed);
515 assert!(r, "hardware_rng should only be called on machines with support for rdrand");
516 }
517 Seed::XorShift(seed)
518 }
519 RngAlgorithm::ChaCha => {
520 let mut seed: [u8; 32] = TestRng::SEED_FOR_CHA_CHA;
522 unsafe {
524 let r = rdrand_slice(&mut seed);
525 assert!(r, "hardware_rng should only be called on machines with support for rdrand");
526 }
527 Seed::ChaCha(seed)
528 }
529 RngAlgorithm::PassThrough => {
530 panic!("deterministic RNG not available for PassThrough")
531 }
532 RngAlgorithm::Recorder => {
533 let mut seed: [u8; 32] = TestRng::SEED_FOR_CHA_CHA;
535 unsafe {
537 let r = rdrand_slice(&mut seed);
538 assert!(r, "hardware_rng should only be called on machines with support for rdrand");
539 }
540 Seed::Recorder(seed)
541 }
542 RngAlgorithm::_NonExhaustive => unreachable!(),
543 })
544 }
545
546 pub fn deterministic_rng(algorithm: RngAlgorithm) -> Self {
561 Self::from_seed_internal(match algorithm {
562 RngAlgorithm::XorShift => {
563 Seed::XorShift(TestRng::SEED_FOR_XOR_SHIFT)
564 }
565 RngAlgorithm::ChaCha => Seed::ChaCha(TestRng::SEED_FOR_CHA_CHA),
566 RngAlgorithm::PassThrough => {
567 panic!("deterministic RNG not available for PassThrough")
568 }
569 RngAlgorithm::Recorder => Seed::Recorder(TestRng::SEED_FOR_CHA_CHA),
570 RngAlgorithm::_NonExhaustive => unreachable!(),
571 })
572 }
573
574 pub(crate) fn gen_rng(&mut self) -> Self {
577 Self::from_seed_internal(self.new_rng_seed())
578 }
579
580 pub(crate) fn set_seed(&mut self, seed: Seed) {
582 *self = Self::from_seed_internal(seed);
583 }
584
585 pub(crate) fn gen_get_seed(&mut self) -> Seed {
588 let seed = self.new_rng_seed();
589 self.set_seed(seed.clone());
590 seed
591 }
592
593 pub(crate) fn new_rng_seed(&mut self) -> Seed {
595 match self.rng {
596 TestRngImpl::XorShift(ref mut rng) => {
597 let mut seed = rng.random::<[u8; 16]>();
598
599 for word in seed.chunks_mut(4) {
603 word[3] ^= 0xde;
604 word[2] ^= 0xad;
605 word[1] ^= 0xbe;
606 word[0] ^= 0xef;
607 }
608
609 Seed::XorShift(seed)
610 }
611
612 TestRngImpl::ChaCha(ref mut rng) => Seed::ChaCha(rng.random()),
613
614 TestRngImpl::PassThrough {
615 ref mut off,
616 ref mut end,
617 ref data,
618 } => {
619 let len = *end - *off;
620 let child_start = *off + len / 2;
621 let child_end = *off + len;
622 *end = child_start;
623 Seed::PassThrough(
624 Some((child_start, child_end)),
625 Arc::clone(data),
626 )
627 }
628
629 TestRngImpl::Recorder { ref mut rng, .. } => {
630 Seed::Recorder(rng.random())
631 }
632 }
633 }
634
635 fn from_seed_internal(seed: Seed) -> Self {
637 Self {
638 rng: match seed {
639 Seed::XorShift(seed) => {
640 TestRngImpl::XorShift(XorShiftRng::from_seed(seed))
641 }
642
643 Seed::ChaCha(seed) => {
644 TestRngImpl::ChaCha(ChaCha20Rng::from_seed(seed))
645 }
646
647 Seed::PassThrough(bounds, data) => {
648 let (start, end) = bounds.unwrap_or((0, data.len()));
649 TestRngImpl::PassThrough {
650 off: start,
651 end,
652 data,
653 }
654 }
655
656 Seed::Recorder(seed) => TestRngImpl::Recorder {
657 rng: ChaCha20Rng::from_seed(seed),
658 record: Vec::new(),
659 },
660 },
661 }
662 }
663}
664
665#[cfg(test)]
666mod test {
667 use crate::std_facade::Vec;
668
669 use rand::{Rng, RngExt};
670
671 use super::{RngAlgorithm, Seed, TestRng};
672 use crate::arbitrary::any;
673 use crate::strategy::*;
674
675 proptest! {
676 #[test]
677 fn gen_parse_seeds(
678 seed in prop_oneof![
679 any::<[u8;16]>().prop_map(Seed::XorShift),
680 any::<[u8;32]>().prop_map(Seed::ChaCha),
681 any::<Vec<u8>>().prop_map(|data| Seed::PassThrough(None, data.into())),
682 any::<[u8;32]>().prop_map(Seed::Recorder),
683 ])
684 {
685 assert_eq!(seed, Seed::from_persistence(&seed.to_persistence()).unwrap());
686 }
687
688 #[test]
689 fn rngs_dont_clone_self_on_genrng(
690 seed in prop_oneof![
691 any::<[u8;16]>().prop_map(Seed::XorShift),
692 any::<[u8;32]>().prop_map(Seed::ChaCha),
693 Just(()).prop_perturb(|_, mut rng| {
694 let mut buf = vec![0u8; 2048];
695 rng.fill_bytes(&mut buf);
696 Seed::PassThrough(None, buf.into())
697 }),
698 any::<[u8;32]>().prop_map(Seed::Recorder),
699 ])
700 {
701 type Value = [u8;32];
702 let orig = TestRng::from_seed_internal(seed);
703
704 {
705 let mut rng1 = orig.clone();
706 let mut rng2 = rng1.gen_rng();
707 assert_ne!(rng1.random::<Value>(), rng2.random::<Value>());
708 }
709
710 {
711 let mut rng1 = orig.clone();
712 let mut rng2 = rng1.gen_rng();
713 let mut rng3 = rng1.gen_rng();
714 let mut rng4 = rng2.gen_rng();
715 let a = rng1.random::<Value>();
716 let b = rng2.random::<Value>();
717 let c = rng3.random::<Value>();
718 let d = rng4.random::<Value>();
719 assert_ne!(a, b);
720 assert_ne!(a, c);
721 assert_ne!(a, d);
722 assert_ne!(b, c);
723 assert_ne!(b, d);
724 assert_ne!(c, d);
725 }
726 }
727
728 #[test]
729 fn rngs_clone(
730 seed in prop_oneof![
731 any::<[u8;16]>().prop_map(Seed::XorShift),
732 any::<[u8;32]>().prop_map(Seed::ChaCha),
733 Just(()).prop_perturb(|_, mut rng| {
734 let mut buf = vec![0u8; 2048];
735 rng.fill_bytes(&mut buf);
736 Seed::PassThrough(None, buf.into())
737 }),
738 any::<[u8;32]>().prop_map(Seed::Recorder),
739 ])
740 {
741 type Value = [u8;32];
742 let orig = TestRng::from_seed_internal(seed);
743
744 {
745 let mut rng1 = orig.clone();
746 rng1.random::<Value>();
747 let mut rng2 = rng1.clone();
748 assert_eq!(rng1.random::<Value>(), rng2.random::<Value>());
749 }
750
751 {
752 let mut rng1 = orig.clone();
753 rng1.random::<Value>();
754 rng1.random::<Value>();
755 let mut rng2 = rng1.clone();
756 let mut rng3 = rng1.clone();
757 let mut rng4 = rng2.clone();
758 let a = rng1.random::<Value>();
759 let b = rng2.random::<Value>();
760 let c = rng3.random::<Value>();
761 let d = rng4.random::<Value>();
762 assert_eq!(a, b);
763 assert_eq!(a, c);
764 assert_eq!(a, d);
765 }
766 }
767 }
768
769 #[test]
770 fn passthrough_rng_behaves_properly() {
771 let mut rng = TestRng::from_seed(
772 RngAlgorithm::PassThrough,
773 &[
774 0xDE, 0xC0, 0x12, 0x34, 0x56, 0x78, 0xFE, 0xCA, 0xEF, 0xBE,
775 0xAD, 0xDE, 0x01, 0x02, 0x03,
776 ],
777 );
778
779 assert_eq!(0x3412C0DE, rng.next_u32());
780 assert_eq!(0xDEADBEEFCAFE7856, rng.next_u64());
781
782 let mut buf = [0u8; 4];
783 rng.fill_bytes(&mut buf[0..4]);
784 assert_eq!([1, 2, 3, 0], buf);
785 rng.fill_bytes(&mut buf[0..4]);
786 assert_eq!([0, 0, 0, 0], buf);
787 }
788
789 #[test]
790 fn seeded_xorshift_output_is_stable() {
791 let seed = [
792 0x00, 0x01, 0x02, 0x03,
793 0x04, 0x05, 0x06, 0x07,
794 0x08, 0x09, 0x0a, 0x0b,
795 0x0c, 0x0d, 0x0e, 0x0f,
796 ];
797 let mut rng_u32 = TestRng::from_seed(RngAlgorithm::XorShift, &seed);
798 let mut rng_u64 = TestRng::from_seed(RngAlgorithm::XorShift, &seed);
799 let mut rng_fill = TestRng::from_seed(RngAlgorithm::XorShift, &seed);
800
801 assert_eq!(
802 [
803 471271404,
804 722341711,
805 1880555887,
806 252576780,
807 ],
808 [
809 rng_u32.next_u32(),
810 rng_u32.next_u32(),
811 rng_u32.next_u32(),
812 rng_u32.next_u32(),
813 ]
814 );
815 assert_eq!(
816 [
817 3102434025752954860,
818 1084809011709542767,
819 17342619095589341798,
820 5127465042768897837,
821 ],
822 [
823 rng_u64.next_u64(),
824 rng_u64.next_u64(),
825 rng_u64.next_u64(),
826 rng_u64.next_u64(),
827 ]
828 );
829
830 let mut fill = [0u8; 16];
831 rng_fill.fill_bytes(&mut fill);
832 assert_eq!(
833 [236, 7, 23, 28, 79, 15, 14, 43, 111, 1, 23, 112, 12, 4, 14, 15],
834 fill
835 );
836 }
837
838 #[test]
839 fn seeded_chacha_output_is_stable() {
840 let seed = [
841 0x00, 0x01, 0x02, 0x03,
842 0x04, 0x05, 0x06, 0x07,
843 0x08, 0x09, 0x0a, 0x0b,
844 0x0c, 0x0d, 0x0e, 0x0f,
845 0x10, 0x11, 0x12, 0x13,
846 0x14, 0x15, 0x16, 0x17,
847 0x18, 0x19, 0x1a, 0x1b,
848 0x1c, 0x1d, 0x1e, 0x1f,
849 ];
850 let mut rng_u32 = TestRng::from_seed(RngAlgorithm::ChaCha, &seed);
851 let mut rng_u64 = TestRng::from_seed(RngAlgorithm::ChaCha, &seed);
852 let mut rng_fill = TestRng::from_seed(RngAlgorithm::ChaCha, &seed);
853
854 assert_eq!(
855 [
856 2100034873,
857 1780073945,
858 1996733837,
859 1229642936,
860 ],
861 [
862 rng_u32.next_u32(),
863 rng_u32.next_u32(),
864 rng_u32.next_u32(),
865 rng_u32.next_u32(),
866 ]
867 );
868 assert_eq!(
869 [
870 7645359380336737593,
871 5281276197874154893,
872 14729830432180286858,
873 10530800043416210610,
874 ],
875 [
876 rng_u64.next_u64(),
877 rng_u64.next_u64(),
878 rng_u64.next_u64(),
879 rng_u64.next_u64(),
880 ]
881 );
882
883 let mut fill = [0u8; 16];
884 rng_fill.fill_bytes(&mut fill);
885 assert_eq!(
886 [57, 253, 43, 125, 217, 197, 25, 106, 141, 189, 3, 119, 184, 220, 74, 73],
887 fill
888 );
889 }
890
891 #[test]
892 fn derived_child_rng_output_is_stable() {
893 let seed = [
894 0x00, 0x01, 0x02, 0x03,
895 0x04, 0x05, 0x06, 0x07,
896 0x08, 0x09, 0x0a, 0x0b,
897 0x0c, 0x0d, 0x0e, 0x0f,
898 0x10, 0x11, 0x12, 0x13,
899 0x14, 0x15, 0x16, 0x17,
900 0x18, 0x19, 0x1a, 0x1b,
901 0x1c, 0x1d, 0x1e, 0x1f,
902 ];
903 let mut parent = TestRng::from_seed(RngAlgorithm::ChaCha, &seed);
904 let mut child = parent.gen_rng();
905
906 assert_eq!(
907 [
908 357635273,
909 1295757006,
910 1334659017,
911 3423482104,
912 ],
913 [
914 child.next_u32(),
915 child.next_u32(),
916 child.next_u32(),
917 child.next_u32(),
918 ],
919 );
920 }
921
922 #[test]
923 fn recorder_bytes_used_matches_emitted_bytes() {
924 let seed = [
925 0x00, 0x01, 0x02, 0x03,
926 0x04, 0x05, 0x06, 0x07,
927 0x08, 0x09, 0x0a, 0x0b,
928 0x0c, 0x0d, 0x0e, 0x0f,
929 0x10, 0x11, 0x12, 0x13,
930 0x14, 0x15, 0x16, 0x17,
931 0x18, 0x19, 0x1a, 0x1b,
932 0x1c, 0x1d, 0x1e, 0x1f,
933 ];
934 let mut rng = TestRng::from_seed(RngAlgorithm::Recorder, &seed);
935 let first = rng.next_u32();
936 let second = rng.next_u64();
937 let mut fill = [0u8; 16];
938 rng.fill_bytes(&mut fill);
939
940 let mut expected = Vec::new();
941 expected.extend_from_slice(&first.to_le_bytes());
942 expected.extend_from_slice(&second.to_le_bytes());
943 expected.extend_from_slice(&fill);
944
945 assert_eq!(expected, rng.bytes_used());
946 }
947
948 #[test]
949 fn recorder_clone_preserves_history() {
950 let mut original = TestRng::from_seed(RngAlgorithm::Recorder, &[42; 32]);
951 original.next_u32();
952 let history = original.bytes_used();
953
954 let mut cloned = original.clone();
955 assert_eq!(history, cloned.bytes_used());
956
957 let next = original.next_u32();
959 assert_eq!(history, cloned.bytes_used());
960
961 assert_eq!(next, cloned.next_u32());
963 assert_eq!(original.bytes_used(), cloned.bytes_used());
964 }
965
966}