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