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