use p3_air::AirBuilder;
use p3_field::Field;
use sp1_derive::AlignedBorrow;
use super::IsZeroOperation;
use crate::air::SP1AirBuilder;
use crate::air::Word;
use crate::disassembler::WORD_SIZE;
#[derive(AlignedBorrow, Default, Debug, Clone, Copy)]
#[repr(C)]
pub struct IsZeroWordOperation<T> {
pub is_zero_byte: [IsZeroOperation<T>; WORD_SIZE],
pub is_lower_half_zero: T,
pub is_upper_half_zero: T,
pub result: T,
}
impl<F: Field> IsZeroWordOperation<F> {
pub fn populate(&mut self, a_u32: u32) -> u32 {
self.populate_from_field_element(Word::from(a_u32))
}
pub fn populate_from_field_element(&mut self, a: Word<F>) -> u32 {
let mut is_zero = true;
for i in 0..WORD_SIZE {
is_zero &= self.is_zero_byte[i].populate_from_field_element(a[i]) == 1;
}
self.is_lower_half_zero = self.is_zero_byte[0].result * self.is_zero_byte[1].result;
self.is_upper_half_zero = self.is_zero_byte[2].result * self.is_zero_byte[3].result;
self.result = F::from_bool(is_zero);
is_zero as u32
}
pub fn eval<AB: SP1AirBuilder>(
builder: &mut AB,
a: Word<AB::Expr>,
cols: IsZeroWordOperation<AB::Var>,
is_real: AB::Expr,
) {
for i in 0..WORD_SIZE {
IsZeroOperation::<AB::F>::eval(
builder,
a[i].clone(),
cols.is_zero_byte[i],
is_real.clone(),
);
}
builder.assert_bool(is_real.clone());
let mut builder_is_real = builder.when(is_real.clone());
builder_is_real.assert_bool(cols.is_lower_half_zero);
builder_is_real.assert_bool(cols.is_upper_half_zero);
builder_is_real.assert_bool(cols.result);
builder_is_real.assert_eq(
cols.is_lower_half_zero,
cols.is_zero_byte[0].result * cols.is_zero_byte[1].result,
);
builder_is_real.assert_eq(
cols.is_upper_half_zero,
cols.is_zero_byte[2].result * cols.is_zero_byte[3].result,
);
builder_is_real.assert_eq(
cols.result,
cols.is_lower_half_zero * cols.is_upper_half_zero,
);
}
}