sp1_core_machine/operations/
is_zero.rs1use serde::{Deserialize, Serialize};
8use slop_air::AirBuilder;
9use slop_algebra::{AbstractField, Field};
10use sp1_derive::{AlignedBorrow, InputExpr, InputParams, IntoShape, SP1OperationBuilder};
11
12use sp1_hypercube::air::SP1AirBuilder;
13
14use crate::air::SP1Operation;
15
16#[derive(
18 AlignedBorrow,
19 Default,
20 Debug,
21 Clone,
22 Copy,
23 Serialize,
24 Deserialize,
25 IntoShape,
26 SP1OperationBuilder,
27)]
28#[repr(C)]
29pub struct IsZeroOperation<T> {
30 pub inverse: T,
32
33 pub result: T,
35}
36
37impl<F: Field> IsZeroOperation<F> {
38 pub fn populate(&mut self, a: u64) -> u64 {
39 self.populate_from_field_element(F::from_canonical_u64(a))
40 }
41
42 pub fn populate_from_field_element(&mut self, a: F) -> u64 {
43 if a == F::zero() {
44 self.inverse = F::zero();
45 self.result = F::one();
46 } else {
47 self.inverse = a.inverse();
48 self.result = F::zero();
49 }
50 let prod = self.inverse * a;
51 debug_assert!(prod == F::one() || prod == F::zero());
52 (a == F::zero()) as u64
53 }
54
55 fn eval_is_zero<AB: SP1AirBuilder>(
58 builder: &mut AB,
59 a: AB::Expr,
60 cols: IsZeroOperation<AB::Var>,
61 is_real: AB::Expr,
62 ) {
63 let one: AB::Expr = AB::Expr::one();
64
65 let is_zero = one.clone() - cols.inverse * a.clone();
76 builder.when(is_real.clone()).assert_eq(is_zero, cols.result);
77 builder.when(is_real.clone()).assert_bool(cols.result);
78
79 builder.when(is_real.clone()).when(cols.result).assert_zero(a.clone());
81 }
82}
83
84#[derive(Clone, InputParams, InputExpr)]
85pub struct IsZeroOperationInput<AB: SP1AirBuilder> {
86 pub a: AB::Expr,
87 pub cols: IsZeroOperation<AB::Var>,
88 pub is_real: AB::Expr,
89}
90
91impl<AB: SP1AirBuilder> SP1Operation<AB> for IsZeroOperation<AB::F> {
92 type Input = IsZeroOperationInput<AB>;
93 type Output = ();
94
95 fn lower(builder: &mut AB, input: Self::Input) {
96 Self::eval_is_zero(builder, input.a, input.cols, input.is_real);
97 }
98}