lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

entropy.rs (1951B)


      1 //! Injected entropy contract and production operating-system adapter.
      2 
      3 use core::fmt;
      4 use std::error::Error;
      5 
      6 /// Failure to obtain cryptographically secure host entropy.
      7 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
      8 pub enum EntropyError {
      9     Unavailable,
     10 }
     11 
     12 impl fmt::Display for EntropyError {
     13     fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
     14         formatter.write_str("host entropy is unavailable")
     15     }
     16 }
     17 
     18 impl Error for EntropyError {}
     19 
     20 /// Injected source of cryptographically secure bytes.
     21 pub trait EntropySource: Send + Sync {
     22     /// Fills the complete destination or returns an error without partial success.
     23     fn fill_bytes(&self, destination: &mut [u8]) -> Result<(), EntropyError>;
     24 }
     25 
     26 /// Production entropy source backed by the operating system.
     27 #[derive(Clone, Copy, Debug, Default)]
     28 pub struct SystemEntropy;
     29 
     30 impl EntropySource for SystemEntropy {
     31     fn fill_bytes(&self, destination: &mut [u8]) -> Result<(), EntropyError> {
     32         getrandom::getrandom(destination).map_err(|_| EntropyError::Unavailable)
     33     }
     34 }
     35 
     36 #[cfg(test)]
     37 mod tests {
     38     use super::*;
     39 
     40     struct FailingEntropy;
     41 
     42     impl EntropySource for FailingEntropy {
     43         fn fill_bytes(&self, _destination: &mut [u8]) -> Result<(), EntropyError> {
     44             Err(EntropyError::Unavailable)
     45         }
     46     }
     47 
     48     #[test]
     49     fn injected_entropy_errors_are_typed_and_safe() {
     50         let mut destination = [0_u8; 16];
     51         let error = FailingEntropy
     52             .fill_bytes(&mut destination)
     53             .expect_err("entropy failure");
     54 
     55         assert_eq!(error, EntropyError::Unavailable);
     56         assert_eq!(error.to_string(), "host entropy is unavailable");
     57         assert_eq!(destination, [0; 16]);
     58     }
     59 
     60     #[test]
     61     fn production_entropy_adapter_smoke_test() {
     62         let mut destination = [0_u8; 32];
     63         SystemEntropy
     64             .fill_bytes(&mut destination)
     65             .expect("operating-system entropy");
     66     }
     67 }