1#[derive(Debug, Clone, Copy)]
14pub struct Exsss {
15 s0: u64,
16 s1: u64,
17}
18
19impl Exsss {
20 pub fn from_seed(seed_bytes: &[u8; 32]) -> Self {
23 let seed = u128::from_le_bytes(seed_bytes[0..16].try_into().unwrap());
25
26 Self::from_seed_u128(seed)
27 }
28
29 pub fn from_seed_u128(seed: u128) -> Self {
31 let (s0, x1) = seed58(seed as u64);
33 let (s1, _x2) = seed58(x1);
34
35 Self { s0, s1 }
36 }
37
38 fn next_u64(&mut self) -> u64 {
41 const MASK_58: u64 = (1u64 << 58) - 1;
42
43 let s1 = self.s0;
48 let s0 = self.s1;
49
50 let s0_1 = s0 & MASK_58;
52
53 let s1_masked = s1 & MASK_58;
57 let s1_b = s1_masked ^ ((s1_masked << 24) & MASK_58);
58 let new_s1 = s1_b ^ s0_1 ^ (s1_b >> 11) ^ (s0_1 >> 41);
59
60 let v_a = (s0_1 + ((s0_1 << 2) & MASK_58)) & MASK_58;
65 let v_b = ((v_a << 7) | (v_a >> 51)) & MASK_58;
66 let output = (v_b + ((v_b << 3) & MASK_58)) & MASK_58;
67
68 self.s0 = s0_1;
71 self.s1 = new_s1 & MASK_58;
72
73 output
74 }
75
76 pub fn uniform_float(&mut self) -> f64 {
78 const TWO_POW_MINUS53: f64 = 1.0 / (1u64 << 53) as f64;
81
82 let i = self.next_u64();
83 let shifted = i >> 5; (shifted as f64) * TWO_POW_MINUS53
85 }
86
87 pub fn uniform(&mut self, range: u64) -> u64 {
89 self.uniform_internal(range, 0)
90 }
91
92 fn uniform_internal(&mut self, range: u64, depth: u32) -> u64 {
93 const BIT_58: u64 = 1u64 << 58;
94
95 if range == 0 {
96 return 0;
97 }
98
99 let v = self.next_u64(); if v < range {
106 return v + 1;
107 }
108
109 let i = v % range;
111 let max_minus_range = BIT_58 - range;
112
113 if v - i <= max_minus_range {
114 i + 1
115 } else {
116 self.uniform_internal(range, depth + 1)
118 }
119 }
120
121 pub fn shuffle<T: Clone>(&mut self, slice: &mut [T]) {
124 if slice.len() <= 1 {
125 return;
126 }
127
128 let mut keyed: Vec<(f64, T)> = slice.iter().map(|val| (self.uniform_float(), val.clone())).collect();
130
131 keyed.sort_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
133
134 for (idx, (_key, val)) in keyed.into_iter().enumerate() {
136 slice[idx] = val;
137 }
138 }
139}
140
141fn splitmix64_next(x0: u64) -> (u64, u64) {
144 let x = x0.wrapping_add(0x9e3779b97f4a7c15);
145 let mut z = x;
146 z = (z ^ (z >> 30)).wrapping_mul(0xbf58476d1ce4e5b9);
147 z = (z ^ (z >> 27)).wrapping_mul(0x94d049bb133111eb);
148 z = z ^ (z >> 31);
149 (z, x)
150}
151
152fn seed58(x0: u64) -> (u64, u64) {
155 const MASK_58: u64 = (1u64 << 58) - 1;
156
157 let (z0, x) = splitmix64_next(x0);
158 let z = z0 & MASK_58;
159
160 if z == 0 {
161 seed58(x)
163 } else {
164 (z, x)
165 }
166}
167
168#[cfg(test)]
169mod tests {
170 use super::*;
171
172 #[test]
173 fn test_state_initialization() {
174 let test_cases = vec![
176 (0u128, 153307352162749871u64, 178066366098138612u64),
177 (42, 132629853624823445, 67522330609774851),
178 (777, 132610673151668814, 220791266393211968),
179 (12345, 149043579997720992, 31205127689074925),
180 (54321, 144632915686665753, 52714770947718356),
181 (99999, 51811462204453670, 95920375662433499),
182 (123456789, 161132163074061945, 185172155811622446),
183 ];
184
185 for (seed, expected_s0, expected_s1) in test_cases {
186 let rng = Exsss::from_seed_u128(seed);
187 assert_eq!(rng.s0, expected_s0, "s0 mismatch for seed {}", seed);
188 assert_eq!(rng.s1, expected_s1, "s1 mismatch for seed {}", seed);
189 }
190 }
191
192 #[test]
193 fn test_seed_test_1() {
194 let seed_bytes: [u8; 32] = [
196 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
197 30, 31, 32,
198 ];
199 let mut rng = Exsss::from_seed(&seed_bytes);
200
201 let r1 = rng.uniform(1000);
202 let r2 = rng.uniform(1000);
203 let r3 = rng.uniform(1000);
204
205 assert_eq!(r1, 829, "first uniform(1000)");
207 assert_eq!(r2, 169, "second uniform(1000)");
208 assert_eq!(r3, 221, "third uniform(1000)");
209 }
210
211 #[test]
212 fn test_shuffle_simple() {
213 let seed_bytes = seed_from_u64(12345);
215 let mut rng = Exsss::from_seed(&seed_bytes);
216
217 let mut list = vec![1, 2, 3, 4, 5];
218 rng.shuffle(&mut list);
219
220 assert_eq!(list, vec![3, 4, 2, 1, 5]);
222 }
223
224 #[test]
225 fn test_shuffle_zero_seed() {
226 let seed_bytes = seed_from_u64(0);
228 let mut rng = Exsss::from_seed(&seed_bytes);
229
230 let mut list: Vec<u32> = (1..=10).collect();
231 rng.shuffle(&mut list);
232
233 assert_eq!(list, vec![5, 2, 1, 7, 9, 4, 8, 6, 10, 3]);
235 }
236
237 #[test]
238 fn test_random_sequence() {
239 let seed_bytes = seed_from_u64(42);
241 let mut rng = Exsss::from_seed(&seed_bytes);
242
243 let mut randoms = Vec::new();
244 for _ in 0..20 {
245 randoms.push(rng.uniform(1000));
246 }
247
248 assert_eq!(
250 randoms,
251 vec![294, 431, 615, 198, 771, 458, 832, 264, 842, 111, 320, 936, 44, 92, 979, 44, 402, 648, 714, 722]
252 );
253 }
254
255 #[test]
256 fn test_shuffle_large() {
257 let seed_bytes = seed_from_u64(54321);
259 let mut rng = Exsss::from_seed(&seed_bytes);
260
261 let mut list: Vec<u32> = (1..=99).collect();
262 rng.shuffle(&mut list);
263
264 let expected_first_50 = vec![
266 74, 86, 38, 82, 89, 10, 84, 26, 98, 85, 34, 91, 87, 51, 93, 45, 41, 30, 17, 96, 28, 6, 27, 78, 23, 25, 92,
267 18, 32, 39, 48, 22, 49, 1, 61, 9, 20, 95, 72, 79, 70, 33, 50, 42, 77, 73, 81, 24, 60, 88,
268 ];
269 assert_eq!(list[0..50], expected_first_50[..]);
270 }
271
272 #[test]
273 fn test_determinism() {
274 let seed_bytes = seed_from_u64(777);
276
277 let mut rng1 = Exsss::from_seed(&seed_bytes);
278 let mut list1 = vec![1, 2, 3, 4, 5, 6, 7, 8];
279 rng1.shuffle(&mut list1);
280
281 let mut rng2 = Exsss::from_seed(&seed_bytes);
282 let mut list2 = vec![1, 2, 3, 4, 5, 6, 7, 8];
283 rng2.shuffle(&mut list2);
284
285 assert_eq!(list1, vec![2, 3, 6, 4, 1, 5, 7, 8]);
287 assert_eq!(list1, list2, "determinism check");
288 }
289
290 fn seed_from_u64(n: u64) -> [u8; 32] {
292 let mut bytes = [0u8; 32];
293 bytes[0..8].copy_from_slice(&n.to_le_bytes());
294 bytes
295 }
296}