use crate::{
core::{
actually_used_field::ActuallyUsedField,
bounds::FieldBounds,
circuits::{
boolean::boolean_value::BooleanValue,
traits::arithmetic_circuit::ArithmeticCircuit,
},
expressions::expr::EvalFailure,
global_value::value::FieldValue,
},
traits::{FromLeBits, GetBit},
utils::{number::Number, used_field::UsedField},
};
use num_bigint::BigInt;
#[derive(Debug, Clone)]
pub struct BitwiseAnd {
signed: bool,
}
impl BitwiseAnd {
pub const fn new(signed: bool) -> Self {
Self { signed }
}
}
impl BitwiseAnd {
pub fn bitwise_and<F: ActuallyUsedField>(
lhs: FieldValue<F>,
rhs: FieldValue<F>,
signed: bool,
) -> FieldValue<F> {
let union_bounds = lhs.bounds().union(rhs.bounds());
let circuit_size = union_bounds.bin_size(signed);
let lhs_bits = (0..circuit_size)
.map(|i| lhs.get_bit(i, signed))
.collect::<Vec<BooleanValue>>();
let rhs_bits = (0..circuit_size)
.map(|i| rhs.get_bit(i, signed))
.collect::<Vec<BooleanValue>>();
let res_bits = lhs_bits
.into_iter()
.zip(rhs_bits)
.map(|(lhs_bit, rhs_bit)| lhs_bit & rhs_bit)
.collect::<Vec<BooleanValue>>();
FieldValue::<F>::from_le_bits(res_bits, signed)
}
}
impl<F: UsedField> ArithmeticCircuit<F> for BitwiseAnd {
fn eval(&self, x: Vec<F>) -> Result<Vec<F>, EvalFailure> {
assert_eq!(x.len(), 2);
let x0 = x[0];
let x1 = x[1];
let v = if self.signed {
let x0 = BigInt::from(x0.to_signed_number());
let x1 = BigInt::from(x1.to_signed_number());
Number::from(x0 & x1).into()
} else {
let x0 = BigInt::from(x0.to_unsigned_number());
let x1 = BigInt::from(x1.to_unsigned_number());
Number::from(x0 & x1).into()
};
Ok(vec![v])
}
fn bounds(&self, bounds: Vec<FieldBounds<F>>) -> Vec<FieldBounds<F>> {
let max_size = if self.signed {
bounds
.into_iter()
.map(|bound| bound.bin_size(self.signed))
.max()
.unwrap()
} else {
bounds
.into_iter()
.map(|bound| bound.bin_size(self.signed))
.min()
.unwrap()
};
let res = if max_size >= F::CAPACITY as usize {
FieldBounds::All
} else if self.signed && max_size > 0 {
let pot = F::power_of_two(max_size - 1);
FieldBounds::new(-pot, pot - F::ONE)
} else {
FieldBounds::new(F::ZERO, F::power_of_two(max_size) - F::ONE)
};
vec![res]
}
fn run(&self, vals: Vec<FieldValue<F>>) -> Vec<FieldValue<F>>
where
F: ActuallyUsedField,
{
let val0 = vals[0];
let val1 = vals[1];
let res = Self::bitwise_and(val0, val1, self.signed);
vec![res]
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
core::circuits::traits::arithmetic_circuit::tests::TestedArithmeticCircuit,
ArcisField,
};
use rand::Rng;
impl TestedArithmeticCircuit<ArcisField> for BitwiseAnd {
fn gen_desc<R: Rng + ?Sized>(rng: &mut R) -> Self {
Self::new(rng.gen())
}
fn gen_n_inputs<R: Rng + ?Sized>(&self, _rng: &mut R) -> usize {
2
}
}
#[test]
fn tested() {
BitwiseAnd::test(16, 16)
}
}