use crate::source::{EntropySource, Platform, SourceCategory, SourceInfo};
#[cfg(target_os = "macos")]
use crate::sources::helpers::{extract_timing_entropy_debiased, mach_time};
static COMMPAGE_CLOCK_TIMING_INFO: SourceInfo = SourceInfo {
name: "commpage_clock_timing",
description: "macOS COMMPAGE seqlock update synchronization timing — bimodal clock read",
physics: "Times gettimeofday(), which reads a seqlock-protected structure in the \
kernel-managed COMMPAGE. When a kernel timer interrupt updates the COMMPAGE \
clock during our read, the seqlock forces a retry, adding one full update \
cycle latency. Creates bimodal distribution: fast mode (~5 ticks, no update) \
vs slow mode (~45 ticks, update in progress). Empirical: 31% fast, 69% slow, \
H=1.54 bits/sample, CV=67.1%. Phase alignment between kernel timer interrupt \
cadence and our instruction dispatch is driven by CPU crystal thermal noise.",
category: SourceCategory::Timing,
platform: Platform::MacOS,
requirements: &[],
entropy_rate_estimate: 1.5,
composite: false,
is_fast: false,
};
pub struct CommPageClockTimingSource;
#[cfg(target_os = "macos")]
impl EntropySource for CommPageClockTimingSource {
fn info(&self) -> &SourceInfo {
&COMMPAGE_CLOCK_TIMING_INFO
}
fn is_available(&self) -> bool {
true
}
fn collect(&self, n_samples: usize) -> Vec<u8> {
let raw = n_samples * 3 + 32;
let mut timings = Vec::with_capacity(raw);
let mut tv = libc_timeval {
tv_sec: 0,
tv_usec: 0,
};
for _ in 0..8 {
unsafe { gettimeofday_sys(&mut tv, core::ptr::null_mut()) };
}
for _ in 0..raw {
let t0 = mach_time();
unsafe { gettimeofday_sys(&mut tv, core::ptr::null_mut()) };
let elapsed = mach_time().wrapping_sub(t0);
if elapsed < 120_000 {
timings.push(elapsed);
}
}
extract_timing_entropy_debiased(&timings, n_samples)
}
}
#[cfg(target_os = "macos")]
#[repr(C)]
struct libc_timeval {
tv_sec: i64,
tv_usec: i32,
}
#[cfg(target_os = "macos")]
#[link(name = "c")]
unsafe extern "C" {
#[link_name = "gettimeofday"]
fn gettimeofday_sys(tv: *mut libc_timeval, tz: *mut core::ffi::c_void) -> i32;
}
#[cfg(not(target_os = "macos"))]
impl EntropySource for CommPageClockTimingSource {
fn info(&self) -> &SourceInfo {
&COMMPAGE_CLOCK_TIMING_INFO
}
fn is_available(&self) -> bool {
false
}
fn collect(&self, _: usize) -> Vec<u8> {
Vec::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn info() {
let src = CommPageClockTimingSource;
assert_eq!(src.info().name, "commpage_clock_timing");
assert!(matches!(src.info().category, SourceCategory::Timing));
assert_eq!(src.info().platform, Platform::MacOS);
assert!(!src.info().composite);
}
#[test]
#[cfg(target_os = "macos")]
fn is_available_on_macos() {
assert!(CommPageClockTimingSource.is_available());
}
#[test]
#[ignore]
fn collects_bimodal_distribution() {
let data = CommPageClockTimingSource.collect(32);
assert!(!data.is_empty());
}
}