acvm_blackbox_solver/
logic.rsuse acir::AcirField;
pub fn bit_and<F: AcirField>(lhs: F, rhs: F, num_bits: u32) -> F {
bitwise_op(lhs, rhs, num_bits, |lhs_byte, rhs_byte| lhs_byte & rhs_byte)
}
pub fn bit_xor<F: AcirField>(lhs: F, rhs: F, num_bits: u32) -> F {
bitwise_op(lhs, rhs, num_bits, |lhs_byte, rhs_byte| lhs_byte ^ rhs_byte)
}
fn bitwise_op<F: AcirField>(lhs: F, rhs: F, num_bits: u32, op: fn(u8, u8) -> u8) -> F {
let lhs_bytes = mask_to_be_bytes(lhs, num_bits);
let rhs_bytes = mask_to_be_bytes(rhs, num_bits);
let and_byte_arr: Vec<_> =
lhs_bytes.into_iter().zip(rhs_bytes).map(|(left, right)| op(left, right)).collect();
F::from_be_bytes_reduce(&and_byte_arr)
}
fn mask_to_be_bytes<F: AcirField>(field: F, num_bits: u32) -> Vec<u8> {
let mut bytes = field.to_be_bytes();
mask_vector_le(&mut bytes, num_bits as usize);
bytes
}
fn mask_vector_le(bytes: &mut [u8], num_bits: usize) {
bytes.reverse();
let mask_power = num_bits % 8;
let array_mask_index = num_bits / 8;
for (index, byte) in bytes.iter_mut().enumerate() {
match index.cmp(&array_mask_index) {
std::cmp::Ordering::Less => {
}
std::cmp::Ordering::Equal => {
let mask = 2u8.pow(mask_power as u32) - 1;
*byte &= mask;
}
std::cmp::Ordering::Greater => {
*byte = 0;
}
}
}
bytes.reverse();
}
#[cfg(test)]
mod tests {
use acir::FieldElement;
use proptest::prelude::*;
use crate::{bit_and, bit_xor};
proptest! {
#[test]
fn matches_bitwise_and_on_u128s(x in 0..=u128::MAX, y in 0..=u128::MAX, bit_size in 128u32..) {
let x_as_field = FieldElement::from(x);
let y_as_field = FieldElement::from(y);
let x_and_y = x & y;
let x_and_y_as_field = bit_and(x_as_field, y_as_field, bit_size);
prop_assert_eq!(x_and_y_as_field, FieldElement::from(x_and_y), "AND on fields should match that on integers");
}
#[test]
fn matches_bitwise_xor_on_u128s(x in 0..=u128::MAX, y in 0..=u128::MAX, bit_size in 128u32..) {
let x_as_field = FieldElement::from(x);
let y_as_field = FieldElement::from(y);
let x_xor_y = x ^ y;
let x_xor_y_as_field = bit_xor(x_as_field, y_as_field, bit_size);
prop_assert_eq!(x_xor_y_as_field, FieldElement::from(x_xor_y), "XOR on fields should match that on integers");
}
}
}