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}