#[cfg(feature = "std")]
extern crate std as alloc_std;
extern crate alloc;
use alloc::vec::Vec;
use crate::hash::sha256;
use crate::motif::DetectorProfile;
pub const CASEFILE_V2_HEADER_DOMAIN: &str = "DSFB-GPU-ATLAS:CASEFILE-V2-HEADER:v1\0";
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CaseFileV2Schema {
HeaderOnlyT10,
}
impl CaseFileV2Schema {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::HeaderOnlyT10 => "HeaderOnlyT10",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum CorpusStage {
InternalAuditPreFreeze,
FrozenT10,
}
impl CorpusStage {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::InternalAuditPreFreeze => "InternalAuditPreFreeze",
Self::FrozenT10 => "FrozenT10",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum AtlasAlgebraStatus {
S1_1TypeSurfaceOnly,
}
impl AtlasAlgebraStatus {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::S1_1TypeSurfaceOnly => "S1_1TypeSurfaceOnly",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct CaseFileV2Header {
pub schema: CaseFileV2Schema,
pub corpus_hash_v1: [u8; 32],
pub corpus_stage: CorpusStage,
pub detector_profile: DetectorProfile,
pub detector_registry_hash: [u8; 32],
pub atlas_algebra_status: AtlasAlgebraStatus,
pub semantic_non_bypass: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum CaseFileV2HeaderError {
ZeroCorpusHash,
SemanticNonBypassFalse,
CorpusStagePreFreeze,
}
pub fn verify_casefile_v2_header(header: &CaseFileV2Header) -> Result<(), CaseFileV2HeaderError> {
if header.corpus_hash_v1 == [0u8; 32] {
return Err(CaseFileV2HeaderError::ZeroCorpusHash);
}
if !header.semantic_non_bypass {
return Err(CaseFileV2HeaderError::SemanticNonBypassFalse);
}
if header.corpus_stage == CorpusStage::InternalAuditPreFreeze {
return Err(CaseFileV2HeaderError::CorpusStagePreFreeze);
}
Ok(())
}
fn write_str(out: &mut Vec<u8>, s: &str) {
let bytes = s.as_bytes();
out.extend_from_slice(&(bytes.len() as u32).to_be_bytes());
out.extend_from_slice(bytes);
}
#[must_use]
pub fn casefile_v2_header_hash(header: &CaseFileV2Header) -> [u8; 32] {
let mut buf: Vec<u8> = Vec::with_capacity(256);
buf.extend_from_slice(CASEFILE_V2_HEADER_DOMAIN.as_bytes());
write_str(&mut buf, header.schema.as_str());
buf.extend_from_slice(&header.corpus_hash_v1);
write_str(&mut buf, header.corpus_stage.as_str());
write_str(&mut buf, header.detector_profile.name());
buf.extend_from_slice(&(header.detector_profile.active_detector_count()).to_be_bytes());
buf.extend_from_slice(&header.detector_registry_hash);
write_str(&mut buf, header.atlas_algebra_status.as_str());
buf.push(u8::from(header.semantic_non_bypass));
sha256(&buf)
}