use blake3::{Hash, Hasher}; use crate::errors::ApiError; pub trait CustomHash { fn updater(&self, hasher: &mut Hasher); fn hash(&self) -> Hash { let mut hasher = Hasher::new(); Self::updater(&self, &mut hasher); hasher.finalize() } } pub struct IntegrityVerifier { mac: Hasher, } impl IntegrityVerifier { pub fn new() -> Result { Ok(Self { mac: Hasher::new_derive_key(include_str!("./verification_secret")), }) } pub fn sign(&self, data: &T) -> Result where T: CustomHash, { let mut mac = self.mac.clone(); mac.update(data.hash().as_bytes()); let signature = mac.finalize(); mac.reset(); Ok(signature) } pub fn verify(&self, data: &T, signature: Hash) -> Result<(), ApiError> where T: CustomHash, { let mut mac = self.mac.clone(); mac.update(data.hash().as_bytes()); let verify = mac.finalize(); mac.reset(); match verify == signature { true => Ok(()), false => Err(ApiError::AccessDenied), } } } #[cfg(test)] mod test { use blake3::Hasher; use crate::api::backend::integrity_verification::{CustomHash, IntegrityVerifier}; #[test] fn integrity_verification() { struct TestData { one: u32, two: String, } impl CustomHash for TestData { fn updater(&self, hasher: &mut Hasher) { hasher.update(&self.one.to_be_bytes()); hasher.update(&self.two.as_bytes()); } } let verifier = IntegrityVerifier::new().unwrap(); let mut item = TestData { one: 24, two: "MyTesting".to_string(), }; let signature = verifier.sign(&item).unwrap(); assert!(verifier.verify(&item, signature).is_ok()); item.two = "Wrong".to_string(); assert!(verifier.verify(&item, signature).is_err()); } }