Files
wifi-densepose/crates/ruvector-wasm/src/kernel/hash.rs
ruv d803bfe2b1 Squashed 'vendor/ruvector/' content from commit b64c2172
git-subtree-dir: vendor/ruvector
git-subtree-split: b64c21726f2bb37286d9ee36a7869fef60cc6900
2026-02-28 14:39:40 -05:00

177 lines
5.0 KiB
Rust

//! SHA256 Hash Verification
//!
//! Provides hash verification for WASM kernel files to ensure integrity.
use crate::kernel::error::VerifyError;
use sha2::{Digest, Sha256};
/// Hash verifier for kernel files
#[derive(Debug, Clone)]
pub struct HashVerifier {
/// Expected hash format prefix (e.g., "sha256:")
prefix: String,
}
impl HashVerifier {
/// Create a new SHA256 hash verifier
pub fn sha256() -> Self {
HashVerifier {
prefix: "sha256:".to_string(),
}
}
/// Compute SHA256 hash of data
pub fn compute_hash(data: &[u8]) -> String {
let mut hasher = Sha256::new();
hasher.update(data);
let result = hasher.finalize();
format!("sha256:{:x}", result)
}
/// Verify kernel data against expected hash
///
/// # Arguments
/// * `kernel_bytes` - The raw WASM kernel bytes
/// * `expected_hash` - Expected hash string (format: "sha256:...")
///
/// # Returns
/// * `Ok(())` if hash matches
/// * `Err(VerifyError::HashMismatch)` if hash doesn't match
pub fn verify(&self, kernel_bytes: &[u8], expected_hash: &str) -> Result<(), VerifyError> {
// Validate expected hash format
if !expected_hash.starts_with(&self.prefix) {
return Err(VerifyError::InvalidManifest {
message: format!(
"Invalid hash format: expected '{}' prefix, got '{}'",
self.prefix,
expected_hash.get(..10).unwrap_or(expected_hash)
),
});
}
let actual_hash = Self::compute_hash(kernel_bytes);
if actual_hash.eq_ignore_ascii_case(expected_hash) {
Ok(())
} else {
Err(VerifyError::HashMismatch {
expected: expected_hash.to_string(),
actual: actual_hash,
})
}
}
/// Verify multiple kernels in batch
///
/// # Arguments
/// * `kernels` - Iterator of (kernel_bytes, expected_hash) pairs
///
/// # Returns
/// * `Ok(())` if all hashes match
/// * `Err` with first mismatch
pub fn verify_batch<'a>(
&self,
kernels: impl Iterator<Item = (&'a [u8], &'a str)>,
) -> Result<(), VerifyError> {
for (bytes, expected) in kernels {
self.verify(bytes, expected)?;
}
Ok(())
}
}
impl Default for HashVerifier {
fn default() -> Self {
Self::sha256()
}
}
/// Compute hash for a kernel file and return formatted string
pub fn hash_kernel(kernel_bytes: &[u8]) -> String {
HashVerifier::compute_hash(kernel_bytes)
}
/// Verify a kernel file against expected hash (convenience function)
pub fn verify_kernel_hash(kernel_bytes: &[u8], expected_hash: &str) -> Result<(), VerifyError> {
HashVerifier::sha256().verify(kernel_bytes, expected_hash)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_compute_hash() {
let data = b"hello world";
let hash = HashVerifier::compute_hash(data);
assert!(hash.starts_with("sha256:"));
// Known SHA256 of "hello world"
assert!(hash.contains("b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"));
}
#[test]
fn test_verify_success() {
let data = b"test kernel data";
let hash = HashVerifier::compute_hash(data);
let verifier = HashVerifier::sha256();
assert!(verifier.verify(data, &hash).is_ok());
}
#[test]
fn test_verify_case_insensitive() {
let data = b"test kernel data";
let hash = HashVerifier::compute_hash(data);
let upper_hash = hash.to_uppercase();
let verifier = HashVerifier::sha256();
assert!(verifier.verify(data, &upper_hash).is_ok());
}
#[test]
fn test_verify_mismatch() {
let data = b"actual data";
let wrong_hash = "sha256:0000000000000000000000000000000000000000000000000000000000000000";
let verifier = HashVerifier::sha256();
let result = verifier.verify(data, wrong_hash);
assert!(matches!(result, Err(VerifyError::HashMismatch { .. })));
}
#[test]
fn test_verify_invalid_format() {
let data = b"test data";
let invalid_hash = "md5:abc123";
let verifier = HashVerifier::sha256();
let result = verifier.verify(data, invalid_hash);
assert!(matches!(result, Err(VerifyError::InvalidManifest { .. })));
}
#[test]
fn test_verify_batch() {
let data1 = b"kernel1";
let data2 = b"kernel2";
let hash1 = HashVerifier::compute_hash(data1);
let hash2 = HashVerifier::compute_hash(data2);
let verifier = HashVerifier::sha256();
let kernels = vec![
(data1.as_slice(), hash1.as_str()),
(data2.as_slice(), hash2.as_str()),
];
assert!(verifier.verify_batch(kernels.into_iter()).is_ok());
}
#[test]
fn test_convenience_function() {
let data = b"convenience test";
let hash = hash_kernel(data);
assert!(verify_kernel_hash(data, &hash).is_ok());
}
}