openvm_circuit_primitives/is_equal/
mod.rs

1use derive_new::new;
2use openvm_stark_backend::{p3_air::AirBuilder, p3_field::Field};
3
4use crate::{
5    is_zero::{IsZeroAuxCols, IsZeroIo, IsZeroSubAir},
6    SubAir, TraceSubRowGenerator,
7};
8
9#[cfg(test)]
10pub mod tests;
11
12#[repr(C)]
13#[derive(Copy, Clone, Debug, new)]
14pub struct IsEqualIo<T> {
15    pub x: T,
16    pub y: T,
17    /// The boolean output, constrained to equal (x == y), when `condition != 0`.
18    pub out: T,
19    /// Constraints only hold when `condition != 0`. When `condition == 0`, setting all trace values
20    /// to zero still passes the constraints.
21    pub condition: T,
22}
23
24pub type IsEqualAuxCols<T> = IsZeroAuxCols<T>;
25
26/// An Air that constrains `out = (x == y)`.
27#[derive(Copy, Clone)]
28pub struct IsEqSubAir;
29
30impl<AB: AirBuilder> SubAir<AB> for IsEqSubAir {
31    /// (io, inv)
32    type AirContext<'a>
33        = (IsEqualIo<AB::Expr>, AB::Var)
34    where
35        AB::Expr: 'a,
36        AB::Var: 'a,
37        AB: 'a;
38
39    fn eval<'a>(&'a self, builder: &'a mut AB, (io, inv): (IsEqualIo<AB::Expr>, AB::Var))
40    where
41        AB::Var: 'a,
42        AB::Expr: 'a,
43    {
44        let is_zero_io = IsZeroIo::new(io.x - io.y, io.out, io.condition);
45        IsZeroSubAir.eval(builder, (is_zero_io, inv));
46    }
47}
48
49impl<F: Field> TraceSubRowGenerator<F> for IsEqSubAir {
50    /// `(x, y)`
51    type TraceContext<'a> = (F, F);
52    /// `(inv, out)`
53    type ColsMut<'a> = (&'a mut F, &'a mut F);
54
55    fn generate_subrow<'a>(&'a self, (x, y): (F, F), (inv, out): (&'a mut F, &'a mut F)) {
56        IsZeroSubAir.generate_subrow(x - y, (inv, out));
57    }
58}