sp1_recursion_core/air/
is_ext_zero.rs1use crate::air::Block;
8use p3_air::AirBuilder;
9use p3_field::{
10 extension::{BinomialExtensionField, BinomiallyExtendable},
11 AbstractField, Field,
12};
13use sp1_derive::AlignedBorrow;
14use sp1_stark::air::{BinomialExtension, SP1AirBuilder};
15
16use crate::air::extension::BinomialExtensionUtils;
17
18use crate::runtime::D;
19
20#[derive(AlignedBorrow, Default, Debug, Clone, Copy)]
22#[repr(C)]
23pub struct IsExtZeroOperation<T> {
24 pub inverse: Block<T>,
26
27 pub result: T,
29}
30
31impl<F: Field + BinomiallyExtendable<D>> IsExtZeroOperation<F> {
32 pub fn populate(&mut self, a: Block<F>) -> F {
33 let a = BinomialExtensionField::<F, D>::from_block(a);
34
35 let (inverse, result) = if a.is_zero() {
36 (BinomialExtensionField::zero(), F::one())
37 } else {
38 (a.inverse(), F::zero())
39 };
40
41 self.inverse = inverse.as_block();
42 self.result = result;
43
44 let prod = inverse * a;
45 debug_assert!(prod == BinomialExtensionField::<F, D>::one() || prod.is_zero());
46
47 result
48 }
49}
50
51impl<F: Field> IsExtZeroOperation<F> {
52 pub fn eval<AB: SP1AirBuilder>(
53 builder: &mut AB,
54 a: BinomialExtension<AB::Expr>,
55 cols: IsExtZeroOperation<AB::Var>,
56 is_real: AB::Expr,
57 ) {
58 builder.assert_bool(is_real.clone());
60 builder.when(is_real.clone()).assert_bool(cols.result);
62
63 let one_ext = BinomialExtension::<AB::Expr>::from_base(AB::Expr::one());
74
75 let inverse = cols.inverse.as_extension::<AB>();
76
77 let is_zero = one_ext.clone() - inverse * a.clone();
78 let result_ext = BinomialExtension::<AB::Expr>::from_base(cols.result.into());
79
80 for (eq_z, res) in is_zero.into_iter().zip(result_ext.0) {
81 builder.when(is_real.clone()).assert_eq(eq_z, res);
82 }
83
84 builder.when(is_real.clone()).assert_bool(cols.result);
85
86 for x in a {
88 builder.when(is_real.clone()).when(cols.result).assert_zero(x.clone());
89 }
90 }
91}