Hash Chain Audit
Tamper-evident audit trail for inference using entrenar's HashChainCollector.
Example
cargo run --example hash_chain_audit
Code
use apr_cookbook::explainable::IntoExplainable;
use apr_cookbook::prelude::*;
use aprender::linear_model::LinearRegression;
use entrenar::monitor::inference::{
path::LinearPath, HashChainCollector, InferenceMonitor, TraceCollector,
};
fn main() -> Result<()> {
// Train model and wrap with explainability
let model = train_model()?;
let explainable = model.into_explainable();
// Create hash chain collector for tamper-evident audit
let collector: HashChainCollector<LinearPath> = HashChainCollector::new();
let mut monitor = InferenceMonitor::new(explainable, collector);
// Run inferences - each one is cryptographically chained
let _ = monitor.predict(&[25.0, 1000.0, 1.0], 1);
let _ = monitor.predict(&[35.0, 5000.0, 2.0], 1);
// Verify chain integrity
let verification = monitor.collector().verify_chain();
println!("Chain valid: {}", verification.valid);
println!("Entries verified: {}", verification.entries_verified);
Ok(())
}
Key Concepts
Hash Chain Structure
Each entry contains a BLAKE3 hash linking it to the previous entry:
Entry[0] --hash--> Entry[1] --hash--> Entry[2] --hash--> ...
Tamper Detection
Any modification to a historical entry breaks the chain. Verification traverses the chain and recomputes hashes to detect breaks.
Export for Compliance
// Export audit log for regulatory review
let json = serde_json::to_string_pretty(&collector.entries())?;
std::fs::write("audit_log.json", json)?;
Tests
The example includes property-based tests verifying:
- Chain is always valid after sequential appends
- Hash determinism for identical inputs
- Sequence numbers are monotonically increasing
prev_hashcorrectly links to previous entry's hash