Reworking bssl_crypto: rand

Change-Id: I49e1b11b6eba1f2ddc190c5c070f133cce10b2f7
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/65175
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/rust/bssl-crypto/src/lib.rs b/rust/bssl-crypto/src/lib.rs
index 61a8dbc..753cc79 100644
--- a/rust/bssl-crypto/src/lib.rs
+++ b/rust/bssl-crypto/src/lib.rs
@@ -50,9 +50,6 @@
 
 pub mod hmac;
 
-/// Random number generation.
-pub mod rand;
-
 pub mod x25519;
 
 pub mod ec;
@@ -63,6 +60,9 @@
 mod mem;
 pub use mem::constant_time_compare;
 
+mod rand;
+pub use rand::{rand_array, rand_bytes};
+
 #[cfg(test)]
 mod test_helpers;
 
diff --git a/rust/bssl-crypto/src/rand.rs b/rust/bssl-crypto/src/rand.rs
index 9fdbe0a..c6d419f 100644
--- a/rust/bssl-crypto/src/rand.rs
+++ b/rust/bssl-crypto/src/rand.rs
@@ -13,29 +13,56 @@
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-use crate::CSliceMut;
+//! Getting random bytes.
 
-/// Fills buf with random bytes. In the event that sufficient random data can not be obtained,
-/// BoringSSL will abort, so the assert will never be hit.
+use crate::{with_output_array, FfiMutSlice};
+
+/// Fills `buf` with random bytes.
 pub fn rand_bytes(buf: &mut [u8]) {
-    let mut ffi_buf = CSliceMut::from(buf);
-    let result = unsafe { bssl_sys::RAND_bytes(ffi_buf.as_mut_ptr(), ffi_buf.len()) };
-    assert_eq!(result, 1, "BoringSSL RAND_bytes API failed unexpectedly");
+    // Safety: `RAND_bytes` writes exactly `buf.len()` bytes.
+    let ret = unsafe { bssl_sys::RAND_bytes(buf.as_mut_ffi_ptr(), buf.len()) };
+
+    // BoringSSL's `RAND_bytes` always succeeds returning 1, or crashes the
+    // address space if the PRNG can not provide random data.
+    debug_assert!(ret == 1);
+}
+
+/// Returns an array of random bytes.
+pub fn rand_array<const N: usize>() -> [u8; N] {
+    unsafe {
+        with_output_array(|out, out_len| {
+            // Safety: `RAND_bytes` writes exactly `out_len` bytes, as required.
+            let ret = bssl_sys::RAND_bytes(out, out_len);
+            // BoringSSL RAND_bytes always succeeds returning 1, or crashes the
+            // address space if the PRNG can not provide random data.
+            debug_assert!(ret == 1);
+        })
+    }
 }
 
 #[cfg(test)]
 mod tests {
-    use super::rand_bytes;
+    use super::*;
 
     #[test]
-    fn test_rand_bytes() {
+    fn fill() {
         let mut buf = [0; 32];
         rand_bytes(&mut buf);
     }
 
     #[test]
-    fn test_rand_bytes_empty() {
+    fn fill_empty() {
         let mut buf = [];
         rand_bytes(&mut buf);
     }
+
+    #[test]
+    fn array() {
+        let _rand: [u8; 32] = rand_array();
+    }
+
+    #[test]
+    fn empty_array() {
+        let _rand: [u8; 0] = rand_array();
+    }
 }