use std::time::Duration;
use tacet::helpers::{byte_arrays_32, byte_vecs, InputPair};
use tacet::{AttackerModel, Outcome, TimingOracle};
#[test]
fn test_input_pair_basic() {
let inputs = InputPair::new(|| 42u64, rand::random::<u64>);
for _ in 0..100 {
assert_eq!(inputs.baseline(), 42);
let _ = inputs.generate_sample(); }
}
#[test]
fn test_input_pair_generator_called() {
let counter = std::cell::Cell::new(0u32);
let inputs = InputPair::new(
|| 0u32,
|| {
let val = counter.get();
counter.set(val + 1);
val
},
);
assert_eq!(inputs.baseline(), 0);
assert_eq!(inputs.baseline(), 0);
assert_eq!(inputs.generate_sample(), 0);
assert_eq!(inputs.generate_sample(), 1);
assert_eq!(inputs.generate_sample(), 2);
}
#[test]
fn test_byte_arrays_helper() {
let inputs = byte_arrays_32();
assert_eq!(inputs.baseline(), [0u8; 32]);
let r1 = inputs.generate_sample();
let r2 = inputs.generate_sample();
assert_ne!(r1, r2); }
#[test]
fn test_byte_vecs_helper() {
let inputs = byte_vecs(128);
assert_eq!(inputs.baseline(), vec![0u8; 128]);
let r = inputs.generate_sample();
assert_eq!(r.len(), 128);
}
#[test]
fn test_no_false_positive_with_helpers() {
let inputs = byte_arrays_32();
let outcome = TimingOracle::for_attacker(AttackerModel::AdjacentNetwork)
.time_budget(Duration::from_secs(10))
.test(inputs, |data| {
let mut result = [0u8; 32];
result.copy_from_slice(data);
std::hint::black_box(result);
});
match outcome {
Outcome::Pass {
leak_probability, ..
} => {
assert!(leak_probability < 0.5);
}
Outcome::Fail {
leak_probability, ..
} => {
panic!(
"Unexpected failure for constant-time XOR: P={:.1}%",
leak_probability * 100.0
);
}
Outcome::Inconclusive {
leak_probability, ..
} => {
assert!(
leak_probability < 0.5,
"Should not detect leak with helpers"
);
}
Outcome::Unmeasurable { .. } => {
}
Outcome::Research(_) => {}
}
}
#[test]
fn test_anomaly_detection_constant_value() {
let constant_value = 42u64;
let inputs = InputPair::new(|| 0u64, || constant_value);
for _ in 0..200 {
let val = inputs.generate_sample();
inputs.track_value(&val);
}
let anomaly = inputs.check_anomaly();
assert!(anomaly.is_some(), "Should detect constant value anomaly");
assert!(anomaly.unwrap().contains("ANOMALY"));
}
#[test]
fn test_anomaly_detection_good_entropy() {
let inputs = InputPair::new(|| 0u64, rand::random::<u64>);
for _ in 0..200 {
let val = inputs.generate_sample();
inputs.track_value(&val);
}
assert!(
inputs.check_anomaly().is_none(),
"Should not warn for good entropy"
);
}
#[test]
fn test_anomaly_detection_low_entropy() {
let counter = std::cell::Cell::new(0u64);
let inputs = InputPair::new(
|| 0u64,
|| {
let val = counter.get() % 10; counter.set(counter.get() + 1);
val
},
);
for _ in 0..200 {
let val = inputs.generate_sample();
inputs.track_value(&val);
}
let anomaly = inputs.check_anomaly();
assert!(anomaly.is_some(), "Should detect low entropy");
assert!(anomaly.unwrap().contains("WARNING"));
}
#[allow(dead_code)]
fn xor_bytes(a: &[u8; 32], b: &[u8; 32]) -> [u8; 32] {
let mut result = [0u8; 32];
for i in 0..32 {
result[i] = a[i] ^ b[i];
}
result
}