|
193 | 193 | #[macro_use]
|
194 | 194 | extern crate cfg_if;
|
195 | 195 |
|
196 |
| -use crate::util::slice_as_uninit_mut; |
| 196 | +use crate::util::{slice_as_uninit_mut, slice_assume_init_mut}; |
| 197 | +use core::mem::MaybeUninit; |
197 | 198 |
|
198 | 199 | mod error;
|
199 | 200 | mod util;
|
@@ -290,22 +291,84 @@ cfg_if! {
|
290 | 291 | /// Fill `dest` with random bytes from the system's preferred random number
|
291 | 292 | /// source.
|
292 | 293 | ///
|
293 |
| -/// This function returns an error on any failure, including partial reads. We |
294 |
| -/// make no guarantees regarding the contents of `dest` on error. If `dest` is |
295 |
| -/// empty, `getrandom` immediately returns success, making no calls to the |
296 |
| -/// underlying operating system. |
297 |
| -/// |
298 |
| -/// Blocking is possible, at least during early boot; see module documentation. |
299 |
| -/// |
300 |
| -/// In general, `getrandom` will be fast enough for interactive usage, though |
301 |
| -/// significantly slower than a user-space CSPRNG; for the latter consider |
302 |
| -/// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html). |
| 294 | +/// Convinence alias for `Options::DEFAULT.fill(dest)`. For more info, see |
| 295 | +/// [`Options::DEFAULT`] and [`Options::fill`]. |
303 | 296 | #[inline]
|
304 | 297 | pub fn getrandom(dest: &mut [u8]) -> Result<(), Error> {
|
305 |
| - if dest.is_empty() { |
306 |
| - return Ok(()); |
| 298 | + Options::DEFAULT.fill(dest) |
| 299 | +} |
| 300 | + |
| 301 | +/// Options for specifying how random bytes should be generated. |
| 302 | +/// |
| 303 | +/// Currently, [`Options::DEFAULT`] is the only allowed option, but we may add |
| 304 | +/// additional options in the future (hense why this enum is `non_exhaustive`). |
| 305 | +#[derive(Clone, Copy, Debug)] |
| 306 | +#[cfg_attr(getrandom_non_exhaustive, non_exhaustive)] |
| 307 | +pub enum Options { |
| 308 | + /// Use the system's preferred random number source. |
| 309 | + /// |
| 310 | + /// This implementation is garunteed to produce cryptographically random |
| 311 | + /// bytes on success. However, it may block in order to do so, |
| 312 | + /// [especially during early boot](https://docs.rs/getrandom#early-boot). |
| 313 | + /// |
| 314 | + /// In general, this sources will be fast enough for |
| 315 | + /// interactive usage, though significantly slower than a user-space CSPRNG. |
| 316 | + /// For a user-space CSPRNG seeded from this source, consider |
| 317 | + /// [`rand::thread_rng`](https://docs.rs/rand/*/rand/fn.thread_rng.html). |
| 318 | + DEFAULT, |
| 319 | +} |
| 320 | + |
| 321 | +impl Options { |
| 322 | + /// Fill `dest` with random bytes. |
| 323 | + /// |
| 324 | + /// This function returns an error on any failure, including partial reads. |
| 325 | + /// We make no guarantees regarding the contents of `dest` on error. If |
| 326 | + /// `dest` is empty, immediately return success, making no calls to the |
| 327 | + /// underlying system RNG source. |
| 328 | + #[inline] |
| 329 | + pub fn fill(self, dest: &mut [u8]) -> Result<(), Error> { |
| 330 | + if dest.is_empty() { |
| 331 | + return Ok(()); |
| 332 | + } |
| 333 | + // SAFETY: The &mut [MaybeUninit<u8>] reference doesn't escape, and |
| 334 | + // `getrandom_inner` will never de-initialize any part of `dest`. |
| 335 | + imp::getrandom_inner(unsafe { slice_as_uninit_mut(dest) }) |
| 336 | + } |
| 337 | + |
| 338 | + /// Initialize `dest` with random bytes. |
| 339 | + /// |
| 340 | + /// On success, this function is guaranteed to return a slice which points |
| 341 | + /// to the same memory as `dest` and has the same length. In this case, it |
| 342 | + /// is safe to assume that `dest` is initialized. |
| 343 | + /// |
| 344 | + /// On either success or failure, no part of `dest` will ever be |
| 345 | + /// de-initialized at any point. |
| 346 | + /// |
| 347 | + /// # Examples |
| 348 | + /// |
| 349 | + /// ``` |
| 350 | + /// # use core::mem::MaybeUninit; |
| 351 | + /// # fn uninit_example() -> Result<(), getrandom::Error> { |
| 352 | + /// use getrandom::Options; |
| 353 | + /// |
| 354 | + /// let mut buf = [MaybeUninit::<u8>::uninit(); 1024]; |
| 355 | + /// let buf: &mut [u8] = Options::DEFAULT.fill_uninit(&mut buf)?; |
| 356 | + /// # Ok(()) } |
| 357 | + /// # uninit_example().unwrap(); |
| 358 | + /// ``` |
| 359 | + #[inline] |
| 360 | + pub fn fill_uninit(self, dest: &mut [MaybeUninit<u8>]) -> Result<&mut [u8], Error> { |
| 361 | + if !dest.is_empty() { |
| 362 | + imp::getrandom_inner(dest)?; |
| 363 | + } |
| 364 | + // SAFETY: `dest` has been fully initialized by `imp::getrandom_inner` |
| 365 | + Ok(unsafe { slice_assume_init_mut(dest) }) |
| 366 | + } |
| 367 | +} |
| 368 | + |
| 369 | +// TODO(MSRV 1.62): Use #[derive(Default)] |
| 370 | +impl Default for Options { |
| 371 | + fn default() -> Self { |
| 372 | + Self::DEFAULT |
307 | 373 | }
|
308 |
| - // SAFETY: The &mut [MaybeUninit<u8>] reference doesn't escape, and |
309 |
| - // `getrandom_inner` will never de-initialize any part of `dest`. |
310 |
| - imp::getrandom_inner(unsafe { slice_as_uninit_mut(dest) }) |
311 | 374 | }
|
0 commit comments