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