p3_uni_stark/
check_constraints.rs

1use alloc::vec::Vec;
2
3use p3_air::{Air, AirBuilder, AirBuilderWithPublicValues};
4use p3_field::Field;
5use p3_matrix::dense::{RowMajorMatrix, RowMajorMatrixView};
6use p3_matrix::stack::VerticalPair;
7use p3_matrix::Matrix;
8use tracing::instrument;
9
10#[instrument(name = "check constraints", skip_all)]
11pub(crate) fn check_constraints<F, A>(air: &A, main: &RowMajorMatrix<F>, public_values: &Vec<F>)
12where
13    F: Field,
14    A: for<'a> Air<DebugConstraintBuilder<'a, F>>,
15{
16    let height = main.height();
17
18    (0..height).for_each(|i| {
19        let i_next = (i + 1) % height;
20
21        let local = main.row_slice(i);
22        let next = main.row_slice(i_next);
23        let main = VerticalPair::new(
24            RowMajorMatrixView::new_row(&*local),
25            RowMajorMatrixView::new_row(&*next),
26        );
27
28        let mut builder = DebugConstraintBuilder {
29            row_index: i,
30            main,
31            public_values,
32            is_first_row: F::from_bool(i == 0),
33            is_last_row: F::from_bool(i == height - 1),
34            is_transition: F::from_bool(i != height - 1),
35        };
36
37        air.eval(&mut builder);
38    });
39}
40
41/// An `AirBuilder` which asserts that each constraint is zero, allowing any failed constraints to
42/// be detected early.
43#[derive(Debug)]
44pub struct DebugConstraintBuilder<'a, F: Field> {
45    row_index: usize,
46    main: VerticalPair<RowMajorMatrixView<'a, F>, RowMajorMatrixView<'a, F>>,
47    public_values: &'a [F],
48    is_first_row: F,
49    is_last_row: F,
50    is_transition: F,
51}
52
53impl<'a, F> AirBuilder for DebugConstraintBuilder<'a, F>
54where
55    F: Field,
56{
57    type F = F;
58    type Expr = F;
59    type Var = F;
60    type M = VerticalPair<RowMajorMatrixView<'a, F>, RowMajorMatrixView<'a, F>>;
61
62    fn main(&self) -> Self::M {
63        self.main
64    }
65
66    fn is_first_row(&self) -> Self::Expr {
67        self.is_first_row
68    }
69
70    fn is_last_row(&self) -> Self::Expr {
71        self.is_last_row
72    }
73
74    fn is_transition_window(&self, size: usize) -> Self::Expr {
75        if size == 2 {
76            self.is_transition
77        } else {
78            panic!("only supports a window size of 2")
79        }
80    }
81
82    fn assert_zero<I: Into<Self::Expr>>(&mut self, x: I) {
83        assert_eq!(
84            x.into(),
85            F::ZERO,
86            "constraints had nonzero value on row {}",
87            self.row_index
88        );
89    }
90
91    fn assert_eq<I1: Into<Self::Expr>, I2: Into<Self::Expr>>(&mut self, x: I1, y: I2) {
92        let x = x.into();
93        let y = y.into();
94        assert_eq!(
95            x, y,
96            "values didn't match on row {}: {} != {}",
97            self.row_index, x, y
98        );
99    }
100}
101
102impl<F: Field> AirBuilderWithPublicValues for DebugConstraintBuilder<'_, F> {
103    type PublicVar = Self::F;
104
105    fn public_values(&self) -> &[Self::F] {
106        self.public_values
107    }
108}