Skip to main content

microvms_edges/
entropy.rs

1// SPDX-License-Identifier: Apache-2.0
2//! The production entropy source.
3//!
4//! The port is `microvms_app::entropy::Entropy`, and why nonces, agent tokens and identity
5//! seeds go through one is written there.
6
7use microvms_app::entropy::Entropy;
8use microvms_app::error::{Error, ErrorKind};
9
10/// The production source: the kernel CSPRNG, through `getrandom`.
11///
12/// `getrandom` reaches the kernel directly. It fails only when the pool is genuinely
13/// unavailable, which is why [`Entropy::fill`] can fail at all.
14#[derive(Clone, Copy, Debug, Default)]
15pub struct OsEntropy;
16
17impl Entropy for OsEntropy {
18    fn fill(&self, buf: &mut [u8]) -> Result<(), Error> {
19        getrandom::fill(buf).map_err(|error| {
20            Error::new(
21                ErrorKind::Unexpected,
22                format!("the OS random pool is unavailable: {error}"),
23            )
24        })
25    }
26}
27
28#[cfg(test)]
29mod tests {
30    use std::collections::HashSet;
31
32    use super::*;
33
34    /// The OS source produces distinct draws. One that returned a constant would pass every
35    /// shape test and fail TRAP-1 in production.
36    #[test]
37    fn the_os_source_draws_distinct_bytes() {
38        let drawn: HashSet<[u8; 8]> = (0..200)
39            .map(|_| {
40                let mut bytes = [0_u8; 8];
41                OsEntropy.fill(&mut bytes).expect("the pool is available");
42                bytes
43            })
44            .collect();
45        assert_eq!(drawn.len(), 200);
46    }
47}