vyre-conform 0.1.0

Conformance suite for vyre backends — proves byte-identical output to CPU reference
Documentation
pub use check_distributive::check_distributive;
pub use fake_mul::fake_mul;
pub use fake_add::fake_add;
pub use fake_broken_mul_is_add::fake_broken_mul_is_add;

use crate::properties::tests::{pair, primitive, result_u32, unary};
use crate::spec::law::AlgebraicLaw;

#[inline]
pub fn check_distributive(
    id: &str,
    f: fn(&[u8]) -> Vec<u8>,
    over_name: &str,
    f_over: fn(&[u8]) -> Vec<u8>,
) {
    // f(a, over(b, c)) == over(f(a, b), f(a, c))
    for a in SAMPLE {
        for b in SAMPLE {
            for c in SAMPLE {
                let bc = apply_binary(f_over, b, c);
                let lhs = apply_binary(f, a, bc);
                let ab = apply_binary(f, a, b);
                let ac = apply_binary(f, a, c);
                let rhs = apply_binary(f_over, ab, ac);
                assert_eq!(
                    lhs, rhs,
                    "{id} violates DistributiveOver({over_name}) at \
                     ({a:#010x}, {b:#010x}, {c:#010x}): \
                     f(a,over(b,c))={lhs:#010x} vs over(f(a,b),f(a,c))={rhs:#010x}"
                );
            }
        }
    }
}


#[test]
fn distributive_checker_accepts_valid_mul() {
    check_distributive("fake.mul", fake_mul, "primitive.math.add", fake_add);
}


#[test]
fn distributive_checker_catches_violation() {
    let result = std::panic::catch_unwind(|| {
        check_distributive(
            "fake.broken_mul",
            fake_broken_mul_is_add,
            "primitive.math.add",
            fake_add,
        );
    });
    assert!(
        result.is_err(),
        "DistributiveOver checker failed to catch an `add` posing as `mul`"
    );
}


#[inline]
pub fn fake_add(input: &[u8]) -> Vec<u8> {
    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.wrapping_add(b).to_le_bytes().to_vec()
}


#[inline]
pub fn fake_broken_mul_is_add(input: &[u8]) -> Vec<u8> {
    // a + b instead of a * b — violates DistributiveOver(add).
    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.wrapping_add(b).to_le_bytes().to_vec()
}


#[inline]
pub fn fake_mul(input: &[u8]) -> Vec<u8> {
    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.wrapping_mul(b).to_le_bytes().to_vec()
}