vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! Certificate registry fingerprinting.

use crate::spec::types::OpSpec;

/// Compute a registry fingerprint that binds the certificate to the actual
/// op source, not just the (id, version) pair.
///
/// Hashes, for every spec in the input list:
/// - the op id bytes (typo-squat detection)
/// - the op version (T06 monotonic_weakening detection)
/// - each declared `AlgebraicLaw` name (T03/T04/T05 claim drift detection)
/// - the input `DataType`s and the output `DataType` (T08 signature lying)
/// - the WGSL source bytes returned by `spec.wgsl_fn()` (T43 cert replay)
#[inline]
pub fn compute_registry_hash(specs: &[OpSpec]) -> [u8; 32] {
    let mut hasher = blake3::Hasher::new();
    hasher.update(b"vyre-conform-registry-hash-v1");

    let mut order: Vec<usize> = (0..specs.len()).collect();
    order.sort_by_key(|&idx| specs[idx].id);
    for idx in order {
        let spec = &specs[idx];
        hash_bytes(&mut hasher, spec.id.as_bytes());
        hasher.update(&(u64::from(spec.version)).to_le_bytes());

        let mut law_names: Vec<&str> = spec.laws.iter().map(|law| law.name()).collect();
        law_names.sort_unstable();
        for name in law_names {
            hash_bytes(&mut hasher, name.as_bytes());
        }
        for input in &spec.signature.inputs {
            hash_bytes(&mut hasher, input.to_string().as_bytes());
        }
        hash_bytes(&mut hasher, spec.signature.output.to_string().as_bytes());

        let wgsl_source = (spec.wgsl_fn)();
        hash_bytes(&mut hasher, wgsl_source.as_bytes());
    }
    *hasher.finalize().as_bytes()
}

fn hash_bytes(hasher: &mut blake3::Hasher, bytes: &[u8]) {
    hasher.update(&(bytes.len() as u64).to_le_bytes());
    hasher.update(bytes);
}