• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 Developers of the Rand project.
2 //
3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your
6 // option. This file may not be copied, modified, or distributed
7 // except according to those terms.
8 
9 #[cfg(feature="serde1")] use serde::{Serialize, Deserialize};
10 use rand_core::impls::fill_bytes_via_next;
11 use rand_core::le::read_u64_into;
12 use rand_core::{SeedableRng, RngCore, Error};
13 
14 /// A xoshiro256** random number generator.
15 ///
16 /// The xoshiro256** algorithm is not suitable for cryptographic purposes, but
17 /// is very fast and has excellent statistical properties.
18 ///
19 /// The algorithm used here is translated from [the `xoshiro256plusplus.c`
20 /// reference source code](http://xoshiro.di.unimi.it/xoshiro256plusplus.c) by
21 /// David Blackman and Sebastiano Vigna.
22 #[derive(Debug, Clone, PartialEq, Eq)]
23 #[cfg_attr(feature="serde1", derive(Serialize, Deserialize))]
24 pub struct Xoshiro256PlusPlus {
25     s: [u64; 4],
26 }
27 
28 impl SeedableRng for Xoshiro256PlusPlus {
29     type Seed = [u8; 32];
30 
31     /// Create a new `Xoshiro256PlusPlus`.  If `seed` is entirely 0, it will be
32     /// mapped to a different seed.
33     #[inline]
from_seed(seed: [u8; 32]) -> Xoshiro256PlusPlus34     fn from_seed(seed: [u8; 32]) -> Xoshiro256PlusPlus {
35         if seed.iter().all(|&x| x == 0) {
36             return Self::seed_from_u64(0);
37         }
38         let mut state = [0; 4];
39         read_u64_into(&seed, &mut state);
40         Xoshiro256PlusPlus { s: state }
41     }
42 
43     /// Create a new `Xoshiro256PlusPlus` from a `u64` seed.
44     ///
45     /// This uses the SplitMix64 generator internally.
seed_from_u64(mut state: u64) -> Self46     fn seed_from_u64(mut state: u64) -> Self {
47         const PHI: u64 = 0x9e3779b97f4a7c15;
48         let mut seed = Self::Seed::default();
49         for chunk in seed.as_mut().chunks_mut(8) {
50             state = state.wrapping_add(PHI);
51             let mut z = state;
52             z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
53             z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
54             z = z ^ (z >> 31);
55             chunk.copy_from_slice(&z.to_le_bytes());
56         }
57         Self::from_seed(seed)
58     }
59 }
60 
61 impl RngCore for Xoshiro256PlusPlus {
62     #[inline]
next_u32(&mut self) -> u3263     fn next_u32(&mut self) -> u32 {
64         // The lowest bits have some linear dependencies, so we use the
65         // upper bits instead.
66         (self.next_u64() >> 32) as u32
67     }
68 
69     #[inline]
next_u64(&mut self) -> u6470     fn next_u64(&mut self) -> u64 {
71         let result_plusplus = self.s[0]
72             .wrapping_add(self.s[3])
73             .rotate_left(23)
74             .wrapping_add(self.s[0]);
75 
76         let t = self.s[1] << 17;
77 
78         self.s[2] ^= self.s[0];
79         self.s[3] ^= self.s[1];
80         self.s[1] ^= self.s[2];
81         self.s[0] ^= self.s[3];
82 
83         self.s[2] ^= t;
84 
85         self.s[3] = self.s[3].rotate_left(45);
86 
87         result_plusplus
88     }
89 
90     #[inline]
fill_bytes(&mut self, dest: &mut [u8])91     fn fill_bytes(&mut self, dest: &mut [u8]) {
92         fill_bytes_via_next(self, dest);
93     }
94 
95     #[inline]
try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>96     fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
97         self.fill_bytes(dest);
98         Ok(())
99     }
100 }
101 
102 #[cfg(test)]
103 mod tests {
104     use super::*;
105 
106     #[test]
reference()107     fn reference() {
108         let mut rng = Xoshiro256PlusPlus::from_seed(
109             [1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
110              3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0]);
111         // These values were produced with the reference implementation:
112         // http://xoshiro.di.unimi.it/xoshiro256plusplus.c
113         let expected = [
114             41943041, 58720359, 3588806011781223, 3591011842654386,
115             9228616714210784205, 9973669472204895162, 14011001112246962877,
116             12406186145184390807, 15849039046786891736, 10450023813501588000,
117         ];
118         for &e in &expected {
119             assert_eq!(rng.next_u64(), e);
120         }
121     }
122 }
123