#![cfg(test)]
use std::collections::{HashMap, HashSet};
use std::str::FromStr;
use std::sync::atomic::{AtomicU64, Ordering};
use super::w3c_trace_context::TraceId;
static TEST_SPAN_SEED: AtomicU64 = AtomicU64::new(1);
fn problematic_splitmix64(mut state: u64) -> u64 {
state = state.wrapping_add(0x9e37_79b9_7f4a_7c15);
let mut z = state;
z = (z ^ (z >> 30)).wrapping_mul(0xbf58_476d_1ce4_e5b9);
z = (z ^ (z >> 27)).wrapping_mul(0x94d0_49bb_1331_11eb);
z ^ (z >> 31)
}
fn trace_id_from_bytes(mut bytes: [u8; 16]) -> TraceId {
if bytes == [0; 16] {
bytes[15] = 1;
}
TraceId::from_str(&hex::encode(bytes)).expect("trace-id bytes must be parseable")
}
fn trace_id_to_bytes(trace_id: TraceId) -> [u8; 16] {
let bytes = hex::decode(trace_id.to_hex()).expect("trace-id hex must decode");
let mut array = [0u8; 16];
array.copy_from_slice(&bytes);
array
}
fn problematic_trace_id_generation() -> TraceId {
let seed = TEST_SPAN_SEED.fetch_add(1, Ordering::Relaxed);
problematic_trace_id_generation_from_seed(seed)
}
fn problematic_trace_id_generation_from_seed(seed: u64) -> TraceId {
let hi = problematic_splitmix64(seed);
let lo = problematic_splitmix64(seed ^ 0x9e37_79b9_7f4a_7c15);
trace_id_from_bytes([
(hi >> 56) as u8,
(hi >> 48) as u8,
(hi >> 40) as u8,
(hi >> 32) as u8,
(hi >> 24) as u8,
(hi >> 16) as u8,
(hi >> 8) as u8,
hi as u8,
(lo >> 56) as u8,
(lo >> 48) as u8,
(lo >> 40) as u8,
(lo >> 32) as u8,
(lo >> 24) as u8,
(lo >> 16) as u8,
(lo >> 8) as u8,
lo as u8,
])
}
fn w3c_compliant_trace_id_generation() -> TraceId {
let mut bytes = [0u8; 16];
getrandom::fill(&mut bytes).expect("failed to generate random trace-id bytes");
trace_id_from_bytes(bytes)
}
#[test]
fn audit_trace_id_w3c_randomness_compliance() {
println!("🔍 AUDIT: W3C Trace Context trace_id 128-bit randomness compliance");
println!("📋 W3C Trace Context specification requirements:");
println!(" • trace_id MUST be 16 random bytes (128 bits)");
println!(" • MUST be globally unique and unpredictable");
println!(" • NOT: deterministic PRNG with predictable sequence");
println!(" • NOT: related 64-bit halves (entropy reduction)");
const SAMPLE_SIZE: usize = 1000;
println!("📊 Testing current implementation (problematic):");
let mut problematic_ids = Vec::with_capacity(SAMPLE_SIZE);
let mut problematic_bytes_freq: HashMap<usize, HashMap<u8, u32>> = HashMap::new();
for _ in 0..SAMPLE_SIZE {
let trace_id = problematic_trace_id_generation();
let bytes = trace_id_to_bytes(trace_id);
problematic_ids.push(bytes);
for (pos, &byte) in bytes.iter().enumerate() {
*problematic_bytes_freq
.entry(pos)
.or_default()
.entry(byte)
.or_insert(0) += 1;
}
}
println!("📊 Testing W3C compliant implementation (correct):");
let mut compliant_ids = Vec::with_capacity(SAMPLE_SIZE);
let mut compliant_bytes_freq: HashMap<usize, HashMap<u8, u32>> = HashMap::new();
for _ in 0..SAMPLE_SIZE {
let trace_id = w3c_compliant_trace_id_generation();
let bytes = trace_id_to_bytes(trace_id);
compliant_ids.push(bytes);
for (pos, &byte) in bytes.iter().enumerate() {
*compliant_bytes_freq
.entry(pos)
.or_default()
.entry(byte)
.or_insert(0) += 1;
}
}
println!("📊 Statistical randomness analysis:");
let problematic_chi_square = calculate_chi_square(&problematic_bytes_freq, SAMPLE_SIZE);
let compliant_chi_square = calculate_chi_square(&compliant_bytes_freq, SAMPLE_SIZE);
println!(
" Problematic implementation chi-square: {:.2}",
problematic_chi_square
);
println!(" W3C compliant chi-square: {:.2}", compliant_chi_square);
const CHI_SQUARE_CRITICAL: f64 = 293.25;
if problematic_chi_square > CHI_SQUARE_CRITICAL {
println!("❌ NON-RANDOM PATTERN DETECTED in current implementation");
println!(
"💡 EVIDENCE: Chi-square {} > critical value {}",
problematic_chi_square, CHI_SQUARE_CRITICAL
);
} else {
println!("✅ Current implementation passes chi-square test");
}
if compliant_chi_square > CHI_SQUARE_CRITICAL {
println!("⚠️ W3C compliant implementation unexpectedly non-random");
} else {
println!("✅ W3C compliant implementation passes chi-square test");
}
println!("📊 Uniqueness analysis:");
let problematic_unique: HashSet<_> = problematic_ids.iter().collect();
let compliant_unique: HashSet<_> = compliant_ids.iter().collect();
println!(
" Problematic unique IDs: {}/{} ({:.1}%)",
problematic_unique.len(),
SAMPLE_SIZE,
(problematic_unique.len() as f64 / SAMPLE_SIZE as f64) * 100.0
);
println!(
" W3C compliant unique IDs: {}/{} ({:.1}%)",
compliant_unique.len(),
SAMPLE_SIZE,
(compliant_unique.len() as f64 / SAMPLE_SIZE as f64) * 100.0
);
println!("📊 Predictability analysis:");
let problematic_sequential_bias = analyze_sequential_bias(&problematic_ids);
let compliant_sequential_bias = analyze_sequential_bias(&compliant_ids);
println!(
" Problematic sequential bias: {:.4}",
problematic_sequential_bias
);
println!(
" W3C compliant sequential bias: {:.4}",
compliant_sequential_bias
);
println!("📊 W3C Trace Context compliance assessment:");
let mut compliance_score = 0.0;
let mut total_checks = 0.0;
total_checks += 1.0;
if problematic_unique.len() == SAMPLE_SIZE {
println!(" ✅ Uniqueness: All {} trace_ids are unique", SAMPLE_SIZE);
compliance_score += 1.0;
} else {
println!(
" ❌ Uniqueness: {} duplicate trace_ids detected",
SAMPLE_SIZE - problematic_unique.len()
);
}
total_checks += 1.0;
if problematic_chi_square <= CHI_SQUARE_CRITICAL {
println!(" ✅ Randomness: Passes chi-square test");
compliance_score += 1.0;
} else {
println!(" ❌ Randomness: Fails chi-square test (non-random pattern)");
}
total_checks += 1.0;
if problematic_sequential_bias < 0.1 {
println!(" ✅ Unpredictability: Low sequential bias");
compliance_score += 1.0;
} else {
println!(" ❌ Unpredictability: High sequential bias (predictable pattern)");
}
let compliance_percentage = (compliance_score / total_checks) * 100.0;
println!("📊 Overall W3C compliance: {:.1}%", compliance_percentage);
if compliance_percentage < 100.0 {
println!("🚨 W3C TRACE CONTEXT VIOLATION DETECTED");
println!("💡 ROOT CAUSE: splitmix64 PRNG with sequential seed");
println!("🔧 REQUIRED FIX: Use cryptographically secure random bytes");
println!("📋 IMPLEMENTATION:");
println!(" - Replace splitmix64 with rand::thread_rng().fill_bytes()");
println!(" - Generate 16 independent random bytes");
println!(" - Ensure each trace_id has full 128-bit entropy");
assert!(
compliance_percentage < 100.0,
"Audit confirms W3C Trace Context violation exists"
);
} else {
println!("✅ W3C TRACE CONTEXT COMPLIANCE: Full specification adherence");
}
}
fn calculate_chi_square(byte_freq: &HashMap<usize, HashMap<u8, u32>>, sample_size: usize) -> f64 {
let expected_freq = sample_size as f64 / 256.0; let mut chi_square = 0.0;
for position in 0..16 {
if let Some(freq_map) = byte_freq.get(&position) {
for byte_value in 0..=255u8 {
let observed = *freq_map.get(&byte_value).unwrap_or(&0) as f64;
let diff = observed - expected_freq;
chi_square += (diff * diff) / expected_freq;
}
}
}
chi_square
}
fn analyze_sequential_bias(trace_ids: &[[u8; 16]]) -> f64 {
if trace_ids.len() < 2 {
return 0.0;
}
let mut total_hamming_distance = 0;
for i in 1..trace_ids.len() {
let hamming = hamming_distance(&trace_ids[i - 1], &trace_ids[i]);
total_hamming_distance += hamming;
}
let avg_hamming = total_hamming_distance as f64 / (trace_ids.len() - 1) as f64;
let expected_hamming = 64.0;
(expected_hamming - avg_hamming).abs() / expected_hamming
}
fn hamming_distance(a: &[u8; 16], b: &[u8; 16]) -> u32 {
a.iter()
.zip(b.iter())
.map(|(x, y)| (x ^ y).count_ones())
.sum()
}
#[test]
fn audit_prng_state_leakage_vulnerability() {
println!("🔍 AUDIT: PRNG state leakage vulnerability in trace_id generation");
println!("📋 Cryptographic security requirements:");
println!(" • Past outputs MUST NOT predict future outputs");
println!(" • Generator state MUST be computationally infeasible to recover");
println!(" • NOT: sequential PRNG with observable patterns");
let observed_ids: Vec<_> = (1000..1010)
.map(problematic_trace_id_generation_from_seed)
.collect();
println!("📊 Observed trace_id sequence (first 3):");
for (i, trace_id) in observed_ids.iter().take(3).enumerate() {
println!(" {}: {}", i + 1, trace_id.to_hex());
}
println!("📊 Predictability test:");
let predicted_ids: Vec<_> = (1000..1010)
.map(problematic_trace_id_generation_from_seed)
.collect();
let matches = observed_ids
.iter()
.zip(predicted_ids.iter())
.filter(|(a, b)| a == b)
.count();
println!(
" Prediction accuracy: {}/10 ({:.1}%)",
matches,
(matches as f64 / 10.0) * 100.0
);
if matches == 10 {
println!("🚨 CRITICAL VULNERABILITY: trace_id sequence is fully predictable");
println!("💡 ATTACK VECTOR: Attacker can predict future trace_ids");
println!("🔧 SECURITY IMPACT: Trace correlation attacks, privacy violation");
} else if matches > 5 {
println!("⚠️ PARTIAL PREDICTABILITY: Some trace_ids are predictable");
} else {
println!("✅ UNPREDICTABLE: trace_id sequence appears random");
}
println!("📊 Root cause analysis:");
println!(" • splitmix64 is deterministic PRNG");
println!(" • Sequential seed progression: seed, seed+1, seed+2, ...");
println!(" • Two related outputs: splitmix64(seed) | splitmix64(seed^const)");
println!(" • No cryptographic security properties");
assert_eq!(
matches, 10,
"AUDIT CONFIRMS: trace_id generation is deterministic"
);
println!("✅ PRNG STATE LEAKAGE VULNERABILITY CONFIRMED");
}