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'`
536 /// * `'a'..='z'`
537 #[inline]
538 fn ascii_alphabetic(&mut self) -> char {
539 *self.choose(&ALPHANUMERIC[..52]).unwrap() as char
540 }
541
542 /// Returns a randomly selected ASCII character from the pool of:
543 ///
544 /// * `'A'..='Z'`
545 #[inline]
546 fn ascii_uppercase(&mut self) -> char {
547 *self.choose(&ALPHANUMERIC[..26]).unwrap() as char
548 }
549
550 /// Returns a randomly selected ASCII character from the pool of:
551 ///
552 /// * `'a'..='z'`
553 #[inline]
554 fn ascii_lowercase(&mut self) -> char {
555 *self.choose(&ALPHANUMERIC[26..52]).unwrap() as char
556 }
557
558 /// Returns a randomly selected ASCII character from the pool of:
559 ///
560 /// * `'A'..='Z'`
561 /// * `'a'..='z'`
562 /// * `'0'..='9'`
563 #[inline]
564 fn ascii_alphanumeric(&mut self) -> char {
565 *self.choose(&ALPHANUMERIC[..]).unwrap() as char
566 }
567
568 /// Returns a randomly selected ASCII character from the pool of:
569 ///
570 /// * `'0'..='9'`
571 #[inline]
572 fn ascii_digit(&mut self) -> char {
573 *self.choose(&ALPHANUMERIC[52..]).unwrap() as char
574 }
575
576 /// Performs a Fisher-Yates shuffle on the contents of `slice`.
577 ///
578 /// This implementation is the modern variant introduced by
579 /// Richard Durstenfeld. It is in-place and O(n).
580 ///
581 /// # Examples
582 ///
583 /// ```
584 /// use ya_rand::*;
585 ///
586 /// let mut rng = new_rng();
587 /// let mut data = [0; 1738];
588 /// for i in 0..data.len() {
589 /// data[i] = i;
590 /// }
591 /// assert!(data.is_sorted() == true);
592 ///
593 /// rng.shuffle(&mut data);
594 /// assert!(data.is_sorted() == false);
595 /// ```
596 #[inline(never)]
597 fn shuffle<T>(&mut self, slice: &mut [T]) {
598 let slice_ptr = slice.as_mut_ptr();
599 for i in (1..slice.len()).rev() {
600 let j = self.bound_inclusive(i as u64) as usize;
601 // SAFETY: Index 'i' will always be in bounds because it's
602 // bounded by slice length; index 'j' will always be
603 // in bounds because it's bounded by 'i'.
604 unsafe {
605 core::ptr::swap(slice_ptr.add(i), slice_ptr.add(j));
606 }
607 }
608 }
609}