use crate::{
ports::crypto::{CryptoError, HashVerifier, SignatureVerifier},
security::allowed_algorithms,
};
use multi_hash::{mh, Multihash};
use multi_key::{Multikey, Views};
use multi_sig::Multisig;
use multi_util::CodecInfo;
pub struct MulticodecHashVerifier;
impl HashVerifier for MulticodecHashVerifier {
fn verify_preimage(&self, hash_bytes: &[u8], preimage: &[u8]) -> Result<(), CryptoError> {
let hash = Multihash::try_from(hash_bytes)
.map_err(|e| CryptoError::Other(format!("Failed to decode multihash: {e}")))?;
let codec = hash.codec().code();
if !self.is_algorithm_allowed(codec) {
return Err(CryptoError::InvalidHashAlgorithm(format!(
"{} (codec: 0x{:x})",
self.algorithm_name(codec),
codec
)));
}
let computed = mh::Builder::new_from_bytes(hash.codec(), preimage)
.map_err(|e| CryptoError::Other(format!("Failed to hash preimage: {e}")))?
.try_build()
.map_err(|e| CryptoError::Other(format!("Failed to build hash: {e}")))?;
if hash == computed {
Ok(())
} else {
Err(CryptoError::HashMismatch)
}
}
fn is_algorithm_allowed(&self, codec: u64) -> bool {
allowed_algorithms::is_hash_allowed(codec)
}
fn algorithm_name(&self, codec: u64) -> &str {
allowed_algorithms::hash_name(codec)
}
}
pub struct MulticodecSignatureVerifier;
impl SignatureVerifier for MulticodecSignatureVerifier {
fn verify_signature(
&self,
public_key_bytes: &[u8],
signature_bytes: &[u8],
message: &[u8],
) -> Result<(), CryptoError> {
let public_key = Multikey::try_from(public_key_bytes).map_err(|e| {
CryptoError::InvalidPublicKey(format!("Failed to decode multikey: {e}"))
})?;
let signature = Multisig::try_from(signature_bytes).map_err(|e| {
CryptoError::InvalidSignature(format!("Failed to decode multisig: {e}"))
})?;
let verify_view = public_key.verify_view().map_err(|e| {
CryptoError::InvalidPublicKey(format!("Failed to get verify view: {e}"))
})?;
verify_view
.verify(&signature, Some(message))
.map_err(|e| CryptoError::SignatureInvalid(e.to_string()))?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hash_verifier_algorithm_validation() {
let verifier = MulticodecHashVerifier;
assert!(verifier.is_algorithm_allowed(0x12)); assert!(verifier.is_algorithm_allowed(0x16));
assert!(!verifier.is_algorithm_allowed(0x11)); assert!(!verifier.is_algorithm_allowed(0xd5)); }
#[test]
fn test_hash_verifier_algorithm_names() {
let verifier = MulticodecHashVerifier;
assert_eq!(verifier.algorithm_name(0x12), "SHA2-256");
assert_eq!(verifier.algorithm_name(0x11), "SHA-1 (deprecated)");
assert_eq!(verifier.algorithm_name(0xd5), "MD5 (broken)");
}
}