Skip to main content

openentropy_core/
source.rs

1//! Abstract entropy source trait and runtime state.
2//!
3//! Every entropy source implements the [`EntropySource`] trait, which provides
4//! metadata via [`SourceInfo`], availability checking, and raw sample collection.
5
6use std::time::Duration;
7
8/// Category of entropy source, used for classification and filtering.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum SourceCategory {
11    Timing,
12    System,
13    Network,
14    Hardware,
15    Silicon,
16    CrossDomain,
17    Novel,
18    Frontier,
19}
20
21impl std::fmt::Display for SourceCategory {
22    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
23        match self {
24            Self::Timing => write!(f, "timing"),
25            Self::System => write!(f, "system"),
26            Self::Network => write!(f, "network"),
27            Self::Hardware => write!(f, "hardware"),
28            Self::Silicon => write!(f, "silicon"),
29            Self::CrossDomain => write!(f, "cross_domain"),
30            Self::Novel => write!(f, "novel"),
31            Self::Frontier => write!(f, "frontier"),
32        }
33    }
34}
35
36/// Metadata about an entropy source.
37///
38/// Each source declares its name, a human-readable description, a physics
39/// explanation of how it harvests entropy, its category, platform requirements,
40/// and an estimated entropy rate in bits per sample.
41#[derive(Debug, Clone)]
42pub struct SourceInfo {
43    /// Unique identifier (e.g. `"clock_jitter"`).
44    pub name: &'static str,
45    /// One-line human-readable description.
46    pub description: &'static str,
47    /// Physics explanation of the entropy mechanism.
48    pub physics: &'static str,
49    /// Source category for classification.
50    pub category: SourceCategory,
51    /// Platform requirements (e.g. `["macos"]`).
52    pub platform_requirements: &'static [&'static str],
53    /// Estimated entropy rate in bits per sample.
54    pub entropy_rate_estimate: f64,
55    /// Whether this is a composite source (combines multiple standalone sources).
56    ///
57    /// Composite sources don't measure a single independent entropy domain.
58    /// They combine or interleave other sources. The CLI displays them
59    /// separately from standalone sources.
60    pub composite: bool,
61}
62
63/// Trait that every entropy source must implement.
64pub trait EntropySource: Send + Sync {
65    /// Source metadata.
66    fn info(&self) -> &SourceInfo;
67
68    /// Check if this source can operate on the current machine.
69    fn is_available(&self) -> bool;
70
71    /// Collect raw entropy samples. Returns a `Vec<u8>` of up to `n_samples` bytes.
72    fn collect(&self, n_samples: usize) -> Vec<u8>;
73
74    /// Convenience: name from info.
75    fn name(&self) -> &'static str {
76        self.info().name
77    }
78}
79
80/// Runtime state for a registered source in the pool.
81pub struct SourceState {
82    pub source: Box<dyn EntropySource>,
83    pub weight: f64,
84    pub total_bytes: u64,
85    pub failures: u64,
86    pub last_entropy: f64,
87    pub last_min_entropy: f64,
88    pub last_collect_time: Duration,
89    pub healthy: bool,
90}
91
92impl SourceState {
93    pub fn new(source: Box<dyn EntropySource>, weight: f64) -> Self {
94        Self {
95            source,
96            weight,
97            total_bytes: 0,
98            failures: 0,
99            last_entropy: 0.0,
100            last_min_entropy: 0.0,
101            last_collect_time: Duration::ZERO,
102            healthy: true,
103        }
104    }
105}