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}