use sha2::{Digest, Sha256}; /// Compute SHA-256 hash as: SHA256(timestamp_bytes + content_bytes). /// The timestamp is serialized as its string representation's bytes, /// matching the spec: `SHA256([timestamp_bytes] + [raw_file_content_bytes])`. pub fn compute_hash(timestamp_ms: i64, content: &[u8]) -> String { let mut hasher = Sha256::new(); hasher.update(timestamp_ms.to_be_bytes()); hasher.update(content); hex::encode(hasher.finalize()) } #[cfg(test)] mod tests { use super::*; #[test] fn test_deterministic_hash() { let ts = 1773014400123i64; let content = b"hello world"; let h1 = compute_hash(ts, content); let h2 = compute_hash(ts, content); assert_eq!(h1, h2); assert_eq!(h1.len(), 64); // SHA-256 hex = 64 chars } #[test] fn test_different_timestamp_different_hash() { let content = b"same content"; let h1 = compute_hash(1000, content); let h2 = compute_hash(2000, content); assert_ne!(h1, h2); } #[test] fn test_different_content_different_hash() { let ts = 1234567890i64; let h1 = compute_hash(ts, b"content A"); let h2 = compute_hash(ts, b"content B"); assert_ne!(h1, h2); } #[test] fn test_empty_content() { let h = compute_hash(0, b""); assert_eq!(h.len(), 64); } }