Skip to content

Complete API documentation for the Rust implementation of tacet.

use tacet::{TimingOracle, AttackerModel, Outcome, helpers::InputPair};
// Create inputs using closures
let inputs = InputPair::new(
|| [0u8; 32], // baseline: returns constant value
|| rand::random(), // sample: generates varied values
);
// Run test with attacker model
let outcome = TimingOracle::for_attacker(AttackerModel::AdjacentNetwork)
.test(inputs, |data| my_function(data));
// Simple: Display prints formatted output with colors
println!("{outcome}");
assert!(outcome.passed(), "Timing leak detected");
// Or access detailed fields when needed
if outcome.failed() {
let effect = outcome.effect().unwrap();
eprintln!("Effect: {:.1}ns shift, {:.1}ns tail", effect.shift_ns, effect.tail_ns);
}

use tacet::{TimingOracle, AttackerModel};
// Shared hardware: SGX, cross-VM, containers (~0.6ns / ~2 cycles)
TimingOracle::for_attacker(AttackerModel::SharedHardware)
// Post-quantum sentinel: Catch KyberSlash-class leaks (~3.3ns / ~10 cycles)
TimingOracle::for_attacker(AttackerModel::PostQuantumSentinel)
// Adjacent network: LAN or HTTP/2 endpoints (100ns) - DEFAULT
TimingOracle::for_attacker(AttackerModel::AdjacentNetwork)
// Remote network: Public APIs, general internet (50us)
TimingOracle::for_attacker(AttackerModel::RemoteNetwork)
// Research: Detect any difference (not for CI)
TimingOracle::for_attacker(AttackerModel::Research)
// Custom threshold in nanoseconds
TimingOracle::for_attacker(AttackerModel::Custom { threshold_ns: 500.0 })
PresetThresholdUse case
SharedHardware~0.6 nsSGX, cross-VM, containers
PostQuantumSentinel~3.3 nsPost-quantum crypto
AdjacentNetwork100 nsLAN, HTTP/2
RemoteNetwork50 usPublic APIs
Research0Academic analysis
use tacet::{TimingOracle, AttackerModel, TimerSpec};
use std::time::Duration;
let oracle = TimingOracle::for_attacker(AttackerModel::AdjacentNetwork)
// Decision thresholds
.pass_threshold(0.05) // Below this = Pass (default: 0.05)
.fail_threshold(0.95) // Above this = Fail (default: 0.95)
// Resource limits
.time_budget(Duration::from_secs(30)) // Max time (default: 60s)
.max_samples(100_000) // Hard cap (default: 1M)
// Advanced tuning
.batch_size(1_000) // Samples per batch
.calibration_samples(5_000) // Calibration samples
.prior_no_leak(0.75) // Prior P(no leak)
.warmup(1_000) // Warmup iterations
// Timer configuration
.timer_spec(TimerSpec::Auto) // Auto-detect (default)
.timer_spec(TimerSpec::CyclePrecision) // Require cycle-accurate timer
.standard_timer() // Force standard timer
// Reproducibility
.seed(42); // Deterministic seed

pub enum Outcome {
Pass { leak_probability, effect, samples_used, quality, diagnostics },
Fail { leak_probability, effect, exploitability, samples_used, quality, diagnostics },
Inconclusive { reason, leak_probability, effect, samples_used, quality, diagnostics },
Unmeasurable { operation_ns, threshold_ns, platform, recommendation },
}

Outcome implements Display for formatted terminal output with colors:

println!("{outcome}"); // Prints formatted result
impl Outcome {
/// Check if test passed
fn passed(&self) -> bool;
/// Check if test failed
fn failed(&self) -> bool;
/// Check if result is conclusive (Pass or Fail)
fn is_conclusive(&self) -> bool;
/// Check if operation was measurable
fn is_measurable(&self) -> bool;
/// Check if measurement is reliable
fn is_reliable(&self) -> bool;
/// Get leak probability if available
fn leak_probability(&self) -> Option<f64>;
/// Get effect estimate if available
fn effect(&self) -> Option<&EffectEstimate>;
}

pub struct EffectEstimate {
pub shift_ns: f64, // Uniform shift component
pub tail_ns: f64, // Tail effect component
pub credible_interval_ns: (f64, f64), // 95% CI
pub pattern: EffectPattern, // UniformShift, TailEffect, Mixed, etc.
}
pub enum Exploitability {
SharedHardwareOnly, // < 10 ns
Http2Multiplexing, // 10-100 ns
StandardRemote, // 100 ns - 10 us
ObviousLeak, // > 10 us
}
pub enum MeasurementQuality {
Excellent, // MDE < 5 ns
Good, // MDE 5-20 ns
Poor, // MDE 20-100 ns
TooNoisy, // MDE > 100 ns
}
pub enum InconclusiveReason {
DataTooNoisy,
NotLearning,
WouldTakeTooLong,
TimeBudgetExceeded,
SampleBudgetExceeded,
ConditionsChanged,
}

use tacet::helpers::InputPair;
// Create input pair with closures
let inputs = InputPair::new(
|| [0u8; 32], // baseline generator
|| rand::random(), // sample generator
);
// Or from iterators
let inputs = InputPair::from_iters(
std::iter::repeat([0u8; 32]),
(0..).map(|i| [i as u8; 32]),
);

With the macros feature:

use tacet::{timing_test_checked, TimingOracle, AttackerModel};
let outcome = timing_test_checked! {
oracle: TimingOracle::for_attacker(AttackerModel::AdjacentNetwork)
.time_budget(Duration::from_secs(30)),
baseline: || [0u8; 32],
sample: || rand::random::<[u8; 32]>(),
measure: |input| my_function(&input),
};

ParameterDefaultDescription
pass_threshold0.05P(leak) below this → Pass
fail_threshold0.95P(leak) above this → Fail
time_budget60 sMaximum analysis time
max_samples1,000,000Maximum samples per class
batch_size1,000Samples per adaptive batch
calibration_samples5,000Samples for calibration
prior_no_leak0.75Prior probability of no leak
warmup1,000Warmup iterations
outlier_percentile0.9999Winsorization threshold