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}