Skip to main content

zenith_session/adapter/
rng.rs

1//! Random-number-generator adapter trait, OS-backed implementation, and deterministic test fake.
2
3use crate::error::SessionError;
4
5/// Abstraction over a random-byte source.
6///
7/// Callers receive `&impl Rng` so that production code can use [`OsRng`] while
8/// tests substitute [`FakeRng`] for full determinism.
9///
10/// The trait is fallible (`Result`) because OS entropy can fail; library code
11/// must not panic on entropy exhaustion or OS error.
12pub trait Rng {
13    /// Fill `buf` with random (or deterministic, in fakes) bytes.
14    fn fill_bytes(&self, buf: &mut [u8]) -> Result<(), SessionError>;
15}
16
17/// Deterministic test RNG: fills every byte of `buf` with `self.0`.
18///
19/// Useful for asserting exact byte sequences in unit tests without needing a
20/// real entropy source.
21pub struct FakeRng(pub u8);
22
23impl Rng for FakeRng {
24    fn fill_bytes(&self, buf: &mut [u8]) -> Result<(), SessionError> {
25        buf.fill(self.0);
26        Ok(())
27    }
28}
29
30/// OS-backed entropy source (via `getrandom`).
31pub struct OsRng;
32
33impl Rng for OsRng {
34    fn fill_bytes(&self, buf: &mut [u8]) -> Result<(), SessionError> {
35        getrandom::fill(buf).map_err(|e| SessionError::new(format!("os entropy failure: {e}")))
36    }
37}
38
39#[cfg(test)]
40mod tests {
41    use super::*;
42
43    #[test]
44    fn fake_rng_fills_all_bytes_with_its_value() {
45        let rng = FakeRng(0xAB);
46        let mut buf = [0u8; 8];
47        rng.fill_bytes(&mut buf).unwrap();
48        assert_eq!(buf, [0xAB; 8]);
49    }
50
51    #[test]
52    fn fake_rng_zero_value() {
53        let rng = FakeRng(0x00);
54        let mut buf = [0xFFu8; 4];
55        rng.fill_bytes(&mut buf).unwrap();
56        assert_eq!(buf, [0x00; 4]);
57    }
58
59    #[test]
60    fn os_rng_smoke() {
61        let result = OsRng.fill_bytes(&mut [0u8; 16]);
62        assert!(result.is_ok());
63    }
64}