#![warn(missing_docs)]
#![warn(clippy::all)]
pub mod adaptive;
mod config;
mod constants;
mod oracle;
pub mod result;
mod thread_pool;
mod types;
pub mod analysis;
pub mod data;
pub mod helpers;
pub mod measurement;
pub mod output;
pub mod preflight;
pub mod statistics;
#[cfg(feature = "power")]
pub mod power;
pub use config::{Config, IterationsPerSample};
pub use constants::{DECILES, LOG_2PI};
pub use measurement::{BoxedTimer, Timer, TimerError, TimerSpec};
pub use oracle::{compute_min_uniqueness_ratio, TimingOracle};
pub use result::{
BatchingInfo, Diagnostics, EffectEstimate, Exploitability, InconclusiveReason, IssueCode,
MeasurementQuality, Metadata, MinDetectableEffect, Outcome, QualityIssue, TopQuantile,
UnmeasurableInfo, UnreliablePolicy,
};
pub use types::{AttackerModel, Class, TimingSample};
pub use helpers::InputPair;
pub use helpers::effect::{
busy_wait_ns, counter_frequency_hz, global_max_delay_ns, set_global_max_delay_ns,
timer_backend_name, timer_resolution_ns, using_precise_timer, BenchmarkEffect, EffectInjector,
};
#[macro_export]
macro_rules! assert_constant_time {
($outcome:expr) => {
match &$outcome {
$crate::Outcome::Pass { .. } => {}
$crate::Outcome::Fail { .. } => {
let summary = $crate::output::format_debug_summary(&$outcome);
panic!("Timing leak detected!\n\n{}", summary,);
}
$crate::Outcome::Inconclusive {
reason,
leak_probability,
..
} => {
let summary = $crate::output::format_debug_summary(&$outcome);
panic!(
"Could not confirm constant-time (P={:.1}%): {}\n\n{}",
leak_probability * 100.0,
reason,
summary,
);
}
$crate::Outcome::Unmeasurable { recommendation, .. } => {
let summary = $crate::output::format_debug_summary(&$outcome);
panic!(
"Cannot measure operation: {}\n\n{}",
recommendation, summary
);
}
$crate::Outcome::Research(research) => {
let summary = $crate::output::format_debug_summary(&$outcome);
panic!(
"Research mode result (use research mode assertions): {:?}\n\n{}",
research.status, summary
);
}
}
};
}
#[macro_export]
macro_rules! assert_no_timing_leak {
($outcome:expr) => {
if let $crate::Outcome::Fail { .. } = &$outcome {
let summary = $crate::output::format_debug_summary(&$outcome);
panic!("Timing leak detected!\n\n{}", summary,);
}
};
}
#[macro_export]
macro_rules! assert_leak_detected {
($outcome:expr) => {
match &$outcome {
$crate::Outcome::Fail { .. } => {}
$crate::Outcome::Pass {
leak_probability, ..
} => {
let summary = $crate::output::format_debug_summary(&$outcome);
panic!(
"Expected timing leak but got Pass (P={:.1}%)\n\n{}",
leak_probability * 100.0,
summary,
);
}
$crate::Outcome::Inconclusive {
reason,
leak_probability,
..
} => {
if *leak_probability >= 0.90 {
} else {
let summary = $crate::output::format_debug_summary(&$outcome);
panic!(
"Expected timing leak but got Inconclusive (P={:.1}%): {}\n\n{}",
leak_probability * 100.0,
reason,
summary,
);
}
}
$crate::Outcome::Unmeasurable { recommendation, .. } => {
let summary = $crate::output::format_debug_summary(&$outcome);
panic!(
"Expected timing leak but operation unmeasurable: {}\n\n{}",
recommendation, summary,
);
}
$crate::Outcome::Research(research) => {
let summary = $crate::output::format_debug_summary(&$outcome);
panic!(
"Expected timing leak but got Research mode result: {:?}\n\n{}",
research.status, summary,
);
}
}
};
}
#[macro_export]
macro_rules! skip_if_unreliable {
($outcome:expr, $name:expr) => {
match $outcome.handle_unreliable($name, $crate::UnreliablePolicy::FailOpen) {
Some(result) => result,
None => return,
}
};
}
#[macro_export]
macro_rules! require_reliable {
($outcome:expr, $name:expr) => {
match $outcome.handle_unreliable($name, $crate::UnreliablePolicy::FailClosed) {
Some(result) => result,
None => unreachable!(),
}
};
}
#[cfg(feature = "macros")]
pub use tacet_macros::{timing_test, timing_test_checked};