use sha2::{Digest, Sha256};
use std::env;
use std::fs;
use std::io::{self, Read};
use std::path::{Path, PathBuf};
const MODULE_FILES: &[&str] = &[
"src/lib.rs",
"src/primitives/mod.rs",
"src/primitives/aead.rs",
"src/primitives/stream.rs",
"src/fips/mod.rs",
"src/fips/selftests.rs",
"src/pqc/mod.rs",
"src/pqc/mlkem.rs",
"src/pqc/mldsa.rs",
"src/protocol.rs",
"src/format.rs",
"src/keys.rs",
];
fn hash_file(path: &Path) -> io::Result<Vec<u8>> {
let mut file = fs::File::open(path)?;
let mut hasher = Sha256::new();
let mut buffer = [0u8; 8192];
loop {
let n = file.read(&mut buffer)?;
if n == 0 {
break;
}
hasher.update(&buffer[..n]);
}
Ok(hasher.finalize().to_vec())
}
fn compute_module_hash() -> io::Result<String> {
let manifest_dir = env::var("CARGO_MANIFEST_DIR")
.unwrap_or_else(|_| ".".to_string());
let base_path = PathBuf::from(manifest_dir);
let mut combined_hasher = Sha256::new();
for file_path in MODULE_FILES {
let full_path = base_path.join(file_path);
if !full_path.exists() {
eprintln!("Warning: Module file not found: {}", full_path.display());
continue;
}
let file_hash = hash_file(&full_path)?;
combined_hasher.update(file_path.as_bytes());
combined_hasher.update(&file_hash);
println!("cargo:rerun-if-changed={}", full_path.display());
}
let final_hash = combined_hasher.finalize();
Ok(hex::encode(final_hash))
}
fn main() {
match compute_module_hash() {
Ok(hash) => {
println!("cargo:rustc-env=FIPS_MODULE_HASH={}", hash);
println!("Module integrity hash: {}", hash);
}
Err(e) => {
eprintln!("Warning: Failed to compute module hash: {}", e);
println!("cargo:rustc-env=FIPS_MODULE_HASH=UNKNOWN");
}
}
let timestamp = chrono::Utc::now().to_rfc3339();
println!("cargo:rustc-env=FIPS_BUILD_TIMESTAMP={}", timestamp);
}