use crate::error::{Result, TensogramError};
use crate::types::HashDescriptor;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HashAlgorithm {
Xxh3,
}
impl HashAlgorithm {
pub fn as_str(&self) -> &'static str {
match self {
HashAlgorithm::Xxh3 => "xxh3",
}
}
pub fn parse(s: &str) -> Result<Self> {
match s {
"xxh3" => Ok(HashAlgorithm::Xxh3),
_ => Err(TensogramError::Metadata(format!("unknown hash type: {s}"))),
}
}
pub fn hex_digest_len(&self) -> usize {
match self {
HashAlgorithm::Xxh3 => 16, }
}
}
pub fn compute_hash(data: &[u8], algorithm: HashAlgorithm) -> String {
match algorithm {
HashAlgorithm::Xxh3 => format_xxh3_digest(xxhash_rust::xxh3::xxh3_64(data)),
}
}
#[inline]
pub(crate) fn format_xxh3_digest(digest: u64) -> String {
format!("{digest:016x}")
}
pub fn verify_hash(data: &[u8], descriptor: &HashDescriptor) -> Result<()> {
let algorithm = match HashAlgorithm::parse(&descriptor.hash_type) {
Ok(algo) => algo,
Err(_) => {
tracing::warn!(
hash_type = %descriptor.hash_type,
"unknown hash algorithm, skipping verification"
);
return Ok(());
}
};
let actual = compute_hash(data, algorithm);
if actual != descriptor.value {
return Err(TensogramError::HashMismatch {
expected: descriptor.value.clone(),
actual,
});
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_xxh3() {
let data = b"hello world";
let hash = compute_hash(data, HashAlgorithm::Xxh3);
assert_eq!(hash.len(), 16); assert_eq!(hash, compute_hash(data, HashAlgorithm::Xxh3));
}
#[test]
fn test_verify_hash() {
let data = b"test data";
let hash = compute_hash(data, HashAlgorithm::Xxh3);
let descriptor = HashDescriptor {
hash_type: "xxh3".to_string(),
value: hash,
};
assert!(verify_hash(data, &descriptor).is_ok());
}
#[test]
fn test_verify_hash_mismatch() {
let data = b"test data";
let descriptor = HashDescriptor {
hash_type: "xxh3".to_string(),
value: "0000000000000000".to_string(),
};
assert!(verify_hash(data, &descriptor).is_err());
}
#[test]
fn test_unknown_hash_type_skips_verification() {
let data = b"test data";
let descriptor = HashDescriptor {
hash_type: "sha256".to_string(),
value: "abc123".to_string(),
};
assert!(verify_hash(data, &descriptor).is_ok());
}
}