use sha2::{Digest, Sha256};
use crate::{
artifact_tree_payload, canonicalize_json_bytes, framed_preimage, framed_tuple_payload,
identity_metadata, AnyHashId, ArtifactEntryKind, ArtifactTreeEntry, CanonicalizationProfile,
HashError, HashKindName, TupleField,
};
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum VectorInput {
RawBytes(Vec<u8>),
TupleFields(Vec<(String, Vec<u8>)>),
TreeEntries(Vec<VectorTreeEntry>),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VectorTreeEntry {
pub path: String,
pub bytes: Vec<u8>,
pub symlink: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct VectorOutcome {
pub canonical_payload: Vec<u8>,
pub preimage: Vec<u8>,
pub digest: [u8; 32],
pub hash_id: AnyHashId,
}
pub fn execute_vector(
kind: HashKindName,
profile: CanonicalizationProfile,
input: &VectorInput,
) -> Result<VectorOutcome, HashError> {
let metadata = identity_metadata(kind);
if metadata.profile != profile {
return Err(HashError::ProfileMismatch {
kind: kind.to_string(),
expected: metadata.profile.to_string(),
actual: profile.to_string(),
});
}
let canonical_payload = match (profile, input) {
(CanonicalizationProfile::RawBytesV1, VectorInput::RawBytes(bytes)) => bytes.clone(),
(CanonicalizationProfile::AreteJcsV1, VectorInput::RawBytes(bytes)) => {
canonicalize_json_bytes(bytes)?
}
(CanonicalizationProfile::FramedTupleV1, VectorInput::TupleFields(fields)) => {
let fields: Vec<TupleField<'_>> = fields
.iter()
.map(|(label, value)| TupleField::new(label, value))
.collect();
framed_tuple_payload(&fields)?
}
(CanonicalizationProfile::ArtifactTreeV1, VectorInput::TreeEntries(entries)) => {
let entries: Vec<ArtifactTreeEntry<'_>> = entries
.iter()
.map(|entry| ArtifactTreeEntry {
path: &entry.path,
bytes: &entry.bytes,
kind: if entry.symlink {
ArtifactEntryKind::Symlink
} else {
ArtifactEntryKind::File
},
})
.collect();
artifact_tree_payload(&entries)?
}
_ => {
return Err(HashError::InvalidHashId(
"vector input encoding does not match the canonicalization profile",
))
}
};
let preimage = framed_preimage(kind, profile, &canonical_payload);
let digest: [u8; 32] = Sha256::digest(&preimage).into();
Ok(VectorOutcome {
canonical_payload,
preimage,
digest,
hash_id: AnyHashId::from_parts(kind, digest),
})
}