use std::time::Duration;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum SourceCategory {
Thermal,
Timing,
Scheduling,
IO,
IPC,
Microarch,
GPU,
Network,
System,
Signal,
Sensor,
Quantum,
}
impl std::fmt::Display for SourceCategory {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Thermal => write!(f, "thermal"),
Self::Timing => write!(f, "timing"),
Self::Scheduling => write!(f, "scheduling"),
Self::IO => write!(f, "io"),
Self::IPC => write!(f, "ipc"),
Self::Microarch => write!(f, "microarch"),
Self::GPU => write!(f, "gpu"),
Self::Network => write!(f, "network"),
Self::System => write!(f, "system"),
Self::Signal => write!(f, "signal"),
Self::Sensor => write!(f, "sensor"),
Self::Quantum => write!(f, "quantum"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Platform {
Any,
MacOS,
Linux,
}
impl std::fmt::Display for Platform {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Any => write!(f, "any"),
Self::MacOS => write!(f, "macos"),
Self::Linux => write!(f, "linux"),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Requirement {
Metal,
AudioUnit,
Wifi,
Usb,
Camera,
AppleSilicon,
Bluetooth,
IOKit,
IOSurface,
SecurityFramework,
RawBlockDevice,
QCicada,
}
impl std::fmt::Display for Requirement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::Metal => write!(f, "metal"),
Self::AudioUnit => write!(f, "audio_unit"),
Self::Wifi => write!(f, "wifi"),
Self::Usb => write!(f, "usb"),
Self::Camera => write!(f, "camera"),
Self::AppleSilicon => write!(f, "apple_silicon"),
Self::Bluetooth => write!(f, "bluetooth"),
Self::IOKit => write!(f, "iokit"),
Self::IOSurface => write!(f, "iosurface"),
Self::SecurityFramework => write!(f, "security_framework"),
Self::RawBlockDevice => write!(f, "raw_block_device"),
Self::QCicada => write!(f, "qcicada"),
}
}
}
impl Requirement {
pub fn icon(&self) -> &'static str {
match self {
Self::QCicada => "🔮",
Self::Camera => "📷",
Self::AudioUnit => "🎤",
Self::Metal => "🎮",
Self::Wifi => "📶",
Self::Bluetooth => "📡",
Self::Usb => "🔌",
Self::RawBlockDevice => "💾",
_ => "", }
}
pub fn label(&self) -> &'static str {
match self {
Self::QCicada => "QCicada QRNG (USB)",
Self::Camera => "Camera",
Self::AudioUnit => "Microphone (CoreAudio)",
Self::Metal => "GPU (Metal)",
Self::Wifi => "WiFi adapter",
Self::Bluetooth => "Bluetooth",
Self::Usb => "USB subsystem",
Self::RawBlockDevice => "Raw block device",
Self::AppleSilicon => "Apple Silicon",
Self::IOKit => "IOKit",
Self::IOSurface => "IOSurface",
Self::SecurityFramework => "Security Framework",
}
}
pub fn from_display_name(name: &str) -> Option<Self> {
match name {
"metal" => Some(Self::Metal),
"audio_unit" => Some(Self::AudioUnit),
"wifi" => Some(Self::Wifi),
"usb" => Some(Self::Usb),
"camera" => Some(Self::Camera),
"apple_silicon" => Some(Self::AppleSilicon),
"bluetooth" => Some(Self::Bluetooth),
"iokit" => Some(Self::IOKit),
"iosurface" => Some(Self::IOSurface),
"security_framework" => Some(Self::SecurityFramework),
"raw_block_device" => Some(Self::RawBlockDevice),
"qcicada" => Some(Self::QCicada),
_ => None,
}
}
pub fn icon_for_display_name(name: &str) -> &'static str {
Self::from_display_name(name).map_or("", |r| r.icon())
}
pub fn label_for_display_name(name: &str) -> &'static str {
Self::from_display_name(name).map_or("Unknown", |r| r.label())
}
}
pub fn best_icon(requirements: &[Requirement]) -> &'static str {
requirements
.iter()
.map(Requirement::icon)
.find(|icon| !icon.is_empty())
.unwrap_or("")
}
pub fn best_icon_from_names(names: &[String]) -> &'static str {
names
.iter()
.map(|n| Requirement::icon_for_display_name(n))
.find(|icon| !icon.is_empty())
.unwrap_or("")
}
#[derive(Debug, Clone)]
pub struct SourceInfo {
pub name: &'static str,
pub description: &'static str,
pub physics: &'static str,
pub category: SourceCategory,
pub platform: Platform,
pub requirements: &'static [Requirement],
pub entropy_rate_estimate: f64,
pub composite: bool,
pub is_fast: bool,
}
pub trait EntropySource: Send + Sync {
fn info(&self) -> &SourceInfo;
fn is_available(&self) -> bool;
fn collect(&self, n_samples: usize) -> Vec<u8>;
fn name(&self) -> &'static str {
self.info().name
}
fn set_config(&self, _key: &str, _value: &str) -> Result<(), String> {
Err("source does not support runtime configuration".into())
}
fn config_options(&self) -> Vec<(&'static str, String)> {
vec![]
}
}
pub struct SourceState {
pub source: std::sync::Arc<dyn EntropySource>,
pub total_bytes: u64,
pub failures: u64,
pub last_entropy: f64,
pub last_min_entropy: f64,
pub last_autocorrelation: f64,
pub last_collect_time: Duration,
pub healthy: bool,
}
impl SourceState {
pub fn new(source: Box<dyn EntropySource>) -> Self {
Self {
source: std::sync::Arc::from(source),
total_bytes: 0,
failures: 0,
last_entropy: 0.0,
last_min_entropy: 0.0,
last_autocorrelation: 0.0,
last_collect_time: Duration::ZERO,
healthy: true,
}
}
}