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>,
) {
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> {
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()
}