use p3_air::AirBuilder;
use p3_field::AbstractField;
use p3_field::Field;
use sp1_derive::AlignedBorrow;
use crate::air::SP1AirBuilder;
#[derive(AlignedBorrow, Default, Debug, Clone, Copy)]
#[repr(C)]
pub struct IsZeroOperation<T> {
pub inverse: T,
pub result: T,
}
impl<F: Field> IsZeroOperation<F> {
pub fn populate(&mut self, a: u32) -> u32 {
self.populate_from_field_element(F::from_canonical_u32(a))
}
pub fn populate_from_field_element(&mut self, a: F) -> u32 {
if a == F::zero() {
self.inverse = F::zero();
self.result = F::one();
} else {
self.inverse = a.inverse();
self.result = F::zero();
}
let prod = self.inverse * a;
debug_assert!(prod == F::one() || prod == F::zero());
(a == F::zero()) as u32
}
pub fn eval<AB: SP1AirBuilder>(
builder: &mut AB,
a: AB::Expr,
cols: IsZeroOperation<AB::Var>,
is_real: AB::Expr,
) {
let one: AB::Expr = AB::F::one().into();
let is_zero = one.clone() - cols.inverse * a.clone();
builder
.when(is_real.clone())
.assert_eq(is_zero, cols.result);
builder.when(is_real.clone()).assert_bool(cols.result);
builder
.when(is_real.clone())
.when(cols.result)
.assert_zero(a.clone());
}
}