use nettle_sys::nettle_hash;
pub trait Hash {
fn digest_size(&self) -> usize;
fn update(&mut self, data: &[u8]);
fn digest(&mut self, digest: &mut [u8]);
fn box_clone(&self) -> Box<dyn Hash>;
}
impl_write_for_hash!(dyn Hash);
pub trait NettleHash: Hash + Default {
#[doc(hidden)]
type Context: Sized;
unsafe fn nettle_hash() -> &'static nettle_hash;
}
impl Hash for Box<dyn Hash> {
fn digest_size(&self) -> usize {
self.as_ref().digest_size()
}
fn update(&mut self, data: &[u8]) {
self.as_mut().update(data)
}
fn digest(&mut self, digest: &mut [u8]) {
self.as_mut().digest(digest)
}
fn box_clone(&self) -> Box<dyn Hash> {
self.as_ref().box_clone()
}
}
impl Clone for Box<dyn Hash> {
fn clone(&self) -> Self {
self.as_ref().box_clone()
}
}
#[cfg(test)]
mod tests {
use crate::hash::{Hash, Sha224, Sha256, Sha3_512};
#[test]
fn polymorphic_one_shot() {
fn hash_with<H: Hash + Default>(data: &[u8]) -> Vec<u8> {
let mut h = H::default();
let mut ret = vec![0u8; h.digest_size()];
h.update(data);
h.digest(&mut ret);
ret
}
let test = &b"test123"[..];
hash_with::<Sha224>(test);
hash_with::<Sha3_512>(test);
}
#[test]
fn polymorphic_multiple() {
fn hash_with<H: Hash>(hash: &mut H, data: &[u8]) {
hash.update(data);
}
let test = &b"test123"[..];
{
let mut h = Sha224::default();
let mut ret = vec![0u8; h.digest_size()];
hash_with(&mut h, test);
h.digest(&mut ret);
}
{
let mut h = Sha3_512::default();
let mut ret = vec![0u8; h.digest_size()];
hash_with(&mut h, test);
h.digest(&mut ret);
}
}
#[test]
fn write_trait() {
use std::io::Write;
let mut h0 = Sha256::default();
let mut d0 = [0u8; 256 / 8];
let mut h1: Box<dyn Hash> = Box::new(Sha256::default());
let mut d1 = [0u8; 256 / 8];
let mut h2 = Sha256::default();
let mut d2 = [0u8; 256 / 8];
fn hash<H: Write + Hash>(hash: &mut H) {
hash.write_all(&b"test123"[..]).unwrap();
}
hash(&mut h0);
hash(&mut h1);
h2.update(&b"test123"[..]);
h0.digest(&mut d0);
h1.digest(&mut d1);
h2.digest(&mut d2);
assert_eq!(d0, d2);
assert_eq!(d1, d2);
}
#[test]
fn clone() {
let mut ctx: Box::<dyn Hash> = Box::new(Sha256::default());
ctx.update(b"\xcf");
let mut ctx2 = ctx.clone();
ctx.update(b"\x00");
ctx2.update(b"\x00");
let mut digest = vec![0u8; ctx.digest_size()];
ctx.digest(&mut digest);
let mut digest2 = vec![0u8; ctx2.digest_size()];
ctx2.digest(&mut digest2);
assert_eq!(digest, digest2);
}
}