ya_rand/
rng.rs

1const F64_MANT: u32 = f64::MANTISSA_DIGITS;
2const F32_MANT: u32 = f32::MANTISSA_DIGITS;
3const F64_MAX_PRECISE: u64 = 1 << F64_MANT;
4const F32_MAX_PRECISE: u64 = 1 << F32_MANT;
5const F64_DIVISOR: f64 = F64_MAX_PRECISE as f64;
6const F32_DIVISOR: f32 = F32_MAX_PRECISE as f32;
7pub const ALPHANUMERIC: &[u8] = b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
8
9/// Trait for RNGs that are known to provide streams of cryptographically secure data.
10#[cfg(feature = "secure")]
11pub trait SecureYARandGenerator: YARandGenerator {
12    /// Fills `dst` with random data, which is safe to be used
13    /// in cryptographic contexts.
14    ///
15    /// # Examples
16    ///
17    /// ```
18    /// use ya_rand::*;
19    ///
20    /// let mut rng = new_rng_secure();
21    /// let mut data = [0; 1738];
22    /// rng.fill_bytes(&mut data);
23    /// assert!(data.into_iter().any(|v| v != 0));
24    /// ```
25    fn fill_bytes(&mut self, dst: &mut [u8]);
26
27    /// Generates a random `String` with length `len`, using the provided
28    /// `Encoder` to determine character set and minimum secure length. Since
29    /// character sets can only contain valid ascii values, the length of the created
30    /// `String` reprensents both the size of the `String` in bytes, and the
31    /// amount of characters it contains.
32    ///
33    /// Only returns `None` when `len` is less than what the encoder declares to be
34    /// secure. The compiler is typically able to remove the `None` branch
35    /// when `len` is a constant satisfying the length requirement of the encoder.
36    ///
37    /// All provided encoders are accessible through [`crate::ya_rand_encoding`].
38    /// Users wishing to implement their own encoding must do so through the
39    /// [`Encoder`](crate::ya_rand_encoding::Encoder) trait.
40    ///
41    /// Originally inspired by golang's addition of [`rand.Text`] in release 1.24,
42    /// but altered to be encoding/length generic and unbiased for non-trivial bases.
43    ///
44    /// [`rand.Text`]:
45    /// https://cs.opensource.google/go/go/+/refs/tags/go1.24.0:src/crypto/rand/text.go
46    ///
47    /// # Examples
48    ///
49    /// ```
50    /// use ya_rand::*;
51    /// use ya_rand_encoding::Base16Lowercase as B16L;
52    ///
53    /// const LEN: usize = 420;
54    /// let mut rng = new_rng_secure();
55    /// // Safe to unwrap because 420 is greater than 32, which
56    /// // is the minimum secure length of `Base16Lowercase`.
57    /// let hex_string = rng.text::<B16L>(LEN).unwrap();
58    /// assert!(hex_string.len() == LEN);
59    /// assert!(hex_string.bytes().count() == LEN);
60    /// assert!(hex_string.chars().count() == LEN);
61    /// for c in hex_string.bytes() {
62    ///     assert!(
63    ///         (b'0' <= c && c <= b'9') ||
64    ///         (b'a' <= c && c <= b'f')
65    ///     );
66    /// }
67    /// ```
68    #[cfg(feature = "std")]
69    #[inline(never)]
70    fn text<E>(&mut self, len: usize) -> Option<std::string::String>
71    where
72        E: crate::ya_rand_encoding::Encoder,
73    {
74        match len >= E::MIN_LEN {
75            true => Some({
76                const BYTE_VALUES: usize = 1 << u8::BITS;
77                // SAFETY: u8's are a trivial type and we pwomise to
78                // always overwrite all of them UwU.
79                let mut data = unsafe {
80                    std::boxed::Box::new_uninit_slice(len)
81                        .assume_init()
82                        .into_vec()
83                };
84                // This branch is evaluated at compile time, so concrete
85                // implementations in final binaries will only have the
86                // contents of the branch suitable for the encoder used.
87                if BYTE_VALUES % E::CHARSET.len() == 0 {
88                    self.fill_bytes(&mut data);
89                    // Directly map each random u8 to a character in the set.
90                    // Since this branch is only reachable when length is a power
91                    // of two, the modulo gets optimized out and the whole thing
92                    // gets vectorized. The assembly for this branch is
93                    // absolutely beautiful.
94                    // This approach is extremely efficient, but only produces
95                    // unbiased random sequences when the length of the current
96                    // `CHARSET` is divisible by the amount of possible u8 values,
97                    // which is why we need a fallback approach.
98                    for d in &mut data {
99                        let random_value = *d as usize;
100                        *d = E::CHARSET[random_value % E::CHARSET.len()];
101                    }
102                } else {
103                    // Alternative approach that's potentially much slower,
104                    // but always produces unbiased results.
105                    // The unwrap gets optimized out since rustc can see that
106                    // `E::CHARSET` has a non-zero length.
107                    data.fill_with(|| *self.choose(E::CHARSET).unwrap());
108                }
109                // SAFETY: All provided encoders only use ascii values, and
110                // custom `Encoder` implementations agree to do the same when
111                // implementing the trait.
112                unsafe { std::string::String::from_utf8_unchecked(data) }
113            }),
114            false => None,
115        }
116    }
117}
118
119/// Trait for RNGs that can be created from a user-provided seed.
120pub trait SeedableYARandGenerator: YARandGenerator + Default {
121    /// Creates a generator from the output of an internal PRNG,
122    /// which is itself seeded from `seed`.
123    ///
124    /// As a rule: unless you are **absolutely certain** that you need to manually
125    /// seed a generator, you don't.
126    /// Instead, use [`crate::new_rng`] when you need to create a new instance.
127    ///
128    /// If you have a scenario where you really do need a set seed, prefer to use the
129    /// `Default` implementation of the desired generator.
130    ///
131    /// # Examples
132    ///
133    /// ```
134    /// use ya_rand::*;
135    ///
136    /// // In actual use these would be declared `mut`.
137    /// let rng1 = ShiroRng::new_with_seed(0);
138    /// let rng2 = ShiroRng::default();
139    /// // Default is just a shortcut for manually seeding with 0.
140    /// assert!(rng1 == rng2);
141    /// ```
142    fn new_with_seed(seed: u64) -> Self;
143}
144
145/* **** WIP ****
146/// Trait for RNGs that can simulate byte-streams, but in a way that is insecure
147/// and shouldn't be used for sensitive applications.
148#[cfg(feature = "std")]
149pub trait InsecureYARandGenerator: YARandGenerator {
150    fn fill_bytes_insecure(&mut self, dst: &mut [u8]) {
151        use core::ptr::copy_nonoverlapping as cpy;
152
153        // Approach #1
154        dst.chunks_exact_mut(size_of::<u32>()).for_each(|cur| {
155            let val = self.u32().to_ne_bytes();
156            unsafe {
157                cpy(val.as_ptr(), cur.as_mut_ptr(), cur.len());
158            }
159        });
160        dst.chunks_exact_mut(size_of::<u32>())
161            .into_remainder()
162            .iter_mut()
163            .for_each(|cur| *cur = self.u8());
164
165        // Approach #2
166        let len = (dst.len() / size_of::<u32>()) + 1;
167        let mut src = unsafe { std::boxed::Box::new_uninit_slice(len).assume_init() };
168        src.fill_with(|| self.u32());
169        unsafe {
170            cpy(src.as_ptr().cast(), dst.as_mut_ptr(), dst.len());
171        }
172    }
173}
174*/
175
176/// Base trait that all RNGs must implement.
177pub trait YARandGenerator: Sized {
178    /// Creates a generator using randomness provided by the OS.
179    ///
180    /// Unlike [`YARandGenerator::new`], which will panic on failure, `try_new`
181    /// propagates the error-handling responsibility to the user. But the probability
182    /// of your operating systems RNG failing is absurdly low, and in the rare case that it
183    /// does fail, that's not really an issue most users are going to be able to address.
184    ///
185    /// Stick to using [`crate::new_rng`], unless you really need a generator of a
186    /// different type (you probably don't), then use `new` on your desired type.
187    fn try_new() -> Result<Self, getrandom::Error>;
188
189    /// Returns a uniformly distributed `u64` in the interval [0, 2<sup>64</sup>).
190    fn u64(&mut self) -> u64;
191
192    /// Creates a generator using randomness provided by the OS.
193    ///
194    /// It is recommended to use the top-level [`crate::new_rng`] instead
195    /// of calling this function on a specific generator type.
196    ///
197    /// # Safety
198    ///
199    /// This function will panic if your OS rng fails to provide enough entropy.
200    /// But this is extremely unlikely, and unless you're working at the kernel level it's
201    /// not something you should ever be concerned with.
202    ///
203    /// Since Windows 10 this function is infallible, thanks to modern Windows versions adopting
204    /// a user-space cryptographic architecture that can't fail during runtime.
205    ///
206    /// # Examples
207    ///
208    /// ```
209    /// use ya_rand::*;
210    ///
211    /// // Recommended usage
212    /// let mut rng1 = new_rng();
213    /// // More explicit
214    /// let mut rng2 = ShiroRng::new();
215    /// // Even more explicit
216    /// let mut rng3 = Xoshiro256pp::new();
217    /// // Since these are all created using OS entropy, the odds of
218    /// // their initial states colliding is vanishingly small.
219    /// assert!(rng1 != rng2);
220    /// assert!(rng1 != rng3);
221    /// assert!(rng2 != rng3);
222    /// ```
223    fn new() -> Self {
224        Self::try_new().expect(
225            "WARNING: retrieving random data from the operating system should never fail; \
226            something has gone terribly wrong",
227        )
228    }
229
230    /// Returns a uniformly distributed `u32` in the interval [0, 2<sup>32</sup>).
231    #[inline]
232    fn u32(&mut self) -> u32 {
233        self.bits(u32::BITS) as u32
234    }
235
236    /// Returns a uniformly distributed `u16` in the interval [0, 2<sup>16</sup>).
237    #[inline]
238    fn u16(&mut self) -> u16 {
239        self.bits(u16::BITS) as u16
240    }
241
242    /// Returns a uniformly distributed `u8` in the interval [0, 2<sup>8</sup>).
243    #[inline]
244    fn u8(&mut self) -> u8 {
245        self.bits(u8::BITS) as u8
246    }
247
248    /// Returns a uniformly distributed `u64` in the interval [0, 2<sup>`bit_count`</sup>).
249    ///
250    /// The value of `bit_count` is clamped to 64.
251    #[inline]
252    fn bits(&mut self, bit_count: u32) -> u64 {
253        self.u64() >> (u64::BITS - bit_count.min(u64::BITS))
254    }
255
256    /// A simple coinflip, returning a `bool` that has a 50% chance of being true.
257    ///
258    /// # Examples
259    ///
260    /// ```
261    /// use ya_rand::*;
262    ///
263    /// const ITERATIONS: u64 = 1 << 24;
264    /// let mut rng = new_rng();
265    /// let mut yes: u64 = 0;
266    /// let mut no: u64 = 0;
267    /// for _ in 0..ITERATIONS {
268    ///     if rng.bool() {
269    ///         yes += 1;
270    ///     } else {
271    ///         no += 1;
272    ///     }
273    /// }
274    /// // We expect the difference to be within ~5%.
275    /// let THRESHOLD: u64 = ITERATIONS / 20;
276    /// assert!(yes.abs_diff(no) <= THRESHOLD);
277    /// ```
278    #[inline]
279    fn bool(&mut self) -> bool {
280        // Compiles to a single "shr 63" instruction.
281        self.bits(1) == 1
282    }
283
284    /// Returns a uniformly distributed `u64` in the interval [0, `max`).
285    ///
286    /// Using [`YARandGenerator::bits`] when `max` happens to be a power of 2
287    /// is faster and generates better assembly.
288    ///
289    /// # Examples
290    ///
291    /// ```
292    /// use ya_rand::*;
293    ///
294    /// let mut rng = new_rng();
295    /// // Special case: bound of 0 always returns 0.
296    /// assert!(rng.bound(0) == 0);
297    /// for i in 1..=2000 {
298    ///     for _ in 0..(i * 2) {
299    ///         assert!(rng.bound(i) < i);
300    ///     }
301    /// }
302    /// ```
303    #[inline]
304    fn bound(&mut self, max: u64) -> u64 {
305        // Lemire's method: https://arxiv.org/abs/1805.10941.
306        let mut mul = || crate::util::wide_mul(self.u64(), max);
307        let (mut high, mut low) = mul();
308        match low < max {
309            false => {}
310            true => {
311                let threshold = max.wrapping_neg() % max;
312                while low < threshold {
313                    (high, low) = mul();
314                }
315            }
316        }
317        debug_assert!(
318            (max != 0 && high < max) || high == 0,
319            "BUG: this assertion should never be reachable"
320        );
321        high
322    }
323
324    /// Returns a uniformly distributed `u64` in the interval \[0, `max`\].
325    ///
326    /// It is expected that `max` < `u64::MAX`.
327    ///
328    /// # Examples
329    ///
330    /// ```
331    /// use ya_rand::*;
332    ///
333    /// let mut rng = new_rng();
334    /// for i in 0..=2000 {
335    ///     for _ in 0..(i * 2) {
336    ///         assert!(rng.bound_inclusive(i) <= i);
337    ///     }
338    /// }
339    /// ```
340    #[inline]
341    fn bound_inclusive(&mut self, max: u64) -> u64 {
342        self.bound(max + 1)
343    }
344
345    /// Returns a uniformly distributed `i64` in the interval [`min`, `max`)
346    ///
347    /// It is expected that `min` < `max`.
348    #[inline]
349    fn range(&mut self, min: i64, max: i64) -> i64 {
350        let delta = max.abs_diff(min);
351        (self.bound(delta) as i64) + min
352    }
353
354    /// Returns a uniformly distributed `i64` in the interval \[`min`, `max`\]
355    ///
356    /// It is expected that `min` <= `max` and `max` < `u64::MAX`.
357    #[inline]
358    fn range_inclusive(&mut self, min: i64, max: i64) -> i64 {
359        self.range(min, max + 1)
360    }
361
362    /// Returns a uniformly distributed `f64` in the interval [0.0, 1.0).
363    #[inline]
364    fn f64(&mut self) -> f64 {
365        self.bits(F64_MANT) as f64 / F64_DIVISOR
366    }
367
368    /// Returns a uniformly distributed `f32` in the interval [0.0, 1.0).
369    #[inline]
370    fn f32(&mut self) -> f32 {
371        self.bits(F32_MANT) as f32 / F32_DIVISOR
372    }
373
374    /// Returns a uniformly distributed `f64` in the interval (0.0, 1.0].
375    #[inline]
376    fn f64_nonzero(&mut self) -> f64 {
377        // Interval of (0, 2^53]
378        let nonzero = self.bits(F64_MANT) + 1;
379        nonzero as f64 / F64_DIVISOR
380    }
381
382    /// Returns a uniformly distributed `f32` in the interval (0.0, 1.0].
383    #[inline]
384    fn f32_nonzero(&mut self) -> f32 {
385        // Interval of (0, 2^24]
386        let nonzero = self.bits(F32_MANT) + 1;
387        nonzero as f32 / F32_DIVISOR
388    }
389
390    /// Returns a uniformly distributed `f64` in the interval (-1.0, 1.0).
391    #[inline]
392    fn f64_wide(&mut self) -> f64 {
393        // This approach is faster than using Generator::range.
394        const BITS: u32 = F64_MANT + 1;
395        const OFFSET: i64 = F64_MAX_PRECISE as i64;
396        let mut x: i64;
397        loop {
398            // Start with an interval of [0, 2^54)
399            x = self.bits(BITS) as i64;
400            // Interval is now (0, 2^54)
401            match x != 0 {
402                true => break,
403                false => {}
404            }
405        }
406        // Shift interval to (-2^53, 2^53)
407        x -= OFFSET;
408        x as f64 / F64_DIVISOR
409    }
410
411    /// Returns a uniformly distributed `f32` in the interval (-1.0, 1.0).
412    #[inline]
413    fn f32_wide(&mut self) -> f32 {
414        // This approach is faster than using Generator::range.
415        const BITS: u32 = F32_MANT + 1;
416        const OFFSET: i64 = F32_MAX_PRECISE as i64;
417        let mut x: i64;
418        loop {
419            // Start with an interval of [0, 2^25)
420            x = self.bits(BITS) as i64;
421            // Interval is now (0, 2^25)
422            match x != 0 {
423                true => break,
424                false => {}
425            }
426        }
427        // Shift interval to (-2^24, 2^24)
428        x -= OFFSET;
429        x as f32 / F32_DIVISOR
430    }
431
432    /// Returns two indepedent and normally distributed `f64` values with
433    /// a `mean` of `0.0` and a `stddev` of `1.0`.
434    #[cfg(feature = "std")]
435    fn f64_normal(&mut self) -> (f64, f64) {
436        // Marsaglia polar method.
437        // TLDR: It projects a point **within** the unit
438        // circle onto the unit radius.
439        let mut x: f64;
440        let mut y: f64;
441        let mut s: f64;
442        loop {
443            x = self.f64_wide();
444            y = self.f64_wide();
445            s = (x * x) + (y * y);
446            // Reroll if s does not lie **within** the unit circle.
447            match s < 1.0 && s != 0.0 {
448                true => break,
449                false => {}
450            }
451        }
452        let t = (2.0 * s.ln().abs() / s).sqrt();
453        (x * t, y * t)
454    }
455
456    /// Returns two indepedent and normally distributed `f64` values with
457    /// user-defined `mean` and `stddev`.
458    ///
459    /// It is expected that `stddev.abs()` != `0.0`.
460    #[cfg(feature = "std")]
461    #[inline]
462    fn f64_normal_distribution(&mut self, mean: f64, stddev: f64) -> (f64, f64) {
463        let (x, y) = self.f64_normal();
464        ((x * stddev) + mean, (y * stddev) + mean)
465    }
466
467    /// Returns an exponentially distributed `f64` with `lambda` of `1.0`.
468    #[cfg(feature = "std")]
469    #[inline]
470    fn f64_exponential(&mut self) -> f64 {
471        // Using abs() instead of negating the result of ln()
472        // to avoid outputs of -0.0.
473        self.f64_nonzero().ln().abs()
474    }
475
476    /// Returns an exponentially distributed `f64` with user-defined `lambda`.
477    ///
478    /// It is expected that `lambda.abs()` != `0.0`.
479    #[cfg(feature = "std")]
480    #[inline]
481    fn f64_exponential_lambda(&mut self, lambda: f64) -> f64 {
482        self.f64_exponential() / lambda
483    }
484
485    /// Returns a randomly chosen item from the iterator of `collection`.
486    ///
487    /// Only returns `None` when the length of the iterator is zero.
488    ///
489    /// # Examples
490    ///
491    /// ```
492    /// use ya_rand::*;
493    ///
494    /// const SIZE: usize = 1738;
495    /// let mut rng = new_rng();
496    /// let mut v = [0; SIZE];
497    /// for i in 0..SIZE {
498    ///     v[i] = i;
499    /// }
500    /// let (top, bottom) = v.split_at(v.len() / 2);
501    ///
502    /// // Sanity check.
503    /// let random_item = rng.choose(&v).expect("vector `v` is not empty");
504    /// assert!(v.contains(random_item));
505    ///
506    /// // Choose `random_item` from the top half of the array.
507    /// let random_item = rng.choose(top).expect("still not empty");
508    /// assert!(top.contains(random_item) == true);
509    ///
510    /// // We're looking in the bottom half so we won't find the
511    /// // `random_item` from the top half.
512    /// assert!(bottom.contains(random_item) == false);
513    /// ```
514    #[inline]
515    fn choose<C>(&mut self, collection: C) -> Option<C::Item>
516    where
517        C: IntoIterator,
518        C::IntoIter: ExactSizeIterator,
519    {
520        let mut iter = collection.into_iter();
521        let len = iter.len();
522        match len != 0 {
523            true => Some({
524                let idx = self.bound(len as u64) as usize;
525                // SAFETY: Since `bound` always returns a value less than
526                // it's input, `nth` will never return `None`.
527                unsafe { iter.nth(idx).unwrap_unchecked() }
528            }),
529            false => None,
530        }
531    }
532
533    /// Returns a randomly selected ASCII character from the pool of:
534    ///
535    /// `'A'..='Z'`, and`'a'..='z'`
536    #[inline]
537    fn ascii_alphabetic(&mut self) -> char {
538        *self.choose(&ALPHANUMERIC[..52]).unwrap() as char
539    }
540
541    /// Returns a randomly selected ASCII character from the pool of:
542    ///
543    /// `'A'..='Z'`
544    #[inline]
545    fn ascii_uppercase(&mut self) -> char {
546        *self.choose(&ALPHANUMERIC[..26]).unwrap() as char
547    }
548
549    /// Returns a randomly selected ASCII character from the pool of:
550    ///
551    /// `'a'..='z'`
552    #[inline]
553    fn ascii_lowercase(&mut self) -> char {
554        *self.choose(&ALPHANUMERIC[26..52]).unwrap() as char
555    }
556
557    /// Returns a randomly selected ASCII character from the pool of:
558    ///
559    /// `'A'..='Z'`, `'a'..='z'`, and `'0'..='9'`
560    #[inline]
561    fn ascii_alphanumeric(&mut self) -> char {
562        *self.choose(&ALPHANUMERIC[..]).unwrap() as char
563    }
564
565    /// Returns a randomly selected ASCII character from the pool of:
566    ///
567    /// `'0'..='9'`
568    #[inline]
569    fn ascii_digit(&mut self) -> char {
570        *self.choose(&ALPHANUMERIC[52..]).unwrap() as char
571    }
572
573    /// Performs a Fisher-Yates shuffle on the contents of `slice`.
574    ///
575    /// This implementation is the modern variant introduced by
576    /// Richard Durstenfeld. It is in-place and O(n).
577    ///
578    /// # Examples
579    ///
580    /// ```
581    /// use ya_rand::*;
582    ///
583    /// let mut rng = new_rng();
584    /// let mut data = [0; 1738];
585    /// for i in 0..data.len() {
586    ///     data[i] = i;
587    /// }
588    /// assert!(data.is_sorted() == true);
589    ///
590    /// rng.shuffle(&mut data);
591    /// assert!(data.is_sorted() == false);
592    /// ```
593    #[inline(never)]
594    fn shuffle<T>(&mut self, slice: &mut [T]) {
595        let slice_ptr = slice.as_mut_ptr();
596        for i in (1..slice.len()).rev() {
597            let j = self.bound_inclusive(i as u64) as usize;
598            // SAFETY: Index 'i' will always be in bounds because it's
599            // bounded by slice length; index 'j' will always be
600            // in bounds because it's bounded by 'i'.
601            unsafe {
602                core::ptr::swap(slice_ptr.add(i), slice_ptr.add(j));
603            }
604        }
605    }
606}