1#![allow(deprecated)]
4
5#[cfg(feature = "rng")]
6use rand_core::{RngCore, SeedableRng, impls};
7use crate::util::mix::rapid_mix;
8
9const RAPID_SEED: u64 = 0xbdd89aa982704029;
11
12const RAPID_SECRET: [u64; 3] = [0x2d358dccaa6c78a5, 0x8bb84b93962eacc9, 0x4b33a62ed433d4a3];
14
15#[inline]
29#[deprecated(since = "4.5.0", note = "use the `rapidrand` crate instead")]
30pub fn rapidrng_fast(seed: &mut u64) -> u64 {
31 *seed = seed.wrapping_add(RAPID_SECRET[0]);
32 rapid_mix::<false>(*seed, *seed ^ RAPID_SECRET[1])
33}
34
35#[inline]
43#[deprecated(since = "4.5.0", note = "use the `rapidrand` crate instead")]
44pub fn rapidrng_fast_not_portable(seed: &mut u64) -> u64 {
45 *seed = seed.wrapping_add(RAPID_SECRET[0]);
46 rapid_mix_np_low_quality(*seed, RAPID_SECRET[1])
47}
48
49#[inline(always)]
55fn rapid_mix_np_low_quality(x: u64, y: u64) -> u64 {
56 #[cfg(any(
57 all(
58 target_pointer_width = "64",
59 not(any(target_arch = "sparc64", target_arch = "wasm64")),
60 ),
61 target_arch = "aarch64",
62 target_arch = "x86_64",
63 all(target_family = "wasm", target_feature = "wide-arithmetic"),
64 ))]
65 {
66 rapid_mix::<false>(x, y)
67 }
68
69 #[cfg(not(any(
70 all(
71 target_pointer_width = "64",
72 not(any(target_arch = "sparc64", target_arch = "wasm64")),
73 ),
74 target_arch = "aarch64",
75 target_arch = "x86_64",
76 all(target_family = "wasm", target_feature = "wide-arithmetic"),
77 )))]
78 {
79 let lx = x as u32;
82 let ly = y as u32;
83 let hx = (x >> 32) as u32;
84 let hy = (y >> 32) as u32;
85
86 let afull = (lx as u64) * (hy as u64);
88 let bfull = (hx as u64) * (ly as u64);
89
90 afull ^ bfull.rotate_right(32)
93 }
94}
95
96#[cfg(any(
118 all(
119 feature = "std",
120 not(any(
121 miri,
122 all(target_family = "wasm", target_os = "unknown"),
123 target_os = "zkvm"
124 ))
125 ),
126 docsrs
127))]
128#[inline]
129#[deprecated(since = "4.5.0", note = "use the `rapidrand` crate instead")]
130pub fn rapidrng_time(seed: &mut u64) -> u64 {
131 let time = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap();
132 let mut teed = (time.as_secs() << 32) | time.subsec_nanos() as u64;
136 teed = rapid_mix::<false>(teed ^ RAPID_SECRET[0], *seed ^ RAPID_SECRET[1]);
137 *seed = rapid_mix::<false>(teed ^ RAPID_SECRET[0], RAPID_SECRET[2]);
138 rapid_mix::<false>(*seed, *seed ^ RAPID_SECRET[1])
139}
140
141#[derive(Clone, Copy, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
156#[deprecated(since = "4.5.0", note = "use the `rapidrand` crate instead")]
157pub struct RapidRng {
158 seed: u64,
159}
160
161#[cfg(any(
162 all(
163 feature = "std",
164 not(any(
165 miri,
166 all(target_family = "wasm", target_os = "unknown"),
167 target_os = "zkvm"
168 ))
169 ),
170 docsrs
171))]
172impl Default for RapidRng {
173 #[inline]
179 fn default() -> Self {
180 let mut seed = RAPID_SEED;
181 Self {
182 seed: rapidrng_time(&mut seed),
183 }
184 }
185}
186
187#[cfg(not(any(
188 all(
189 feature = "std",
190 not(any(
191 miri,
192 all(target_family = "wasm", target_os = "unknown"),
193 target_os = "zkvm"
194 ))
195 ),
196 docsrs
197)))]
198impl Default for RapidRng {
199 #[inline]
205 fn default() -> Self {
206 Self {
207 seed: RAPID_SEED,
208 }
209 }
210}
211
212impl RapidRng {
213 #[inline]
218 pub fn new(seed: u64) -> Self {
219 Self {
220 seed,
221 }
222 }
223
224 #[inline]
226 pub fn state(&self) -> [u8; 8] {
227 self.seed.to_le_bytes()
228 }
229
230 #[inline]
232 #[allow(clippy::should_implement_trait)]
233 pub fn next(&mut self) -> u64 {
234 rapidrng_fast(&mut self.seed)
235 }
236}
237
238#[cfg(feature = "rng")]
239impl RngCore for RapidRng {
240 #[inline]
241 fn next_u32(&mut self) -> u32 {
242 self.next_u64() as u32
243 }
244
245 #[inline]
246 fn next_u64(&mut self) -> u64 {
247 self.next()
248 }
249
250 #[inline]
251 fn fill_bytes(&mut self, dest: &mut [u8]) {
252 impls::fill_bytes_via_next(self, dest)
253 }
254}
255
256#[cfg(feature = "rng")]
257impl SeedableRng for RapidRng {
258 type Seed = [u8; 8];
259
260 #[inline]
261 fn from_seed(seed: Self::Seed) -> Self {
262 Self {
263 seed: u64::from_le_bytes(seed),
264 }
265 }
266
267 #[inline]
268 fn seed_from_u64(state: u64) -> Self {
269 Self::new(state)
270 }
271}
272
273#[cfg(test)]
274mod tests {
275 use super::*;
276
277 #[cfg(feature = "rng")]
278 #[test]
279 fn test_rapidrng() {
280 let mut rng = RapidRng::new(0);
281 let x = rng.next();
282 let y = rng.next();
283 assert_ne!(x, 0);
284 assert_ne!(x, y);
285 }
286
287 #[cfg(all(feature = "rng", feature = "std"))]
288 #[test]
289 fn bit_flip_trial() {
290 let cycles = 100_000;
291 let mut seen = std::collections::HashSet::with_capacity(cycles);
292 let mut flips = std::vec::Vec::with_capacity(cycles);
293 let mut rng = RapidRng::new(0);
294
295 let mut prev = 0;
296 for _ in 0..cycles {
297 let next = rng.next_u64();
298
299 let xor = prev ^ next;
300 let flipped = xor.count_ones() as u64;
301 assert!(xor.count_ones() >= 10, "Flipping bit changed only {} bits", flipped);
302 flips.push(flipped);
303
304 assert!(!seen.contains(&next), "RapidRngFast produced a duplicate value");
305 seen.insert(next);
306
307 prev = next;
308 }
309
310 let average = flips.iter().sum::<u64>() as f64 / flips.len() as f64;
311 assert!(average > 31.95 && average < 32.05, "Did not flip an average of half the bits. average: {}, expected: 32.0", average);
312 }
313
314 #[cfg(feature = "std")]
315 #[test]
316 fn bit_flip_trial_fast() {
317 let cycles = 100_000;
318 let mut seen = std::collections::HashSet::with_capacity(cycles);
319 let mut flips = std::vec::Vec::with_capacity(cycles);
320
321 let mut prev = 0;
322 for _ in 0..cycles {
323 let next = rapidrng_fast(&mut prev);
324
325 let xor = prev ^ next;
326 let flipped = xor.count_ones() as u64;
327 assert!(xor.count_ones() >= 10, "Flipping bit changed only {} bits", flipped);
328 flips.push(flipped);
329
330 assert!(!seen.contains(&next), "rapidrng_fast produced a duplicate value");
331 seen.insert(next);
332
333 prev = next;
334 }
335
336 let average = flips.iter().sum::<u64>() as f64 / flips.len() as f64;
337 assert!(average > 31.95 && average < 32.05, "Did not flip an average of half the bits. average: {}, expected: 32.0", average);
338 }
339
340 #[cfg(feature = "std")]
341 #[test]
342 fn bit_flip_trial_time() {
343 let cycles = 100_000;
344 let mut seen = std::collections::HashSet::with_capacity(cycles);
345 let mut flips = std::vec::Vec::with_capacity(cycles);
346
347 let mut prev = 0;
348 for _ in 0..cycles {
349 let next = rapidrng_time(&mut prev);
350
351 let xor = prev ^ next;
352 let flipped = xor.count_ones() as u64;
353 assert!(xor.count_ones() >= 10, "Flipping bit changed only {} bits", flipped);
354 flips.push(flipped);
355
356 assert!(!seen.contains(&next), "rapidrng_time produced a duplicate value");
357 seen.insert(next);
358
359 prev = next;
360 }
361
362 let average = flips.iter().sum::<u64>() as f64 / flips.len() as f64;
363 assert!(average > 31.95 && average < 32.05, "Did not flip an average of half the bits. average: {}, expected: 32.0", average);
364 }
365
366 #[test]
369 #[ignore]
370 fn find_cycle() {
371 let mut fast = 0;
372 let mut slow = 0;
373
374 let mut power: u64 = 1;
375 let mut lam: u64 = 1;
376 rapidrng_fast(&mut fast);
377 while fast != slow {
378 if power == lam {
379 slow = fast;
380 power *= 2;
381 lam = 0;
382 }
383 rapidrng_fast(&mut fast);
384 lam += 1;
385 }
386
387 panic!("Cycle found after {power}:{lam} iterations.");
388 }
389
390 #[cfg(feature = "rng")]
391 #[test]
392 #[ignore]
393 fn find_cycle_slow() {
394 let mut rng = RapidRng::new(0);
395
396 let mut power: u64 = 1;
397 let mut lam: u64 = 1;
398 let mut fast = rng.next_u64();
399 let mut slow = 0;
400 while fast != slow {
401 if power == lam {
402 slow = fast;
403 power *= 2;
404 lam = 0;
405 }
406 fast = rng.next_u64();
407 lam += 1;
408 }
409
410 assert!(false, "Cycle found after {power}:{lam} iterations.");
411 }
412
413 #[cfg(feature = "rng")]
414 #[test]
415 fn test_construction() {
416 let mut rng = RapidRng::default();
417 assert_ne!(rng.next(), 0);
418 }
419}