use aws_lc_rs::digest::{Context, SHA256};
use crate::hash::{Digest, HashAlgo, IncrementalHashState, Sealed};
pub const SHA256_OUTPUT_LEN: usize = aws_lc_rs::digest::SHA256_OUTPUT_LEN;
pub type Sha256Hash = Digest<SHA256_OUTPUT_LEN, Sha256>;
#[derive(Debug)]
pub struct Sha256;
impl Sealed for Sha256 {}
impl HashAlgo<SHA256_OUTPUT_LEN> for Sha256 {
type Context<D> = Sha256State;
fn incremental() -> Self::Context<Self> {
Sha256State(Context::new(&SHA256))
}
}
pub struct Sha256State(aws_lc_rs::digest::Context);
impl std::fmt::Debug for Sha256State {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("Sha256State").finish()
}
}
impl IncrementalHashState<SHA256_OUTPUT_LEN, Sha256> for Sha256State {
fn update(&mut self, data: &[u8]) {
self.0.update(data);
}
fn finish(self) -> Digest<SHA256_OUTPUT_LEN, Sha256> {
Digest::from_raw(
self.0
.finish()
.as_ref()
.try_into()
.expect("sha256 digest is 32 bytes"),
)
}
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::prelude::*;
#[test]
fn test_fixture() {
let input = b"bananas";
let got = Sha256::hash(&input[..]);
let want = [
228, 186, 92, 189, 37, 28, 152, 230, 205, 28, 35, 241, 38, 163, 184, 29, 141, 131, 40,
171, 201, 83, 135, 34, 152, 80, 149, 43, 62, 249, 249, 4,
];
assert_eq!(want, got.as_bytes());
}
proptest! {
#[test]
fn prop_hash(
input in prop::collection::vec(any::<u8>(), 0..258),
) {
let a = Sha256::hash(&input[..]);
let b = Sha256::hash(&input[..]);
assert_eq!(a, b);
let mut modified = input.clone();
modified.push(42);
let c = Sha256::hash(&modified);
assert_ne!(a, c);
let mut inc = Sha256::incremental();
inc.update(&input);
inc.update(&[42]);
let d = inc.finish();
assert_eq!(c, d); }
}
}