1use std::cmp::max;
2use std::ops::Mul;
3
4use constraint_circuit::ConstraintCircuitBuilder;
5use constraint_circuit::ConstraintCircuitMonad;
6use constraint_circuit::DualRowIndicator;
7use constraint_circuit::DualRowIndicator::CurrentAux;
8use constraint_circuit::DualRowIndicator::CurrentMain;
9use constraint_circuit::DualRowIndicator::NextAux;
10use constraint_circuit::DualRowIndicator::NextMain;
11use constraint_circuit::InputIndicator;
12use constraint_circuit::SingleRowIndicator;
13use constraint_circuit::SingleRowIndicator::Aux;
14use constraint_circuit::SingleRowIndicator::Main;
15use isa::instruction::ALL_INSTRUCTIONS;
16use isa::instruction::Instruction;
17use isa::instruction::InstructionBit;
18use isa::op_stack::NUM_OP_STACK_REGISTERS;
19use isa::op_stack::NumberOfWords;
20use isa::op_stack::OpStackElement;
21use itertools::Itertools;
22use itertools::izip;
23use strum::EnumCount;
24use twenty_first::math::x_field_element::EXTENSION_DEGREE;
25use twenty_first::prelude::*;
26
27use crate::AIR;
28use crate::challenge_id::ChallengeId;
29use crate::cross_table_argument::CrossTableArg;
30use crate::cross_table_argument::EvalArg;
31use crate::cross_table_argument::LookupArg;
32use crate::cross_table_argument::PermArg;
33use crate::table;
34use crate::table_column::MasterAuxColumn;
35use crate::table_column::MasterMainColumn;
36
37pub const NUM_HELPER_VARIABLE_REGISTERS: usize = 6;
39
40#[derive(Debug, Copy, Clone, Eq, PartialEq)]
41pub struct ProcessorTable;
42
43impl crate::private::Seal for ProcessorTable {}
44
45type MainColumn = <ProcessorTable as AIR>::MainColumn;
46type AuxColumn = <ProcessorTable as AIR>::AuxColumn;
47
48impl ProcessorTable {
49 pub fn op_stack_column_by_index(index: usize) -> MainColumn {
53 match index {
54 0 => MainColumn::ST0,
55 1 => MainColumn::ST1,
56 2 => MainColumn::ST2,
57 3 => MainColumn::ST3,
58 4 => MainColumn::ST4,
59 5 => MainColumn::ST5,
60 6 => MainColumn::ST6,
61 7 => MainColumn::ST7,
62 8 => MainColumn::ST8,
63 9 => MainColumn::ST9,
64 10 => MainColumn::ST10,
65 11 => MainColumn::ST11,
66 12 => MainColumn::ST12,
67 13 => MainColumn::ST13,
68 14 => MainColumn::ST14,
69 15 => MainColumn::ST15,
70 _ => panic!("Op Stack column index must be in [0, 15], not {index}"),
71 }
72 }
73}
74
75impl AIR for ProcessorTable {
76 type MainColumn = crate::table_column::ProcessorMainColumn;
77 type AuxColumn = crate::table_column::ProcessorAuxColumn;
78
79 fn initial_constraints(
80 circuit_builder: &ConstraintCircuitBuilder<SingleRowIndicator>,
81 ) -> Vec<ConstraintCircuitMonad<SingleRowIndicator>> {
82 let constant = |c: u32| circuit_builder.b_constant(c);
83 let x_constant = |x| circuit_builder.x_constant(x);
84 let challenge = |c| circuit_builder.challenge(c);
85 let main_row = |col: MainColumn| circuit_builder.input(Main(col.master_main_index()));
86 let aux_row = |col: AuxColumn| circuit_builder.input(Aux(col.master_aux_index()));
87
88 let clk_is_0 = main_row(MainColumn::CLK);
89 let ip_is_0 = main_row(MainColumn::IP);
90 let jsp_is_0 = main_row(MainColumn::JSP);
91 let jso_is_0 = main_row(MainColumn::JSO);
92 let jsd_is_0 = main_row(MainColumn::JSD);
93 let st0_is_0 = main_row(MainColumn::ST0);
94 let st1_is_0 = main_row(MainColumn::ST1);
95 let st2_is_0 = main_row(MainColumn::ST2);
96 let st3_is_0 = main_row(MainColumn::ST3);
97 let st4_is_0 = main_row(MainColumn::ST4);
98 let st5_is_0 = main_row(MainColumn::ST5);
99 let st6_is_0 = main_row(MainColumn::ST6);
100 let st7_is_0 = main_row(MainColumn::ST7);
101 let st8_is_0 = main_row(MainColumn::ST8);
102 let st9_is_0 = main_row(MainColumn::ST9);
103 let st10_is_0 = main_row(MainColumn::ST10);
104 let op_stack_pointer_is_16 = main_row(MainColumn::OpStackPointer) - constant(16);
105
106 let program_digest: [_; Digest::LEN] = [
109 main_row(MainColumn::ST11),
110 main_row(MainColumn::ST12),
111 main_row(MainColumn::ST13),
112 main_row(MainColumn::ST14),
113 main_row(MainColumn::ST15),
114 ];
115 let compressed_program_digest = program_digest.into_iter().fold(
116 circuit_builder.x_constant(EvalArg::default_initial()),
117 |acc, digest_element| {
118 acc * challenge(ChallengeId::CompressProgramDigestIndeterminate) + digest_element
119 },
120 );
121 let compressed_program_digest_is_expected_program_digest =
122 compressed_program_digest - challenge(ChallengeId::CompressedProgramDigest);
123
124 let running_evaluation_for_standard_input_is_initialized_correctly =
129 aux_row(AuxColumn::InputTableEvalArg) - x_constant(EvalArg::default_initial());
130
131 let instruction_lookup_indeterminate =
133 challenge(ChallengeId::InstructionLookupIndeterminate);
134 let instruction_ci_weight = challenge(ChallengeId::ProgramInstructionWeight);
135 let instruction_nia_weight = challenge(ChallengeId::ProgramNextInstructionWeight);
136 let compressed_row_for_instruction_lookup = instruction_ci_weight
137 * main_row(MainColumn::CI)
138 + instruction_nia_weight * main_row(MainColumn::NIA);
139 let instruction_lookup_log_derivative_is_initialized_correctly =
140 (aux_row(AuxColumn::InstructionLookupClientLogDerivative)
141 - x_constant(LookupArg::default_initial()))
142 * (instruction_lookup_indeterminate - compressed_row_for_instruction_lookup)
143 - constant(1);
144
145 let running_evaluation_for_standard_output_is_initialized_correctly =
147 aux_row(AuxColumn::OutputTableEvalArg) - x_constant(EvalArg::default_initial());
148
149 let running_product_for_op_stack_table_is_initialized_correctly =
150 aux_row(AuxColumn::OpStackTablePermArg) - x_constant(PermArg::default_initial());
151
152 let running_product_for_ram_table_is_initialized_correctly =
154 aux_row(AuxColumn::RamTablePermArg) - x_constant(PermArg::default_initial());
155
156 let jump_stack_indeterminate = challenge(ChallengeId::JumpStackIndeterminate);
158 let jump_stack_ci_weight = challenge(ChallengeId::JumpStackCiWeight);
159 let compressed_row_for_jump_stack_table = jump_stack_ci_weight * main_row(MainColumn::CI);
161 let running_product_for_jump_stack_table_is_initialized_correctly =
162 aux_row(AuxColumn::JumpStackTablePermArg)
163 - x_constant(PermArg::default_initial())
164 * (jump_stack_indeterminate - compressed_row_for_jump_stack_table);
165
166 let clock_jump_diff_lookup_log_derivative_is_initialized_correctly =
173 aux_row(AuxColumn::ClockJumpDifferenceLookupServerLogDerivative)
174 * challenge(ChallengeId::ClockJumpDifferenceLookupIndeterminate)
175 - main_row(MainColumn::ClockJumpDifferenceLookupMultiplicity);
176
177 let hash_selector = main_row(MainColumn::CI) - constant(Instruction::Hash.opcode());
179 let hash_deselector = instruction_deselector_single_row(circuit_builder, Instruction::Hash);
180 let hash_input_indeterminate = challenge(ChallengeId::HashInputIndeterminate);
181 let compressed_row = constant(0);
184 let running_evaluation_hash_input_has_absorbed_first_row =
185 aux_row(AuxColumn::HashInputEvalArg)
186 - hash_input_indeterminate * x_constant(EvalArg::default_initial())
187 - compressed_row;
188 let running_evaluation_hash_input_is_default_initial =
189 aux_row(AuxColumn::HashInputEvalArg) - x_constant(EvalArg::default_initial());
190 let running_evaluation_hash_input_is_initialized_correctly = hash_selector
191 * running_evaluation_hash_input_is_default_initial
192 + hash_deselector * running_evaluation_hash_input_has_absorbed_first_row;
193
194 let running_evaluation_hash_digest_is_initialized_correctly =
196 aux_row(AuxColumn::HashDigestEvalArg) - x_constant(EvalArg::default_initial());
197
198 let running_evaluation_sponge_absorb_is_initialized_correctly =
200 aux_row(AuxColumn::SpongeEvalArg) - x_constant(EvalArg::default_initial());
201
202 let running_sum_log_derivative_for_u32_table_is_initialized_correctly =
204 aux_row(AuxColumn::U32LookupClientLogDerivative)
205 - x_constant(LookupArg::default_initial());
206
207 vec![
208 clk_is_0,
209 ip_is_0,
210 jsp_is_0,
211 jso_is_0,
212 jsd_is_0,
213 st0_is_0,
214 st1_is_0,
215 st2_is_0,
216 st3_is_0,
217 st4_is_0,
218 st5_is_0,
219 st6_is_0,
220 st7_is_0,
221 st8_is_0,
222 st9_is_0,
223 st10_is_0,
224 compressed_program_digest_is_expected_program_digest,
225 op_stack_pointer_is_16,
226 running_evaluation_for_standard_input_is_initialized_correctly,
227 instruction_lookup_log_derivative_is_initialized_correctly,
228 running_evaluation_for_standard_output_is_initialized_correctly,
229 running_product_for_op_stack_table_is_initialized_correctly,
230 running_product_for_ram_table_is_initialized_correctly,
231 running_product_for_jump_stack_table_is_initialized_correctly,
232 clock_jump_diff_lookup_log_derivative_is_initialized_correctly,
233 running_evaluation_hash_input_is_initialized_correctly,
234 running_evaluation_hash_digest_is_initialized_correctly,
235 running_evaluation_sponge_absorb_is_initialized_correctly,
236 running_sum_log_derivative_for_u32_table_is_initialized_correctly,
237 ]
238 }
239
240 fn consistency_constraints(
241 circuit_builder: &ConstraintCircuitBuilder<SingleRowIndicator>,
242 ) -> Vec<ConstraintCircuitMonad<SingleRowIndicator>> {
243 let constant = |c: u32| circuit_builder.b_constant(c);
244 let main_row = |col: MainColumn| circuit_builder.input(Main(col.master_main_index()));
245
246 let ib_composition = main_row(MainColumn::IB0)
249 + constant(1 << 1) * main_row(MainColumn::IB1)
250 + constant(1 << 2) * main_row(MainColumn::IB2)
251 + constant(1 << 3) * main_row(MainColumn::IB3)
252 + constant(1 << 4) * main_row(MainColumn::IB4)
253 + constant(1 << 5) * main_row(MainColumn::IB5)
254 + constant(1 << 6) * main_row(MainColumn::IB6);
255 let ci_corresponds_to_ib0_thru_ib7 = main_row(MainColumn::CI) - ib_composition;
256
257 let ib0_is_bit = main_row(MainColumn::IB0) * (main_row(MainColumn::IB0) - constant(1));
258 let ib1_is_bit = main_row(MainColumn::IB1) * (main_row(MainColumn::IB1) - constant(1));
259 let ib2_is_bit = main_row(MainColumn::IB2) * (main_row(MainColumn::IB2) - constant(1));
260 let ib3_is_bit = main_row(MainColumn::IB3) * (main_row(MainColumn::IB3) - constant(1));
261 let ib4_is_bit = main_row(MainColumn::IB4) * (main_row(MainColumn::IB4) - constant(1));
262 let ib5_is_bit = main_row(MainColumn::IB5) * (main_row(MainColumn::IB5) - constant(1));
263 let ib6_is_bit = main_row(MainColumn::IB6) * (main_row(MainColumn::IB6) - constant(1));
264 let is_padding_is_bit =
265 main_row(MainColumn::IsPadding) * (main_row(MainColumn::IsPadding) - constant(1));
266
267 let clock_jump_diff_lookup_multiplicity_is_0_in_padding_rows =
272 main_row(MainColumn::IsPadding)
273 * (main_row(MainColumn::CLK) - constant(1))
274 * main_row(MainColumn::ClockJumpDifferenceLookupMultiplicity);
275
276 vec![
277 ib0_is_bit,
278 ib1_is_bit,
279 ib2_is_bit,
280 ib3_is_bit,
281 ib4_is_bit,
282 ib5_is_bit,
283 ib6_is_bit,
284 is_padding_is_bit,
285 ci_corresponds_to_ib0_thru_ib7,
286 clock_jump_diff_lookup_multiplicity_is_0_in_padding_rows,
287 ]
288 }
289
290 fn transition_constraints(
291 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
292 ) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
293 let constant = |c: u64| circuit_builder.b_constant(c);
294 let curr_main_row =
295 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
296 let next_main_row =
297 |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
298
299 let clk_increases_by_1 =
301 next_main_row(MainColumn::CLK) - curr_main_row(MainColumn::CLK) - constant(1);
302 let is_padding_is_0_or_does_not_change = curr_main_row(MainColumn::IsPadding)
303 * (next_main_row(MainColumn::IsPadding) - curr_main_row(MainColumn::IsPadding));
304
305 let instruction_independent_constraints =
306 vec![clk_increases_by_1, is_padding_is_0_or_does_not_change];
307
308 let transition_constraints_for_instruction =
310 |instr| transition_constraints_for_instruction(circuit_builder, instr);
311 let all_instructions_and_their_transition_constraints =
312 ALL_INSTRUCTIONS.map(|instr| (instr, transition_constraints_for_instruction(instr)));
313 let deselected_transition_constraints = combine_instruction_constraints_with_deselectors(
314 circuit_builder,
315 all_instructions_and_their_transition_constraints,
316 );
317
318 let doubly_deselected_transition_constraints =
321 combine_transition_constraints_with_padding_constraints(
322 circuit_builder,
323 deselected_transition_constraints,
324 );
325
326 let table_linking_constraints = vec![
327 log_derivative_accumulates_clk_next(circuit_builder),
328 log_derivative_for_instruction_lookup_updates_correctly(circuit_builder),
329 running_product_for_jump_stack_table_updates_correctly(circuit_builder),
330 running_evaluation_hash_input_updates_correctly(circuit_builder),
331 running_evaluation_hash_digest_updates_correctly(circuit_builder),
332 running_evaluation_sponge_updates_correctly(circuit_builder),
333 log_derivative_with_u32_table_updates_correctly(circuit_builder),
334 ];
335
336 [
337 instruction_independent_constraints,
338 doubly_deselected_transition_constraints,
339 table_linking_constraints,
340 ]
341 .concat()
342 }
343
344 fn terminal_constraints(
345 circuit_builder: &ConstraintCircuitBuilder<SingleRowIndicator>,
346 ) -> Vec<ConstraintCircuitMonad<SingleRowIndicator>> {
347 let main_row = |col: MainColumn| circuit_builder.input(Main(col.master_main_index()));
348 let constant = |c| circuit_builder.b_constant(c);
349
350 let last_ci_is_halt = main_row(MainColumn::CI) - constant(Instruction::Halt.opcode_b());
351
352 vec![last_ci_is_halt]
353 }
354}
355
356fn combine_instruction_constraints_with_deselectors(
374 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
375 instr_tc_polys_tuples: [(Instruction, Vec<ConstraintCircuitMonad<DualRowIndicator>>);
376 Instruction::COUNT],
377) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
378 let (all_instructions, all_tc_polys_for_all_instructions): (Vec<_>, Vec<_>) =
379 instr_tc_polys_tuples.into_iter().unzip();
380
381 let all_instruction_deselectors = all_instructions
382 .into_iter()
383 .map(|instr| instruction_deselector_current_row(circuit_builder, instr))
384 .collect_vec();
385
386 let max_number_of_constraints = all_tc_polys_for_all_instructions
387 .iter()
388 .map(|tc_polys_for_instr| tc_polys_for_instr.len())
389 .max()
390 .unwrap();
391
392 let zero_poly = circuit_builder.b_constant(0);
393 let all_tc_polys_for_all_instructions_transposed = (0..max_number_of_constraints)
394 .map(|idx| {
395 all_tc_polys_for_all_instructions
396 .iter()
397 .map(|tc_polys_for_instr| tc_polys_for_instr.get(idx).unwrap_or(&zero_poly))
398 .collect_vec()
399 })
400 .collect_vec();
401
402 all_tc_polys_for_all_instructions_transposed
403 .into_iter()
404 .map(|row| {
405 all_instruction_deselectors
406 .clone()
407 .into_iter()
408 .zip(row)
409 .map(|(deselector, instruction_tc)| deselector * instruction_tc.to_owned())
410 .sum()
411 })
412 .collect_vec()
413}
414
415fn combine_transition_constraints_with_padding_constraints(
416 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
417 instruction_transition_constraints: Vec<ConstraintCircuitMonad<DualRowIndicator>>,
418) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
419 let constant = |c: u64| circuit_builder.b_constant(c);
420 let curr_main_row =
421 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
422 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
423
424 let padding_row_transition_constraints = [
425 vec![
426 next_main_row(MainColumn::IP) - curr_main_row(MainColumn::IP),
427 next_main_row(MainColumn::CI) - curr_main_row(MainColumn::CI),
428 next_main_row(MainColumn::NIA) - curr_main_row(MainColumn::NIA),
429 ],
430 instruction_group_keep_jump_stack(circuit_builder),
431 instruction_group_keep_op_stack(circuit_builder),
432 instruction_group_no_ram(circuit_builder),
433 instruction_group_no_io(circuit_builder),
434 ]
435 .concat();
436
437 let padding_row_deselector = constant(1) - next_main_row(MainColumn::IsPadding);
438 let padding_row_selector = next_main_row(MainColumn::IsPadding);
439
440 let max_number_of_constraints = max(
441 instruction_transition_constraints.len(),
442 padding_row_transition_constraints.len(),
443 );
444
445 (0..max_number_of_constraints)
446 .map(|idx| {
447 let instruction_constraint = instruction_transition_constraints
448 .get(idx)
449 .unwrap_or(&constant(0))
450 .to_owned();
451 let padding_constraint = padding_row_transition_constraints
452 .get(idx)
453 .unwrap_or(&constant(0))
454 .to_owned();
455
456 instruction_constraint * padding_row_deselector.clone()
457 + padding_constraint * padding_row_selector.clone()
458 })
459 .collect_vec()
460}
461
462fn instruction_group_decompose_arg(
463 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
464) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
465 let constant = |c: u32| circuit_builder.b_constant(c);
466 let curr_main_row =
467 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
468
469 let hv0_is_a_bit =
470 curr_main_row(MainColumn::HV0) * (curr_main_row(MainColumn::HV0) - constant(1));
471 let hv1_is_a_bit =
472 curr_main_row(MainColumn::HV1) * (curr_main_row(MainColumn::HV1) - constant(1));
473 let hv2_is_a_bit =
474 curr_main_row(MainColumn::HV2) * (curr_main_row(MainColumn::HV2) - constant(1));
475 let hv3_is_a_bit =
476 curr_main_row(MainColumn::HV3) * (curr_main_row(MainColumn::HV3) - constant(1));
477
478 let helper_variables_are_binary_decomposition_of_nia = curr_main_row(MainColumn::NIA)
479 - constant(8) * curr_main_row(MainColumn::HV3)
480 - constant(4) * curr_main_row(MainColumn::HV2)
481 - constant(2) * curr_main_row(MainColumn::HV1)
482 - curr_main_row(MainColumn::HV0);
483
484 vec![
485 hv0_is_a_bit,
486 hv1_is_a_bit,
487 hv2_is_a_bit,
488 hv3_is_a_bit,
489 helper_variables_are_binary_decomposition_of_nia,
490 ]
491}
492
493fn instruction_group_no_ram(
496 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
497) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
498 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
499 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
500
501 vec![next_aux_row(AuxColumn::RamTablePermArg) - curr_aux_row(AuxColumn::RamTablePermArg)]
502}
503
504fn instruction_group_no_io(
505 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
506) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
507 vec![
508 running_evaluation_for_standard_input_remains_unchanged(circuit_builder),
509 running_evaluation_for_standard_output_remains_unchanged(circuit_builder),
510 ]
511}
512
513fn instruction_group_op_stack_remains_except_top_n(
516 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
517 n: usize,
518) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
519 assert!(n <= NUM_OP_STACK_REGISTERS);
520
521 let curr_row = |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
522 let next_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
523
524 let stack = (0..OpStackElement::COUNT)
525 .map(ProcessorTable::op_stack_column_by_index)
526 .collect_vec();
527 let next_stack = stack.iter().map(|&st| next_row(st)).collect_vec();
528 let curr_stack = stack.iter().map(|&st| curr_row(st)).collect_vec();
529
530 let compress_stack_except_top_n = |stack: Vec<_>| -> ConstraintCircuitMonad<_> {
531 assert_eq!(NUM_OP_STACK_REGISTERS, stack.len());
532 let weight = |i| circuit_builder.challenge(stack_weight_by_index(i));
533 stack
534 .into_iter()
535 .enumerate()
536 .skip(n)
537 .map(|(i, st)| weight(i) * st)
538 .sum()
539 };
540
541 let all_but_n_top_elements_remain =
542 compress_stack_except_top_n(next_stack) - compress_stack_except_top_n(curr_stack);
543
544 let mut constraints = instruction_group_keep_op_stack_height(circuit_builder);
545 constraints.push(all_but_n_top_elements_remain);
546 constraints
547}
548
549fn instruction_group_keep_op_stack(
551 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
552) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
553 instruction_group_op_stack_remains_except_top_n(circuit_builder, 0)
554}
555
556fn instruction_group_keep_op_stack_height(
560 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
561) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
562 let op_stack_pointer_curr =
563 circuit_builder.input(CurrentMain(MainColumn::OpStackPointer.master_main_index()));
564 let op_stack_pointer_next =
565 circuit_builder.input(NextMain(MainColumn::OpStackPointer.master_main_index()));
566 let osp_remains_unchanged = op_stack_pointer_next - op_stack_pointer_curr;
567
568 let op_stack_table_perm_arg_curr = circuit_builder.input(CurrentAux(
569 AuxColumn::OpStackTablePermArg.master_aux_index(),
570 ));
571 let op_stack_table_perm_arg_next =
572 circuit_builder.input(NextAux(AuxColumn::OpStackTablePermArg.master_aux_index()));
573 let perm_arg_remains_unchanged = op_stack_table_perm_arg_next - op_stack_table_perm_arg_curr;
574
575 vec![osp_remains_unchanged, perm_arg_remains_unchanged]
576}
577
578fn instruction_group_grow_op_stack_and_top_two_elements_unconstrained(
579 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
580) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
581 let constant = |c: u32| circuit_builder.b_constant(c);
582 let curr_main_row =
583 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
584 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
585
586 vec![
587 next_main_row(MainColumn::ST2) - curr_main_row(MainColumn::ST1),
588 next_main_row(MainColumn::ST3) - curr_main_row(MainColumn::ST2),
589 next_main_row(MainColumn::ST4) - curr_main_row(MainColumn::ST3),
590 next_main_row(MainColumn::ST5) - curr_main_row(MainColumn::ST4),
591 next_main_row(MainColumn::ST6) - curr_main_row(MainColumn::ST5),
592 next_main_row(MainColumn::ST7) - curr_main_row(MainColumn::ST6),
593 next_main_row(MainColumn::ST8) - curr_main_row(MainColumn::ST7),
594 next_main_row(MainColumn::ST9) - curr_main_row(MainColumn::ST8),
595 next_main_row(MainColumn::ST10) - curr_main_row(MainColumn::ST9),
596 next_main_row(MainColumn::ST11) - curr_main_row(MainColumn::ST10),
597 next_main_row(MainColumn::ST12) - curr_main_row(MainColumn::ST11),
598 next_main_row(MainColumn::ST13) - curr_main_row(MainColumn::ST12),
599 next_main_row(MainColumn::ST14) - curr_main_row(MainColumn::ST13),
600 next_main_row(MainColumn::ST15) - curr_main_row(MainColumn::ST14),
601 next_main_row(MainColumn::OpStackPointer)
602 - curr_main_row(MainColumn::OpStackPointer)
603 - constant(1),
604 running_product_op_stack_accounts_for_growing_stack_by(circuit_builder, 1),
605 ]
606}
607
608fn instruction_group_grow_op_stack(
609 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
610) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
611 let curr_main_row =
612 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
613 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
614
615 let specific_constraints =
616 vec![next_main_row(MainColumn::ST1) - curr_main_row(MainColumn::ST0)];
617 let inherited_constraints =
618 instruction_group_grow_op_stack_and_top_two_elements_unconstrained(circuit_builder);
619
620 [specific_constraints, inherited_constraints].concat()
621}
622
623fn instruction_group_op_stack_shrinks_and_top_three_elements_unconstrained(
624 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
625) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
626 let constant = |c: u32| circuit_builder.b_constant(c);
627 let curr_main_row =
628 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
629 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
630
631 vec![
632 next_main_row(MainColumn::ST3) - curr_main_row(MainColumn::ST4),
633 next_main_row(MainColumn::ST4) - curr_main_row(MainColumn::ST5),
634 next_main_row(MainColumn::ST5) - curr_main_row(MainColumn::ST6),
635 next_main_row(MainColumn::ST6) - curr_main_row(MainColumn::ST7),
636 next_main_row(MainColumn::ST7) - curr_main_row(MainColumn::ST8),
637 next_main_row(MainColumn::ST8) - curr_main_row(MainColumn::ST9),
638 next_main_row(MainColumn::ST9) - curr_main_row(MainColumn::ST10),
639 next_main_row(MainColumn::ST10) - curr_main_row(MainColumn::ST11),
640 next_main_row(MainColumn::ST11) - curr_main_row(MainColumn::ST12),
641 next_main_row(MainColumn::ST12) - curr_main_row(MainColumn::ST13),
642 next_main_row(MainColumn::ST13) - curr_main_row(MainColumn::ST14),
643 next_main_row(MainColumn::ST14) - curr_main_row(MainColumn::ST15),
644 next_main_row(MainColumn::OpStackPointer) - curr_main_row(MainColumn::OpStackPointer)
645 + constant(1),
646 running_product_op_stack_accounts_for_shrinking_stack_by(circuit_builder, 1),
647 ]
648}
649
650fn instruction_group_binop(
651 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
652) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
653 let curr_main_row =
654 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
655 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
656
657 let specific_constraints = vec![
658 next_main_row(MainColumn::ST1) - curr_main_row(MainColumn::ST2),
659 next_main_row(MainColumn::ST2) - curr_main_row(MainColumn::ST3),
660 ];
661 let inherited_constraints =
662 instruction_group_op_stack_shrinks_and_top_three_elements_unconstrained(circuit_builder);
663
664 [specific_constraints, inherited_constraints].concat()
665}
666
667fn instruction_group_shrink_op_stack(
668 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
669) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
670 let curr_main_row =
671 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
672 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
673
674 let specific_constraints =
675 vec![next_main_row(MainColumn::ST0) - curr_main_row(MainColumn::ST1)];
676 let inherited_constraints = instruction_group_binop(circuit_builder);
677
678 [specific_constraints, inherited_constraints].concat()
679}
680
681fn instruction_group_keep_jump_stack(
682 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
683) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
684 let curr_main_row =
685 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
686 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
687
688 let jsp_does_not_change = next_main_row(MainColumn::JSP) - curr_main_row(MainColumn::JSP);
689 let jso_does_not_change = next_main_row(MainColumn::JSO) - curr_main_row(MainColumn::JSO);
690 let jsd_does_not_change = next_main_row(MainColumn::JSD) - curr_main_row(MainColumn::JSD);
691
692 vec![
693 jsp_does_not_change,
694 jso_does_not_change,
695 jsd_does_not_change,
696 ]
697}
698
699fn instruction_group_step_1(
701 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
702) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
703 let constant = |c: u32| circuit_builder.b_constant(c);
704 let curr_main_row =
705 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
706 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
707
708 let instruction_pointer_increases_by_one =
709 next_main_row(MainColumn::IP) - curr_main_row(MainColumn::IP) - constant(1);
710 [
711 instruction_group_keep_jump_stack(circuit_builder),
712 vec![instruction_pointer_increases_by_one],
713 ]
714 .concat()
715}
716
717fn instruction_group_step_2(
719 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
720) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
721 let constant = |c: u32| circuit_builder.b_constant(c);
722 let curr_main_row =
723 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
724 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
725
726 let instruction_pointer_increases_by_two =
727 next_main_row(MainColumn::IP) - curr_main_row(MainColumn::IP) - constant(2);
728 [
729 instruction_group_keep_jump_stack(circuit_builder),
730 vec![instruction_pointer_increases_by_two],
731 ]
732 .concat()
733}
734
735fn instruction_deselector_common_functionality<II: InputIndicator>(
739 circuit_builder: &ConstraintCircuitBuilder<II>,
740 instruction: Instruction,
741 instruction_bit_polynomials: [ConstraintCircuitMonad<II>; InstructionBit::COUNT],
742) -> ConstraintCircuitMonad<II> {
743 let one = || circuit_builder.b_constant(1);
744
745 let selector_bits: [_; InstructionBit::COUNT] = [
746 instruction.ib(InstructionBit::IB0),
747 instruction.ib(InstructionBit::IB1),
748 instruction.ib(InstructionBit::IB2),
749 instruction.ib(InstructionBit::IB3),
750 instruction.ib(InstructionBit::IB4),
751 instruction.ib(InstructionBit::IB5),
752 instruction.ib(InstructionBit::IB6),
753 ];
754 let deselector_polynomials = selector_bits.map(|b| one() - circuit_builder.b_constant(b));
755
756 instruction_bit_polynomials
757 .into_iter()
758 .zip_eq(deselector_polynomials)
759 .map(|(instruction_bit_poly, deselector_poly)| instruction_bit_poly - deselector_poly)
760 .fold(one(), ConstraintCircuitMonad::mul)
761}
762
763fn instruction_deselector_current_row(
766 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
767 instruction: Instruction,
768) -> ConstraintCircuitMonad<DualRowIndicator> {
769 let curr_main_row =
770 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
771
772 let instruction_bit_polynomials = [
773 curr_main_row(MainColumn::IB0),
774 curr_main_row(MainColumn::IB1),
775 curr_main_row(MainColumn::IB2),
776 curr_main_row(MainColumn::IB3),
777 curr_main_row(MainColumn::IB4),
778 curr_main_row(MainColumn::IB5),
779 curr_main_row(MainColumn::IB6),
780 ];
781
782 instruction_deselector_common_functionality(
783 circuit_builder,
784 instruction,
785 instruction_bit_polynomials,
786 )
787}
788
789fn instruction_deselector_next_row(
792 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
793 instruction: Instruction,
794) -> ConstraintCircuitMonad<DualRowIndicator> {
795 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
796
797 let instruction_bit_polynomials = [
798 next_main_row(MainColumn::IB0),
799 next_main_row(MainColumn::IB1),
800 next_main_row(MainColumn::IB2),
801 next_main_row(MainColumn::IB3),
802 next_main_row(MainColumn::IB4),
803 next_main_row(MainColumn::IB5),
804 next_main_row(MainColumn::IB6),
805 ];
806
807 instruction_deselector_common_functionality(
808 circuit_builder,
809 instruction,
810 instruction_bit_polynomials,
811 )
812}
813
814fn instruction_deselector_single_row(
817 circuit_builder: &ConstraintCircuitBuilder<SingleRowIndicator>,
818 instruction: Instruction,
819) -> ConstraintCircuitMonad<SingleRowIndicator> {
820 let main_row = |col: MainColumn| circuit_builder.input(Main(col.master_main_index()));
821
822 let instruction_bit_polynomials = [
823 main_row(MainColumn::IB0),
824 main_row(MainColumn::IB1),
825 main_row(MainColumn::IB2),
826 main_row(MainColumn::IB3),
827 main_row(MainColumn::IB4),
828 main_row(MainColumn::IB5),
829 main_row(MainColumn::IB6),
830 ];
831
832 instruction_deselector_common_functionality(
833 circuit_builder,
834 instruction,
835 instruction_bit_polynomials,
836 )
837}
838
839fn instruction_pop(
840 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
841) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
842 [
843 instruction_group_step_2(circuit_builder),
844 instruction_group_decompose_arg(circuit_builder),
845 stack_shrinks_by_any_of(circuit_builder, &NumberOfWords::legal_values()),
846 prohibit_any_illegal_number_of_words(circuit_builder),
847 instruction_group_no_ram(circuit_builder),
848 instruction_group_no_io(circuit_builder),
849 ]
850 .concat()
851}
852
853fn instruction_push(
854 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
855) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
856 let curr_main_row =
857 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
858 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
859
860 let specific_constraints =
861 vec![next_main_row(MainColumn::ST0) - curr_main_row(MainColumn::NIA)];
862 [
863 specific_constraints,
864 instruction_group_grow_op_stack(circuit_builder),
865 instruction_group_step_2(circuit_builder),
866 instruction_group_no_ram(circuit_builder),
867 instruction_group_no_io(circuit_builder),
868 ]
869 .concat()
870}
871
872fn instruction_divine(
873 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
874) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
875 [
876 instruction_group_step_2(circuit_builder),
877 instruction_group_decompose_arg(circuit_builder),
878 stack_grows_by_any_of(circuit_builder, &NumberOfWords::legal_values()),
879 prohibit_any_illegal_number_of_words(circuit_builder),
880 instruction_group_no_ram(circuit_builder),
881 instruction_group_no_io(circuit_builder),
882 ]
883 .concat()
884}
885
886fn instruction_pick(
887 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
888) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
889 let curr_row = |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
890 let next_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
891
892 let stack = (0..OpStackElement::COUNT)
893 .map(ProcessorTable::op_stack_column_by_index)
894 .collect_vec();
895 let stack_with_picked_i = |i| {
896 let mut stack = stack.clone();
897 let new_top = stack.remove(i);
898 stack.insert(0, new_top);
899 stack.into_iter()
900 };
901
902 let next_stack = stack.iter().map(|&st| next_row(st)).collect_vec();
903 let curr_stack_with_picked_i = |i| stack_with_picked_i(i).map(curr_row).collect_vec();
904
905 let compress = |stack: Vec<_>| -> ConstraintCircuitMonad<_> {
906 assert_eq!(OpStackElement::COUNT, stack.len());
907 let weight = |i| circuit_builder.challenge(stack_weight_by_index(i));
908 let enumerated_stack = stack.into_iter().enumerate();
909 enumerated_stack.map(|(i, st)| weight(i) * st).sum()
910 };
911
912 let next_stack_is_current_stack_with_picked_i = |i| {
913 indicator_polynomial(circuit_builder, i)
914 * (compress(next_stack.clone()) - compress(curr_stack_with_picked_i(i)))
915 };
916 let next_stack_is_current_stack_with_correct_element_picked = (0..OpStackElement::COUNT)
917 .map(next_stack_is_current_stack_with_picked_i)
918 .sum();
919
920 [
921 vec![next_stack_is_current_stack_with_correct_element_picked],
922 instruction_group_decompose_arg(circuit_builder),
923 instruction_group_step_2(circuit_builder),
924 instruction_group_no_ram(circuit_builder),
925 instruction_group_no_io(circuit_builder),
926 instruction_group_keep_op_stack_height(circuit_builder),
927 ]
928 .concat()
929}
930
931fn instruction_place(
932 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
933) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
934 let curr_row = |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
935 let next_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
936
937 let stack = (0..OpStackElement::COUNT)
938 .map(ProcessorTable::op_stack_column_by_index)
939 .collect_vec();
940 let stack_with_placed_i = |i| {
941 let mut stack = stack.clone();
942 let old_top = stack.remove(0);
943 stack.insert(i, old_top);
944 stack.into_iter()
945 };
946
947 let next_stack = stack.iter().map(|&st| next_row(st)).collect_vec();
948 let curr_stack_with_placed_i = |i| stack_with_placed_i(i).map(curr_row).collect_vec();
949
950 let compress = |stack: Vec<_>| -> ConstraintCircuitMonad<_> {
951 assert_eq!(OpStackElement::COUNT, stack.len());
952 let weight = |i| circuit_builder.challenge(stack_weight_by_index(i));
953 let enumerated_stack = stack.into_iter().enumerate();
954 enumerated_stack.map(|(i, st)| weight(i) * st).sum()
955 };
956
957 let next_stack_is_current_stack_with_placed_i = |i| {
958 indicator_polynomial(circuit_builder, i)
959 * (compress(next_stack.clone()) - compress(curr_stack_with_placed_i(i)))
960 };
961 let next_stack_is_current_stack_with_correct_element_placed = (0..OpStackElement::COUNT)
962 .map(next_stack_is_current_stack_with_placed_i)
963 .sum();
964
965 [
966 vec![next_stack_is_current_stack_with_correct_element_placed],
967 instruction_group_decompose_arg(circuit_builder),
968 instruction_group_step_2(circuit_builder),
969 instruction_group_no_ram(circuit_builder),
970 instruction_group_no_io(circuit_builder),
971 instruction_group_keep_op_stack_height(circuit_builder),
972 ]
973 .concat()
974}
975
976fn instruction_dup(
977 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
978) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
979 let indicator_poly = |idx| indicator_polynomial(circuit_builder, idx);
980 let curr_row = |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
981 let next_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
982
983 let st_column = ProcessorTable::op_stack_column_by_index;
984 let duplicate_element =
985 |i| indicator_poly(i) * (next_row(MainColumn::ST0) - curr_row(st_column(i)));
986 let duplicate_indicated_element = (0..OpStackElement::COUNT).map(duplicate_element).sum();
987
988 [
989 vec![duplicate_indicated_element],
990 instruction_group_decompose_arg(circuit_builder),
991 instruction_group_step_2(circuit_builder),
992 instruction_group_grow_op_stack(circuit_builder),
993 instruction_group_no_ram(circuit_builder),
994 instruction_group_no_io(circuit_builder),
995 ]
996 .concat()
997}
998
999fn instruction_swap(
1000 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1001) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1002 let curr_row = |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1003 let next_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1004
1005 let stack = (0..OpStackElement::COUNT)
1006 .map(ProcessorTable::op_stack_column_by_index)
1007 .collect_vec();
1008 let stack_with_swapped_i = |i| {
1009 let mut stack = stack.clone();
1010 stack.swap(0, i);
1011 stack.into_iter()
1012 };
1013
1014 let next_stack = stack.iter().map(|&st| next_row(st)).collect_vec();
1015 let curr_stack_with_swapped_i = |i| stack_with_swapped_i(i).map(curr_row).collect_vec();
1016 let compress = |stack: Vec<_>| -> ConstraintCircuitMonad<_> {
1017 assert_eq!(OpStackElement::COUNT, stack.len());
1018 let weight = |i| circuit_builder.challenge(stack_weight_by_index(i));
1019 let enumerated_stack = stack.into_iter().enumerate();
1020 enumerated_stack.map(|(i, st)| weight(i) * st).sum()
1021 };
1022
1023 let next_stack_is_current_stack_with_swapped_i = |i| {
1024 indicator_polynomial(circuit_builder, i)
1025 * (compress(next_stack.clone()) - compress(curr_stack_with_swapped_i(i)))
1026 };
1027 let next_stack_is_current_stack_with_correct_element_swapped = (0..OpStackElement::COUNT)
1028 .map(next_stack_is_current_stack_with_swapped_i)
1029 .sum();
1030
1031 [
1032 vec![next_stack_is_current_stack_with_correct_element_swapped],
1033 instruction_group_decompose_arg(circuit_builder),
1034 instruction_group_step_2(circuit_builder),
1035 instruction_group_no_ram(circuit_builder),
1036 instruction_group_no_io(circuit_builder),
1037 instruction_group_keep_op_stack_height(circuit_builder),
1038 ]
1039 .concat()
1040}
1041
1042fn instruction_nop(
1043 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1044) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1045 [
1046 instruction_group_step_1(circuit_builder),
1047 instruction_group_keep_op_stack(circuit_builder),
1048 instruction_group_no_ram(circuit_builder),
1049 instruction_group_no_io(circuit_builder),
1050 ]
1051 .concat()
1052}
1053
1054fn instruction_skiz(
1055 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1056) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1057 let constant = |c: u32| circuit_builder.b_constant(c);
1058 let one = || constant(1);
1059 let curr_main_row =
1060 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1061 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1062
1063 let hv0_is_inverse_of_st0 =
1064 curr_main_row(MainColumn::HV0) * curr_main_row(MainColumn::ST0) - one();
1065 let hv0_is_inverse_of_st0_or_hv0_is_0 =
1066 hv0_is_inverse_of_st0.clone() * curr_main_row(MainColumn::HV0);
1067 let hv0_is_inverse_of_st0_or_st0_is_0 = hv0_is_inverse_of_st0 * curr_main_row(MainColumn::ST0);
1068
1069 let nia_decomposes_to_hvs = curr_main_row(MainColumn::NIA)
1071 - curr_main_row(MainColumn::HV1)
1072 - constant(1 << 1) * curr_main_row(MainColumn::HV2)
1073 - constant(1 << 3) * curr_main_row(MainColumn::HV3)
1074 - constant(1 << 5) * curr_main_row(MainColumn::HV4)
1075 - constant(1 << 7) * curr_main_row(MainColumn::HV5);
1076
1077 let ip_case_1 = (next_main_row(MainColumn::IP) - curr_main_row(MainColumn::IP) - constant(1))
1090 * curr_main_row(MainColumn::ST0);
1091 let ip_case_2 = (next_main_row(MainColumn::IP) - curr_main_row(MainColumn::IP) - constant(2))
1092 * (curr_main_row(MainColumn::ST0) * curr_main_row(MainColumn::HV0) - one())
1093 * (curr_main_row(MainColumn::HV1) - one());
1094 let ip_case_3 = (next_main_row(MainColumn::IP) - curr_main_row(MainColumn::IP) - constant(3))
1095 * (curr_main_row(MainColumn::ST0) * curr_main_row(MainColumn::HV0) - one())
1096 * curr_main_row(MainColumn::HV1);
1097 let ip_incr_by_1_or_2_or_3 = ip_case_1 + ip_case_2 + ip_case_3;
1098
1099 let specific_constraints = vec![
1100 hv0_is_inverse_of_st0_or_hv0_is_0,
1101 hv0_is_inverse_of_st0_or_st0_is_0,
1102 nia_decomposes_to_hvs,
1103 ip_incr_by_1_or_2_or_3,
1104 ];
1105 [
1106 specific_constraints,
1107 next_instruction_range_check_constraints_for_instruction_skiz(circuit_builder),
1108 instruction_group_keep_jump_stack(circuit_builder),
1109 instruction_group_shrink_op_stack(circuit_builder),
1110 instruction_group_no_ram(circuit_builder),
1111 instruction_group_no_io(circuit_builder),
1112 ]
1113 .concat()
1114}
1115
1116fn next_instruction_range_check_constraints_for_instruction_skiz(
1117 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1118) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1119 let constant = |c: u32| circuit_builder.b_constant(c);
1120 let curr_main_row =
1121 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1122
1123 let is_0_or_1 = |var: MainColumn| curr_main_row(var) * (curr_main_row(var) - constant(1));
1124 let is_0_or_1_or_2_or_3 = |var: MainColumn| {
1125 curr_main_row(var)
1126 * (curr_main_row(var) - constant(1))
1127 * (curr_main_row(var) - constant(2))
1128 * (curr_main_row(var) - constant(3))
1129 };
1130
1131 vec![
1132 is_0_or_1(MainColumn::HV1),
1133 is_0_or_1_or_2_or_3(MainColumn::HV2),
1134 is_0_or_1_or_2_or_3(MainColumn::HV3),
1135 is_0_or_1_or_2_or_3(MainColumn::HV4),
1136 is_0_or_1_or_2_or_3(MainColumn::HV5),
1137 ]
1138}
1139
1140fn instruction_call(
1141 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1142) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1143 let constant = |c: u32| circuit_builder.b_constant(c);
1144 let curr_main_row =
1145 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1146 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1147
1148 let jsp_incr_1 = next_main_row(MainColumn::JSP) - curr_main_row(MainColumn::JSP) - constant(1);
1149 let jso_becomes_ip_plus_2 =
1150 next_main_row(MainColumn::JSO) - curr_main_row(MainColumn::IP) - constant(2);
1151 let jsd_becomes_nia = next_main_row(MainColumn::JSD) - curr_main_row(MainColumn::NIA);
1152 let ip_becomes_nia = next_main_row(MainColumn::IP) - curr_main_row(MainColumn::NIA);
1153
1154 let specific_constraints = vec![
1155 jsp_incr_1,
1156 jso_becomes_ip_plus_2,
1157 jsd_becomes_nia,
1158 ip_becomes_nia,
1159 ];
1160 [
1161 specific_constraints,
1162 instruction_group_keep_op_stack(circuit_builder),
1163 instruction_group_no_ram(circuit_builder),
1164 instruction_group_no_io(circuit_builder),
1165 ]
1166 .concat()
1167}
1168
1169fn instruction_return(
1170 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1171) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1172 let constant = |c: u32| circuit_builder.b_constant(c);
1173 let curr_main_row =
1174 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1175 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1176
1177 let jsp_decrements_by_1 =
1178 next_main_row(MainColumn::JSP) - curr_main_row(MainColumn::JSP) + constant(1);
1179 let ip_is_set_to_jso = next_main_row(MainColumn::IP) - curr_main_row(MainColumn::JSO);
1180 let specific_constraints = vec![jsp_decrements_by_1, ip_is_set_to_jso];
1181
1182 [
1183 specific_constraints,
1184 instruction_group_keep_op_stack(circuit_builder),
1185 instruction_group_no_ram(circuit_builder),
1186 instruction_group_no_io(circuit_builder),
1187 ]
1188 .concat()
1189}
1190
1191fn instruction_recurse(
1192 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1193) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1194 let curr_main_row =
1195 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1196 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1197
1198 let ip_becomes_jsd = next_main_row(MainColumn::IP) - curr_main_row(MainColumn::JSD);
1200 let specific_constraints = vec![ip_becomes_jsd];
1201 [
1202 specific_constraints,
1203 instruction_group_keep_jump_stack(circuit_builder),
1204 instruction_group_keep_op_stack(circuit_builder),
1205 instruction_group_no_ram(circuit_builder),
1206 instruction_group_no_io(circuit_builder),
1207 ]
1208 .concat()
1209}
1210
1211fn instruction_recurse_or_return(
1212 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1213) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1214 let one = || circuit_builder.b_constant(1);
1215 let curr_row = |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1216 let next_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1217
1218 let st5_eq_st6 =
1220 || curr_row(MainColumn::HV0) * (curr_row(MainColumn::ST6) - curr_row(MainColumn::ST5));
1221 let st5_neq_st6 = || one() - st5_eq_st6();
1222
1223 let maybe_return = vec![
1224 st5_neq_st6() * curr_row(MainColumn::HV0),
1226 st5_neq_st6() * (curr_row(MainColumn::ST6) - curr_row(MainColumn::ST5)),
1227 st5_neq_st6() * (next_row(MainColumn::IP) - curr_row(MainColumn::JSO)),
1228 st5_neq_st6() * (next_row(MainColumn::JSP) - curr_row(MainColumn::JSP) + one()),
1229 ];
1230 let maybe_recurse = vec![
1231 st5_eq_st6() * (next_row(MainColumn::JSO) - curr_row(MainColumn::JSO)),
1233 st5_eq_st6() * (next_row(MainColumn::JSD) - curr_row(MainColumn::JSD)),
1234 st5_eq_st6() * (next_row(MainColumn::IP) - curr_row(MainColumn::JSD)),
1235 st5_eq_st6() * (next_row(MainColumn::JSP) - curr_row(MainColumn::JSP)),
1236 ];
1237
1238 let constraint_groups = vec![maybe_return, maybe_recurse];
1243 let specific_constraints =
1244 combine_mutually_exclusive_constraint_groups(circuit_builder, constraint_groups);
1245
1246 [
1247 specific_constraints,
1248 instruction_group_keep_op_stack(circuit_builder),
1249 instruction_group_no_ram(circuit_builder),
1250 instruction_group_no_io(circuit_builder),
1251 ]
1252 .concat()
1253}
1254
1255fn instruction_assert(
1256 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1257) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1258 let constant = |c: u32| circuit_builder.b_constant(c);
1259 let curr_main_row =
1260 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1261
1262 let st_0_is_1 = curr_main_row(MainColumn::ST0) - constant(1);
1264
1265 let specific_constraints = vec![st_0_is_1];
1266 [
1267 specific_constraints,
1268 instruction_group_step_1(circuit_builder),
1269 instruction_group_shrink_op_stack(circuit_builder),
1270 instruction_group_no_ram(circuit_builder),
1271 instruction_group_no_io(circuit_builder),
1272 ]
1273 .concat()
1274}
1275
1276fn instruction_halt(
1277 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1278) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1279 let curr_main_row =
1280 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1281 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1282
1283 let halt_is_followed_by_halt = next_main_row(MainColumn::CI) - curr_main_row(MainColumn::CI);
1285
1286 let specific_constraints = vec![halt_is_followed_by_halt];
1287 [
1288 specific_constraints,
1289 instruction_group_step_1(circuit_builder),
1290 instruction_group_keep_op_stack(circuit_builder),
1291 instruction_group_no_ram(circuit_builder),
1292 instruction_group_no_io(circuit_builder),
1293 ]
1294 .concat()
1295}
1296
1297fn instruction_read_mem(
1298 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1299) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1300 [
1301 instruction_group_step_2(circuit_builder),
1302 instruction_group_decompose_arg(circuit_builder),
1303 read_from_ram_any_of(circuit_builder, &NumberOfWords::legal_values()),
1304 prohibit_any_illegal_number_of_words(circuit_builder),
1305 instruction_group_no_io(circuit_builder),
1306 ]
1307 .concat()
1308}
1309
1310fn instruction_write_mem(
1311 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1312) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1313 [
1314 instruction_group_step_2(circuit_builder),
1315 instruction_group_decompose_arg(circuit_builder),
1316 write_to_ram_any_of(circuit_builder, &NumberOfWords::legal_values()),
1317 prohibit_any_illegal_number_of_words(circuit_builder),
1318 instruction_group_no_io(circuit_builder),
1319 ]
1320 .concat()
1321}
1322
1323fn instruction_hash(
1325 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1326) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1327 let constant = |c: u32| circuit_builder.b_constant(c);
1328 let curr_main_row =
1329 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1330 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1331
1332 let op_stack_shrinks_by_5_and_top_5_unconstrained = vec![
1333 next_main_row(MainColumn::ST5) - curr_main_row(MainColumn::ST10),
1334 next_main_row(MainColumn::ST6) - curr_main_row(MainColumn::ST11),
1335 next_main_row(MainColumn::ST7) - curr_main_row(MainColumn::ST12),
1336 next_main_row(MainColumn::ST8) - curr_main_row(MainColumn::ST13),
1337 next_main_row(MainColumn::ST9) - curr_main_row(MainColumn::ST14),
1338 next_main_row(MainColumn::ST10) - curr_main_row(MainColumn::ST15),
1339 next_main_row(MainColumn::OpStackPointer) - curr_main_row(MainColumn::OpStackPointer)
1340 + constant(5),
1341 running_product_op_stack_accounts_for_shrinking_stack_by(circuit_builder, 5),
1342 ];
1343
1344 [
1345 instruction_group_step_1(circuit_builder),
1346 op_stack_shrinks_by_5_and_top_5_unconstrained,
1347 instruction_group_no_ram(circuit_builder),
1348 instruction_group_no_io(circuit_builder),
1349 ]
1350 .concat()
1351}
1352
1353fn instruction_merkle_step(
1354 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1355) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1356 [
1357 instruction_merkle_step_shared_constraints(circuit_builder),
1358 instruction_group_op_stack_remains_except_top_n(circuit_builder, 6),
1359 instruction_group_no_ram(circuit_builder),
1360 ]
1361 .concat()
1362}
1363
1364fn instruction_merkle_step_mem(
1365 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1366) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1367 let constant = |c: u32| circuit_builder.b_constant(c);
1368 let stack_weight = |i| circuit_builder.challenge(stack_weight_by_index(i));
1369 let curr = |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1370 let next = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1371
1372 let ram_pointers = [0, 1, 2, 3, 4].map(|i| curr(MainColumn::ST7) + constant(i));
1373 let ram_read_destinations = [
1374 MainColumn::HV0,
1375 MainColumn::HV1,
1376 MainColumn::HV2,
1377 MainColumn::HV3,
1378 MainColumn::HV4,
1379 ]
1380 .map(curr);
1381 let read_from_ram_to_hvs =
1382 read_from_ram_to(circuit_builder, ram_pointers, ram_read_destinations);
1383
1384 let st6_does_not_change = next(MainColumn::ST6) - curr(MainColumn::ST6);
1385 let st7_increments_by_5 = next(MainColumn::ST7) - curr(MainColumn::ST7) - constant(5);
1386 let st6_and_st7_update_correctly =
1387 stack_weight(6) * st6_does_not_change + stack_weight(7) * st7_increments_by_5;
1388
1389 [
1390 vec![st6_and_st7_update_correctly, read_from_ram_to_hvs],
1391 instruction_merkle_step_shared_constraints(circuit_builder),
1392 instruction_group_op_stack_remains_except_top_n(circuit_builder, 8),
1393 ]
1394 .concat()
1395}
1396
1397fn instruction_merkle_step_shared_constraints(
1403 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1404) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1405 let constant = |c: u32| circuit_builder.b_constant(c);
1406 let one = || constant(1);
1407 let curr = |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1408 let next = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1409
1410 let hv5_is_0_or_1 = curr(MainColumn::HV5) * (curr(MainColumn::HV5) - one());
1411 let new_st5_is_previous_st5_div_2 =
1412 constant(2) * next(MainColumn::ST5) + curr(MainColumn::HV5) - curr(MainColumn::ST5);
1413 let update_merkle_tree_node_index = vec![hv5_is_0_or_1, new_st5_is_previous_st5_div_2];
1414
1415 [
1416 update_merkle_tree_node_index,
1417 instruction_group_step_1(circuit_builder),
1418 instruction_group_no_io(circuit_builder),
1419 ]
1420 .concat()
1421}
1422
1423fn instruction_assert_vector(
1424 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1425) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1426 let curr_main_row =
1427 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1428
1429 let specific_constraints = vec![
1430 curr_main_row(MainColumn::ST5) - curr_main_row(MainColumn::ST0),
1431 curr_main_row(MainColumn::ST6) - curr_main_row(MainColumn::ST1),
1432 curr_main_row(MainColumn::ST7) - curr_main_row(MainColumn::ST2),
1433 curr_main_row(MainColumn::ST8) - curr_main_row(MainColumn::ST3),
1434 curr_main_row(MainColumn::ST9) - curr_main_row(MainColumn::ST4),
1435 ];
1436 [
1437 specific_constraints,
1438 instruction_group_step_1(circuit_builder),
1439 constraints_for_shrinking_stack_by(circuit_builder, 5),
1440 instruction_group_no_ram(circuit_builder),
1441 instruction_group_no_io(circuit_builder),
1442 ]
1443 .concat()
1444}
1445
1446fn instruction_sponge_init(
1447 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1448) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1449 [
1450 instruction_group_step_1(circuit_builder),
1451 instruction_group_keep_op_stack(circuit_builder),
1452 instruction_group_no_ram(circuit_builder),
1453 instruction_group_no_io(circuit_builder),
1454 ]
1455 .concat()
1456}
1457
1458fn instruction_sponge_absorb(
1459 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1460) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1461 [
1462 instruction_group_step_1(circuit_builder),
1463 constraints_for_shrinking_stack_by(circuit_builder, 10),
1464 instruction_group_no_ram(circuit_builder),
1465 instruction_group_no_io(circuit_builder),
1466 ]
1467 .concat()
1468}
1469
1470fn instruction_sponge_absorb_mem(
1471 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1472) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1473 let curr_main_row =
1474 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1475 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1476 let constant = |c| circuit_builder.b_constant(c);
1477
1478 let increment_ram_pointer = next_main_row(MainColumn::ST0)
1479 - curr_main_row(MainColumn::ST0)
1480 - constant(tip5::RATE as u32);
1481
1482 [
1483 vec![increment_ram_pointer],
1484 instruction_group_step_1(circuit_builder),
1485 instruction_group_op_stack_remains_except_top_n(circuit_builder, 5),
1486 instruction_group_no_io(circuit_builder),
1487 ]
1488 .concat()
1489}
1490
1491fn instruction_sponge_squeeze(
1492 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1493) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1494 [
1495 instruction_group_step_1(circuit_builder),
1496 constraints_for_growing_stack_by(circuit_builder, 10),
1497 instruction_group_no_ram(circuit_builder),
1498 instruction_group_no_io(circuit_builder),
1499 ]
1500 .concat()
1501}
1502
1503fn instruction_add(
1504 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1505) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1506 let curr_main_row =
1507 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1508 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1509
1510 let specific_constraints = vec![
1511 next_main_row(MainColumn::ST0)
1512 - curr_main_row(MainColumn::ST0)
1513 - curr_main_row(MainColumn::ST1),
1514 ];
1515 [
1516 specific_constraints,
1517 instruction_group_step_1(circuit_builder),
1518 instruction_group_binop(circuit_builder),
1519 instruction_group_no_ram(circuit_builder),
1520 instruction_group_no_io(circuit_builder),
1521 ]
1522 .concat()
1523}
1524
1525fn instruction_addi(
1526 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1527) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1528 let curr_main_row =
1529 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1530 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1531
1532 let specific_constraints = vec![
1533 next_main_row(MainColumn::ST0)
1534 - curr_main_row(MainColumn::ST0)
1535 - curr_main_row(MainColumn::NIA),
1536 ];
1537 [
1538 specific_constraints,
1539 instruction_group_step_2(circuit_builder),
1540 instruction_group_op_stack_remains_except_top_n(circuit_builder, 1),
1541 instruction_group_no_ram(circuit_builder),
1542 instruction_group_no_io(circuit_builder),
1543 ]
1544 .concat()
1545}
1546
1547fn instruction_mul(
1548 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1549) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1550 let curr_main_row =
1551 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1552 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1553
1554 let specific_constraints = vec![
1555 next_main_row(MainColumn::ST0)
1556 - curr_main_row(MainColumn::ST0) * curr_main_row(MainColumn::ST1),
1557 ];
1558 [
1559 specific_constraints,
1560 instruction_group_step_1(circuit_builder),
1561 instruction_group_binop(circuit_builder),
1562 instruction_group_no_ram(circuit_builder),
1563 instruction_group_no_io(circuit_builder),
1564 ]
1565 .concat()
1566}
1567
1568fn instruction_invert(
1569 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1570) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1571 let constant = |c: u32| circuit_builder.b_constant(c);
1572 let one = || constant(1);
1573 let curr_main_row =
1574 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1575 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1576
1577 let specific_constraints =
1578 vec![next_main_row(MainColumn::ST0) * curr_main_row(MainColumn::ST0) - one()];
1579 [
1580 specific_constraints,
1581 instruction_group_step_1(circuit_builder),
1582 instruction_group_op_stack_remains_except_top_n(circuit_builder, 1),
1583 instruction_group_no_ram(circuit_builder),
1584 instruction_group_no_io(circuit_builder),
1585 ]
1586 .concat()
1587}
1588
1589fn instruction_eq(
1590 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1591) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1592 let constant = |c: u32| circuit_builder.b_constant(c);
1593 let one = || constant(1);
1594 let curr_main_row =
1595 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1596 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1597
1598 let st0_eq_st1 = || {
1599 one()
1600 - curr_main_row(MainColumn::HV0)
1601 * (curr_main_row(MainColumn::ST1) - curr_main_row(MainColumn::ST0))
1602 };
1603
1604 let hv0_is_inverse_of_diff_or_hv0_is_0 = curr_main_row(MainColumn::HV0) * st0_eq_st1();
1607
1608 let hv0_is_inverse_of_diff_or_diff_is_0 =
1611 (curr_main_row(MainColumn::ST1) - curr_main_row(MainColumn::ST0)) * st0_eq_st1();
1612
1613 let st0_becomes_1_if_diff_is_not_invertible = next_main_row(MainColumn::ST0) - st0_eq_st1();
1617
1618 let specific_constraints = vec![
1619 hv0_is_inverse_of_diff_or_hv0_is_0,
1620 hv0_is_inverse_of_diff_or_diff_is_0,
1621 st0_becomes_1_if_diff_is_not_invertible,
1622 ];
1623 [
1624 specific_constraints,
1625 instruction_group_step_1(circuit_builder),
1626 instruction_group_binop(circuit_builder),
1627 instruction_group_no_ram(circuit_builder),
1628 instruction_group_no_io(circuit_builder),
1629 ]
1630 .concat()
1631}
1632
1633fn instruction_split(
1634 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1635) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1636 let constant = |c: u64| circuit_builder.b_constant(c);
1637 let one = || constant(1);
1638 let curr_main_row =
1639 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1640 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1641
1642 let st0_decomposes_to_two_32_bit_chunks = curr_main_row(MainColumn::ST0)
1645 - (constant(1 << 32) * next_main_row(MainColumn::ST1) + next_main_row(MainColumn::ST0));
1646
1647 let hv0_holds_inverse_of_chunk_difference_or_low_bits_are_0 = {
1655 let hv0 = curr_main_row(MainColumn::HV0);
1656 let hi = next_main_row(MainColumn::ST1);
1657 let lo = next_main_row(MainColumn::ST0);
1658 let ffff_ffff = constant(0xffff_ffff);
1659
1660 lo * (hv0 * (hi - ffff_ffff) - one())
1661 };
1662
1663 let specific_constraints = vec![
1664 st0_decomposes_to_two_32_bit_chunks,
1665 hv0_holds_inverse_of_chunk_difference_or_low_bits_are_0,
1666 ];
1667 [
1668 specific_constraints,
1669 instruction_group_grow_op_stack_and_top_two_elements_unconstrained(circuit_builder),
1670 instruction_group_step_1(circuit_builder),
1671 instruction_group_no_ram(circuit_builder),
1672 instruction_group_no_io(circuit_builder),
1673 ]
1674 .concat()
1675}
1676
1677fn instruction_lt(
1678 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1679) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1680 [
1681 instruction_group_step_1(circuit_builder),
1682 instruction_group_binop(circuit_builder),
1683 instruction_group_no_ram(circuit_builder),
1684 instruction_group_no_io(circuit_builder),
1685 ]
1686 .concat()
1687}
1688
1689fn instruction_and(
1690 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1691) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1692 [
1693 instruction_group_step_1(circuit_builder),
1694 instruction_group_binop(circuit_builder),
1695 instruction_group_no_ram(circuit_builder),
1696 instruction_group_no_io(circuit_builder),
1697 ]
1698 .concat()
1699}
1700
1701fn instruction_xor(
1702 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1703) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1704 [
1705 instruction_group_step_1(circuit_builder),
1706 instruction_group_binop(circuit_builder),
1707 instruction_group_no_ram(circuit_builder),
1708 instruction_group_no_io(circuit_builder),
1709 ]
1710 .concat()
1711}
1712
1713fn instruction_log_2_floor(
1714 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1715) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1716 [
1717 instruction_group_step_1(circuit_builder),
1718 instruction_group_op_stack_remains_except_top_n(circuit_builder, 1),
1719 instruction_group_no_ram(circuit_builder),
1720 instruction_group_no_io(circuit_builder),
1721 ]
1722 .concat()
1723}
1724
1725fn instruction_pow(
1726 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1727) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1728 [
1729 instruction_group_step_1(circuit_builder),
1730 instruction_group_binop(circuit_builder),
1731 instruction_group_no_ram(circuit_builder),
1732 instruction_group_no_io(circuit_builder),
1733 ]
1734 .concat()
1735}
1736
1737fn instruction_div_mod(
1738 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1739) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1740 let curr_main_row =
1741 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1742 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1743
1744 let numerator_is_quotient_times_denominator_plus_remainder = curr_main_row(MainColumn::ST0)
1746 - curr_main_row(MainColumn::ST1) * next_main_row(MainColumn::ST1)
1747 - next_main_row(MainColumn::ST0);
1748
1749 let specific_constraints = vec![numerator_is_quotient_times_denominator_plus_remainder];
1750 [
1751 specific_constraints,
1752 instruction_group_step_1(circuit_builder),
1753 instruction_group_op_stack_remains_except_top_n(circuit_builder, 2),
1754 instruction_group_no_ram(circuit_builder),
1755 instruction_group_no_io(circuit_builder),
1756 ]
1757 .concat()
1758}
1759
1760fn instruction_pop_count(
1761 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1762) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1763 [
1764 instruction_group_step_1(circuit_builder),
1765 instruction_group_op_stack_remains_except_top_n(circuit_builder, 1),
1766 instruction_group_no_ram(circuit_builder),
1767 instruction_group_no_io(circuit_builder),
1768 ]
1769 .concat()
1770}
1771
1772fn instruction_xx_add(
1773 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1774) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1775 let curr_main_row =
1776 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1777 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1778
1779 let st0_becomes_st0_plus_st3 = next_main_row(MainColumn::ST0)
1780 - curr_main_row(MainColumn::ST0)
1781 - curr_main_row(MainColumn::ST3);
1782 let st1_becomes_st1_plus_st4 = next_main_row(MainColumn::ST1)
1783 - curr_main_row(MainColumn::ST1)
1784 - curr_main_row(MainColumn::ST4);
1785 let st2_becomes_st2_plus_st5 = next_main_row(MainColumn::ST2)
1786 - curr_main_row(MainColumn::ST2)
1787 - curr_main_row(MainColumn::ST5);
1788 let specific_constraints = vec![
1789 st0_becomes_st0_plus_st3,
1790 st1_becomes_st1_plus_st4,
1791 st2_becomes_st2_plus_st5,
1792 ];
1793
1794 [
1795 specific_constraints,
1796 constraints_for_shrinking_stack_by_3_and_top_3_unconstrained(circuit_builder),
1797 instruction_group_step_1(circuit_builder),
1798 instruction_group_no_ram(circuit_builder),
1799 instruction_group_no_io(circuit_builder),
1800 ]
1801 .concat()
1802}
1803
1804fn instruction_xx_mul(
1805 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1806) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1807 let curr_main_row =
1808 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1809 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1810
1811 let [x0, x1, x2, y0, y1, y2] = [
1812 MainColumn::ST0,
1813 MainColumn::ST1,
1814 MainColumn::ST2,
1815 MainColumn::ST3,
1816 MainColumn::ST4,
1817 MainColumn::ST5,
1818 ]
1819 .map(curr_main_row);
1820 let [c0, c1, c2] = xx_product([x0, x1, x2], [y0, y1, y2]);
1821
1822 let specific_constraints = vec![
1823 next_main_row(MainColumn::ST0) - c0,
1824 next_main_row(MainColumn::ST1) - c1,
1825 next_main_row(MainColumn::ST2) - c2,
1826 ];
1827 [
1828 specific_constraints,
1829 constraints_for_shrinking_stack_by_3_and_top_3_unconstrained(circuit_builder),
1830 instruction_group_step_1(circuit_builder),
1831 instruction_group_no_ram(circuit_builder),
1832 instruction_group_no_io(circuit_builder),
1833 ]
1834 .concat()
1835}
1836
1837fn instruction_xinv(
1838 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1839) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1840 let constant = |c: u64| circuit_builder.b_constant(c);
1841 let curr_main_row =
1842 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1843 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1844
1845 let first_coefficient_of_product_of_element_and_inverse_is_1 = curr_main_row(MainColumn::ST0)
1846 * next_main_row(MainColumn::ST0)
1847 - curr_main_row(MainColumn::ST2) * next_main_row(MainColumn::ST1)
1848 - curr_main_row(MainColumn::ST1) * next_main_row(MainColumn::ST2)
1849 - constant(1);
1850
1851 let second_coefficient_of_product_of_element_and_inverse_is_0 = curr_main_row(MainColumn::ST1)
1852 * next_main_row(MainColumn::ST0)
1853 + curr_main_row(MainColumn::ST0) * next_main_row(MainColumn::ST1)
1854 - curr_main_row(MainColumn::ST2) * next_main_row(MainColumn::ST2)
1855 + curr_main_row(MainColumn::ST2) * next_main_row(MainColumn::ST1)
1856 + curr_main_row(MainColumn::ST1) * next_main_row(MainColumn::ST2);
1857
1858 let third_coefficient_of_product_of_element_and_inverse_is_0 = curr_main_row(MainColumn::ST2)
1859 * next_main_row(MainColumn::ST0)
1860 + curr_main_row(MainColumn::ST1) * next_main_row(MainColumn::ST1)
1861 + curr_main_row(MainColumn::ST0) * next_main_row(MainColumn::ST2)
1862 + curr_main_row(MainColumn::ST2) * next_main_row(MainColumn::ST2);
1863
1864 let specific_constraints = vec![
1865 first_coefficient_of_product_of_element_and_inverse_is_1,
1866 second_coefficient_of_product_of_element_and_inverse_is_0,
1867 third_coefficient_of_product_of_element_and_inverse_is_0,
1868 ];
1869 [
1870 specific_constraints,
1871 instruction_group_op_stack_remains_except_top_n(circuit_builder, 3),
1872 instruction_group_step_1(circuit_builder),
1873 instruction_group_no_ram(circuit_builder),
1874 instruction_group_no_io(circuit_builder),
1875 ]
1876 .concat()
1877}
1878
1879fn instruction_xb_mul(
1880 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1881) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1882 let curr_main_row =
1883 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1884 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
1885
1886 let [x, y0, y1, y2] = [
1887 MainColumn::ST0,
1888 MainColumn::ST1,
1889 MainColumn::ST2,
1890 MainColumn::ST3,
1891 ]
1892 .map(curr_main_row);
1893 let [c0, c1, c2] = xb_product([y0, y1, y2], x);
1894
1895 let specific_constraints = vec![
1896 next_main_row(MainColumn::ST0) - c0,
1897 next_main_row(MainColumn::ST1) - c1,
1898 next_main_row(MainColumn::ST2) - c2,
1899 ];
1900 [
1901 specific_constraints,
1902 instruction_group_op_stack_shrinks_and_top_three_elements_unconstrained(circuit_builder),
1903 instruction_group_step_1(circuit_builder),
1904 instruction_group_no_ram(circuit_builder),
1905 instruction_group_no_io(circuit_builder),
1906 ]
1907 .concat()
1908}
1909
1910fn instruction_read_io(
1911 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1912) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1913 let constraint_groups_for_legal_arguments = NumberOfWords::legal_values()
1914 .map(|n| grow_stack_by_n_and_read_n_symbols_from_input(circuit_builder, n))
1915 .to_vec();
1916 let read_any_legal_number_of_words = combine_mutually_exclusive_constraint_groups(
1917 circuit_builder,
1918 constraint_groups_for_legal_arguments,
1919 );
1920
1921 [
1922 instruction_group_step_2(circuit_builder),
1923 instruction_group_decompose_arg(circuit_builder),
1924 read_any_legal_number_of_words,
1925 prohibit_any_illegal_number_of_words(circuit_builder),
1926 instruction_group_no_ram(circuit_builder),
1927 vec![running_evaluation_for_standard_output_remains_unchanged(
1928 circuit_builder,
1929 )],
1930 ]
1931 .concat()
1932}
1933
1934fn instruction_write_io(
1935 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1936) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
1937 let constraint_groups_for_legal_arguments = NumberOfWords::legal_values()
1938 .map(|n| shrink_stack_by_n_and_write_n_symbols_to_output(circuit_builder, n))
1939 .to_vec();
1940 let write_any_of_1_through_5_elements = combine_mutually_exclusive_constraint_groups(
1941 circuit_builder,
1942 constraint_groups_for_legal_arguments,
1943 );
1944
1945 [
1946 instruction_group_step_2(circuit_builder),
1947 instruction_group_decompose_arg(circuit_builder),
1948 write_any_of_1_through_5_elements,
1949 prohibit_any_illegal_number_of_words(circuit_builder),
1950 instruction_group_no_ram(circuit_builder),
1951 vec![running_evaluation_for_standard_input_remains_unchanged(
1952 circuit_builder,
1953 )],
1954 ]
1955 .concat()
1956}
1957
1958fn read_from_ram_to<const N: usize>(
1967 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
1968 ram_pointers: [ConstraintCircuitMonad<DualRowIndicator>; N],
1969 destinations: [ConstraintCircuitMonad<DualRowIndicator>; N],
1970) -> ConstraintCircuitMonad<DualRowIndicator> {
1971 let curr_main_row =
1972 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
1973 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
1974 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
1975 let challenge = |c: ChallengeId| circuit_builder.challenge(c);
1976 let constant = |bfe| circuit_builder.b_constant(bfe);
1977
1978 let compress_row = |(ram_pointer, destination)| {
1979 curr_main_row(MainColumn::CLK) * challenge(ChallengeId::RamClkWeight)
1980 + constant(table::ram::INSTRUCTION_TYPE_READ)
1981 * challenge(ChallengeId::RamInstructionTypeWeight)
1982 + ram_pointer * challenge(ChallengeId::RamPointerWeight)
1983 + destination * challenge(ChallengeId::RamValueWeight)
1984 };
1985
1986 let factor = ram_pointers
1987 .into_iter()
1988 .zip(destinations)
1989 .map(compress_row)
1990 .map(|compressed_row| challenge(ChallengeId::RamIndeterminate) - compressed_row)
1991 .reduce(|l, r| l * r)
1992 .unwrap_or_else(|| constant(bfe!(1)));
1993 curr_aux_row(AuxColumn::RamTablePermArg) * factor - next_aux_row(AuxColumn::RamTablePermArg)
1994}
1995
1996fn xx_product<Indicator: InputIndicator>(
1997 [x_0, x_1, x_2]: [ConstraintCircuitMonad<Indicator>; EXTENSION_DEGREE],
1998 [y_0, y_1, y_2]: [ConstraintCircuitMonad<Indicator>; EXTENSION_DEGREE],
1999) -> [ConstraintCircuitMonad<Indicator>; EXTENSION_DEGREE] {
2000 let z0 = x_0.clone() * y_0.clone();
2001 let z1 = x_1.clone() * y_0.clone() + x_0.clone() * y_1.clone();
2002 let z2 = x_2.clone() * y_0 + x_1.clone() * y_1.clone() + x_0 * y_2.clone();
2003 let z3 = x_2.clone() * y_1 + x_1 * y_2.clone();
2004 let z4 = x_2 * y_2;
2005
2006 [z0 - z3.clone(), z1 - z4.clone() + z3, z2 + z4]
2008}
2009
2010fn xb_product<Indicator: InputIndicator>(
2011 [x_0, x_1, x_2]: [ConstraintCircuitMonad<Indicator>; EXTENSION_DEGREE],
2012 y: ConstraintCircuitMonad<Indicator>,
2013) -> [ConstraintCircuitMonad<Indicator>; EXTENSION_DEGREE] {
2014 let z0 = x_0 * y.clone();
2015 let z1 = x_1 * y.clone();
2016 let z2 = x_2 * y;
2017 [z0, z1, z2]
2018}
2019
2020fn update_dotstep_accumulator(
2021 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2022 accumulator_indices: [MainColumn; EXTENSION_DEGREE],
2023 difference: [ConstraintCircuitMonad<DualRowIndicator>; EXTENSION_DEGREE],
2024) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2025 let curr_main_row =
2026 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2027 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2028 let curr = accumulator_indices.map(curr_main_row);
2029 let next = accumulator_indices.map(next_main_row);
2030 izip!(curr, next, difference)
2031 .map(|(c, n, d)| n - c - d)
2032 .collect()
2033}
2034
2035fn instruction_xx_dot_step(
2036 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2037) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2038 let curr_main_row =
2039 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2040 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2041 let constant = |c| circuit_builder.b_constant(c);
2042
2043 let increment_ram_pointer_st0 =
2044 next_main_row(MainColumn::ST0) - curr_main_row(MainColumn::ST0) - constant(3);
2045 let increment_ram_pointer_st1 =
2046 next_main_row(MainColumn::ST1) - curr_main_row(MainColumn::ST1) - constant(3);
2047
2048 let rhs_ptr0 = curr_main_row(MainColumn::ST0);
2049 let rhs_ptr1 = rhs_ptr0.clone() + constant(1);
2050 let rhs_ptr2 = rhs_ptr0.clone() + constant(2);
2051 let lhs_ptr0 = curr_main_row(MainColumn::ST1);
2052 let lhs_ptr1 = lhs_ptr0.clone() + constant(1);
2053 let lhs_ptr2 = lhs_ptr0.clone() + constant(2);
2054 let ram_read_sources = [rhs_ptr0, rhs_ptr1, rhs_ptr2, lhs_ptr0, lhs_ptr1, lhs_ptr2];
2055 let ram_read_destinations = [
2056 MainColumn::HV0,
2057 MainColumn::HV1,
2058 MainColumn::HV2,
2059 MainColumn::HV3,
2060 MainColumn::HV4,
2061 MainColumn::HV5,
2062 ]
2063 .map(curr_main_row);
2064 let read_two_xfes_from_ram =
2065 read_from_ram_to(circuit_builder, ram_read_sources, ram_read_destinations);
2066
2067 let ram_pointer_constraints = vec![
2068 increment_ram_pointer_st0,
2069 increment_ram_pointer_st1,
2070 read_two_xfes_from_ram,
2071 ];
2072
2073 let [hv0, hv1, hv2, hv3, hv4, hv5] = [
2074 MainColumn::HV0,
2075 MainColumn::HV1,
2076 MainColumn::HV2,
2077 MainColumn::HV3,
2078 MainColumn::HV4,
2079 MainColumn::HV5,
2080 ]
2081 .map(curr_main_row);
2082 let hv_product = xx_product([hv0, hv1, hv2], [hv3, hv4, hv5]);
2083
2084 [
2085 ram_pointer_constraints,
2086 update_dotstep_accumulator(
2087 circuit_builder,
2088 [MainColumn::ST2, MainColumn::ST3, MainColumn::ST4],
2089 hv_product,
2090 ),
2091 instruction_group_step_1(circuit_builder),
2092 instruction_group_no_io(circuit_builder),
2093 instruction_group_op_stack_remains_except_top_n(circuit_builder, 5),
2094 ]
2095 .concat()
2096}
2097
2098fn instruction_xb_dot_step(
2099 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2100) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2101 let curr_main_row =
2102 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2103 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2104 let constant = |c| circuit_builder.b_constant(c);
2105
2106 let increment_ram_pointer_st0 =
2107 next_main_row(MainColumn::ST0) - curr_main_row(MainColumn::ST0) - constant(1);
2108 let increment_ram_pointer_st1 =
2109 next_main_row(MainColumn::ST1) - curr_main_row(MainColumn::ST1) - constant(3);
2110
2111 let rhs_ptr0 = curr_main_row(MainColumn::ST0);
2112 let lhs_ptr0 = curr_main_row(MainColumn::ST1);
2113 let lhs_ptr1 = lhs_ptr0.clone() + constant(1);
2114 let lhs_ptr2 = lhs_ptr0.clone() + constant(2);
2115 let ram_read_sources = [rhs_ptr0, lhs_ptr0, lhs_ptr1, lhs_ptr2];
2116 let ram_read_destinations = [
2117 MainColumn::HV0,
2118 MainColumn::HV1,
2119 MainColumn::HV2,
2120 MainColumn::HV3,
2121 ]
2122 .map(curr_main_row);
2123 let read_bfe_and_xfe_from_ram =
2124 read_from_ram_to(circuit_builder, ram_read_sources, ram_read_destinations);
2125
2126 let ram_pointer_constraints = vec![
2127 increment_ram_pointer_st0,
2128 increment_ram_pointer_st1,
2129 read_bfe_and_xfe_from_ram,
2130 ];
2131
2132 let [hv0, hv1, hv2, hv3] = [
2133 MainColumn::HV0,
2134 MainColumn::HV1,
2135 MainColumn::HV2,
2136 MainColumn::HV3,
2137 ]
2138 .map(curr_main_row);
2139 let hv_product = xb_product([hv1, hv2, hv3], hv0);
2140
2141 [
2142 ram_pointer_constraints,
2143 update_dotstep_accumulator(
2144 circuit_builder,
2145 [MainColumn::ST2, MainColumn::ST3, MainColumn::ST4],
2146 hv_product,
2147 ),
2148 instruction_group_step_1(circuit_builder),
2149 instruction_group_no_io(circuit_builder),
2150 instruction_group_op_stack_remains_except_top_n(circuit_builder, 5),
2151 ]
2152 .concat()
2153}
2154
2155#[doc(hidden)] pub fn transition_constraints_for_instruction(
2157 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2158 instruction: Instruction,
2159) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2160 match instruction {
2161 Instruction::Pop(_) => instruction_pop(circuit_builder),
2162 Instruction::Push(_) => instruction_push(circuit_builder),
2163 Instruction::Divine(_) => instruction_divine(circuit_builder),
2164 Instruction::Pick(_) => instruction_pick(circuit_builder),
2165 Instruction::Place(_) => instruction_place(circuit_builder),
2166 Instruction::Dup(_) => instruction_dup(circuit_builder),
2167 Instruction::Swap(_) => instruction_swap(circuit_builder),
2168 Instruction::Halt => instruction_halt(circuit_builder),
2169 Instruction::Nop => instruction_nop(circuit_builder),
2170 Instruction::Skiz => instruction_skiz(circuit_builder),
2171 Instruction::Call(_) => instruction_call(circuit_builder),
2172 Instruction::Return => instruction_return(circuit_builder),
2173 Instruction::Recurse => instruction_recurse(circuit_builder),
2174 Instruction::RecurseOrReturn => instruction_recurse_or_return(circuit_builder),
2175 Instruction::Assert => instruction_assert(circuit_builder),
2176 Instruction::ReadMem(_) => instruction_read_mem(circuit_builder),
2177 Instruction::WriteMem(_) => instruction_write_mem(circuit_builder),
2178 Instruction::Hash => instruction_hash(circuit_builder),
2179 Instruction::AssertVector => instruction_assert_vector(circuit_builder),
2180 Instruction::SpongeInit => instruction_sponge_init(circuit_builder),
2181 Instruction::SpongeAbsorb => instruction_sponge_absorb(circuit_builder),
2182 Instruction::SpongeAbsorbMem => instruction_sponge_absorb_mem(circuit_builder),
2183 Instruction::SpongeSqueeze => instruction_sponge_squeeze(circuit_builder),
2184 Instruction::Add => instruction_add(circuit_builder),
2185 Instruction::AddI(_) => instruction_addi(circuit_builder),
2186 Instruction::Mul => instruction_mul(circuit_builder),
2187 Instruction::Invert => instruction_invert(circuit_builder),
2188 Instruction::Eq => instruction_eq(circuit_builder),
2189 Instruction::Split => instruction_split(circuit_builder),
2190 Instruction::Lt => instruction_lt(circuit_builder),
2191 Instruction::And => instruction_and(circuit_builder),
2192 Instruction::Xor => instruction_xor(circuit_builder),
2193 Instruction::Log2Floor => instruction_log_2_floor(circuit_builder),
2194 Instruction::Pow => instruction_pow(circuit_builder),
2195 Instruction::DivMod => instruction_div_mod(circuit_builder),
2196 Instruction::PopCount => instruction_pop_count(circuit_builder),
2197 Instruction::XxAdd => instruction_xx_add(circuit_builder),
2198 Instruction::XxMul => instruction_xx_mul(circuit_builder),
2199 Instruction::XInvert => instruction_xinv(circuit_builder),
2200 Instruction::XbMul => instruction_xb_mul(circuit_builder),
2201 Instruction::ReadIo(_) => instruction_read_io(circuit_builder),
2202 Instruction::WriteIo(_) => instruction_write_io(circuit_builder),
2203 Instruction::MerkleStep => instruction_merkle_step(circuit_builder),
2204 Instruction::MerkleStepMem => instruction_merkle_step_mem(circuit_builder),
2205 Instruction::XxDotStep => instruction_xx_dot_step(circuit_builder),
2206 Instruction::XbDotStep => instruction_xb_dot_step(circuit_builder),
2207 }
2208}
2209
2210fn prohibit_any_illegal_number_of_words(
2212 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2213) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2214 let prohibitions = NumberOfWords::illegal_values()
2215 .map(|n| indicator_polynomial(circuit_builder, n))
2216 .into_iter()
2217 .sum();
2218
2219 vec![prohibitions]
2220}
2221
2222fn log_derivative_accumulates_clk_next(
2223 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2224) -> ConstraintCircuitMonad<DualRowIndicator> {
2225 let challenge = |c: ChallengeId| circuit_builder.challenge(c);
2226 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2227 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2228 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2229
2230 (next_aux_row(AuxColumn::ClockJumpDifferenceLookupServerLogDerivative)
2231 - curr_aux_row(AuxColumn::ClockJumpDifferenceLookupServerLogDerivative))
2232 * (challenge(ChallengeId::ClockJumpDifferenceLookupIndeterminate)
2233 - next_main_row(MainColumn::CLK))
2234 - next_main_row(MainColumn::ClockJumpDifferenceLookupMultiplicity)
2235}
2236
2237fn running_evaluation_for_standard_input_remains_unchanged(
2238 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2239) -> ConstraintCircuitMonad<DualRowIndicator> {
2240 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2241 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2242
2243 next_aux_row(AuxColumn::InputTableEvalArg) - curr_aux_row(AuxColumn::InputTableEvalArg)
2244}
2245
2246fn running_evaluation_for_standard_output_remains_unchanged(
2247 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2248) -> ConstraintCircuitMonad<DualRowIndicator> {
2249 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2250 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2251
2252 next_aux_row(AuxColumn::OutputTableEvalArg) - curr_aux_row(AuxColumn::OutputTableEvalArg)
2253}
2254
2255fn grow_stack_by_n_and_read_n_symbols_from_input(
2256 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2257 n: usize,
2258) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2259 let indeterminate = || circuit_builder.challenge(ChallengeId::StandardInputIndeterminate);
2260 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2261 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2262 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2263
2264 let mut running_evaluation = curr_aux_row(AuxColumn::InputTableEvalArg);
2265 for i in (0..n).rev() {
2266 let stack_element = ProcessorTable::op_stack_column_by_index(i);
2267 running_evaluation = indeterminate() * running_evaluation + next_main_row(stack_element);
2268 }
2269 let running_evaluation_update = next_aux_row(AuxColumn::InputTableEvalArg) - running_evaluation;
2270 let conditional_running_evaluation_update =
2271 indicator_polynomial(circuit_builder, n) * running_evaluation_update;
2272
2273 let mut constraints = conditional_constraints_for_growing_stack_by(circuit_builder, n);
2274 constraints.push(conditional_running_evaluation_update);
2275 constraints
2276}
2277
2278fn shrink_stack_by_n_and_write_n_symbols_to_output(
2279 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2280 n: usize,
2281) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2282 let indeterminate = || circuit_builder.challenge(ChallengeId::StandardOutputIndeterminate);
2283 let curr_main_row =
2284 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2285 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2286 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2287
2288 let mut running_evaluation = curr_aux_row(AuxColumn::OutputTableEvalArg);
2289 for i in 0..n {
2290 let stack_element = ProcessorTable::op_stack_column_by_index(i);
2291 running_evaluation = indeterminate() * running_evaluation + curr_main_row(stack_element);
2292 }
2293 let running_evaluation_update =
2294 next_aux_row(AuxColumn::OutputTableEvalArg) - running_evaluation;
2295 let conditional_running_evaluation_update =
2296 indicator_polynomial(circuit_builder, n) * running_evaluation_update;
2297
2298 let mut constraints = conditional_constraints_for_shrinking_stack_by(circuit_builder, n);
2299 constraints.push(conditional_running_evaluation_update);
2300 constraints
2301}
2302
2303fn log_derivative_for_instruction_lookup_updates_correctly(
2304 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2305) -> ConstraintCircuitMonad<DualRowIndicator> {
2306 let one = || circuit_builder.b_constant(1);
2307 let challenge = |c: ChallengeId| circuit_builder.challenge(c);
2308 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2309 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2310 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2311
2312 let compressed_row = challenge(ChallengeId::ProgramAddressWeight)
2313 * next_main_row(MainColumn::IP)
2314 + challenge(ChallengeId::ProgramInstructionWeight) * next_main_row(MainColumn::CI)
2315 + challenge(ChallengeId::ProgramNextInstructionWeight) * next_main_row(MainColumn::NIA);
2316 let log_derivative_updates = (next_aux_row(AuxColumn::InstructionLookupClientLogDerivative)
2317 - curr_aux_row(AuxColumn::InstructionLookupClientLogDerivative))
2318 * (challenge(ChallengeId::InstructionLookupIndeterminate) - compressed_row)
2319 - one();
2320 let log_derivative_remains = next_aux_row(AuxColumn::InstructionLookupClientLogDerivative)
2321 - curr_aux_row(AuxColumn::InstructionLookupClientLogDerivative);
2322
2323 (one() - next_main_row(MainColumn::IsPadding)) * log_derivative_updates
2324 + next_main_row(MainColumn::IsPadding) * log_derivative_remains
2325}
2326
2327fn constraints_for_shrinking_stack_by_3_and_top_3_unconstrained(
2328 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2329) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2330 let constant = |c: u64| circuit_builder.b_constant(c);
2331 let curr_main_row =
2332 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2333 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2334
2335 vec![
2336 next_main_row(MainColumn::ST3) - curr_main_row(MainColumn::ST6),
2337 next_main_row(MainColumn::ST4) - curr_main_row(MainColumn::ST7),
2338 next_main_row(MainColumn::ST5) - curr_main_row(MainColumn::ST8),
2339 next_main_row(MainColumn::ST6) - curr_main_row(MainColumn::ST9),
2340 next_main_row(MainColumn::ST7) - curr_main_row(MainColumn::ST10),
2341 next_main_row(MainColumn::ST8) - curr_main_row(MainColumn::ST11),
2342 next_main_row(MainColumn::ST9) - curr_main_row(MainColumn::ST12),
2343 next_main_row(MainColumn::ST10) - curr_main_row(MainColumn::ST13),
2344 next_main_row(MainColumn::ST11) - curr_main_row(MainColumn::ST14),
2345 next_main_row(MainColumn::ST12) - curr_main_row(MainColumn::ST15),
2346 next_main_row(MainColumn::OpStackPointer) - curr_main_row(MainColumn::OpStackPointer)
2347 + constant(3),
2348 running_product_op_stack_accounts_for_shrinking_stack_by(circuit_builder, 3),
2349 ]
2350}
2351
2352fn stack_shrinks_by_any_of(
2353 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2354 shrinkages: &[usize],
2355) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2356 let all_constraints_for_all_shrinkages = shrinkages
2357 .iter()
2358 .map(|&n| conditional_constraints_for_shrinking_stack_by(circuit_builder, n))
2359 .collect_vec();
2360
2361 combine_mutually_exclusive_constraint_groups(
2362 circuit_builder,
2363 all_constraints_for_all_shrinkages,
2364 )
2365}
2366
2367fn stack_grows_by_any_of(
2368 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2369 growths: &[usize],
2370) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2371 let all_constraints_for_all_growths = growths
2372 .iter()
2373 .map(|&n| conditional_constraints_for_growing_stack_by(circuit_builder, n))
2374 .collect_vec();
2375
2376 combine_mutually_exclusive_constraint_groups(circuit_builder, all_constraints_for_all_growths)
2377}
2378
2379fn combine_mutually_exclusive_constraint_groups(
2423 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2424 all_constraint_groups: Vec<Vec<ConstraintCircuitMonad<DualRowIndicator>>>,
2425) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2426 let constraint_group_lengths = all_constraint_groups.iter().map(|x| x.len());
2427 let num_constraints = constraint_group_lengths.max().unwrap_or(0);
2428
2429 let zero_constraint = || circuit_builder.b_constant(0);
2430 let mut combined_constraints = vec![];
2431 for i in 0..num_constraints {
2432 let combined_constraint = all_constraint_groups
2433 .iter()
2434 .filter_map(|constraint_group| constraint_group.get(i))
2435 .fold(zero_constraint(), |acc, summand| acc + summand.clone());
2436 combined_constraints.push(combined_constraint);
2437 }
2438 combined_constraints
2439}
2440
2441fn constraints_for_shrinking_stack_by(
2442 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2443 n: usize,
2444) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2445 let constant = |c: usize| circuit_builder.b_constant(u64::try_from(c).unwrap());
2446 let curr_row = |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2447 let next_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2448
2449 let stack = || (0..OpStackElement::COUNT).map(ProcessorTable::op_stack_column_by_index);
2450 let new_stack = stack().dropping_back(n).map(next_row).collect_vec();
2451 let old_stack_with_top_n_removed = stack().skip(n).map(curr_row).collect_vec();
2452
2453 let compress = |stack: Vec<_>| -> ConstraintCircuitMonad<_> {
2454 assert_eq!(OpStackElement::COUNT - n, stack.len());
2455 let weight = |i| circuit_builder.challenge(stack_weight_by_index(i));
2456 let enumerated_stack = stack.into_iter().enumerate();
2457 enumerated_stack.map(|(i, st)| weight(i) * st).sum()
2458 };
2459 let compressed_new_stack = compress(new_stack);
2460 let compressed_old_stack = compress(old_stack_with_top_n_removed);
2461
2462 let op_stack_pointer_shrinks_by_n =
2463 next_row(MainColumn::OpStackPointer) - curr_row(MainColumn::OpStackPointer) + constant(n);
2464 let new_stack_is_old_stack_with_top_n_removed = compressed_new_stack - compressed_old_stack;
2465
2466 vec![
2467 op_stack_pointer_shrinks_by_n,
2468 new_stack_is_old_stack_with_top_n_removed,
2469 running_product_op_stack_accounts_for_shrinking_stack_by(circuit_builder, n),
2470 ]
2471}
2472
2473fn constraints_for_growing_stack_by(
2474 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2475 n: usize,
2476) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2477 let constant = |c: usize| circuit_builder.b_constant(u32::try_from(c).unwrap());
2478 let curr_row = |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2479 let next_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2480
2481 let stack = || (0..OpStackElement::COUNT).map(ProcessorTable::op_stack_column_by_index);
2482 let new_stack = stack().skip(n).map(next_row).collect_vec();
2483 let old_stack_with_top_n_added = stack().map(curr_row).dropping_back(n).collect_vec();
2484
2485 let compress = |stack: Vec<_>| -> ConstraintCircuitMonad<_> {
2486 assert_eq!(OpStackElement::COUNT - n, stack.len());
2487 let weight = |i| circuit_builder.challenge(stack_weight_by_index(i));
2488 let enumerated_stack = stack.into_iter().enumerate();
2489 enumerated_stack.map(|(i, st)| weight(i) * st).sum()
2490 };
2491 let compressed_new_stack = compress(new_stack);
2492 let compressed_old_stack = compress(old_stack_with_top_n_added);
2493
2494 let op_stack_pointer_grows_by_n =
2495 next_row(MainColumn::OpStackPointer) - curr_row(MainColumn::OpStackPointer) - constant(n);
2496 let new_stack_is_old_stack_with_top_n_added = compressed_new_stack - compressed_old_stack;
2497
2498 vec![
2499 op_stack_pointer_grows_by_n,
2500 new_stack_is_old_stack_with_top_n_added,
2501 running_product_op_stack_accounts_for_growing_stack_by(circuit_builder, n),
2502 ]
2503}
2504
2505fn conditional_constraints_for_shrinking_stack_by(
2506 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2507 n: usize,
2508) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2509 constraints_for_shrinking_stack_by(circuit_builder, n)
2510 .into_iter()
2511 .map(|constraint| indicator_polynomial(circuit_builder, n) * constraint)
2512 .collect()
2513}
2514
2515fn conditional_constraints_for_growing_stack_by(
2516 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2517 n: usize,
2518) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2519 constraints_for_growing_stack_by(circuit_builder, n)
2520 .into_iter()
2521 .map(|constraint| indicator_polynomial(circuit_builder, n) * constraint)
2522 .collect()
2523}
2524
2525fn running_product_op_stack_accounts_for_growing_stack_by(
2526 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2527 n: usize,
2528) -> ConstraintCircuitMonad<DualRowIndicator> {
2529 let constant = |c: u32| circuit_builder.b_constant(c);
2530 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2531 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2532 let single_grow_factor = |op_stack_pointer_offset| {
2533 single_factor_for_permutation_argument_with_op_stack_table(
2534 circuit_builder,
2535 CurrentMain,
2536 op_stack_pointer_offset,
2537 )
2538 };
2539
2540 let mut factor = constant(1);
2541 for op_stack_pointer_offset in 0..n {
2542 factor = factor * single_grow_factor(op_stack_pointer_offset);
2543 }
2544
2545 next_aux_row(AuxColumn::OpStackTablePermArg)
2546 - curr_aux_row(AuxColumn::OpStackTablePermArg) * factor
2547}
2548
2549fn running_product_op_stack_accounts_for_shrinking_stack_by(
2550 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2551 n: usize,
2552) -> ConstraintCircuitMonad<DualRowIndicator> {
2553 let constant = |c: u32| circuit_builder.b_constant(c);
2554 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2555 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2556 let single_shrink_factor = |op_stack_pointer_offset| {
2557 single_factor_for_permutation_argument_with_op_stack_table(
2558 circuit_builder,
2559 NextMain,
2560 op_stack_pointer_offset,
2561 )
2562 };
2563
2564 let mut factor = constant(1);
2565 for op_stack_pointer_offset in 0..n {
2566 factor = factor * single_shrink_factor(op_stack_pointer_offset);
2567 }
2568
2569 next_aux_row(AuxColumn::OpStackTablePermArg)
2570 - curr_aux_row(AuxColumn::OpStackTablePermArg) * factor
2571}
2572
2573fn single_factor_for_permutation_argument_with_op_stack_table(
2574 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2575 row_with_shorter_stack_indicator: fn(usize) -> DualRowIndicator,
2576 op_stack_pointer_offset: usize,
2577) -> ConstraintCircuitMonad<DualRowIndicator> {
2578 let constant = |c: u32| circuit_builder.b_constant(c);
2579 let challenge = |c: ChallengeId| circuit_builder.challenge(c);
2580 let curr_main_row =
2581 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2582 let row_with_shorter_stack = |col: MainColumn| {
2583 circuit_builder.input(row_with_shorter_stack_indicator(col.master_main_index()))
2584 };
2585
2586 let max_stack_element_index = OpStackElement::COUNT - 1;
2587 let stack_element_index = max_stack_element_index - op_stack_pointer_offset;
2588 let stack_element = ProcessorTable::op_stack_column_by_index(stack_element_index);
2589 let underflow_element = row_with_shorter_stack(stack_element);
2590
2591 let op_stack_pointer = row_with_shorter_stack(MainColumn::OpStackPointer);
2592 let offset = constant(op_stack_pointer_offset as u32);
2593 let offset_op_stack_pointer = op_stack_pointer + offset;
2594
2595 let compressed_row = challenge(ChallengeId::OpStackClkWeight) * curr_main_row(MainColumn::CLK)
2596 + challenge(ChallengeId::OpStackIb1Weight) * curr_main_row(MainColumn::IB1)
2597 + challenge(ChallengeId::OpStackPointerWeight) * offset_op_stack_pointer
2598 + challenge(ChallengeId::OpStackFirstUnderflowElementWeight) * underflow_element;
2599 challenge(ChallengeId::OpStackIndeterminate) - compressed_row
2600}
2601
2602fn write_to_ram_any_of(
2605 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2606 number_of_words: &[usize],
2607) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2608 let all_constraint_groups = number_of_words
2609 .iter()
2610 .map(|&n| conditional_constraints_for_writing_n_elements_to_ram(circuit_builder, n))
2611 .collect_vec();
2612 combine_mutually_exclusive_constraint_groups(circuit_builder, all_constraint_groups)
2613}
2614
2615fn read_from_ram_any_of(
2621 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2622 number_of_words: &[usize],
2623) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2624 let all_constraint_groups = number_of_words
2625 .iter()
2626 .map(|&n| conditional_constraints_for_reading_n_elements_from_ram(circuit_builder, n))
2627 .collect_vec();
2628 combine_mutually_exclusive_constraint_groups(circuit_builder, all_constraint_groups)
2629}
2630
2631fn conditional_constraints_for_writing_n_elements_to_ram(
2632 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2633 n: usize,
2634) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2635 shrink_stack_by_n_and_write_n_elements_to_ram(circuit_builder, n)
2636 .into_iter()
2637 .map(|constraint| indicator_polynomial(circuit_builder, n) * constraint)
2638 .collect()
2639}
2640
2641fn conditional_constraints_for_reading_n_elements_from_ram(
2642 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2643 n: usize,
2644) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2645 grow_stack_by_n_and_read_n_elements_from_ram(circuit_builder, n)
2646 .into_iter()
2647 .map(|constraint| indicator_polynomial(circuit_builder, n) * constraint)
2648 .collect()
2649}
2650
2651fn shrink_stack_by_n_and_write_n_elements_to_ram(
2652 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2653 n: usize,
2654) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2655 let constant = |c: usize| circuit_builder.b_constant(u32::try_from(c).unwrap());
2656 let curr_main_row =
2657 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2658 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2659
2660 let op_stack_pointer_shrinks_by_n = next_main_row(MainColumn::OpStackPointer)
2661 - curr_main_row(MainColumn::OpStackPointer)
2662 + constant(n);
2663 let ram_pointer_grows_by_n =
2664 next_main_row(MainColumn::ST0) - curr_main_row(MainColumn::ST0) - constant(n);
2665
2666 let mut constraints = vec![
2667 op_stack_pointer_shrinks_by_n,
2668 ram_pointer_grows_by_n,
2669 running_product_op_stack_accounts_for_shrinking_stack_by(circuit_builder, n),
2670 running_product_ram_accounts_for_writing_n_elements(circuit_builder, n),
2671 ];
2672
2673 let num_ram_pointers = 1;
2674 for i in n + num_ram_pointers..OpStackElement::COUNT {
2675 let curr_stack_element = ProcessorTable::op_stack_column_by_index(i);
2676 let next_stack_element = ProcessorTable::op_stack_column_by_index(i - n);
2677 let element_i_is_shifted_by_n =
2678 next_main_row(next_stack_element) - curr_main_row(curr_stack_element);
2679 constraints.push(element_i_is_shifted_by_n);
2680 }
2681 constraints
2682}
2683
2684fn grow_stack_by_n_and_read_n_elements_from_ram(
2685 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2686 n: usize,
2687) -> Vec<ConstraintCircuitMonad<DualRowIndicator>> {
2688 let constant = |c: usize| circuit_builder.b_constant(u64::try_from(c).unwrap());
2689 let curr_main_row =
2690 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2691 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2692
2693 let op_stack_pointer_grows_by_n = next_main_row(MainColumn::OpStackPointer)
2694 - curr_main_row(MainColumn::OpStackPointer)
2695 - constant(n);
2696 let ram_pointer_shrinks_by_n =
2697 next_main_row(MainColumn::ST0) - curr_main_row(MainColumn::ST0) + constant(n);
2698
2699 let mut constraints = vec![
2700 op_stack_pointer_grows_by_n,
2701 ram_pointer_shrinks_by_n,
2702 running_product_op_stack_accounts_for_growing_stack_by(circuit_builder, n),
2703 running_product_ram_accounts_for_reading_n_elements(circuit_builder, n),
2704 ];
2705
2706 let num_ram_pointers = 1;
2707 for i in num_ram_pointers..OpStackElement::COUNT - n {
2708 let curr_stack_element = ProcessorTable::op_stack_column_by_index(i);
2709 let next_stack_element = ProcessorTable::op_stack_column_by_index(i + n);
2710 let element_i_is_shifted_by_n =
2711 next_main_row(next_stack_element) - curr_main_row(curr_stack_element);
2712 constraints.push(element_i_is_shifted_by_n);
2713 }
2714 constraints
2715}
2716
2717fn running_product_ram_accounts_for_writing_n_elements(
2718 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2719 n: usize,
2720) -> ConstraintCircuitMonad<DualRowIndicator> {
2721 let constant = |c: u32| circuit_builder.b_constant(c);
2722 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2723 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2724 let single_write_factor = |ram_pointer_offset| {
2725 single_factor_for_permutation_argument_with_ram_table(
2726 circuit_builder,
2727 CurrentMain,
2728 table::ram::INSTRUCTION_TYPE_WRITE,
2729 ram_pointer_offset,
2730 )
2731 };
2732
2733 let mut factor = constant(1);
2734 for ram_pointer_offset in 0..n {
2735 factor = factor * single_write_factor(ram_pointer_offset);
2736 }
2737
2738 next_aux_row(AuxColumn::RamTablePermArg) - curr_aux_row(AuxColumn::RamTablePermArg) * factor
2739}
2740
2741fn running_product_ram_accounts_for_reading_n_elements(
2742 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2743 n: usize,
2744) -> ConstraintCircuitMonad<DualRowIndicator> {
2745 let constant = |c: u32| circuit_builder.b_constant(c);
2746 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2747 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2748 let single_read_factor = |ram_pointer_offset| {
2749 single_factor_for_permutation_argument_with_ram_table(
2750 circuit_builder,
2751 NextMain,
2752 table::ram::INSTRUCTION_TYPE_READ,
2753 ram_pointer_offset,
2754 )
2755 };
2756
2757 let mut factor = constant(1);
2758 for ram_pointer_offset in 0..n {
2759 factor = factor * single_read_factor(ram_pointer_offset);
2760 }
2761
2762 next_aux_row(AuxColumn::RamTablePermArg) - curr_aux_row(AuxColumn::RamTablePermArg) * factor
2763}
2764
2765fn single_factor_for_permutation_argument_with_ram_table(
2766 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2767 row_with_longer_stack_indicator: fn(usize) -> DualRowIndicator,
2768 instruction_type: BFieldElement,
2769 ram_pointer_offset: usize,
2770) -> ConstraintCircuitMonad<DualRowIndicator> {
2771 let constant = |c: u32| circuit_builder.b_constant(c);
2772 let b_constant = |c| circuit_builder.b_constant(c);
2773 let challenge = |c: ChallengeId| circuit_builder.challenge(c);
2774 let curr_main_row =
2775 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2776 let row_with_longer_stack = |col: MainColumn| {
2777 circuit_builder.input(row_with_longer_stack_indicator(col.master_main_index()))
2778 };
2779
2780 let num_ram_pointers = 1;
2781 let ram_value_index = ram_pointer_offset + num_ram_pointers;
2782 let ram_value_column = ProcessorTable::op_stack_column_by_index(ram_value_index);
2783 let ram_value = row_with_longer_stack(ram_value_column);
2784
2785 let additional_offset = match instruction_type {
2786 table::ram::INSTRUCTION_TYPE_READ => 1,
2787 table::ram::INSTRUCTION_TYPE_WRITE => 0,
2788 _ => panic!("Invalid instruction type"),
2789 };
2790
2791 let ram_pointer = row_with_longer_stack(MainColumn::ST0);
2792 let offset = constant(additional_offset + ram_pointer_offset as u32);
2793 let offset_ram_pointer = ram_pointer + offset;
2794
2795 let compressed_row = curr_main_row(MainColumn::CLK) * challenge(ChallengeId::RamClkWeight)
2796 + b_constant(instruction_type) * challenge(ChallengeId::RamInstructionTypeWeight)
2797 + offset_ram_pointer * challenge(ChallengeId::RamPointerWeight)
2798 + ram_value * challenge(ChallengeId::RamValueWeight);
2799 challenge(ChallengeId::RamIndeterminate) - compressed_row
2800}
2801
2802fn running_product_for_jump_stack_table_updates_correctly(
2803 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2804) -> ConstraintCircuitMonad<DualRowIndicator> {
2805 let challenge = |c: ChallengeId| circuit_builder.challenge(c);
2806 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2807 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2808 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2809
2810 let compressed_row = challenge(ChallengeId::JumpStackClkWeight)
2811 * next_main_row(MainColumn::CLK)
2812 + challenge(ChallengeId::JumpStackCiWeight) * next_main_row(MainColumn::CI)
2813 + challenge(ChallengeId::JumpStackJspWeight) * next_main_row(MainColumn::JSP)
2814 + challenge(ChallengeId::JumpStackJsoWeight) * next_main_row(MainColumn::JSO)
2815 + challenge(ChallengeId::JumpStackJsdWeight) * next_main_row(MainColumn::JSD);
2816
2817 next_aux_row(AuxColumn::JumpStackTablePermArg)
2818 - curr_aux_row(AuxColumn::JumpStackTablePermArg)
2819 * (challenge(ChallengeId::JumpStackIndeterminate) - compressed_row)
2820}
2821
2822fn running_evaluation_hash_input_updates_correctly(
2834 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2835) -> ConstraintCircuitMonad<DualRowIndicator> {
2836 let constant = |c: u32| circuit_builder.b_constant(c);
2837 let one = || constant(1);
2838 let challenge = |c: ChallengeId| circuit_builder.challenge(c);
2839 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2840 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2841 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2842
2843 let hash_deselector = instruction_deselector_next_row(circuit_builder, Instruction::Hash);
2844 let merkle_step_deselector =
2845 instruction_deselector_next_row(circuit_builder, Instruction::MerkleStep);
2846 let merkle_step_mem_deselector =
2847 instruction_deselector_next_row(circuit_builder, Instruction::MerkleStepMem);
2848 let hash_and_merkle_step_selector = (next_main_row(MainColumn::CI)
2849 - constant(Instruction::Hash.opcode()))
2850 * (next_main_row(MainColumn::CI) - constant(Instruction::MerkleStep.opcode()))
2851 * (next_main_row(MainColumn::CI) - constant(Instruction::MerkleStepMem.opcode()));
2852
2853 let weights = [
2854 ChallengeId::StackWeight0,
2855 ChallengeId::StackWeight1,
2856 ChallengeId::StackWeight2,
2857 ChallengeId::StackWeight3,
2858 ChallengeId::StackWeight4,
2859 ChallengeId::StackWeight5,
2860 ChallengeId::StackWeight6,
2861 ChallengeId::StackWeight7,
2862 ChallengeId::StackWeight8,
2863 ChallengeId::StackWeight9,
2864 ]
2865 .map(challenge);
2866
2867 let state_for_hash = [
2869 MainColumn::ST0,
2870 MainColumn::ST1,
2871 MainColumn::ST2,
2872 MainColumn::ST3,
2873 MainColumn::ST4,
2874 MainColumn::ST5,
2875 MainColumn::ST6,
2876 MainColumn::ST7,
2877 MainColumn::ST8,
2878 MainColumn::ST9,
2879 ]
2880 .map(next_main_row);
2881 let compressed_hash_row = weights
2882 .iter()
2883 .zip_eq(state_for_hash)
2884 .map(|(weight, state)| weight.clone() * state)
2885 .sum();
2886
2887 let is_left_sibling = || next_main_row(MainColumn::HV5);
2889 let is_right_sibling = || one() - next_main_row(MainColumn::HV5);
2890 let merkle_step_state_element =
2891 |l, r| is_right_sibling() * next_main_row(l) + is_left_sibling() * next_main_row(r);
2892 let state_for_merkle_step = [
2893 merkle_step_state_element(MainColumn::ST0, MainColumn::HV0),
2894 merkle_step_state_element(MainColumn::ST1, MainColumn::HV1),
2895 merkle_step_state_element(MainColumn::ST2, MainColumn::HV2),
2896 merkle_step_state_element(MainColumn::ST3, MainColumn::HV3),
2897 merkle_step_state_element(MainColumn::ST4, MainColumn::HV4),
2898 merkle_step_state_element(MainColumn::HV0, MainColumn::ST0),
2899 merkle_step_state_element(MainColumn::HV1, MainColumn::ST1),
2900 merkle_step_state_element(MainColumn::HV2, MainColumn::ST2),
2901 merkle_step_state_element(MainColumn::HV3, MainColumn::ST3),
2902 merkle_step_state_element(MainColumn::HV4, MainColumn::ST4),
2903 ];
2904 let compressed_merkle_step_row = weights
2905 .into_iter()
2906 .zip_eq(state_for_merkle_step)
2907 .map(|(weight, state)| weight * state)
2908 .sum::<ConstraintCircuitMonad<_>>();
2909
2910 let running_evaluation_updates_with = |compressed_row| {
2911 next_aux_row(AuxColumn::HashInputEvalArg)
2912 - challenge(ChallengeId::HashInputIndeterminate)
2913 * curr_aux_row(AuxColumn::HashInputEvalArg)
2914 - compressed_row
2915 };
2916 let running_evaluation_remains =
2917 next_aux_row(AuxColumn::HashInputEvalArg) - curr_aux_row(AuxColumn::HashInputEvalArg);
2918
2919 hash_and_merkle_step_selector * running_evaluation_remains
2920 + hash_deselector * running_evaluation_updates_with(compressed_hash_row)
2921 + merkle_step_deselector
2922 * running_evaluation_updates_with(compressed_merkle_step_row.clone())
2923 + merkle_step_mem_deselector * running_evaluation_updates_with(compressed_merkle_step_row)
2924}
2925
2926fn running_evaluation_hash_digest_updates_correctly(
2927 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2928) -> ConstraintCircuitMonad<DualRowIndicator> {
2929 let constant = |c: u32| circuit_builder.b_constant(c);
2930 let challenge = |c: ChallengeId| circuit_builder.challenge(c);
2931 let curr_main_row =
2932 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2933 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2934 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2935 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2936
2937 let hash_deselector = instruction_deselector_current_row(circuit_builder, Instruction::Hash);
2938 let merkle_step_deselector =
2939 instruction_deselector_current_row(circuit_builder, Instruction::MerkleStep);
2940 let merkle_step_mem_deselector =
2941 instruction_deselector_current_row(circuit_builder, Instruction::MerkleStepMem);
2942 let hash_and_merkle_step_selector = (curr_main_row(MainColumn::CI)
2943 - constant(Instruction::Hash.opcode()))
2944 * (curr_main_row(MainColumn::CI) - constant(Instruction::MerkleStep.opcode()))
2945 * (curr_main_row(MainColumn::CI) - constant(Instruction::MerkleStepMem.opcode()));
2946
2947 let weights = [
2948 ChallengeId::StackWeight0,
2949 ChallengeId::StackWeight1,
2950 ChallengeId::StackWeight2,
2951 ChallengeId::StackWeight3,
2952 ChallengeId::StackWeight4,
2953 ]
2954 .map(challenge);
2955 let state = [
2956 MainColumn::ST0,
2957 MainColumn::ST1,
2958 MainColumn::ST2,
2959 MainColumn::ST3,
2960 MainColumn::ST4,
2961 ]
2962 .map(next_main_row);
2963 let compressed_row = weights
2964 .into_iter()
2965 .zip_eq(state)
2966 .map(|(weight, state)| weight * state)
2967 .sum();
2968
2969 let running_evaluation_updates = next_aux_row(AuxColumn::HashDigestEvalArg)
2970 - challenge(ChallengeId::HashDigestIndeterminate)
2971 * curr_aux_row(AuxColumn::HashDigestEvalArg)
2972 - compressed_row;
2973 let running_evaluation_remains =
2974 next_aux_row(AuxColumn::HashDigestEvalArg) - curr_aux_row(AuxColumn::HashDigestEvalArg);
2975
2976 hash_and_merkle_step_selector * running_evaluation_remains
2977 + (hash_deselector + merkle_step_deselector + merkle_step_mem_deselector)
2978 * running_evaluation_updates
2979}
2980
2981fn running_evaluation_sponge_updates_correctly(
2982 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
2983) -> ConstraintCircuitMonad<DualRowIndicator> {
2984 let constant = |c: u32| circuit_builder.b_constant(c);
2985 let challenge = |c: ChallengeId| circuit_builder.challenge(c);
2986 let curr_main_row =
2987 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
2988 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
2989 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
2990 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
2991
2992 let sponge_init_deselector =
2993 instruction_deselector_current_row(circuit_builder, Instruction::SpongeInit);
2994 let sponge_absorb_deselector =
2995 instruction_deselector_current_row(circuit_builder, Instruction::SpongeAbsorb);
2996 let sponge_absorb_mem_deselector =
2997 instruction_deselector_current_row(circuit_builder, Instruction::SpongeAbsorbMem);
2998 let sponge_squeeze_deselector =
2999 instruction_deselector_current_row(circuit_builder, Instruction::SpongeSqueeze);
3000
3001 let sponge_instruction_selector = (curr_main_row(MainColumn::CI)
3002 - constant(Instruction::SpongeInit.opcode()))
3003 * (curr_main_row(MainColumn::CI) - constant(Instruction::SpongeAbsorb.opcode()))
3004 * (curr_main_row(MainColumn::CI) - constant(Instruction::SpongeAbsorbMem.opcode()))
3005 * (curr_main_row(MainColumn::CI) - constant(Instruction::SpongeSqueeze.opcode()));
3006
3007 let weighted_sum = |state| {
3008 let weights = [
3009 ChallengeId::StackWeight0,
3010 ChallengeId::StackWeight1,
3011 ChallengeId::StackWeight2,
3012 ChallengeId::StackWeight3,
3013 ChallengeId::StackWeight4,
3014 ChallengeId::StackWeight5,
3015 ChallengeId::StackWeight6,
3016 ChallengeId::StackWeight7,
3017 ChallengeId::StackWeight8,
3018 ChallengeId::StackWeight9,
3019 ];
3020 let weights = weights.map(challenge).into_iter();
3021 weights.zip_eq(state).map(|(w, st)| w * st).sum()
3022 };
3023
3024 let state = [
3025 MainColumn::ST0,
3026 MainColumn::ST1,
3027 MainColumn::ST2,
3028 MainColumn::ST3,
3029 MainColumn::ST4,
3030 MainColumn::ST5,
3031 MainColumn::ST6,
3032 MainColumn::ST7,
3033 MainColumn::ST8,
3034 MainColumn::ST9,
3035 ];
3036 let compressed_row_current = weighted_sum(state.map(curr_main_row));
3037 let compressed_row_next = weighted_sum(state.map(next_main_row));
3038
3039 let running_evaluation_updates_for_sponge_init = next_aux_row(AuxColumn::SpongeEvalArg)
3042 - challenge(ChallengeId::SpongeIndeterminate) * curr_aux_row(AuxColumn::SpongeEvalArg)
3043 - challenge(ChallengeId::HashCIWeight) * curr_main_row(MainColumn::CI);
3044 let running_evaluation_updates_for_absorb =
3045 running_evaluation_updates_for_sponge_init.clone() - compressed_row_current;
3046 let running_evaluation_updates_for_squeeze =
3047 running_evaluation_updates_for_sponge_init.clone() - compressed_row_next;
3048 let running_evaluation_remains =
3049 next_aux_row(AuxColumn::SpongeEvalArg) - curr_aux_row(AuxColumn::SpongeEvalArg);
3050
3051 let stack_elements = [
3053 MainColumn::ST1,
3054 MainColumn::ST2,
3055 MainColumn::ST3,
3056 MainColumn::ST4,
3057 ]
3058 .map(next_main_row);
3059 let hv_elements = [
3060 MainColumn::HV0,
3061 MainColumn::HV1,
3062 MainColumn::HV2,
3063 MainColumn::HV3,
3064 MainColumn::HV4,
3065 MainColumn::HV5,
3066 ]
3067 .map(curr_main_row);
3068 let absorb_mem_elements = stack_elements.into_iter().chain(hv_elements);
3069 let absorb_mem_elements = absorb_mem_elements.collect_vec().try_into().unwrap();
3070 let compressed_row_absorb_mem = weighted_sum(absorb_mem_elements);
3071 let running_evaluation_updates_for_absorb_mem = next_aux_row(AuxColumn::SpongeEvalArg)
3072 - challenge(ChallengeId::SpongeIndeterminate) * curr_aux_row(AuxColumn::SpongeEvalArg)
3073 - challenge(ChallengeId::HashCIWeight) * constant(Instruction::SpongeAbsorb.opcode())
3074 - compressed_row_absorb_mem;
3075
3076 sponge_instruction_selector * running_evaluation_remains
3077 + sponge_init_deselector * running_evaluation_updates_for_sponge_init
3078 + sponge_absorb_deselector * running_evaluation_updates_for_absorb
3079 + sponge_absorb_mem_deselector * running_evaluation_updates_for_absorb_mem
3080 + sponge_squeeze_deselector * running_evaluation_updates_for_squeeze
3081}
3082
3083fn log_derivative_with_u32_table_updates_correctly(
3084 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
3085) -> ConstraintCircuitMonad<DualRowIndicator> {
3086 let constant = |c: u32| circuit_builder.b_constant(c);
3087 let one = || constant(1);
3088 let two_inverse = circuit_builder.b_constant(bfe!(2).inverse());
3089 let challenge = |c: ChallengeId| circuit_builder.challenge(c);
3090 let curr_main_row =
3091 |col: MainColumn| circuit_builder.input(CurrentMain(col.master_main_index()));
3092 let next_main_row = |col: MainColumn| circuit_builder.input(NextMain(col.master_main_index()));
3093 let curr_aux_row = |col: AuxColumn| circuit_builder.input(CurrentAux(col.master_aux_index()));
3094 let next_aux_row = |col: AuxColumn| circuit_builder.input(NextAux(col.master_aux_index()));
3095
3096 let split_deselector = instruction_deselector_current_row(circuit_builder, Instruction::Split);
3097 let lt_deselector = instruction_deselector_current_row(circuit_builder, Instruction::Lt);
3098 let and_deselector = instruction_deselector_current_row(circuit_builder, Instruction::And);
3099 let xor_deselector = instruction_deselector_current_row(circuit_builder, Instruction::Xor);
3100 let pow_deselector = instruction_deselector_current_row(circuit_builder, Instruction::Pow);
3101 let log_2_floor_deselector =
3102 instruction_deselector_current_row(circuit_builder, Instruction::Log2Floor);
3103 let div_mod_deselector =
3104 instruction_deselector_current_row(circuit_builder, Instruction::DivMod);
3105 let pop_count_deselector =
3106 instruction_deselector_current_row(circuit_builder, Instruction::PopCount);
3107 let merkle_step_deselector =
3108 instruction_deselector_current_row(circuit_builder, Instruction::MerkleStep);
3109 let merkle_step_mem_deselector =
3110 instruction_deselector_current_row(circuit_builder, Instruction::MerkleStepMem);
3111
3112 let running_sum = curr_aux_row(AuxColumn::U32LookupClientLogDerivative);
3113 let running_sum_next = next_aux_row(AuxColumn::U32LookupClientLogDerivative);
3114
3115 let split_factor = challenge(ChallengeId::U32Indeterminate)
3116 - challenge(ChallengeId::U32LhsWeight) * next_main_row(MainColumn::ST0)
3117 - challenge(ChallengeId::U32RhsWeight) * next_main_row(MainColumn::ST1)
3118 - challenge(ChallengeId::U32CiWeight) * curr_main_row(MainColumn::CI);
3119 let binop_factor = challenge(ChallengeId::U32Indeterminate)
3120 - challenge(ChallengeId::U32LhsWeight) * curr_main_row(MainColumn::ST0)
3121 - challenge(ChallengeId::U32RhsWeight) * curr_main_row(MainColumn::ST1)
3122 - challenge(ChallengeId::U32CiWeight) * curr_main_row(MainColumn::CI)
3123 - challenge(ChallengeId::U32ResultWeight) * next_main_row(MainColumn::ST0);
3124 let xor_factor = challenge(ChallengeId::U32Indeterminate)
3125 - challenge(ChallengeId::U32LhsWeight) * curr_main_row(MainColumn::ST0)
3126 - challenge(ChallengeId::U32RhsWeight) * curr_main_row(MainColumn::ST1)
3127 - challenge(ChallengeId::U32CiWeight) * constant(Instruction::And.opcode())
3128 - challenge(ChallengeId::U32ResultWeight)
3129 * (curr_main_row(MainColumn::ST0) + curr_main_row(MainColumn::ST1)
3130 - next_main_row(MainColumn::ST0))
3131 * two_inverse;
3132 let unop_factor = challenge(ChallengeId::U32Indeterminate)
3133 - challenge(ChallengeId::U32LhsWeight) * curr_main_row(MainColumn::ST0)
3134 - challenge(ChallengeId::U32CiWeight) * curr_main_row(MainColumn::CI)
3135 - challenge(ChallengeId::U32ResultWeight) * next_main_row(MainColumn::ST0);
3136 let div_mod_factor_for_lt = challenge(ChallengeId::U32Indeterminate)
3137 - challenge(ChallengeId::U32LhsWeight) * next_main_row(MainColumn::ST0)
3138 - challenge(ChallengeId::U32RhsWeight) * curr_main_row(MainColumn::ST1)
3139 - challenge(ChallengeId::U32CiWeight) * constant(Instruction::Lt.opcode())
3140 - challenge(ChallengeId::U32ResultWeight);
3141 let div_mod_factor_for_range_check = challenge(ChallengeId::U32Indeterminate)
3142 - challenge(ChallengeId::U32LhsWeight) * curr_main_row(MainColumn::ST0)
3143 - challenge(ChallengeId::U32RhsWeight) * next_main_row(MainColumn::ST1)
3144 - challenge(ChallengeId::U32CiWeight) * constant(Instruction::Split.opcode());
3145 let merkle_step_range_check_factor = challenge(ChallengeId::U32Indeterminate)
3146 - challenge(ChallengeId::U32LhsWeight) * curr_main_row(MainColumn::ST5)
3147 - challenge(ChallengeId::U32RhsWeight) * next_main_row(MainColumn::ST5)
3148 - challenge(ChallengeId::U32CiWeight) * constant(Instruction::Split.opcode());
3149
3150 let running_sum_absorbs_split_factor =
3151 (running_sum_next.clone() - running_sum.clone()) * split_factor - one();
3152 let running_sum_absorbs_binop_factor =
3153 (running_sum_next.clone() - running_sum.clone()) * binop_factor - one();
3154 let running_sum_absorb_xor_factor =
3155 (running_sum_next.clone() - running_sum.clone()) * xor_factor - one();
3156 let running_sum_absorbs_unop_factor =
3157 (running_sum_next.clone() - running_sum.clone()) * unop_factor - one();
3158 let running_sum_absorbs_merkle_step_factor =
3159 (running_sum_next.clone() - running_sum.clone()) * merkle_step_range_check_factor - one();
3160
3161 let split_summand = split_deselector * running_sum_absorbs_split_factor;
3162 let lt_summand = lt_deselector * running_sum_absorbs_binop_factor.clone();
3163 let and_summand = and_deselector * running_sum_absorbs_binop_factor.clone();
3164 let xor_summand = xor_deselector * running_sum_absorb_xor_factor;
3165 let pow_summand = pow_deselector * running_sum_absorbs_binop_factor;
3166 let log_2_floor_summand = log_2_floor_deselector * running_sum_absorbs_unop_factor.clone();
3167 let div_mod_summand = div_mod_deselector
3168 * ((running_sum_next.clone() - running_sum.clone())
3169 * div_mod_factor_for_lt.clone()
3170 * div_mod_factor_for_range_check.clone()
3171 - div_mod_factor_for_lt
3172 - div_mod_factor_for_range_check);
3173 let pop_count_summand = pop_count_deselector * running_sum_absorbs_unop_factor;
3174 let merkle_step_summand =
3175 merkle_step_deselector * running_sum_absorbs_merkle_step_factor.clone();
3176 let merkle_step_mem_summand =
3177 merkle_step_mem_deselector * running_sum_absorbs_merkle_step_factor;
3178 let no_update_summand =
3179 (one() - curr_main_row(MainColumn::IB2)) * (running_sum_next - running_sum);
3180
3181 split_summand
3182 + lt_summand
3183 + and_summand
3184 + xor_summand
3185 + pow_summand
3186 + log_2_floor_summand
3187 + div_mod_summand
3188 + pop_count_summand
3189 + merkle_step_summand
3190 + merkle_step_mem_summand
3191 + no_update_summand
3192}
3193
3194fn stack_weight_by_index(i: usize) -> ChallengeId {
3195 match i {
3196 0 => ChallengeId::StackWeight0,
3197 1 => ChallengeId::StackWeight1,
3198 2 => ChallengeId::StackWeight2,
3199 3 => ChallengeId::StackWeight3,
3200 4 => ChallengeId::StackWeight4,
3201 5 => ChallengeId::StackWeight5,
3202 6 => ChallengeId::StackWeight6,
3203 7 => ChallengeId::StackWeight7,
3204 8 => ChallengeId::StackWeight8,
3205 9 => ChallengeId::StackWeight9,
3206 10 => ChallengeId::StackWeight10,
3207 11 => ChallengeId::StackWeight11,
3208 12 => ChallengeId::StackWeight12,
3209 13 => ChallengeId::StackWeight13,
3210 14 => ChallengeId::StackWeight14,
3211 15 => ChallengeId::StackWeight15,
3212 i => panic!("Op Stack weight index must be in [0, 15], not {i}."),
3213 }
3214}
3215
3216fn indicator_polynomial(
3218 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
3219 index: usize,
3220) -> ConstraintCircuitMonad<DualRowIndicator> {
3221 let one = || circuit_builder.b_constant(1);
3222 let hv = |idx| helper_variable(circuit_builder, idx);
3223
3224 match index {
3225 0 => (one() - hv(3)) * (one() - hv(2)) * (one() - hv(1)) * (one() - hv(0)),
3226 1 => (one() - hv(3)) * (one() - hv(2)) * (one() - hv(1)) * hv(0),
3227 2 => (one() - hv(3)) * (one() - hv(2)) * hv(1) * (one() - hv(0)),
3228 3 => (one() - hv(3)) * (one() - hv(2)) * hv(1) * hv(0),
3229 4 => (one() - hv(3)) * hv(2) * (one() - hv(1)) * (one() - hv(0)),
3230 5 => (one() - hv(3)) * hv(2) * (one() - hv(1)) * hv(0),
3231 6 => (one() - hv(3)) * hv(2) * hv(1) * (one() - hv(0)),
3232 7 => (one() - hv(3)) * hv(2) * hv(1) * hv(0),
3233 8 => hv(3) * (one() - hv(2)) * (one() - hv(1)) * (one() - hv(0)),
3234 9 => hv(3) * (one() - hv(2)) * (one() - hv(1)) * hv(0),
3235 10 => hv(3) * (one() - hv(2)) * hv(1) * (one() - hv(0)),
3236 11 => hv(3) * (one() - hv(2)) * hv(1) * hv(0),
3237 12 => hv(3) * hv(2) * (one() - hv(1)) * (one() - hv(0)),
3238 13 => hv(3) * hv(2) * (one() - hv(1)) * hv(0),
3239 14 => hv(3) * hv(2) * hv(1) * (one() - hv(0)),
3240 15 => hv(3) * hv(2) * hv(1) * hv(0),
3241 i => panic!("indicator polynomial index {i} out of bounds"),
3242 }
3243}
3244
3245fn helper_variable(
3246 circuit_builder: &ConstraintCircuitBuilder<DualRowIndicator>,
3247 index: usize,
3248) -> ConstraintCircuitMonad<DualRowIndicator> {
3249 match index {
3250 0 => circuit_builder.input(CurrentMain(MainColumn::HV0.master_main_index())),
3251 1 => circuit_builder.input(CurrentMain(MainColumn::HV1.master_main_index())),
3252 2 => circuit_builder.input(CurrentMain(MainColumn::HV2.master_main_index())),
3253 3 => circuit_builder.input(CurrentMain(MainColumn::HV3.master_main_index())),
3254 4 => circuit_builder.input(CurrentMain(MainColumn::HV4.master_main_index())),
3255 5 => circuit_builder.input(CurrentMain(MainColumn::HV5.master_main_index())),
3256 i => unimplemented!("Helper variable index {i} out of bounds."),
3257 }
3258}
3259
3260#[cfg(test)]
3261#[cfg_attr(coverage_nightly, coverage(off))]
3262mod tests {
3263 use ndarray::Array2;
3264 use ndarray::s;
3265 use num_traits::identities::Zero;
3266 use proptest::prop_assert_eq;
3267 use proptest_arbitrary_interop::arb;
3268 use test_strategy::proptest;
3269
3270 use crate::table::NUM_AUX_COLUMNS;
3271 use crate::table::NUM_MAIN_COLUMNS;
3272
3273 use super::*;
3274
3275 type MainColumn = <ProcessorTable as AIR>::MainColumn;
3276
3277 #[test]
3278 fn instruction_deselector_gives_0_for_all_other_instructions() {
3279 let circuit_builder = ConstraintCircuitBuilder::new();
3280
3281 let mut master_main_table = Array2::zeros([2, NUM_MAIN_COLUMNS]);
3282 let master_aux_table = Array2::zeros([2, NUM_AUX_COLUMNS]);
3283
3284 let dummy_challenges = (0..ChallengeId::COUNT)
3286 .map(|i| XFieldElement::from(i as u64))
3287 .collect_vec();
3288 for instruction in ALL_INSTRUCTIONS {
3289 let deselector = instruction_deselector_current_row(&circuit_builder, instruction);
3290
3291 println!("\n\nThe Deselector for instruction {instruction} is:\n{deselector}",);
3292
3293 for other_instruction in ALL_INSTRUCTIONS
3295 .into_iter()
3296 .filter(|other_instruction| *other_instruction != instruction)
3297 {
3298 let mut curr_row = master_main_table.slice_mut(s![0, ..]);
3299 curr_row[MainColumn::IB0.master_main_index()] =
3300 other_instruction.ib(InstructionBit::IB0);
3301 curr_row[MainColumn::IB1.master_main_index()] =
3302 other_instruction.ib(InstructionBit::IB1);
3303 curr_row[MainColumn::IB2.master_main_index()] =
3304 other_instruction.ib(InstructionBit::IB2);
3305 curr_row[MainColumn::IB3.master_main_index()] =
3306 other_instruction.ib(InstructionBit::IB3);
3307 curr_row[MainColumn::IB4.master_main_index()] =
3308 other_instruction.ib(InstructionBit::IB4);
3309 curr_row[MainColumn::IB5.master_main_index()] =
3310 other_instruction.ib(InstructionBit::IB5);
3311 curr_row[MainColumn::IB6.master_main_index()] =
3312 other_instruction.ib(InstructionBit::IB6);
3313 let result = deselector.clone().consume().evaluate(
3314 master_main_table.view(),
3315 master_aux_table.view(),
3316 &dummy_challenges,
3317 );
3318
3319 assert!(
3320 result.is_zero(),
3321 "Deselector for {instruction} should return 0 for all other instructions, \
3322 including {other_instruction} whose opcode is {}",
3323 other_instruction.opcode()
3324 )
3325 }
3326
3327 let mut curr_row = master_main_table.slice_mut(s![0, ..]);
3329 curr_row[MainColumn::IB0.master_main_index()] = instruction.ib(InstructionBit::IB0);
3330 curr_row[MainColumn::IB1.master_main_index()] = instruction.ib(InstructionBit::IB1);
3331 curr_row[MainColumn::IB2.master_main_index()] = instruction.ib(InstructionBit::IB2);
3332 curr_row[MainColumn::IB3.master_main_index()] = instruction.ib(InstructionBit::IB3);
3333 curr_row[MainColumn::IB4.master_main_index()] = instruction.ib(InstructionBit::IB4);
3334 curr_row[MainColumn::IB5.master_main_index()] = instruction.ib(InstructionBit::IB5);
3335 curr_row[MainColumn::IB6.master_main_index()] = instruction.ib(InstructionBit::IB6);
3336 let result = deselector.consume().evaluate(
3337 master_main_table.view(),
3338 master_aux_table.view(),
3339 &dummy_challenges,
3340 );
3341 assert!(
3342 !result.is_zero(),
3343 "Deselector for {instruction} should be non-zero when CI is {}",
3344 instruction.opcode()
3345 )
3346 }
3347 }
3348
3349 #[test]
3350 fn print_number_and_degrees_of_transition_constraints_for_all_instructions() {
3351 println!();
3352 println!("| Instruction | #polys | max deg | Degrees");
3353 println!("|:--------------------|-------:|--------:|:------------");
3354 let circuit_builder = ConstraintCircuitBuilder::new();
3355 for instruction in ALL_INSTRUCTIONS {
3356 let constraints = transition_constraints_for_instruction(&circuit_builder, instruction);
3357 let degrees = constraints
3358 .iter()
3359 .map(|circuit| circuit.clone().consume().degree())
3360 .collect_vec();
3361 let max_degree = degrees.iter().max().unwrap_or(&0);
3362 let degrees_str = degrees.iter().join(", ");
3363 println!(
3364 "| {:<19} | {:>6} | {max_degree:>7} | [{degrees_str}]",
3365 format!("{instruction}"),
3366 constraints.len(),
3367 );
3368 }
3369 }
3370 #[test]
3371 fn range_check_for_skiz_is_as_efficient_as_possible() {
3372 let range_check_constraints = next_instruction_range_check_constraints_for_instruction_skiz(
3373 &ConstraintCircuitBuilder::new(),
3374 );
3375 let range_check_constraints = range_check_constraints.iter();
3376 let all_degrees = range_check_constraints.map(|c| c.clone().consume().degree());
3377 let max_constraint_degree = all_degrees.max().unwrap_or(0);
3378 assert!(
3379 crate::TARGET_DEGREE <= max_constraint_degree,
3380 "Can the range check constraints be of a higher degree, saving columns?"
3381 );
3382 }
3383
3384 #[test]
3385 fn helper_variables_in_bounds() {
3386 let circuit_builder = ConstraintCircuitBuilder::new();
3387 for index in 0..NUM_HELPER_VARIABLE_REGISTERS {
3388 helper_variable(&circuit_builder, index);
3389 }
3390 }
3391
3392 #[proptest]
3393 #[should_panic(expected = "out of bounds")]
3394 fn cannot_get_helper_variable_for_out_of_range_index(
3395 #[strategy(NUM_HELPER_VARIABLE_REGISTERS..)] index: usize,
3396 ) {
3397 let circuit_builder = ConstraintCircuitBuilder::new();
3398 helper_variable(&circuit_builder, index);
3399 }
3400
3401 #[test]
3402 fn indicator_polynomial_in_bounds() {
3403 let circuit_builder = ConstraintCircuitBuilder::new();
3404 for index in 0..16 {
3405 indicator_polynomial(&circuit_builder, index);
3406 }
3407 }
3408
3409 #[proptest]
3410 #[should_panic(expected = "out of bounds")]
3411 fn cannot_get_indicator_polynomial_for_out_of_range_index(
3412 #[strategy(16_usize..
3413 )]
3414 index: usize,
3415 ) {
3416 let circuit_builder = ConstraintCircuitBuilder::new();
3417 indicator_polynomial(&circuit_builder, index);
3418 }
3419
3420 #[proptest]
3421 fn indicator_polynomial_is_one_on_indicated_index_and_zero_on_all_other_indices(
3422 #[strategy(0_usize..16)] indicator_poly_index: usize,
3423 #[strategy(0_u64..16)] query_index: u64,
3424 ) {
3425 let mut main_table = Array2::ones([2, NUM_MAIN_COLUMNS]);
3426 let aux_table = Array2::ones([2, NUM_AUX_COLUMNS]);
3427
3428 main_table[[0, MainColumn::HV0.master_main_index()]] = bfe!(query_index % 2);
3429 main_table[[0, MainColumn::HV1.master_main_index()]] = bfe!((query_index >> 1) % 2);
3430 main_table[[0, MainColumn::HV2.master_main_index()]] = bfe!((query_index >> 2) % 2);
3431 main_table[[0, MainColumn::HV3.master_main_index()]] = bfe!((query_index >> 3) % 2);
3432
3433 let builder = ConstraintCircuitBuilder::new();
3434 let indicator_poly = indicator_polynomial(&builder, indicator_poly_index).consume();
3435 let evaluation = indicator_poly.evaluate(main_table.view(), aux_table.view(), &[]);
3436
3437 if indicator_poly_index as u64 == query_index {
3438 prop_assert_eq!(xfe!(1), evaluation);
3439 } else {
3440 prop_assert_eq!(xfe!(0), evaluation);
3441 }
3442 }
3443
3444 #[test]
3445 fn can_get_op_stack_column_for_in_range_index() {
3446 for index in 0..OpStackElement::COUNT {
3447 let _ = ProcessorTable::op_stack_column_by_index(index);
3448 }
3449 }
3450
3451 #[proptest]
3452 #[should_panic(expected = "[0, 15]")]
3453 fn cannot_get_op_stack_column_for_out_of_range_index(
3454 #[strategy(OpStackElement::COUNT..)] index: usize,
3455 ) {
3456 let _ = ProcessorTable::op_stack_column_by_index(index);
3457 }
3458
3459 #[test]
3460 fn can_get_stack_weight_for_in_range_index() {
3461 for index in 0..OpStackElement::COUNT {
3462 let _ = stack_weight_by_index(index);
3463 }
3464 }
3465
3466 #[proptest]
3467 #[should_panic(expected = "[0, 15]")]
3468 fn cannot_get_stack_weight_for_out_of_range_index(
3469 #[strategy(OpStackElement::COUNT..)] index: usize,
3470 ) {
3471 let _ = stack_weight_by_index(index);
3472 }
3473
3474 #[proptest]
3475 fn xx_product_is_accurate(
3476 #[strategy(arb())] a: XFieldElement,
3477 #[strategy(arb())] b: XFieldElement,
3478 ) {
3479 let circuit_builder = ConstraintCircuitBuilder::new();
3480 let main_row = |col: MainColumn| circuit_builder.input(Main(col.master_main_index()));
3481 let [x0, x1, x2, y0, y1, y2] = [
3482 MainColumn::ST0,
3483 MainColumn::ST1,
3484 MainColumn::ST2,
3485 MainColumn::ST3,
3486 MainColumn::ST4,
3487 MainColumn::ST5,
3488 ]
3489 .map(main_row);
3490
3491 let mut main_table = Array2::zeros([1, NUM_MAIN_COLUMNS]);
3492 let aux_table = Array2::zeros([1, NUM_AUX_COLUMNS]);
3493 main_table[[0, MainColumn::ST0.master_main_index()]] = a.coefficients[0];
3494 main_table[[0, MainColumn::ST1.master_main_index()]] = a.coefficients[1];
3495 main_table[[0, MainColumn::ST2.master_main_index()]] = a.coefficients[2];
3496 main_table[[0, MainColumn::ST3.master_main_index()]] = b.coefficients[0];
3497 main_table[[0, MainColumn::ST4.master_main_index()]] = b.coefficients[1];
3498 main_table[[0, MainColumn::ST5.master_main_index()]] = b.coefficients[2];
3499
3500 let [c0, c1, c2] = xx_product([x0, x1, x2], [y0, y1, y2])
3501 .map(|c| c.consume())
3502 .map(|c| c.evaluate(main_table.view(), aux_table.view(), &[]))
3503 .map(|xfe| xfe.unlift().unwrap());
3504
3505 let c = a * b;
3506 prop_assert_eq!(c.coefficients[0], c0);
3507 prop_assert_eq!(c.coefficients[1], c1);
3508 prop_assert_eq!(c.coefficients[2], c2);
3509 }
3510
3511 #[proptest]
3512 fn xb_product_is_accurate(
3513 #[strategy(arb())] a: XFieldElement,
3514 #[strategy(arb())] b: BFieldElement,
3515 ) {
3516 let circuit_builder = ConstraintCircuitBuilder::new();
3517 let main_row = |col: MainColumn| circuit_builder.input(Main(col.master_main_index()));
3518 let [x0, x1, x2, y] = [
3519 MainColumn::ST0,
3520 MainColumn::ST1,
3521 MainColumn::ST2,
3522 MainColumn::ST3,
3523 ]
3524 .map(main_row);
3525
3526 let mut main_table = Array2::zeros([1, NUM_MAIN_COLUMNS]);
3527 let aux_table = Array2::zeros([1, NUM_AUX_COLUMNS]);
3528 main_table[[0, MainColumn::ST0.master_main_index()]] = a.coefficients[0];
3529 main_table[[0, MainColumn::ST1.master_main_index()]] = a.coefficients[1];
3530 main_table[[0, MainColumn::ST2.master_main_index()]] = a.coefficients[2];
3531 main_table[[0, MainColumn::ST3.master_main_index()]] = b;
3532
3533 let [c0, c1, c2] = xb_product([x0, x1, x2], y)
3534 .map(|c| c.consume())
3535 .map(|c| c.evaluate(main_table.view(), aux_table.view(), &[]))
3536 .map(|xfe| xfe.unlift().unwrap());
3537
3538 let c = a * b;
3539 prop_assert_eq!(c.coefficients[0], c0);
3540 prop_assert_eq!(c.coefficients[1], c1);
3541 prop_assert_eq!(c.coefficients[2], c2);
3542 }
3543}