vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! CRC32C (Castagnoli) hash specification.
//!
//! Polynomial: 0x1EDC6F41 (reflected: 0x82F63B78)
//! Used in: iSCSI, SCTP, ext4, Btrfs, network protocols

use crate::OpSpec;
use vyre_spec::GoldenSample;

/// Location-agnostic operation metadata.
pub const VYRE_OP_METADATA: vyre_spec::OpMetadata = vyre_spec::OpMetadata {
    id: "primitive.hash.crc32c",
    layer: vyre_spec::Layer::L2,
    category: vyre_spec::MetadataCategory::A,
    version: 1,
    description: "hash crc32c",
    signature: "(Bytes) -> U32",
    strictness: "strict",
    archetype_signature: "(Bytes) -> U32",
};

/// Golden samples for this op.
pub const GOLDEN: &[vyre_spec::GoldenSample] = &[
    GoldenSample {
        op_id: "primitive.hash.crc32c",
        input: &[0x00; 32],
        expected: &[0xAA, 0x36, 0x91, 0x8A],
        reason: "CRC32C Intel SSE4.2 vector: 32 zero bytes",
    },
    GoldenSample {
        op_id: "primitive.hash.crc32c",
        input: &[0xFF; 32],
        expected: &[0x43, 0xAB, 0xA8, 0x62],
        reason: "CRC32C Intel SSE4.2 vector: 32 0xff bytes",
    },
    GoldenSample {
        op_id: "primitive.hash.crc32c",
        input: b"0123456789",
        expected: &[0x9E, 0x06, 0x0C, 0x28],
        reason: "CRC32C Intel SSE4.2 vector: 0123456789 (LE bytes of 0x280C069E)",
    },
];

/// Known-answer tests for this op.
pub const KAT: &[vyre_spec::KatVector] = &[
    vyre_spec::KatVector {
        input: &[0x00; 32],
        expected: &[0xAA, 0x36, 0x91, 0x8A],
        source: "hand-verified reference vector from Rust semantics",
    },
    vyre_spec::KatVector {
        input: &[0xFF; 32],
        expected: &[0x43, 0xAB, 0xA8, 0x62],
        source: "hand-verified reference vector from Rust semantics",
    },
    vyre_spec::KatVector {
        input: b"0123456789",
        expected: &[0x9E, 0x06, 0x0C, 0x28],
        source: "derived from the Rust cpu reference, LE bytes of 0x280C069E",
    },
];

/// Adversarial inputs for this op.
pub const ADVERSARIAL: &[vyre_spec::AdversarialInput] = &[vyre_spec::AdversarialInput {
    input: &[],
    reason: "empty input exercises validation and boundary handling",
}];

fn cpu(input: &[u8]) -> Vec<u8> {
    let mut crc: u32 = 0xFFFF_FFFF;
    for &byte in input {
        crc ^= u32::from(byte);
        for _ in 0..8 {
            if crc & 1 != 0 {
                crc = (crc >> 1) ^ 0x82F6_3B78;
            } else {
                crc >>= 1;
            }
        }
    }
    (crc ^ 0xFFFF_FFFF).to_le_bytes().to_vec()
}

fn wgsl() -> String {
    r"
fn vyre_op(index: u32, input_len: u32) -> u32 {
    var crc: u32 = 0xFFFFFFFFu;
    for (var i: u32 = 0u; i < input_len; i = i + 1u) {
        // Extract byte i from the packed u32 array
        let word_idx = i / 4u;
        let byte_idx = i % 4u;
        let byte_val = (input.data[word_idx] >> (byte_idx * 8u)) & 0xFFu;
        crc = crc ^ byte_val;
        // Unrolled 8 iterations of the bit loop for performance
        for (var j: u32 = 0u; j < 8u; j = j + 1u) {
            let mask = select(0u, 0x82F63B78u, (crc & 1u) != 0u);
            crc = (crc >> 1u) ^ mask;
        }
    }
    return crc ^ 0xFFFFFFFFu;
}
"
    .to_string()
}

/// Build the CRC32C OpSpec.
#[inline]
pub fn vyre_op() -> OpSpec {
    OpSpec::builder("primitive.hash.crc32c")
        .signature(crate::spec::types::OpSignature {
            inputs: vec![crate::spec::types::DataType::Bytes],
            output: crate::spec::types::DataType::U32,
        })
        .cpu_fn(cpu)
        .wgsl_fn(wgsl)
        .category(crate::Category::A {
            composition_of: vec!["primitive.hash.crc32c"],
        })
        .laws(vec![crate::spec::law::AlgebraicLaw::Bounded {
            lo: 0,
            hi: u32::MAX,
        }])
        .overflow_contract(crate::spec::types::OverflowContract::Unchecked)
        .strictness(crate::spec::types::Strictness::Strict)
        .version(1)
        .boundary_values(vec![
            crate::spec::types::BoundaryValue {
                label: "empty",
                inputs: vec![0],
            },
            crate::spec::types::BoundaryValue {
                label: "single_zero",
                inputs: vec![0],
            },
            crate::spec::types::BoundaryValue {
                label: "single_ff",
                inputs: vec![255],
            },
            crate::spec::types::BoundaryValue {
                label: "ascii_a",
                inputs: vec![0x61],
            },
        ])
        .equivalence_classes(vec![
            crate::spec::types::EquivalenceClass::specific("empty input", vec![0]),
            crate::spec::types::EquivalenceClass::specific("single byte", vec![0x41]),
            crate::spec::types::EquivalenceClass::specific("multi-byte", vec![0x61, 0x62, 0x63]),
        ])
        .expect("Fix: checked-in conform spec must satisfy the typestate builder")
}

#[cfg(test)]
mod tests {

    use super::cpu;

    #[test]
    fn crc32c_empty() {
        assert_eq!(cpu(&[]), 0u32.to_le_bytes().to_vec());
    }

    #[test]
    fn crc32c_known_vector() {
        // CRC32C("123456789") = 0xE3069283
        let result = cpu(b"123456789");
        let crc = u32::from_le_bytes([result[0], result[1], result[2], result[3]]);
        assert_eq!(crc, 0xE306_9283, "CRC32C of '123456789' must be 0xE3069283");
    }
}

#[cfg(test)]
mod proptests {
    #[test]
    fn coverage_artifacts_are_registered() {
        assert!(!super::KAT.is_empty());
        assert!(!super::ADVERSARIAL.is_empty());
    }
}