block_pseudorand/
lib.rs

1//! # block-pseudorand
2//!
3//! This crate allows multi-threaded creation of pseudorandom `Vec<T>`'s of arbitrary length. It does this
4//! by generating arbitrary byte vectors randomly and transmuting to the provided type.
5//!
6//! <p style="background:rgba(255,181,77,0.16);padding:0.75em;">
7//! <strong>Warning:</strong> This is wildly unsafe for some types as it does not uphold any invariants your type might expect.
8//! Only use this crate if your type can be safely generated from completely arbitrary bytes.
9//! Generally, this means your type should consist of nothing but primitive numbers such as u32, i64, or f32.
10//! </p>
11//!
12//! ## Notes
13//!
14//!  - Generated data is not guaranteed to be cryptographically secure
15//!  - Output can be deterministic if you provide a seed
16//!  - This is very unsafe for certain types, see the warning above
17//!
18//! ## Use cases
19//!
20//! If you need a lot of random numbers quickly for something non-production critical like unit tests, this may be
21//! a good candidate. Otherwise, if you are planning to use this at runtime, or with types that are non-numeric
22//! or otherwise cannot be created from arbitrary bytes, I would recommend you to choose another, safer crate.
23//!
24//! ## Usage
25//!
26//! If you are certain the above warnings do not apply to the type you are generating, you can use this library like so:
27//!
28//! ### Without Seed
29//!
30//! ```rust
31//! use block_pseudorand::block_rand;
32//!
33//! let random_data: Vec<u64> = block_rand(128);
34//!
35//! assert_eq!(random_data.len(), 128);
36//! ```
37//!
38//! ### With Seed
39//!
40//! ```rust
41//! use block_pseudorand::block_rand_with_seed;
42//!
43//! // Populate this seed as you wish
44//! let seed = [0u8; 32];
45//! let random_data: Vec<u64> = block_rand_with_seed(128, &seed);
46//!
47//! assert_eq!(random_data.len(), 128);
48//! ```
49
50use std::mem::size_of;
51use chiapos_chacha8::ChaCha8;
52use nanorand::{Rng, WyRand};
53
54#[inline]
55const fn cdiv(a: usize, b: usize) -> usize {
56    (a + b - 1) / b
57}
58
59/// Randomly populates a `Vec` of data based upon a provided seed.
60///
61/// Usage:
62///
63/// ```rust
64/// use block_pseudorand::block_rand_with_seed;
65///
66/// let seed = [0u8; 32];
67/// let random_data: Vec<u32> = block_rand_with_seed(128, &seed);
68///
69/// assert_eq!(random_data.len(), 128);
70/// ```
71pub fn block_rand_with_seed<T: Copy>(count: usize, seed: &[u8; 32]) -> Vec<T> {
72    let expected_len_bytes = count * size_of::<T>();
73    let gen_len = cdiv(expected_len_bytes, 64) * 64;
74
75    let mut bytes = Vec::with_capacity(gen_len);
76    unsafe {
77        bytes.set_len(gen_len);
78    };
79
80    let chacha8 = ChaCha8::new_from_256bit_key(seed);
81    chacha8.get_keystream(0, &mut bytes);
82
83    bytes.truncate(expected_len_bytes);
84
85    let mut out = std::mem::ManuallyDrop::new(bytes);
86
87    unsafe {
88        Vec::from_raw_parts(
89            out.as_mut_ptr() as *mut T,
90            count,
91            count
92        )
93    }
94}
95
96/// Randomly populates a `Vec` of data based upon a randomly chosen seed.
97///
98/// Usage:
99///
100/// ```rust
101/// use block_pseudorand::block_rand;
102///
103/// let random_data: Vec<u32> = block_rand(128);
104///
105/// assert_eq!(random_data.len(), 128);
106/// ```
107pub fn block_rand<T: Copy>(count: usize) -> Vec<T> {
108    let mut rng = WyRand::new();
109    let mut key = [0u8; 32];
110    for v in key.iter_mut() {
111        *v = rng.generate();
112    }
113
114    block_rand_with_seed(count, &key)
115}
116
117#[cfg(test)]
118mod tests {
119    use crate::*;
120
121    fn test_count<T: Copy>(count: usize) {
122        let rand_data: Vec<T> = block_rand(count);
123        assert_eq!(rand_data.len(), count);
124    }
125
126    fn test_medley<T: Copy>() {
127        test_count::<T>(0);
128        test_count::<T>(1);
129        test_count::<T>(2);
130        test_count::<T>(3);
131        test_count::<T>(10_000);
132        test_count::<T>(1_000_000);
133        test_count::<T>(10_000_000);
134    }
135
136    #[test]
137    fn u8_works() {
138        test_medley::<u8>();
139    }
140
141    #[test]
142    fn u16_works() {
143        test_medley::<u16>();
144    }
145
146    #[test]
147    fn u32_works() {
148        test_medley::<u32>();
149    }
150
151    #[test]
152    fn u64_works() {
153        test_medley::<u64>();
154    }
155
156    #[test]
157    fn u128_works() {
158        test_medley::<u128>();
159    }
160
161    #[test]
162    fn usize_works() {
163        test_medley::<usize>();
164    }
165
166    #[test]
167    fn i8_works() {
168        test_medley::<i8>();
169    }
170
171    #[test]
172    fn i16_works() {
173        test_medley::<i16>();
174    }
175
176    #[test]
177    fn i32_works() {
178        test_medley::<i32>();
179    }
180
181    #[test]
182    fn i64_works() {
183        test_medley::<i64>();
184    }
185
186    #[test]
187    fn i128_works() {
188        test_medley::<i128>();
189    }
190
191    #[test]
192    fn isize_works() {
193        test_medley::<isize>();
194    }
195
196    #[test]
197    fn f32_works() {
198        test_medley::<f32>();
199    }
200
201    #[test]
202    fn f64_works() {
203        test_medley::<f64>();
204    }
205}