use alloc::vec::Vec;
use super::{
Sha224,
kernels::{ALL, Sha224KernelId, compress_blocks_fn, required_caps},
};
use crate::{hashes::crypto::dispatch_util::SizeClassDispatch, traits::Digest as _};
#[derive(Clone, Debug)]
pub struct KernelResult {
pub name: &'static str,
pub digest: [u8; 28],
}
fn hasher_for_kernel(id: Sha224KernelId) -> Sha224 {
let compress = compress_blocks_fn(id);
Sha224 {
compress_blocks: compress,
dispatch: Some(SizeClassDispatch {
boundaries: [usize::MAX; 3],
xs: compress,
s: compress,
m: compress,
l: compress,
}),
..Default::default()
}
}
fn digest_with_kernel(id: Sha224KernelId, data: &[u8]) -> [u8; 28] {
let mut h = hasher_for_kernel(id);
h.update(data);
h.finalize()
}
#[must_use]
pub fn run_all_sha224_kernels(data: &[u8]) -> Vec<KernelResult> {
let caps = crate::platform::caps();
let mut out = Vec::with_capacity(ALL.len());
for &id in ALL {
if caps.has(required_caps(id)) {
out.push(KernelResult {
name: id.as_str(),
digest: digest_with_kernel(id, data),
});
}
}
out
}
pub fn verify_sha224_kernels(data: &[u8]) -> Result<(), &'static str> {
let results = run_all_sha224_kernels(data);
let Some(first) = results.first() else {
return Ok(());
};
for r in &results[1..] {
if r.digest != first.digest {
return Err("sha224 kernel mismatch");
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
fn pattern(len: usize) -> Vec<u8> {
(0..len)
.map(|i| (i as u8).wrapping_mul(17).wrapping_add((i >> 8) as u8))
.collect()
}
#[test]
fn all_kernels_match_sha2_oracle_and_streaming_splits() {
let caps = crate::platform::caps();
#[cfg(not(miri))]
let lens = [
0usize, 1, 2, 3, 55, 56, 57, 63, 64, 65, 119, 120, 121, 127, 128, 129, 1000,
];
#[cfg(miri)]
let lens = [0usize, 1, 55, 56, 57, 63, 64, 65, 127, 128, 129];
#[cfg(not(miri))]
let chunks = [1usize, 7, 31, 32, 63, 64, 65, 128, 1024];
#[cfg(miri)]
let chunks = [1usize, 31, 32, 63, 64, 65, 128];
for &id in ALL {
if !caps.has(required_caps(id)) {
continue;
}
for &len in &lens {
let msg = pattern(len);
let ours = digest_with_kernel(id, &msg);
use sha2::Digest as _;
let expected = sha2::Sha224::digest(&msg);
let mut exp = [0u8; 28];
exp.copy_from_slice(&expected);
assert_eq!(ours, exp, "sha224 oracle mismatch for kernel={}", id.as_str());
for &chunk in &chunks {
let mut h = hasher_for_kernel(id);
for part in msg.chunks(chunk) {
h.update(part);
}
assert_eq!(
h.finalize(),
ours,
"sha224 chunk mismatch kernel={} len={}",
id.as_str(),
len
);
}
}
}
}
}