osom_lib_rand/traits.rs
1//! Holds traits for random number generators and randomness sources.
2use crate::number::Number;
3
4/// Simple trait for pseudo random number generators. Types implementing
5/// this trait should aim for efficiency above all.
6///
7/// In its essence this is the same as [`RandomnessSource`].
8/// We distinguish those types mostly for type safety. These
9/// have different purposes.
10pub trait PseudoRandomNumberGenerator {
11 type TNumber: Number;
12
13 /// Whether the generator is cryptographically secure.
14 const IS_CRYPTOGRAPHICALLY_SECURE: bool = false;
15
16 /// Creates a new [`PseudoRandomNumberGenerator`] seeded from a [`RandomnessSource`].
17 fn from_randomness_source(source: &mut impl RandomnessSource<TNumber = Self::TNumber>) -> Self;
18
19 /// Returns the next random number.
20 fn next_number(&mut self) -> Self::TNumber;
21
22 /// Fills the given mut slice with random bytes.
23 fn fill_bytes(&mut self, bytes: &mut [u8]) {
24 fill_bytes_from_gens(bytes, || self.next_number());
25 }
26}
27
28/// Simple trait for randomness source.
29///
30/// This looks (and in fact is)
31/// the same as [`PseudoRandomNumberGenerator`], however it is distinguished
32/// by the way it works. It is allowed for implementors of this trait
33/// to be inefficient, but have potentially better randomness (e.g. by
34/// reading from appropriate hardware source).
35///
36/// It is also a good idea to seed [`PseudoRandomNumberGenerator`] objects
37/// with whatever [`RandomnessSource`] returns.
38///
39/// In its essence this is the same as [`PseudoRandomNumberGenerator`].
40/// We distinguish those types mostly for type safety. These
41/// have different purposes.
42pub trait RandomnessSource: Default {
43 type TNumber: Number;
44
45 /// Returns the next random number.
46 fn next_number(&mut self) -> Self::TNumber;
47
48 /// Fills the given mut slice with random bytes.
49 fn fill_bytes(&mut self, bytes: &mut [u8]) {
50 fill_bytes_from_gens(bytes, || self.next_number());
51 }
52}
53
54fn fill_bytes_from_gens<T: Number, F: FnMut() -> T>(bytes: &mut [u8], mut generator: F) {
55 if bytes.is_empty() {
56 return;
57 }
58
59 let size = T::SIZE;
60 let bytes_len = bytes.len();
61 let number_of_chunks = bytes_len / size;
62 let missing_elements = bytes_len % size;
63 let mut ptr = bytes.as_mut_ptr().cast::<T>();
64 for _ in 0..number_of_chunks {
65 unsafe {
66 ptr.write(generator());
67 ptr = ptr.add(1);
68 }
69 }
70
71 if missing_elements > 0 {
72 let mut value_bytes = T::ByteRepr::default();
73 let value_bytes_slice = value_bytes.as_mut();
74 let value_ptr = value_bytes_slice.as_mut_ptr().cast::<T>();
75 unsafe {
76 value_ptr.write(generator());
77 }
78 let index = number_of_chunks * size;
79 let remaining_bytes = &mut bytes[index..(index + missing_elements)];
80 remaining_bytes.copy_from_slice(&value_bytes_slice[..missing_elements]);
81 }
82}