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