triton_air/table/
op_stack.rs1use constraint_circuit::ConstraintCircuitBuilder;
2use constraint_circuit::ConstraintCircuitMonad;
3use constraint_circuit::DualRowIndicator;
4use constraint_circuit::DualRowIndicator::CurrentAux;
5use constraint_circuit::DualRowIndicator::CurrentMain;
6use constraint_circuit::DualRowIndicator::NextAux;
7use constraint_circuit::DualRowIndicator::NextMain;
8use constraint_circuit::SingleRowIndicator;
9use constraint_circuit::SingleRowIndicator::Aux;
10use constraint_circuit::SingleRowIndicator::Main;
11use isa::op_stack::OpStackElement;
12use strum::EnumCount;
13use twenty_first::prelude::*;
14
15use crate::AIR;
16use crate::challenge_id::ChallengeId;
17use crate::cross_table_argument::CrossTableArg;
18use crate::cross_table_argument::LookupArg;
19use crate::cross_table_argument::PermArg;
20use crate::table_column::MasterAuxColumn;
21use crate::table_column::MasterMainColumn;
22
23pub const PADDING_VALUE: BFieldElement = BFieldElement::new(2);
26
27#[derive(Debug, Copy, Clone, Eq, PartialEq)]
28pub struct OpStackTable;
29
30impl crate::private::Seal for OpStackTable {}
31
32impl AIR for OpStackTable {
33 type MainColumn = crate::table_column::OpStackMainColumn;
34 type AuxColumn = crate::table_column::OpStackAuxColumn;
35
36 fn initial_constraints(
37 circuit_builder: &ConstraintCircuitBuilder<SingleRowIndicator>,
38 ) -> Vec<ConstraintCircuitMonad<SingleRowIndicator>> {
39 let challenge = |c| circuit_builder.challenge(c);
40 let constant = |c| circuit_builder.b_constant(c);
41 let x_constant = |c| circuit_builder.x_constant(c);
42 let main_row =
43 |column: Self::MainColumn| circuit_builder.input(Main(column.master_main_index()));
44 let aux_row =
45 |column: Self::AuxColumn| circuit_builder.input(Aux(column.master_aux_index()));
46
47 let initial_stack_length = u32::try_from(OpStackElement::COUNT).unwrap();
48 let initial_stack_length = constant(initial_stack_length.into());
49 let padding_indicator = constant(PADDING_VALUE);
50
51 let stack_pointer_is_16 =
52 main_row(Self::MainColumn::StackPointer) - initial_stack_length.clone();
53
54 let compressed_row = challenge(ChallengeId::OpStackClkWeight)
55 * main_row(Self::MainColumn::CLK)
56 + challenge(ChallengeId::OpStackIb1Weight) * main_row(Self::MainColumn::IB1ShrinkStack)
57 + challenge(ChallengeId::OpStackPointerWeight) * initial_stack_length
58 + challenge(ChallengeId::OpStackFirstUnderflowElementWeight)
59 * main_row(Self::MainColumn::FirstUnderflowElement);
60 let rppa_initial = challenge(ChallengeId::OpStackIndeterminate) - compressed_row;
61 let rppa_has_accumulated_first_row =
62 aux_row(Self::AuxColumn::RunningProductPermArg) - rppa_initial;
63
64 let rppa_is_default_initial = aux_row(Self::AuxColumn::RunningProductPermArg)
65 - x_constant(PermArg::default_initial());
66
67 let first_row_is_padding_row =
68 main_row(Self::MainColumn::IB1ShrinkStack) - padding_indicator;
69 let first_row_is_not_padding_row = main_row(Self::MainColumn::IB1ShrinkStack)
70 * (main_row(Self::MainColumn::IB1ShrinkStack) - constant(bfe!(1)));
71
72 let rppa_starts_correctly = rppa_has_accumulated_first_row * first_row_is_padding_row
73 + rppa_is_default_initial * first_row_is_not_padding_row;
74
75 let lookup_argument_initial = x_constant(LookupArg::default_initial());
76 let clock_jump_diff_log_derivative_is_initialized_correctly =
77 aux_row(Self::AuxColumn::ClockJumpDifferenceLookupClientLogDerivative)
78 - lookup_argument_initial;
79
80 vec![
81 stack_pointer_is_16,
82 rppa_starts_correctly,
83 clock_jump_diff_log_derivative_is_initialized_correctly,
84 ]
85 }
86
87 fn consistency_constraints(
88 _circuit_builder: &ConstraintCircuitBuilder<SingleRowIndicator>,
89 ) -> Vec<ConstraintCircuitMonad<SingleRowIndicator>> {
90 vec![]
92 }
93
94 fn transition_constraints(
95 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
96 ) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
97 let constant = |c| circuit_builder.b_constant(c);
98 let challenge = |c| circuit_builder.challenge(c);
99 let current_main_row = |column: Self::MainColumn| {
100 circuit_builder.input(CurrentMain(column.master_main_index()))
101 };
102 let current_aux_row =
103 |column: Self::AuxColumn| circuit_builder.input(CurrentAux(column.master_aux_index()));
104 let next_main_row =
105 |column: Self::MainColumn| circuit_builder.input(NextMain(column.master_main_index()));
106 let next_aux_row =
107 |column: Self::AuxColumn| circuit_builder.input(NextAux(column.master_aux_index()));
108
109 let one = constant(1_u32.into());
110 let padding_indicator = constant(PADDING_VALUE);
111
112 let clk = current_main_row(Self::MainColumn::CLK);
113 let ib1_shrink_stack = current_main_row(Self::MainColumn::IB1ShrinkStack);
114 let stack_pointer = current_main_row(Self::MainColumn::StackPointer);
115 let first_underflow_element = current_main_row(Self::MainColumn::FirstUnderflowElement);
116 let rppa = current_aux_row(Self::AuxColumn::RunningProductPermArg);
117 let clock_jump_diff_log_derivative =
118 current_aux_row(Self::AuxColumn::ClockJumpDifferenceLookupClientLogDerivative);
119
120 let clk_next = next_main_row(Self::MainColumn::CLK);
121 let ib1_shrink_stack_next = next_main_row(Self::MainColumn::IB1ShrinkStack);
122 let stack_pointer_next = next_main_row(Self::MainColumn::StackPointer);
123 let first_underflow_element_next = next_main_row(Self::MainColumn::FirstUnderflowElement);
124 let rppa_next = next_aux_row(Self::AuxColumn::RunningProductPermArg);
125 let clock_jump_diff_log_derivative_next =
126 next_aux_row(Self::AuxColumn::ClockJumpDifferenceLookupClientLogDerivative);
127
128 let stack_pointer_increases_by_1_or_does_not_change =
129 (stack_pointer_next.clone() - stack_pointer.clone() - one.clone())
130 * (stack_pointer_next.clone() - stack_pointer.clone());
131
132 let stack_pointer_inc_by_1_or_underflow_element_doesnt_change_or_next_ci_grows_stack =
133 (stack_pointer_next.clone() - stack_pointer.clone() - one.clone())
134 * (first_underflow_element_next.clone() - first_underflow_element.clone())
135 * ib1_shrink_stack_next.clone();
136
137 let next_row_is_padding_row = ib1_shrink_stack_next.clone() - padding_indicator.clone();
138 let if_current_row_is_padding_row_then_next_row_is_padding_row = ib1_shrink_stack.clone()
139 * (ib1_shrink_stack - one.clone())
140 * next_row_is_padding_row.clone();
141
142 let compressed_row = circuit_builder.challenge(ChallengeId::OpStackClkWeight)
145 * clk_next.clone()
146 + circuit_builder.challenge(ChallengeId::OpStackIb1Weight)
147 * ib1_shrink_stack_next.clone()
148 + circuit_builder.challenge(ChallengeId::OpStackPointerWeight)
149 * stack_pointer_next.clone()
150 + circuit_builder.challenge(ChallengeId::OpStackFirstUnderflowElementWeight)
151 * first_underflow_element_next;
152
153 let rppa_updates = rppa_next.clone()
154 - rppa.clone() * (challenge(ChallengeId::OpStackIndeterminate) - compressed_row);
155
156 let next_row_is_not_padding_row =
157 ib1_shrink_stack_next.clone() * (ib1_shrink_stack_next.clone() - one.clone());
158 let rppa_remains = rppa_next - rppa;
159
160 let rppa_updates_correctly = rppa_updates * next_row_is_padding_row.clone()
161 + rppa_remains * next_row_is_not_padding_row.clone();
162
163 let clk_diff = clk_next - clk;
164 let log_derivative_accumulates = (clock_jump_diff_log_derivative_next.clone()
165 - clock_jump_diff_log_derivative.clone())
166 * (challenge(ChallengeId::ClockJumpDifferenceLookupIndeterminate) - clk_diff)
167 - one.clone();
168 let log_derivative_remains =
169 clock_jump_diff_log_derivative_next.clone() - clock_jump_diff_log_derivative.clone();
170
171 let log_derivative_accumulates_or_stack_pointer_changes_or_next_row_is_padding_row =
172 log_derivative_accumulates
173 * (stack_pointer_next.clone() - stack_pointer.clone() - one.clone())
174 * next_row_is_padding_row;
175 let log_derivative_remains_or_stack_pointer_doesnt_change =
176 log_derivative_remains.clone() * (stack_pointer_next.clone() - stack_pointer.clone());
177 let log_derivatve_remains_or_next_row_is_not_padding_row =
178 log_derivative_remains * next_row_is_not_padding_row;
179
180 let log_derivative_updates_correctly =
181 log_derivative_accumulates_or_stack_pointer_changes_or_next_row_is_padding_row
182 + log_derivative_remains_or_stack_pointer_doesnt_change
183 + log_derivatve_remains_or_next_row_is_not_padding_row;
184
185 vec![
186 stack_pointer_increases_by_1_or_does_not_change,
187 stack_pointer_inc_by_1_or_underflow_element_doesnt_change_or_next_ci_grows_stack,
188 if_current_row_is_padding_row_then_next_row_is_padding_row,
189 rppa_updates_correctly,
190 log_derivative_updates_correctly,
191 ]
192 }
193
194 fn terminal_constraints(
195 _circuit_builder: &ConstraintCircuitBuilder<SingleRowIndicator>,
196 ) -> Vec<ConstraintCircuitMonad<SingleRowIndicator>> {
197 vec![]
199 }
200}