use sha2::{Digest, Sha256};
#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub struct RequestFingerprint {
pub static_prefix_sha256: String,
pub full_prefix_sha256: String,
}
#[must_use]
pub fn sha256_hex(bytes: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(bytes);
format!("{:x}", hasher.finalize())
}
#[must_use]
pub fn compute_request_fingerprint(static_prefix: &[u8], full_prefix: &[u8]) -> RequestFingerprint {
RequestFingerprint {
static_prefix_sha256: sha256_hex(static_prefix),
full_prefix_sha256: sha256_hex(full_prefix),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn sha256_hex_is_deterministic() {
assert_eq!(sha256_hex(b"hello"), sha256_hex(b"hello"),);
assert_ne!(sha256_hex(b"hello"), sha256_hex(b"world"));
}
#[test]
fn compute_splits_static_and_full_layers() {
let fp = compute_request_fingerprint(b"static", b"static+messages");
assert_ne!(fp.static_prefix_sha256, fp.full_prefix_sha256);
assert_eq!(
fp.static_prefix_sha256,
compute_request_fingerprint(b"static", b"static").static_prefix_sha256,
);
}
}