vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
//! The Defender catalog - hand-crafted wrong CPU references.
//!
//! Each `Defendant` is a CPU reference function that is deliberately wrong in
//! a specific, minimal way. The catalog below is intentionally large: each
//! entry names one concrete mutation class, primitive operation, and parameter
//! or law corruption that the adversarial gauntlet must kill.

/// Build-time-generated defender corpus loaded from `conform/defenders/`.
pub mod corpus;

pub use corpus::{corpus_catalogs, corpus_metadata};

pub mod builtin_drop_lsb_add;
pub mod builtin_drop_msb_not;
pub mod builtin_hardcoded_input_add;
pub mod builtin_hardcoded_zero_add;
pub mod builtin_mod_mask_shl;
pub mod builtin_nondeterministic_add;
pub mod builtin_off_by_one_add;
pub mod builtin_pseudo_correct_add;
pub mod builtin_sign_flip_negate;
pub mod builtin_swapped_operand_sub;

pub(crate) use builtin_drop_lsb_add::builtin_drop_lsb_add;
pub(crate) use builtin_hardcoded_input_add::builtin_hardcoded_input_add;
pub(crate) use builtin_hardcoded_zero_add::builtin_hardcoded_zero_add;
pub(crate) use builtin_nondeterministic_add::builtin_nondeterministic_add;
pub(crate) use builtin_off_by_one_add::builtin_off_by_one_add;
pub(crate) use builtin_pseudo_correct_add::builtin_pseudo_correct_add;

/// Mutation families used to group deliberate defender sabotages.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum DefenderClass {
    /// Hidden input-triggered corruption that only fires on keyed values.
    Backdoor,
    /// Corruption that discards or ignores least-significant-bit information.
    DropLsb,
    /// Corruption that discards or ignores most-significant-bit information.
    DropMsb,
    /// Corruption that always returns a fixed nonzero input-like value.
    HardcodedInput,
    /// Corruption that collapses behavior to zero or zero-case handling.
    HardcodedZero,
    /// Corruption that masks shift/modulus parameters instead of applying the spec rule.
    ModMask,
    /// Corruption that depends on mutable state, time, or call order.
    Nondeterministic,
    /// Corruption that uses an inclusive/exclusive boundary one step from the spec.
    OffByOne,
    /// Corruption that is correct on shallow domains but fails wider witnesses.
    PseudoCorrect,
    /// Corruption that flips a sign, negation, complement, or mask polarity.
    SignFlip,
    /// Corruption that swaps operand order or falsely treats operand order as irrelevant.
    SwappedOperand,
    /// Corruption outside the current gauntlet's supported execution surface.
    Unsupported,
}

/// A deliberately-wrong CPU reference used to test that the declared law set catches a targeted sabotage.
#[derive(Clone)]
pub struct Defendant {
    /// Unique identifier for the defendant.
    pub id: &'static str,
    /// Target op id this defendant sabotages.
    pub target_op_id: &'static str,
    /// Human-readable description of the sabotage.
    pub description: &'static str,
    /// Mutation family exercised by this defendant.
    pub class: DefenderClass,
    /// The wrong CPU reference function.
    pub broken_fn: fn(&[u8]) -> Vec<u8>,
    /// Law fingerprints expected to fire when the declared law set is strong enough.
    pub fails_laws: &'static [&'static str],
    /// Concrete witness pair where the broken CPU reference disagrees with the target CPU reference.
    pub expected_witness: &'static [(u32, u32)],
}

/// A collection of defendants against a single target op.
pub struct DefendantCatalog {
    /// Target op id.
    pub target_op_id: &'static str,
    /// The defendants.
    pub defendants: Vec<Defendant>,
}

#[inline]
pub(crate) fn read_binary(input: &[u8]) -> (u32, u32) {
    assert!(
        input.len() >= 8,
        "read_binary called with {} bytes; expected at least 8 bytes",
        input.len()
    );
    let a = u32::from_le_bytes([input[0], input[1], input[2], input[3]]);
    let b = u32::from_le_bytes([input[4], input[5], input[6], input[7]]);
    (a, b)
}

#[inline]
pub(crate) fn read_unary(input: &[u8]) -> u32 {
    assert!(
        input.len() >= 4,
        "read_unary called with {} bytes; expected at least 4 bytes",
        input.len()
    );
    u32::from_le_bytes([input[0], input[1], input[2], input[3]])
}

#[inline]
pub(crate) fn write_u32(value: u32) -> Vec<u8> {
    value.to_le_bytes().to_vec()
}

#[inline]
pub(crate) fn tweak(value: u32, mode: u8) -> u32 {
    let wrong = match mode % 8 {
        0 => value.wrapping_add(1),
        1 => value.wrapping_sub(1),
        2 => value ^ 1,
        3 => !value,
        4 => value.rotate_left(1),
        5 => value.rotate_right(1),
        6 => value.wrapping_add(0x9E37_79B9),
        _ => value ^ 0xA5A5_5A5A,
    };
    if wrong == value {
        value ^ 1
    } else {
        wrong
    }
}

#[inline]
pub(crate) fn bool_tweak(value: u32, mode: u8) -> u32 {
    match mode % 5 {
        0 => 1 - (value & 1),
        1 => 2,
        2 => u32::MAX,
        3 => value ^ 1,
        _ => 42,
    }
}

pub mod catalogs;
pub mod macros;

/// Backward-compatible alias.
pub type MutationClass = DefenderClass;

/// Map a defender-centric class to the spec mutation class used by the engine.
#[must_use]
pub const fn defender_class_to_spec(class: DefenderClass) -> crate::spec::types::MutationClass {
    use crate::spec::types::MutationClass as C;
    match class {
        DefenderClass::Backdoor => C::ControlFlowMutations,
        DefenderClass::DropLsb => C::BitwiseMutations,
        DefenderClass::DropMsb => C::BitwiseMutations,
        DefenderClass::HardcodedInput => C::BufferAccessMutations,
        DefenderClass::HardcodedZero => C::ConstantMutations,
        DefenderClass::ModMask => C::LoweringMutations,
        DefenderClass::Nondeterministic => C::OrderingMutations,
        DefenderClass::OffByOne => C::BufferAccessMutations,
        DefenderClass::PseudoCorrect => C::LawMutations,
        DefenderClass::SignFlip => C::ArithmeticMutations,
        DefenderClass::SwappedOperand => C::ComparisonMutations,
        DefenderClass::Unsupported => C::IrStructuralMutations,
    }
}

/// Build the full adversarial defendant catalog including auto-discovered corpus defenders.
#[must_use]
#[inline]
pub fn full_catalog() -> Vec<DefendantCatalog> {
    let mut catalogs = catalogs::built_in_catalogs();
    catalogs.extend(corpus::corpus_catalogs());
    catalogs
}