1#![doc = include_str!("../README.md")]
2
3use std::convert::Infallible;
4
5use rand::TryRng;
6
7#[cfg(feature = "uniffi")]
8uniffi::setup_scaffolding!();
9
10mod ffi;
11pub use ffi::{GenBytesError, GenRangeError, SdkRandomNumberClient};
12
13#[cfg(feature = "dangerous-seeded-rng-for-testing")]
14mod seeded;
15#[cfg(feature = "dangerous-seeded-rng-for-testing")]
16pub use seeded::{Scene, clear_seed, rng_set_scene, set_seed_raw};
17
18#[cfg(feature = "snow")]
19mod snow_resolver;
20#[cfg(feature = "snow")]
21pub use snow_resolver::SdkCryptoResolver;
22
23pub trait SdkRng: rand::CryptoRng + Send + Sync {}
29
30impl<T: rand::CryptoRng + Send + Sync + ?Sized> SdkRng for T {}
31
32#[derive(Clone, Debug)]
34pub struct SdkRngImpl(Inner);
35
36#[derive(Clone, Debug)]
37enum Inner {
38 Os,
40 #[cfg(feature = "dangerous-seeded-rng-for-testing")]
43 Seeded,
44}
45
46impl Default for SdkRngImpl {
47 fn default() -> Self {
48 Self(Inner::Os)
49 }
50}
51
52impl SdkRngImpl {
53 pub fn new() -> Self {
55 Self::default()
56 }
57}
58
59pub fn rng() -> SdkRngImpl {
61 #[cfg(feature = "dangerous-seeded-rng-for-testing")]
62 if seeded::is_seeded() {
63 return SdkRngImpl(Inner::Seeded);
64 }
65 SdkRngImpl::default()
66}
67
68impl TryRng for SdkRngImpl {
69 type Error = Infallible;
70
71 fn try_next_u32(&mut self) -> Result<u32, Self::Error> {
72 match &self.0 {
73 Inner::Os => Ok(rand::rngs::SysRng
74 .try_next_u32()
75 .expect("system RNG must not fail")),
76 #[cfg(feature = "dangerous-seeded-rng-for-testing")]
77 Inner::Seeded => Ok(seeded::next_u32()),
78 }
79 }
80
81 fn try_next_u64(&mut self) -> Result<u64, Self::Error> {
82 match &self.0 {
83 Inner::Os => Ok(rand::rngs::SysRng
84 .try_next_u64()
85 .expect("system RNG must not fail")),
86 #[cfg(feature = "dangerous-seeded-rng-for-testing")]
87 Inner::Seeded => Ok(seeded::next_u64()),
88 }
89 }
90
91 fn try_fill_bytes(&mut self, dst: &mut [u8]) -> Result<(), Self::Error> {
92 match &self.0 {
93 Inner::Os => rand::rngs::SysRng
94 .try_fill_bytes(dst)
95 .expect("system RNG must not fail"),
96 #[cfg(feature = "dangerous-seeded-rng-for-testing")]
97 Inner::Seeded => seeded::fill_bytes(dst),
98 }
99 Ok(())
100 }
101}
102
103impl rand::TryCryptoRng for SdkRngImpl {}
104
105#[cfg(test)]
106mod tests {
107 use rand::RngExt;
108
109 use super::*;
110
111 fn _assert_bounds<T: SdkRng + rand::CryptoRng + rand::Rng + Send + Sync>() {}
113 const _: fn() = || _assert_bounds::<SdkRngImpl>();
114
115 #[test]
116 fn os_rng_produces_distinct_bytes() {
117 let mut rng = rng();
118 let a: [u8; 32] = rng.random();
119 let b: [u8; 32] = rng.random();
120 assert_ne!(a, b);
121 }
122}