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}