ya_rand/
rng.rs

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