use serde::{Deserialize, Serialize};
use slop_air::AirBuilder;
use slop_algebra::Field;
use sp1_derive::{AlignedBorrow, InputExpr, InputParams, IntoShape, SP1OperationBuilder};
use sp1_hypercube::{air::SP1AirBuilder, Word};
use sp1_primitives::consts::WORD_SIZE;
use crate::air::{SP1Operation, SP1OperationBuilder};
use super::{IsZeroOperation, IsZeroOperationInput};
#[derive(
AlignedBorrow,
Default,
Debug,
Clone,
Copy,
Serialize,
Deserialize,
IntoShape,
SP1OperationBuilder,
)]
#[repr(C)]
pub struct IsZeroWordOperation<T> {
pub is_zero_limb: [IsZeroOperation<T>; WORD_SIZE],
pub is_zero_first_half: T,
pub is_zero_second_half: T,
pub result: T,
}
impl<F: Field> IsZeroWordOperation<F> {
pub fn populate(&mut self, a_u64: u64) -> u64 {
self.populate_from_field_element(Word::from(a_u64))
}
pub fn populate_from_field_element(&mut self, a: Word<F>) -> u64 {
let mut is_zero = true;
for i in 0..WORD_SIZE {
is_zero &= self.is_zero_limb[i].populate_from_field_element(a[i]) == 1;
}
self.result = F::from_bool(is_zero);
self.is_zero_first_half = self.is_zero_limb[0].result * self.is_zero_limb[1].result;
self.is_zero_second_half = self.is_zero_limb[2].result * self.is_zero_limb[3].result;
is_zero as u64
}
fn eval_zero_word<
AB: SP1AirBuilder + SP1OperationBuilder<IsZeroOperation<<AB as AirBuilder>::F>>,
>(
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,
IsZeroOperationInput::new(a[i].clone(), cols.is_zero_limb[i], is_real.clone()),
)
}
builder.assert_bool(is_real.clone());
builder.assert_bool(cols.result);
builder.assert_eq(
cols.is_zero_first_half,
cols.is_zero_limb[0].result * cols.is_zero_limb[1].result,
);
builder.assert_eq(
cols.is_zero_second_half,
cols.is_zero_limb[2].result * cols.is_zero_limb[3].result,
);
builder
.when(is_real.clone())
.assert_eq(cols.result, cols.is_zero_first_half * cols.is_zero_second_half);
}
}
#[derive(Clone, InputParams, InputExpr)]
pub struct IsZeroWordOperationInput<AB: SP1AirBuilder> {
pub a: Word<AB::Expr>,
pub cols: IsZeroWordOperation<AB::Var>,
pub is_real: AB::Expr,
}
impl<AB: SP1AirBuilder + SP1OperationBuilder<IsZeroOperation<<AB as AirBuilder>::F>>>
SP1Operation<AB> for IsZeroWordOperation<AB::F>
{
type Input = IsZeroWordOperationInput<AB>;
type Output = ();
fn lower(builder: &mut AB, input: Self::Input) {
Self::eval_zero_word(builder, input.a, input.cols, input.is_real);
}
}