coven_crypto/
randomness.rs1use crate::CryptoError;
4
5#[cfg(any(test, feature = "test-utils"))]
6thread_local! {
7 #[cfg_attr(target_os = "android", allow(clippy::missing_const_for_thread_local))]
11 static REFUSALS: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
12}
13
14#[cfg(any(test, feature = "test-utils"))]
18pub fn refuse_randomness(count: usize) {
19 REFUSALS.set(count);
20}
21
22pub(crate) fn fill(bytes: &mut [u8]) -> Result<(), CryptoError> {
23 #[cfg(any(test, feature = "test-utils"))]
24 if let Some(left) = REFUSALS.get().checked_sub(1) {
25 REFUSALS.set(left);
26 return fill_with(bytes, |_| Err(getrandom::Error::UNSUPPORTED));
27 }
28 fill_with(bytes, getrandom::fill)
29}
30
31pub(crate) fn secret_bytes() -> Result<zeroize::Zeroizing<[u8; 32]>, CryptoError> {
34 let mut bytes = zeroize::Zeroizing::new([0; 32]);
35 fill(bytes.as_mut())?;
36 Ok(bytes)
37}
38
39pub fn random_secret() -> Result<crate::SecretText, CryptoError> {
42 Ok(crate::SecretText::new(hex::encode(secret_bytes()?.as_ref())))
43}
44
45fn fill_with(
46 bytes: &mut [u8],
47 source: impl FnOnce(&mut [u8]) -> Result<(), getrandom::Error>,
48) -> Result<(), CryptoError> {
49 source(bytes).map_err(|error| CryptoError::Unavailable(Box::new(error)))
50}
51
52#[cfg(test)]
53#[path = "randomness_tests.rs"]
54mod tests;