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 based on physical mechanism.
9#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
10pub enum SourceCategory {
11    /// Thermal noise in circuits/oscillators.
12    Thermal,
13    /// CPU/memory timing jitter.
14    Timing,
15    /// OS scheduler nondeterminism.
16    Scheduling,
17    /// Storage/peripheral latency variance.
18    IO,
19    /// Inter-process/kernel communication jitter.
20    IPC,
21    /// CPU microarchitecture race conditions.
22    Microarch,
23    /// Graphics pipeline nondeterminism.
24    GPU,
25    /// Network timing/signal noise.
26    Network,
27    /// OS counters/state.
28    System,
29    /// Combines multiple sources.
30    Composite,
31    /// Signal processing entropy.
32    Signal,
33    /// Hardware sensor readings.
34    Sensor,
35}
36
37impl std::fmt::Display for SourceCategory {
38    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
39        match self {
40            Self::Thermal => write!(f, "thermal"),
41            Self::Timing => write!(f, "timing"),
42            Self::Scheduling => write!(f, "scheduling"),
43            Self::IO => write!(f, "io"),
44            Self::IPC => write!(f, "ipc"),
45            Self::Microarch => write!(f, "microarch"),
46            Self::GPU => write!(f, "gpu"),
47            Self::Network => write!(f, "network"),
48            Self::System => write!(f, "system"),
49            Self::Composite => write!(f, "composite"),
50            Self::Signal => write!(f, "signal"),
51            Self::Sensor => write!(f, "sensor"),
52        }
53    }
54}
55
56/// Target platform for an entropy source.
57#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
58pub enum Platform {
59    /// Works on any platform.
60    Any,
61    /// Requires macOS.
62    MacOS,
63    /// Requires Linux.
64    Linux,
65}
66
67impl std::fmt::Display for Platform {
68    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        match self {
70            Self::Any => write!(f, "any"),
71            Self::MacOS => write!(f, "macos"),
72            Self::Linux => write!(f, "linux"),
73        }
74    }
75}
76
77/// Hardware/software requirement for an entropy source.
78#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
79pub enum Requirement {
80    /// GPU compute (Metal framework).
81    Metal,
82    /// CoreAudio (AudioUnit/AudioObject).
83    AudioUnit,
84    /// WiFi hardware.
85    Wifi,
86    /// USB subsystem.
87    Usb,
88    /// Camera hardware.
89    Camera,
90    /// Apple Silicon specific features (AMX, etc.).
91    AppleSilicon,
92    /// Bluetooth hardware.
93    Bluetooth,
94    /// IOKit framework.
95    IOKit,
96    /// IOSurface framework.
97    IOSurface,
98    /// Security framework (Keychain).
99    SecurityFramework,
100}
101
102impl std::fmt::Display for Requirement {
103    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104        match self {
105            Self::Metal => write!(f, "metal"),
106            Self::AudioUnit => write!(f, "audio_unit"),
107            Self::Wifi => write!(f, "wifi"),
108            Self::Usb => write!(f, "usb"),
109            Self::Camera => write!(f, "camera"),
110            Self::AppleSilicon => write!(f, "apple_silicon"),
111            Self::Bluetooth => write!(f, "bluetooth"),
112            Self::IOKit => write!(f, "iokit"),
113            Self::IOSurface => write!(f, "iosurface"),
114            Self::SecurityFramework => write!(f, "security_framework"),
115        }
116    }
117}
118
119/// Metadata about an entropy source.
120///
121/// Each source declares its name, a human-readable description, a physics
122/// explanation of how it harvests entropy, its category, platform requirements,
123/// and an estimated entropy rate in bits per sample.
124#[derive(Debug, Clone)]
125pub struct SourceInfo {
126    /// Unique identifier (e.g. `"clock_jitter"`).
127    pub name: &'static str,
128    /// One-line human-readable description.
129    pub description: &'static str,
130    /// Physics explanation of the entropy mechanism.
131    pub physics: &'static str,
132    /// Source category for classification.
133    pub category: SourceCategory,
134    /// Target platform.
135    pub platform: Platform,
136    /// Hardware/software requirements beyond the platform.
137    pub requirements: &'static [Requirement],
138    /// Estimated entropy rate in bits per sample.
139    pub entropy_rate_estimate: f64,
140    /// Whether this is a composite source (combines multiple standalone sources).
141    ///
142    /// Composite sources don't measure a single independent entropy domain.
143    /// They combine or interleave other sources. The CLI displays them
144    /// separately from standalone sources.
145    pub composite: bool,
146}
147
148/// Trait that every entropy source must implement.
149pub trait EntropySource: Send + Sync {
150    /// Source metadata.
151    fn info(&self) -> &SourceInfo;
152
153    /// Check if this source can operate on the current machine.
154    fn is_available(&self) -> bool;
155
156    /// Collect raw entropy samples. Returns a `Vec<u8>` of up to `n_samples` bytes.
157    fn collect(&self, n_samples: usize) -> Vec<u8>;
158
159    /// Convenience: name from info.
160    fn name(&self) -> &'static str {
161        self.info().name
162    }
163}
164
165/// Runtime state for a registered source in the pool.
166pub struct SourceState {
167    pub source: Box<dyn EntropySource>,
168    pub weight: f64,
169    pub total_bytes: u64,
170    pub failures: u64,
171    pub last_entropy: f64,
172    pub last_min_entropy: f64,
173    pub last_collect_time: Duration,
174    pub healthy: bool,
175}
176
177impl SourceState {
178    pub fn new(source: Box<dyn EntropySource>, weight: f64) -> Self {
179        Self {
180            source,
181            weight,
182            total_bytes: 0,
183            failures: 0,
184            last_entropy: 0.0,
185            last_min_entropy: 0.0,
186            last_collect_time: Duration::ZERO,
187            healthy: true,
188        }
189    }
190}