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::{next_u64_via_u32, fill_bytes_via_next};
11 use rand_core::le::read_u32_into;
12 use rand_core::{SeedableRng, RngCore, Error};
13 
14 /// A xoshiro128++ random number generator.
15 ///
16 /// The xoshiro128++ 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 `xoshiro128plusplus.c`
20 /// reference source code](http://xoshiro.di.unimi.it/xoshiro128plusplus.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 Xoshiro128PlusPlus {
25     s: [u32; 4],
26 }
27 
28 impl SeedableRng for Xoshiro128PlusPlus {
29     type Seed = [u8; 16];
30 
31     /// Create a new `Xoshiro128PlusPlus`.  If `seed` is entirely 0, it will be
32     /// mapped to a different seed.
33     #[inline]
from_seed(seed: [u8; 16]) -> Xoshiro128PlusPlus34     fn from_seed(seed: [u8; 16]) -> Xoshiro128PlusPlus {
35         if seed.iter().all(|&x| x == 0) {
36             return Self::seed_from_u64(0);
37         }
38         let mut state = [0; 4];
39         read_u32_into(&seed, &mut state);
40         Xoshiro128PlusPlus { s: state }
41     }
42 
43     /// Create a new `Xoshiro128PlusPlus` 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 Xoshiro128PlusPlus {
62     #[inline]
next_u32(&mut self) -> u3263     fn next_u32(&mut self) -> u32 {
64         let result_starstar = self.s[0]
65             .wrapping_add(self.s[3])
66             .rotate_left(7)
67             .wrapping_add(self.s[0]);
68 
69         let t = self.s[1] << 9;
70 
71         self.s[2] ^= self.s[0];
72         self.s[3] ^= self.s[1];
73         self.s[1] ^= self.s[2];
74         self.s[0] ^= self.s[3];
75 
76         self.s[2] ^= t;
77 
78         self.s[3] = self.s[3].rotate_left(11);
79 
80         result_starstar
81     }
82 
83     #[inline]
next_u64(&mut self) -> u6484     fn next_u64(&mut self) -> u64 {
85         next_u64_via_u32(self)
86     }
87 
88     #[inline]
fill_bytes(&mut self, dest: &mut [u8])89     fn fill_bytes(&mut self, dest: &mut [u8]) {
90         fill_bytes_via_next(self, dest);
91     }
92 
93     #[inline]
try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error>94     fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), Error> {
95         self.fill_bytes(dest);
96         Ok(())
97     }
98 }
99 
100 #[cfg(test)]
101 mod tests {
102     use super::*;
103 
104     #[test]
reference()105     fn reference() {
106         let mut rng = Xoshiro128PlusPlus::from_seed(
107             [1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0]);
108         // These values were produced with the reference implementation:
109         // http://xoshiro.di.unimi.it/xoshiro128plusplus.c
110         let expected = [
111             641, 1573767, 3222811527, 3517856514, 836907274, 4247214768,
112             3867114732, 1355841295, 495546011, 621204420,
113         ];
114         for &e in &expected {
115             assert_eq!(rng.next_u32(), e);
116         }
117     }
118 }
119