tasm_lib/verifier/
stark_verify.rs

1use itertools::Itertools;
2use triton_vm::challenges::Challenges;
3use triton_vm::prelude::*;
4use triton_vm::proof_item::ProofItemVariant;
5use triton_vm::proof_stream::ProofStream;
6use triton_vm::table::NUM_QUOTIENT_SEGMENTS;
7use triton_vm::table::master_table::MasterAuxTable;
8use triton_vm::table::master_table::MasterMainTable;
9use twenty_first::math::x_field_element::EXTENSION_DEGREE;
10use twenty_first::prelude::MerkleTreeInclusionProof;
11
12use super::master_table::air_constraint_evaluation::AirConstraintEvaluation;
13use super::master_table::air_constraint_evaluation::MemoryLayout;
14use crate::arithmetic::bfe::primitive_root_of_unity::PrimitiveRootOfUnity;
15use crate::array::horner_evaluation::HornerEvaluation;
16use crate::array::inner_product_of_three_rows_with_weights::InnerProductOfThreeRowsWithWeights;
17use crate::array::inner_product_of_three_rows_with_weights::MainElementType;
18use crate::array::inner_product_of_xfes::InnerProductOfXfes;
19use crate::field;
20use crate::hashing::algebraic_hasher::sample_scalar_one::SampleScalarOne;
21use crate::hashing::algebraic_hasher::sample_scalars_static_length_dyn_malloc::SampleScalarsStaticLengthDynMalloc;
22use crate::prelude::*;
23use crate::verifier::challenges;
24use crate::verifier::claim::instantiate_fiat_shamir_with_claim::InstantiateFiatShamirWithClaim;
25use crate::verifier::claim::shared::claim_type;
26use crate::verifier::fri;
27use crate::verifier::fri::verify::FriSnippet;
28use crate::verifier::fri::verify::FriVerify;
29use crate::verifier::master_table::divide_out_zerofiers::DivideOutZerofiers;
30use crate::verifier::master_table::verify_table_rows::ColumnType;
31use crate::verifier::master_table::verify_table_rows::VerifyTableRows;
32use crate::verifier::out_of_domain_points::OodPoint;
33use crate::verifier::out_of_domain_points::OutOfDomainPoints;
34use crate::verifier::vm_proof_iter::dequeue_next_as::DequeueNextAs;
35use crate::verifier::vm_proof_iter::drop::Drop;
36use crate::verifier::vm_proof_iter::new::New;
37
38pub(crate) const NUM_PROOF_ITEMS_PER_FRI_ROUND: usize = 2;
39pub(crate) const NUM_PROOF_ITEMS_EXCLUDING_FRI: usize = 15;
40
41/// Verify a STARK proof.
42///
43/// Verify a STARK proof located in memory. Assumes the nondeterministic digests
44/// stream has been updated with the digests extracted from the proof using
45/// [`update_nondeterminism`](Self::update_nondeterminism). Crashes the VM if the
46/// proof is invalid.
47///
48/// Stack signature:
49///  - BEFORE: _ *claim *proof
50///  - AFTER:  _
51#[derive(Debug, Copy, Clone)]
52pub struct StarkVerify {
53    stark: Stark,
54    memory_layout: MemoryLayout,
55}
56
57impl StarkVerify {
58    pub fn new_with_static_layout(stark: Stark) -> Self {
59        Self {
60            stark,
61            memory_layout: MemoryLayout::conventional_static(),
62        }
63    }
64
65    pub fn new_with_dynamic_layout(stark: Stark) -> Self {
66        Self {
67            stark,
68            memory_layout: MemoryLayout::conventional_dynamic(),
69        }
70    }
71
72    /// The number of nondeterministic digests that will be
73    /// consumed when this snippet verifies the given proof.
74    pub fn number_of_nondeterministic_digests_consumed(&self, proof: &Proof) -> usize {
75        const NUM_FULL_DOMAIN_AUTH_PATHS: usize = 4;
76
77        let padded_height = proof.padded_height().unwrap();
78        let fri_params = self.stark.fri(padded_height).unwrap();
79        let num_fri_rounds = fri_params.num_rounds();
80
81        let mut j = 0;
82        let mut tree_height: usize = fri_params.domain.length.ilog2().try_into().unwrap();
83
84        let mut acc = NUM_FULL_DOMAIN_AUTH_PATHS * tree_height * fri_params.num_collinearity_checks;
85        while j < num_fri_rounds {
86            acc += fri_params.num_collinearity_checks * tree_height;
87            j += 1;
88            tree_height -= 1;
89        }
90
91        acc
92    }
93
94    /// The number of nondeterministic individual tokens that will be consumed when
95    /// this snippet verifies the given (claim, proof) pair.
96    // Right now this number is zero, but that might change in the future.
97    pub fn number_of_nondeterministic_tokens_consumed(
98        &self,
99        _proof: &Proof,
100        _claim: &Claim,
101    ) -> usize {
102        0
103    }
104
105    /// Prepares the non-determinism for verifying a STARK proof. Specifically,
106    /// extracts the digests for traversing authentication paths and appends them
107    /// to nondeterministic digests. Leaves memory and individual tokens intact.
108    pub fn update_nondeterminism(
109        &self,
110        nondeterminism: &mut NonDeterminism,
111        proof: &Proof,
112        claim: &Claim,
113    ) {
114        nondeterminism
115            .digests
116            .append(&mut self.extract_nondeterministic_digests(proof, claim));
117    }
118
119    fn extract_nondeterministic_digests(&self, proof: &Proof, claim: &Claim) -> Vec<Digest> {
120        const NUM_DEEP_CODEWORD_COMPONENTS: usize = 3;
121
122        fn extract_paths<R: BFieldCodec>(
123            indices: Vec<usize>,
124            leaf_preimages: Vec<R>,
125            tree_height: u32,
126            authentication_structure: Vec<Digest>,
127        ) -> Vec<Vec<Digest>> {
128            let indexed_leafs = indices
129                .into_iter()
130                .zip(leaf_preimages.iter().map(Tip5::hash))
131                .collect();
132            MerkleTreeInclusionProof {
133                tree_height,
134                indexed_leafs,
135                authentication_structure,
136            }
137            .into_authentication_paths()
138            .unwrap()
139        }
140
141        // We do need to carefully update the sponge state because otherwise
142        // we end up sampling indices that generate different authentication
143        // paths.
144        let mut proof_stream = ProofStream::try_from(proof).unwrap();
145        let log2_padded_height = proof_stream
146            .dequeue()
147            .unwrap()
148            .try_into_log2_padded_height()
149            .unwrap();
150        proof_stream.alter_fiat_shamir_state_with(claim);
151
152        // Main-table Merkle root
153        let _main_table_root = proof_stream
154            .dequeue()
155            .unwrap()
156            .try_into_merkle_root()
157            .unwrap();
158
159        // Auxiliary challenge weights
160        let _challenges = proof_stream.sample_scalars(Challenges::SAMPLE_COUNT);
161
162        // Auxiliary-table Merkle root
163        let _aux_mt_root = proof_stream
164            .dequeue()
165            .unwrap()
166            .try_into_merkle_root()
167            .unwrap();
168
169        // Quotient codeword weights
170        proof_stream.sample_scalars(MasterAuxTable::NUM_CONSTRAINTS);
171
172        // Quotient codeword Merkle root
173        let _quotient_root = proof_stream
174            .dequeue()
175            .unwrap()
176            .try_into_merkle_root()
177            .unwrap();
178
179        // Out-of-domain point current row
180        let _out_of_domain_point_curr_row = proof_stream.sample_scalars(1);
181
182        // Five out-of-domain values
183        proof_stream
184            .dequeue()
185            .unwrap()
186            .try_into_out_of_domain_main_row()
187            .unwrap();
188        proof_stream
189            .dequeue()
190            .unwrap()
191            .try_into_out_of_domain_aux_row()
192            .unwrap();
193        proof_stream
194            .dequeue()
195            .unwrap()
196            .try_into_out_of_domain_main_row()
197            .unwrap();
198        proof_stream
199            .dequeue()
200            .unwrap()
201            .try_into_out_of_domain_aux_row()
202            .unwrap();
203        proof_stream
204            .dequeue()
205            .unwrap()
206            .try_into_out_of_domain_quot_segments()
207            .unwrap();
208
209        // `beqd_weights`
210        proof_stream.sample_scalars(
211            MasterMainTable::NUM_COLUMNS
212                + MasterAuxTable::NUM_COLUMNS
213                + NUM_QUOTIENT_SEGMENTS
214                + NUM_DEEP_CODEWORD_COMPONENTS,
215        );
216
217        // FRI digests
218        let padded_height = 1 << log2_padded_height;
219        let fri = self.stark.fri(padded_height).unwrap();
220        let fri_proof_stream = proof_stream.clone();
221        let fri_verify_result = fri.verify(&mut proof_stream).unwrap();
222        let indices = fri_verify_result.iter().map(|(i, _)| *i).collect_vec();
223        let tree_height = fri.domain.length.ilog2();
224        let fri_digests =
225            FriVerify::from(fri).extract_digests_required_for_proving(&fri_proof_stream);
226
227        // main
228        let main_table_rows = proof_stream
229            .dequeue()
230            .unwrap()
231            .try_into_master_main_table_rows()
232            .unwrap();
233        let main_authentication_structure = proof_stream
234            .dequeue()
235            .unwrap()
236            .try_into_authentication_structure()
237            .unwrap();
238        let main_tree_auth_paths = extract_paths(
239            indices.clone(),
240            main_table_rows,
241            tree_height,
242            main_authentication_structure,
243        );
244
245        // aux
246        let aux_table_rows = proof_stream
247            .dequeue()
248            .unwrap()
249            .try_into_master_aux_table_rows()
250            .unwrap();
251        let aux_authentication_structure = proof_stream
252            .dequeue()
253            .unwrap()
254            .try_into_authentication_structure()
255            .unwrap();
256        let aux_tree_auth_paths = extract_paths(
257            indices.clone(),
258            aux_table_rows,
259            tree_height,
260            aux_authentication_structure,
261        );
262
263        // quotient
264        let quot_table_rows = proof_stream
265            .dequeue()
266            .unwrap()
267            .try_into_quot_segments_elements()
268            .unwrap();
269        let quot_authentication_structure = proof_stream
270            .dequeue()
271            .unwrap()
272            .try_into_authentication_structure()
273            .unwrap();
274        let quot_tree_auth_paths = extract_paths(
275            indices,
276            quot_table_rows,
277            tree_height,
278            quot_authentication_structure,
279        );
280
281        let stark_digests = [
282            main_tree_auth_paths,
283            aux_tree_auth_paths,
284            quot_tree_auth_paths,
285        ]
286        .concat()
287        .concat();
288
289        [fri_digests, stark_digests].concat()
290    }
291}
292
293impl BasicSnippet for StarkVerify {
294    fn inputs(&self) -> Vec<(DataType, String)> {
295        let claim_type = DataType::StructRef(claim_type());
296        vec![
297            (claim_type, "claim".to_string()),
298            (DataType::VoidPointer, "*proof".to_string()),
299        ]
300    }
301
302    fn outputs(&self) -> Vec<(DataType, String)> {
303        vec![]
304    }
305
306    fn entrypoint(&self) -> String {
307        let memory_layout_category = self.memory_layout.label_friendly_name();
308        format!("tasmlib_verifier_stark_verify_{memory_layout_category}")
309    }
310
311    fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
312        const NUM_DEEP_CODEWORD_COMPONENTS: usize = 3;
313        const NUM_OOD_ROWS_WO_QUOTIENT: u32 = 4;
314
315        fn fri_snippet() -> FriSnippet {
316            #[cfg(not(test))]
317            {
318                FriSnippet {}
319            }
320            #[cfg(test)]
321            {
322                FriSnippet {
323                    test_instance: FriVerify::dummy(),
324                }
325            }
326        }
327
328        let entrypoint = self.entrypoint();
329
330        let proof_to_vm_proof_iter = library.import(Box::new(New));
331        let drop_vm_proof_iter = library.import(Box::new(Drop));
332
333        let ood_curr_row_main_and_aux_value_pointer_alloc =
334            library.kmalloc(EXTENSION_DEGREE.try_into().unwrap());
335        let ood_next_row_main_and_aux_value_pointer_alloc =
336            library.kmalloc(EXTENSION_DEGREE.try_into().unwrap());
337        let ood_curr_row_quotient_segment_value_pointer_alloc =
338            library.kmalloc(EXTENSION_DEGREE.try_into().unwrap());
339
340        let out_of_domain_curr_row_quot_segments_pointer_alloc = library.kmalloc(1);
341
342        let instantiate_fiat_shamir_with_claim =
343            library.import(Box::new(InstantiateFiatShamirWithClaim));
344        let next_as_log_2_padded_height = library.import(Box::new(DequeueNextAs {
345            proof_item: ProofItemVariant::Log2PaddedHeight,
346        }));
347        let next_as_merkleroot = library.import(Box::new(DequeueNextAs {
348            proof_item: ProofItemVariant::MerkleRoot,
349        }));
350        let next_as_outofdomainmainrow = library.import(Box::new(DequeueNextAs {
351            proof_item: ProofItemVariant::OutOfDomainMainRow,
352        }));
353        let next_as_outofdomainauxrow = library.import(Box::new(DequeueNextAs {
354            proof_item: ProofItemVariant::OutOfDomainAuxRow,
355        }));
356        let next_as_outofdomainquotientsegments = library.import(Box::new(DequeueNextAs {
357            proof_item: ProofItemVariant::OutOfDomainQuotientSegments,
358        }));
359        let next_as_maintablerows = library.import(Box::new(DequeueNextAs {
360            proof_item: ProofItemVariant::MasterMainTableRows,
361        }));
362        let next_as_authentication_path = library.import(Box::new(DequeueNextAs {
363            proof_item: ProofItemVariant::AuthenticationStructure,
364        }));
365        let next_as_auxtablerows = library.import(Box::new(DequeueNextAs {
366            proof_item: ProofItemVariant::MasterAuxTableRows,
367        }));
368        let next_as_quotient_segment_elements = library.import(Box::new(DequeueNextAs {
369            proof_item: ProofItemVariant::QuotientSegmentsElements,
370        }));
371        let derive_fri_parameters =
372            library.import(Box::new(fri::derive_from_stark::DeriveFriFromStark {
373                stark: self.stark,
374            }));
375        let num_collinearity_checks_field = field!(FriVerify::num_collinearity_checks);
376        let domain_length_field = field!(FriVerify::domain_length);
377        let domain_offset_field = field!(FriVerify::domain_offset);
378        let domain_generator_field = field!(FriVerify::domain_generator);
379
380        let fri_verify = library.import(Box::new(fri_snippet()));
381
382        let get_challenges = library.import(Box::new(
383            challenges::new_generic_dyn_claim::NewGenericDynClaim::tvm_challenges(
384                self.memory_layout.challenges_pointer(),
385            ),
386        ));
387        let sample_quotient_codeword_weights =
388            library.import(Box::new(SampleScalarsStaticLengthDynMalloc {
389                num_elements: MasterAuxTable::NUM_CONSTRAINTS,
390            }));
391        let domain_generator = library.import(Box::new(PrimitiveRootOfUnity));
392        let sample_scalar_one = library.import(Box::new(SampleScalarOne));
393        let calculate_out_of_domain_points = library.import(Box::new(OutOfDomainPoints));
394        let divide_out_zerofiers = library.import(Box::new(DivideOutZerofiers));
395        let inner_product_quotient_summands = library.import(Box::new(InnerProductOfXfes {
396            length: MasterAuxTable::NUM_CONSTRAINTS,
397        }));
398        let horner_evaluation_of_ood_curr_row_quot_segments =
399            library.import(Box::new(HornerEvaluation {
400                num_coefficients: NUM_QUOTIENT_SEGMENTS,
401            }));
402        let sample_beqd_weights = library.import(Box::new(SampleScalarsStaticLengthDynMalloc {
403            num_elements: MasterMainTable::NUM_COLUMNS
404                + MasterAuxTable::NUM_COLUMNS
405                + NUM_QUOTIENT_SEGMENTS
406                + NUM_DEEP_CODEWORD_COMPONENTS,
407        }));
408        let verify_main_table_rows = library.import(Box::new(VerifyTableRows {
409            column_type: ColumnType::Main,
410        }));
411        let verify_aux_table_rows = library.import(Box::new(VerifyTableRows {
412            column_type: ColumnType::Aux,
413        }));
414        let verify_quotient_segments = library.import(Box::new(VerifyTableRows {
415            column_type: ColumnType::Quotient,
416        }));
417        let inner_product_three_rows_with_weights_bfe_main = library.import(Box::new(
418            InnerProductOfThreeRowsWithWeights::triton_vm_parameters(MainElementType::Bfe),
419        ));
420        let inner_product_three_rows_with_weights_xfe_main = library.import(Box::new(
421            InnerProductOfThreeRowsWithWeights::triton_vm_parameters(MainElementType::Xfe),
422        ));
423        let inner_product_4_xfes = library.import(Box::new(InnerProductOfXfes { length: 4 }));
424        let quotient_segment_codeword_weights_from_be_weights = triton_asm!(
425            // _ *beqd_ws
426
427            push {(MasterMainTable::NUM_COLUMNS + MasterAuxTable::NUM_COLUMNS) * EXTENSION_DEGREE}
428            add
429            // _ *quotient_segment_weights
430        );
431        let deep_codeword_weights_read_address = |n: usize| {
432            assert!(n < NUM_DEEP_CODEWORD_COMPONENTS);
433            triton_asm!(
434                // _ *beqd_ws
435
436                push {(MasterMainTable::NUM_COLUMNS + MasterAuxTable::NUM_COLUMNS + NUM_QUOTIENT_SEGMENTS + n) * EXTENSION_DEGREE + {EXTENSION_DEGREE - 1}}
437                add
438                // _ *deep_codeword_weight[n]_last_word
439            )
440        };
441
442        let dequeue_four_ood_rows = triton_asm! {
443            // _ *proof_iter
444            dup 0
445            call {next_as_outofdomainmainrow}
446            hint out_of_domain_curr_main_row: Pointer = stack[0]
447
448            dup 1
449            call {next_as_outofdomainauxrow}
450            hint out_of_domain_curr_aux_row: Pointer = stack[0]
451
452            dup 2
453            call {next_as_outofdomainmainrow}
454            hint out_of_domain_next_main_row: Pointer = stack[0]
455
456            dup 3
457            call {next_as_outofdomainauxrow}
458            hint out_of_domain_next_aux_row: Pointer = stack[0]
459            // _ *proof_iter *curr_main *curr_aux *next_main *next_aux
460        };
461
462        // BEFORE:
463        // _ *p_iter - - - *quot_cw_ws - dom_gen [out_of_domain_curr_row] padded_height *proof_iter *curr_main *curr_aux *next_main *next_aux
464        // AFTER:
465        // _ *p_iter - - - *quot_cw_ws - dom_gen [out_of_domain_curr_row] padded_height *air_evaluation_result
466        let ood_pointers_alloc = library.kmalloc(NUM_OOD_ROWS_WO_QUOTIENT);
467        let evaluate_air_and_store_ood_pointers = match self.memory_layout {
468            MemoryLayout::Static(static_layout) => {
469                let static_eval =
470                    library.import(Box::new(AirConstraintEvaluation::new_static(static_layout)));
471                triton_asm! {
472                    push {ood_pointers_alloc.write_address()}
473                    write_mem {ood_pointers_alloc.num_words()}
474
475                    pop 2
476                    // _ ... padded_height
477
478                    call {static_eval}
479                    // _ ... padded_height *air_evaluation_result
480                }
481            }
482            MemoryLayout::Dynamic(dynamic_layout) => {
483                let dynamic_eval = library.import(Box::new(AirConstraintEvaluation::new_dynamic(
484                    dynamic_layout,
485                )));
486                triton_asm! {
487                    // store pointers to static memory
488                    dup 3
489                    dup 3
490                    dup 3
491                    dup 3
492                    push {ood_pointers_alloc.write_address()}
493                    write_mem {ood_pointers_alloc.num_words()}
494                    pop 1
495                    // _ ... padded_height *proof_iter *curr_main *curr_aux *next_main *next_aux
496
497                    call {dynamic_eval}
498                    // _ ... padded_height *proof_iter *air_evaluation_result
499
500                    pick 1 pop 1
501                    // _ ... padded_height *air_evaluation_result
502                }
503            }
504        };
505
506        let put_ood_row_pointers_back_on_stack = triton_asm! {
507            // _
508            push {ood_pointers_alloc.read_address()}
509            read_mem {ood_pointers_alloc.num_words()}
510            pop 1
511
512            // _ *curr_main *curr_aux *next_main *next_aux
513        };
514
515        let challenges_ptr = self.memory_layout.challenges_pointer();
516
517        let assert_top_two_xfes_eq = triton_asm!(
518            // _ y2 y1 y0 x2 x1 x0
519            pick 3
520            eq
521            assert error_id 230
522
523            // _ y2 y1 x2 x1
524            pick 2
525            eq
526            assert error_id 231
527
528            // _ y2 x2
529            eq
530            assert error_id 232
531
532            // _
533        );
534
535        let main_loop_label = format!("{entrypoint}_main_loop");
536        let main_loop_body = triton_asm!(
537            //                                                        (u32, XFieldElement)
538            // _ remaining_rounds fri_gen fri_offset *etrow *btrow *qseg_elem *fri_revealed_idx *beqd_ws *oodpnts
539            // Calculate `current_fri_domain_value`
540            pick 2
541            read_mem 1
542            place 3
543            // _ remaining_rounds fri_gen fri_offset *etrow *btrow *qseg_elem *fri_revealed_xfe *beqd_ws *oodpnts fri_idx
544
545            dup 8
546            pow
547            dup 7
548            mul
549            push -1
550            mul
551            hint neg_fri_domain_point = stack[0]
552            // _ remaining_rounds fri_gen fri_offset *etrow *btrow *qseg_elem *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt)
553
554
555            dup 6
556            dup 6
557            dup 4
558            call {inner_product_three_rows_with_weights_bfe_main} // expect arguments: *aux *main *ws
559            hint main_and_aux_opened_row_element: Xfe = stack[0..3]
560            // _ remaining_rounds fri_gen fri_offset *etrow *btrow *qseg_elem *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [be_opnd_elem]
561
562            // Update `*btrow` and `*etrow` pointer values to point to previous element
563            pick 9
564            addi {-bfe!(EXTENSION_DEGREE * MasterAuxTable::NUM_COLUMNS)}
565            place 9
566            pick 8
567            addi {-bfe!(MasterMainTable::NUM_COLUMNS)}
568            place 8
569            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [be_opnd_elem]
570
571            push -1
572            xb_mul
573            hint neg_main_and_aux_opened_row_element: Xfe = stack[0..3]
574
575            // Calculate `cuotient_curr_row_deep_value`
576            dup 4
577            {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRowPowNumSegments)}
578            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [oodp_pow_nsegs]
579
580            dup 6
581            add
582            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [oodp_pow_nsegs - fdom_pnt]
583
584            x_invert
585            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [1/(oodp_pow_nsegs - fdom_pnt)]
586
587            dup 8
588            {&quotient_segment_codeword_weights_from_be_weights}
589            dup 11
590            call {inner_product_4_xfes}
591            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [1/(oodp_pow_nsegs - fdom_pnt)] [inner_prod]
592
593            pick 13
594            addi {-bfe!(NUM_QUOTIENT_SEGMENTS * EXTENSION_DEGREE)}
595            place 13
596            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [1/(oodp_pow_nsegs - fdom_pnt)] [inner_prod]
597
598            push -1
599            xb_mul
600            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [1/(oodp_pow_nsegs - fdom_pnt)] [-inner_prod]
601
602            push {ood_curr_row_quotient_segment_value_pointer_alloc.read_address()}
603            read_mem {EXTENSION_DEGREE}
604            pop 1
605            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [1/(oodp_pow_nsegs - fdom_pnt)] [-inner_prod] [out_of_domain_curr_row_quotient_segment_value]
606
607            xx_add
608            xx_mul
609            hint quot_curr_row_deep_value: XFieldElement = stack[0..3]
610            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [(out_of_domain_curr_row_quotient_segment_value - inner_prod) / (oodp_pow_nsegs - fdom_pnt)]
611            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [quot_curr_row_deep_value]
612
613
614            /* Calculate $dv2 = quot_curr_row_deep_value * deep_codeword_weights[2]$ */
615            dup 8
616            {&deep_codeword_weights_read_address(2)}
617            read_mem {EXTENSION_DEGREE}
618            pop 1
619            xx_mul
620            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [quot_curr_row_deep_value * deep_codeword_weights[2]]
621            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [dv2]
622
623            dup 7
624            {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRow)}
625            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [dv2] [ood_point_curr_row]
626
627            dup 9
628            add
629            x_invert
630            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [dv2] [1/(ood_point_curr_row - fdom_pnt)]
631
632            push {ood_curr_row_main_and_aux_value_pointer_alloc.read_address()}
633            read_mem {EXTENSION_DEGREE}
634            pop 1
635            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [dv2] [1/(ood_point_curr_row - fdom_pnt)] [out_of_domain_curr_row_main_and_aux_value]
636
637            dup 11
638            dup 11
639            dup 11
640            xx_add
641            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [dv2] [1/(ood_point_curr_row - fdom_pnt)] [out_of_domain_curr_row_main_and_aux_value - be_opnd_elem]
642
643            xx_mul
644            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [dv2] [(out_of_domain_curr_row_main_and_aux_value - be_opnd_elem)/(ood_point_curr_row - fdom_pnt)]
645
646            dup 11
647            {&deep_codeword_weights_read_address(0)}
648            read_mem {EXTENSION_DEGREE}              // read deep_codeword_weights[0]
649            pop 1
650            xx_mul
651            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [dv2] [deep_codeword_weights[0] * (out_of_domain_curr_row_main_and_aux_value - be_opnd_elem)/(ood_point_curr_row - fdom_pnt)]
652            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [dv2] [dv0]
653
654            xx_add
655            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [-be_opnd_elem] [dv2 + dv0]
656            hint dv2_plus_dv0: XFieldElement = stack[0..3]
657
658            pick 5
659            pick 5
660            pick 5
661            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [dv2 + dv0] [-be_opnd_elem]
662
663            push {ood_next_row_main_and_aux_value_pointer_alloc.read_address()}
664            read_mem {EXTENSION_DEGREE}
665            pop 1
666            xx_add
667            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [dv2 + dv0] [ood_next_row_be_value - be_opnd_elem]
668
669            dup 7
670            {&OutOfDomainPoints::read_ood_point(OodPoint::NextRow)}
671            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [dv2 + dv0] [ood_next_row_be_value - be_opnd_elem] [out_of_domain_point_next_row]
672
673            dup 9
674            add
675            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [dv2 + dv0] [ood_next_row_be_value - be_opnd_elem] [out_of_domain_point_next_row - fdom_pnt]
676
677            x_invert
678            xx_mul
679            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [dv2 + dv0] [(ood_next_row_be_value - be_opnd_elem)/(out_of_domain_point_next_row - fdom_pnt)]
680
681            dup 8
682            {&deep_codeword_weights_read_address(1)}
683            read_mem {EXTENSION_DEGREE}              // read deep_codeword_weights[1]
684            pop 1
685            xx_mul
686            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [dv2 + dv0] [deep_codeword_weights[1] * (ood_next_row_be_value - be_opnd_elem)/(out_of_domain_point_next_row - fdom_pnt)]
687            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [dv2 + dv0] [dv1]
688
689            xx_add
690            hint deep_value: XFieldElement = stack[0..3]
691            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [dv2 + dv0 + dv1]
692            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts (-fdom_pnt) [deep_value]
693
694            pick 3
695            pop 1
696            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_xfe *beqd_ws *oodpnts [deep_value]
697
698            pick 5
699            read_mem {EXTENSION_DEGREE}
700            place 8
701            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_idx_prev *beqd_ws *oodpnts [deep_value] [fri_revealed_value]
702
703            {&assert_top_two_xfes_eq}
704
705            // _ remaining_rounds fri_gen fri_offset *etrow_prev *btrow_prev *qseg_elem_prev *fri_revealed_idx_prev *beqd_ws *oodpnts
706        );
707        let main_loop = triton_asm!(
708            // The loop goes from last index to 1st index
709            // Invariant: _ num_colli fri_gen fri_offset *etrow *btrow *qseg_elem *fri_revealed_elem *beqd_ws *oodpnts
710            {main_loop_label}:
711                // test end-condition
712                dup 8
713                push 0
714                eq
715                skiz
716                    return
717
718                {&main_loop_body}
719
720                // Update counter
721                pick 8
722                addi -1
723                place 8
724                recurse
725        );
726
727        triton_asm!(
728            {entrypoint}:
729                sponge_init
730                // _ *claim *proof
731
732                call {proof_to_vm_proof_iter}
733                hint proof_iter = stack[0]
734
735                // _ *clm *proof_iter
736
737
738                /* Fiat-Shamir: Claim */
739                dup 1
740                call {instantiate_fiat_shamir_with_claim}
741                // _ *clm *p_iter
742
743
744                /* derive additional parameters */
745                dup 0
746                call {next_as_log_2_padded_height}
747                // _ *clm *p_iter *log_2_padded_height
748
749                read_mem 1
750                pop 1
751                // _ *clm *p_iter log_2_padded_height
752
753                push 2
754                pow
755                hint padded_height = stack[0]
756                // _ *clm *p_iter padded_height
757
758                dup 0
759                call {derive_fri_parameters}
760                hint fri = stack[0]
761                // _ *clm *p_iter padded_height *fri
762
763                /* Fiat-Shamir 1 */
764                dup 2
765                call {next_as_merkleroot}
766                hint b_mr = stack[0]
767                // _ *clm *p_iter padded_height *fri *b_mr
768
769                swap 4
770                // _ *b_mr *p_iter padded_height *fri *clm
771
772                call {get_challenges}
773                // _ *b_mr *p_iter padded_height *fri *challenges
774
775                // verify that the challenges are stored at the right place
776                push {challenges_ptr}
777                eq
778                assert error_id 233
779                // _ *b_mr *p_iter padded_height *fri
780
781                dup 2
782                call {next_as_merkleroot}
783                hint e_mr = stack[0]
784                // _ *b_mr *p_iter padded_height *fri *e_mr
785
786                call {sample_quotient_codeword_weights}
787                // _ *b_mr *p_iter padded_height *fri *e_mr *quot_cw_ws
788                hint quot_codeword_weights = stack[0]
789
790                dup 4
791                call {next_as_merkleroot}
792                hint quot_mr = stack[0]
793                // _ *b_mr *p_iter padded_height *fri *e_mr *quot_cw_ws *quot_mr
794
795
796                /* sample and calculate OOD points (not rows) */
797                push 0
798                dup 5
799                call {domain_generator}
800                hint trace_domain_generator = stack[0]
801                // _ *b_mr *p_iter padded_height *fri *e_mr *quot_cw_ws *quot_mr dom_gen
802
803                dup 0
804                // _ *b_mr *p_iter padded_height *fri *e_mr *quot_cw_ws *quot_mr dom_gen dom_gen
805
806                call {sample_scalar_one}
807                // _ *b_mr *p_iter padded_height *fri *e_mr *quot_cw_ws *quot_mr dom_gen dom_gen [ood_curr_row]
808
809                call {calculate_out_of_domain_points}
810                hint out_of_domain_points = stack[0]
811                // _ *b_mr *p_iter padded_height *fri *e_mr *quot_cw_ws *quot_mr dom_gen *oodpnts
812
813
814                /* out-of-domain quotient summands */
815                push 2
816                add
817                read_mem {EXTENSION_DEGREE}
818                push 1
819                add
820                // _ *b_mr *p_iter padded_height *fri *e_mr *quot_cw_ws *quot_mr dom_gen [out_of_domain_curr_row] *oodpnts
821
822                swap 9
823                // _ *b_mr *p_iter *oodpnts *fri *e_mr *quot_cw_ws *quot_mr dom_gen [out_of_domain_curr_row] padded_height
824
825                dup 10
826                {&dequeue_four_ood_rows}
827                // _ *b_mr *p_iter *oodpnts *fri *e_mr *quot_cw_ws *quot_mr dom_gen [out_of_domain_curr_row] padded_height *proof_iter *curr_main *curr_aux *next_main *next_aux
828
829                {&evaluate_air_and_store_ood_pointers}
830                // _ *b_mr *p_iter *oodpnts *fri *e_mr *quot_cw_ws *quot_mr dom_gen [out_of_domain_curr_row] padded_height *air_evaluation_result
831
832                swap 5
833                // _ *b_mr *p_iter *oodpnts *fri *e_mr *quot_cw_ws *quot_mr *air_evaluation_result [out_of_domain_curr_row] padded_height dom_gen
834
835                call {divide_out_zerofiers}
836                // _ *b_mr *p_iter *oodpnts *fri *e_mr *quot_cw_ws *quot_mr *quotient_summands
837
838                {&put_ood_row_pointers_back_on_stack}
839                // _ *b_mr *p_iter *oodpnts *fri *e_mr *quot_cw_ws *quot_mr *quotient_summands *ood_brow_curr *ood_erow_curr *odd_brow_nxt *ood_erow_nxt
840
841                dup 10
842                call {next_as_outofdomainquotientsegments}
843                hint out_of_domain_quotient_segments: Pointer = stack[0]
844                // _ *b_mr *p_iter *oodpnts *fri *e_mr *quot_cw_ws *quot_mr *quotient_summands *ood_brow_curr *ood_erow_curr *odd_brow_nxt *ood_erow_nxt *ood_quotient_segments
845
846                dup 0
847                push {out_of_domain_curr_row_quot_segments_pointer_alloc.write_address()}
848                write_mem {out_of_domain_curr_row_quot_segments_pointer_alloc.num_words()}
849                pop 1
850
851
852                /* Calculate `sum_of_evaluated_out_of_domain_quotient_segments` */
853                dup 10
854                {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRow)}
855                // _ *b_mr *p_iter *oodpnts *fri *e_mr *quot_cw_ws *quot_mr *quotient_summands *ood_brow_curr *ood_erow_curr *odd_brow_nxt *ood_erow_nxt *ood_quotient_segments [ood_curr_row]
856
857                call {horner_evaluation_of_ood_curr_row_quot_segments}
858                // _ *b_mr *p_iter *oodpnts *fri *e_mr *quot_cw_ws *quot_mr *quotient_summands *ood_brow_curr *ood_erow_curr *odd_brow_nxt *ood_erow_nxt [sum_of_evaluated_out_of_domain_quotient_segments]
859
860
861                /* Calculate inner product `out_of_domain_quotient_value` */
862                pick 4 place 9
863                pick 3 place 6
864                pick 8 pick 6
865                // _ *b_mr *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr [sum_of_evaluated_out_of_domain_quotient_segments] *quot_cw_ws *quotient_summands
866
867                call {inner_product_quotient_summands}
868                // _ *b_mr *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr [sum_of_evaluated_out_of_domain_quotient_segments] [out_of_domain_quotient_value]
869
870                /* Verify quotient's segments */
871                {&assert_top_two_xfes_eq}
872                // _ *b_mr *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr
873
874                /* Fiat-shamir 2 */
875                call {sample_beqd_weights}
876                hint beqd_weights = stack[0]
877                // _ *b_mr *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *beqd_ws
878
879                swap 10
880                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *b_mr
881
882
883                /* FRI */
884                // We need the `fri` data structure for field values later, so we preserve its pointer on the stack
885                dup 9
886                dup 8
887                call {fri_verify}
888                hint fri_revealed = stack[0]
889                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *b_mr *fri_revealed
890
891
892                /* Dequeue main-table rows and verify against its Merkle root */
893                dup 10
894                call {next_as_maintablerows}
895                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *b_mr *fri_revealed *btrows
896
897
898                dup 9
899                {&num_collinearity_checks_field}
900                read_mem 1
901                pop 1
902                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *b_mr *fri_revealed *btrows num_colli
903
904                dup 10
905                {&domain_length_field}
906                read_mem 1
907                pop 1
908                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *b_mr *fri_revealed *btrows num_colli dom_len
909
910                log_2_floor
911                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *b_mr *fri_revealed *btrows num_colli mt_height
912
913                pick 4
914                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *btrows num_colli mt_height *b_mr
915
916                dup 4
917                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *btrows num_colli mt_height *b_mr *fri_revealed
918
919                dup 4
920                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *btrows num_colli mt_height *b_mr *fri_revealed *btrows
921
922                call {verify_main_table_rows}
923                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *btrows
924
925
926                /* Dequeue and ignore main-table's authentication path */
927                dup 10
928                call {next_as_authentication_path}
929                pop 1
930                // _ *beqd_ws *p_iter *oodpnts *fri *e_mr *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *btrows
931
932                swap 7
933                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *e_mr
934
935
936                /* Dequeue aux-table rows and verify against its Merkle root */
937                dup 10
938                call {next_as_auxtablerows}
939                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *e_mr *etrows
940
941                pick 1
942                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_nxt *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *etrows *e_mr
943
944                dup 9
945                {&num_collinearity_checks_field}
946                read_mem 1
947                pop 1
948                dup 10
949                {&domain_length_field}
950                read_mem 1
951                pop 1
952                log_2_floor
953                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *etrows *e_mr num_colli mt_height
954
955                pick 2
956                dup 4
957                dup 4
958                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *etrows num_colli mt_height *e_mr *fri_revealed *etrows
959
960                call {verify_aux_table_rows}
961                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *quot_mr *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *etrows
962
963
964                /* Dequeue and ignore aux-table's authentication path */
965                dup 10
966                call {next_as_authentication_path}
967                pop 1
968
969                swap 5
970                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *quot_mr
971
972
973                /* Dequeue quotient-table rows and verify against its Merkle root */
974                dup 10
975                call {next_as_quotient_segment_elements}
976                swap 1
977                dup 9
978                {&num_collinearity_checks_field}
979                read_mem 1
980                pop 1
981                dup 10
982                {&domain_length_field}
983                read_mem 1
984                pop 1
985                log_2_floor
986                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *qseg_elems *quot_mr num_colli mt_height
987
988                pick 2
989                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *qseg_elems num_colli mt_height *quot_mr
990
991                dup 4
992                dup 4
993                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *qseg_elems num_colli mt_height *quot_mr *fri_revealed *qseg_elems
994
995                call {verify_quotient_segments}
996                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *qseg_elems
997
998                /* Various length asserts */
999                // assert!(num_combination_codeword_checks == quotient_segment_elements.len());
1000                dup 8
1001                {&num_collinearity_checks_field}
1002                read_mem 1
1003                pop 1
1004                hint num_combination_codeword_checks = stack[0]
1005                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *qseg_elems num_colli
1006
1007                // assert!(num_combination_codeword_checks == revealed_fri_indices_and_elements.len())
1008                dup 2
1009                read_mem 1
1010                pop 1
1011                dup 1
1012                eq
1013                assert error_id 234
1014                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *qseg_elems num_colli
1015
1016                // assert!(num_combination_codeword_checks == main_table_rows.len());
1017                dup 8
1018                read_mem 1
1019                pop 1
1020                dup 1
1021                eq
1022                assert error_id 235
1023
1024                // assert!(num_combination_codeword_checks == aux_table_rows.len())
1025                dup 6
1026                read_mem 1
1027                pop 1
1028                dup 1
1029                eq
1030                assert error_id 236
1031
1032                // assert!(num_combination_codeword_checks == quotient_segment_elements.len());
1033                dup 1
1034                read_mem 1
1035                pop 1
1036                dup 1
1037                eq
1038                assert error_id 237
1039                // _ *beqd_ws *p_iter *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *qseg_elems num_colli
1040
1041
1042                /* Dequeue last authentication path, and verify that p_iter ends up in consistent state */
1043                swap 12
1044                swap 11
1045                dup 0
1046                call {next_as_authentication_path}
1047                pop 1
1048
1049                call {drop_vm_proof_iter}
1050                // _ num_colli *beqd_ws *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *fri_revealed *qseg_elems
1051
1052                /* Sum out-of-domain values */
1053                // Goal for stack: `_ *ood_erow_curr *ood_brow_curr *beqd_ws`, preserving `*beqd_ws`.
1054
1055                dup 10
1056                swap 2
1057                // _ num_colli *beqd_ws *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *ood_brow_curr *ood_erow_curr *beqd_ws *qseg_elems *fri_revealed
1058
1059                swap 4
1060                swap 1
1061                swap 3
1062                swap 2
1063                // _ num_colli *beqd_ws *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *fri_revealed *qseg_elems *ood_erow_curr *ood_brow_curr *beqd_ws
1064
1065                call {inner_product_three_rows_with_weights_xfe_main} // expects arguments: *aux *main *ws
1066                hint out_of_domain_curr_row_main_and_aux_value: XFieldElement = stack[0..3]
1067                // _ num_colli *beqd_ws *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *fri_revealed *qseg_elems [ood_curr_beval]
1068
1069                push {ood_curr_row_main_and_aux_value_pointer_alloc.write_address()}
1070                write_mem {ood_curr_row_main_and_aux_value_pointer_alloc.num_words()}
1071                pop 1
1072                // _ num_colli *beqd_ws *oodpnts *fri *btrows *odd_brow_next *etrows *ood_erow_nxt *fri_revealed *qseg_elems
1073
1074                // Goal: `_ *ood_erow_nxt *odd_brow_next *beqd_ws`, preserving `*beqd_ws`.
1075
1076                swap 2
1077                swap 1
1078                swap 4
1079                dup 8
1080                // _ num_colli *beqd_ws *oodpnts *fri *btrows *fri_revealed *etrows *qseg_elems *ood_erow_nxt *odd_brow_next *beqd_ws
1081
1082                call {inner_product_three_rows_with_weights_xfe_main}  // expects arguments: *aux *main *ws
1083                hint out_of_domain_next_row_main_and_aux_value: XFieldElement = stack[0..3]
1084                // _ num_colli *beqd_ws *oodpnts *fri *btrows *fri_revealed *etrows *qseg_elems [ood_next_value]
1085
1086                push {ood_next_row_main_and_aux_value_pointer_alloc.write_address()}
1087                write_mem {ood_next_row_main_and_aux_value_pointer_alloc.num_words()}
1088                pop 1
1089                // _ num_colli *beqd_ws *oodpnts *fri *btrows *fri_revealed *etrows *qseg_elems
1090
1091                // Goal: `_ *quotient_segment_codeword_weights *ood_curr_row_quot_segments`
1092                dup 6
1093                {&quotient_segment_codeword_weights_from_be_weights}
1094                // _ num_colli *beqd_ws *oodpnts *fri *btrows *fri_revealed *etrows *qseg_elems *quotient_segment_codeword_weights
1095
1096                push {out_of_domain_curr_row_quot_segments_pointer_alloc.read_address()}
1097                read_mem {out_of_domain_curr_row_quot_segments_pointer_alloc.num_words()}
1098                pop 1
1099                // _ num_colli *beqd_ws *oodpnts *fri *btrows *fri_revealed *etrows *qseg_elems *quotient_segment_codeword_weights *ood_curr_row_quot_segments
1100
1101                call {inner_product_4_xfes}
1102                hint out_of_domain_curr_row_quotient_segment_value: XFieldElement = stack[0..3]
1103                // _ num_colli *beqd_ws *oodpnts *fri *btrows *fri_revealed *etrows *qseg_elems [out_of_domain_curr_row_quotient_segment_value]
1104
1105                push {ood_curr_row_quotient_segment_value_pointer_alloc.write_address()}
1106                write_mem {ood_curr_row_quotient_segment_value_pointer_alloc.num_words()}
1107                pop 1
1108                // _ num_colli *beqd_ws *oodpnts *fri *btrows *fri_revealed *etrows *qseg_elems
1109
1110                // Put fri domain generator and domain offset on stack
1111                swap 4
1112                dup 0
1113                {&domain_offset_field}
1114                read_mem 1
1115                pop 1
1116                hint fri_domain_offset = stack[0]
1117                // _ num_colli *beqd_ws *oodpnts *qseg_elems *btrows *fri_revealed *etrows *fri fri_offset
1118
1119                swap 1
1120                {&domain_generator_field}
1121                read_mem 1
1122                pop 1
1123                hint fri_domain_gen = stack[0]
1124                // _ num_colli *beqd_ws *oodpnts *qseg_elems *btrows *fri_revealed *etrows fri_offset fri_gen
1125
1126                // adjust relevant pointers to point to last word in sequence, as they are traversed
1127                // high-to-low in the main loop
1128
1129                // Adjust *fri_revealed (list) to point to last word
1130                pick 3
1131                dup 8
1132                push {EXTENSION_DEGREE + 1} // size of element in `fri_revealed` list
1133                mul
1134                add
1135                hint fri_revealed_elem = stack[0]
1136                place 3
1137
1138                // Adjust *btrows (list) to point to last element
1139                pick 4
1140                addi 1
1141                dup 8
1142                addi -1
1143                push {MasterMainTable::NUM_COLUMNS} // size of element of main row list
1144                mul
1145                add
1146                hint main_table_row = stack[0]
1147                place 4
1148
1149                // Adjust *etrows (list) to point to last element
1150                pick 2
1151                addi 1
1152                dup 8
1153                addi -1
1154                push {MasterAuxTable::NUM_COLUMNS * EXTENSION_DEGREE} // size of element of aux row list
1155                mul
1156                add
1157                hint aux_table_row = stack[0]
1158                place 2
1159
1160                // Adjust *qseg_elems to point to last element
1161                pick 5
1162                addi 1
1163                dup 8
1164                addi -1
1165                push {NUM_QUOTIENT_SEGMENTS * EXTENSION_DEGREE} // size of element of quot row list
1166                mul
1167                add
1168                hint quotient_segment_elem = stack[0]
1169                place 5
1170
1171                // _ num_colli *beqd_ws *oodpnts *qseg_elems *btrows *fri_revealed *etrows fri_offset fri_gen
1172
1173                /* reorganize stack for main-loop */
1174                place 7
1175                place 6
1176                place 5
1177                place 4
1178                place 4
1179                place 3
1180                // _ num_colli fri_gen fri_offset *etrows_last_elem *btrows_last_elem *qseg_elems_last_elem *fri_revealed_last_elem *beqd_ws *oodpnts
1181
1182                call {main_loop_label}
1183                // _ 0 fri_gen fri_offset *etrow_elem *btrows_elem *qseg_elem *fri_revealed_elem *beqd_ws *oodpnts
1184
1185                /* Cleanup stack */
1186                pop 5 pop 4
1187
1188                return
1189
1190                {&main_loop}
1191        )
1192    }
1193}
1194
1195#[cfg(test)]
1196pub mod tests {
1197    use std::collections::HashMap;
1198
1199    use num_traits::ConstZero;
1200    use tasm_object_derive::TasmObject;
1201
1202    use super::*;
1203    use crate::execute_test;
1204    use crate::maybe_write_debuggable_vm_state_to_disk;
1205    use crate::memory::FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS;
1206    use crate::memory::encode_to_memory;
1207    use crate::test_helpers::maybe_write_tvm_output_to_disk;
1208    use crate::verifier::claim::shared::insert_claim_into_static_memory;
1209    use crate::verifier::master_table::air_constraint_evaluation::an_integral_but_profane_dynamic_memory_layout;
1210
1211    #[ignore = "Used for debugging when comparing two versions of the verifier"]
1212    #[test]
1213    fn verify_from_stored_proof_output() {
1214        use std::fs::File;
1215        let stark = File::open("stark.json").expect("stark file should open read only");
1216        let stark: Stark = serde_json::from_reader(stark).unwrap();
1217        let claim = File::open("claim.json").expect("claim file should open read only");
1218        let claim_for_proof: Claim = serde_json::from_reader(claim).unwrap();
1219        let proof = File::open("proof.json").expect("proof file should open read only");
1220        let proof: Proof = serde_json::from_reader(proof).unwrap();
1221
1222        let snippet = StarkVerify {
1223            stark,
1224            memory_layout: MemoryLayout::conventional_dynamic(),
1225        };
1226        let mut nondeterminism = NonDeterminism::new(vec![]);
1227        snippet.update_nondeterminism(&mut nondeterminism, &proof, &claim_for_proof);
1228
1229        let (claim_pointer, claim_size) =
1230            insert_claim_into_static_memory(&mut nondeterminism.ram, &claim_for_proof);
1231
1232        let default_proof_pointer = BFieldElement::ZERO;
1233
1234        let mut init_stack = [
1235            snippet.init_stack_for_isolated_run(),
1236            vec![claim_pointer, default_proof_pointer],
1237        ]
1238        .concat();
1239        let code = snippet.link_for_isolated_run_populated_static_memory(claim_size);
1240        let _final_tasm_state = execute_test(
1241            &code,
1242            &mut init_stack,
1243            snippet.stack_diff(),
1244            vec![],
1245            nondeterminism,
1246            None,
1247        );
1248    }
1249
1250    /// Run the verifier, and return the cycle count and inner padded
1251    /// height for crude benchmarking.
1252    fn test_verify_and_report_basic_features(
1253        inner_nondeterminism: NonDeterminism,
1254        inner_program: Program,
1255        inner_public_input: &[BFieldElement],
1256        stark: Stark,
1257        layout: MemoryLayout,
1258    ) -> (usize, usize) {
1259        let (mut non_determinism, claim_for_proof) = prove_and_get_non_determinism_and_claim(
1260            inner_program.clone(),
1261            inner_public_input,
1262            inner_nondeterminism.clone(),
1263            &stark,
1264        );
1265
1266        let (claim_pointer, claim_size) =
1267            insert_claim_into_static_memory(&mut non_determinism.ram, &claim_for_proof);
1268
1269        let default_proof_pointer = bfe!(0);
1270
1271        let snippet = StarkVerify {
1272            stark,
1273            memory_layout: layout,
1274        };
1275        let mut init_stack = [
1276            snippet.init_stack_for_isolated_run(),
1277            vec![claim_pointer, default_proof_pointer],
1278        ]
1279        .concat();
1280        let code = snippet.link_for_isolated_run_populated_static_memory(claim_size);
1281
1282        let program = Program::new(&code);
1283        let mut vm_state = VMState::new(program, [].into(), non_determinism.clone());
1284        vm_state.op_stack.stack = init_stack.clone();
1285        maybe_write_debuggable_vm_state_to_disk(&vm_state);
1286
1287        let final_tasm_state = execute_test(
1288            &code,
1289            &mut init_stack,
1290            snippet.stack_diff(),
1291            vec![],
1292            non_determinism,
1293            None,
1294        );
1295
1296        let (aet, _public_output) = VM::trace_execution(
1297            inner_program,
1298            (&claim_for_proof.input).into(),
1299            inner_nondeterminism,
1300        )
1301        .unwrap();
1302        let inner_padded_height = aet.padded_height();
1303
1304        (final_tasm_state.cycle_count as usize, inner_padded_height)
1305    }
1306
1307    #[test]
1308    fn different_fri_expansion_factors() {
1309        const FACTORIAL_ARGUMENT: u32 = 3;
1310
1311        for log2_of_fri_expansion_factor in 2..=5 {
1312            println!("log2_of_fri_expansion_factor: {log2_of_fri_expansion_factor}");
1313            let factorial_program = factorial_program_with_io();
1314            let stark = Stark::new(160, log2_of_fri_expansion_factor);
1315            let (cycle_count, inner_padded_height) = test_verify_and_report_basic_features(
1316                NonDeterminism::default(),
1317                factorial_program,
1318                &[FACTORIAL_ARGUMENT.into()],
1319                stark,
1320                MemoryLayout::conventional_static(),
1321            );
1322            println!(
1323                "TASM-verifier of factorial({FACTORIAL_ARGUMENT}):\n
1324                Fri expansion factor: {}\n
1325                clock cycle count: {}.\n
1326                Inner padded height was: {}",
1327                1 << log2_of_fri_expansion_factor,
1328                cycle_count,
1329                inner_padded_height,
1330            );
1331        }
1332    }
1333
1334    fn verify_tvm_proof_factorial_program_basic_properties(mem_layout: MemoryLayout) {
1335        const FACTORIAL_ARGUMENT: u32 = 3;
1336
1337        let factorial_program = factorial_program_with_io();
1338        let stark = Stark::default();
1339        let (cycle_count, inner_padded_height) = test_verify_and_report_basic_features(
1340            NonDeterminism::default(),
1341            factorial_program,
1342            &[FACTORIAL_ARGUMENT.into()],
1343            stark,
1344            mem_layout,
1345        );
1346
1347        println!(
1348            "TASM-verifier of factorial({FACTORIAL_ARGUMENT}):\n
1349            clock cycle count: {cycle_count}.\n
1350            Inner padded height was: {inner_padded_height}",
1351        );
1352    }
1353
1354    #[test]
1355    fn verify_tvm_proof_factorial_program_conventional_static_memlayout() {
1356        verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::conventional_static());
1357    }
1358
1359    #[test]
1360    fn verify_tvm_proof_factorial_program_conventional_dynamic_memlayout() {
1361        verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::conventional_dynamic());
1362    }
1363
1364    #[test]
1365    fn verify_tvm_proof_factorial_program_profane_dynamic_memlayout() {
1366        verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::Dynamic(
1367            an_integral_but_profane_dynamic_memory_layout(),
1368        ));
1369    }
1370
1371    pub(super) fn factorial_program_with_io() -> Program {
1372        triton_program!(
1373            read_io 1
1374            push 1               // n accumulator
1375            call factorial       // 0 accumulator!
1376            write_io 1
1377            halt
1378
1379            factorial:           // n acc
1380                // if n == 0: return
1381                dup 1            // n acc n
1382                push 0 eq        // n acc n==0
1383                skiz             // n acc
1384                return           // 0 acc
1385                // else: multiply accumulator with n and recurse
1386                dup 1            // n acc n
1387                mul              // n acc·n
1388                pick 1           // acc·n n
1389                addi -1          // acc·n n-1
1390                place 1          // n-1 acc·n
1391
1392                recurse
1393        )
1394    }
1395
1396    /// Return data needed to verify a program execution's proof.
1397    ///
1398    /// Prepares the caller so that the caller can call verify on a simple program
1399    /// execution. Specifically, given an inner program, inner public input, inner
1400    /// nondeterminism, and stark parameters; produce the proof, and use it to
1401    /// populate non-determism (both memory and streams). Returns the claim that
1402    /// the caller will then have to put into memory. Proof is stored on first
1403    /// address of the ND-memory region.
1404    pub fn prove_and_get_non_determinism_and_claim(
1405        inner_program: Program,
1406        inner_public_input: &[BFieldElement],
1407        inner_nondeterminism: NonDeterminism,
1408        stark: &Stark,
1409    ) -> (NonDeterminism, Claim) {
1410        println!("Generating proof for non-determinism");
1411
1412        let inner_input = inner_public_input.to_vec();
1413        let claim = Claim::about_program(&inner_program).with_input(inner_input.clone());
1414        let (aet, inner_output) =
1415            VM::trace_execution(inner_program, inner_input.into(), inner_nondeterminism).unwrap();
1416        let claim = claim.with_output(inner_output);
1417
1418        triton_vm::profiler::start("inner program");
1419        let seed = [
1420            227, 232, 115, 183, 84, 194, 68, 59, 166, 60, 140, 218, 88, 117, 227, 129, 10, 121,
1421            108, 40, 65, 125, 143, 31, 155, 128, 202, 75, 218, 44, 120, 170,
1422        ];
1423        let prover = Prover::new(*stark).set_randomness_seed_which_may_break_zero_knowledge(seed);
1424        let proof = prover.prove(&claim, &aet).unwrap();
1425        let profile = triton_vm::profiler::finish();
1426        let padded_height = proof.padded_height().unwrap();
1427        let report = profile
1428            .with_cycle_count(aet.processor_trace.nrows())
1429            .with_padded_height(padded_height)
1430            .with_fri_domain_len(stark.fri(padded_height).unwrap().domain.length);
1431        println!("Done generating proof for non-determinism");
1432        println!("{report}");
1433
1434        assert!(
1435            stark.verify(&claim, &proof).is_ok(),
1436            "Proof from TVM must verify through TVM"
1437        );
1438
1439        maybe_write_tvm_output_to_disk(stark, &claim, &proof);
1440
1441        let mut nondeterminism = NonDeterminism::new(vec![]);
1442        let stark_verify = StarkVerify {
1443            stark: *stark,
1444            memory_layout: MemoryLayout::conventional_static(),
1445        };
1446
1447        // Verify nd-digest count
1448        let actual_num_extracted_digests = stark_verify
1449            .extract_nondeterministic_digests(&proof, &claim)
1450            .len();
1451        let expected_num_extracted_digests =
1452            stark_verify.number_of_nondeterministic_digests_consumed(&proof);
1453        assert_eq!(
1454            actual_num_extracted_digests, expected_num_extracted_digests,
1455            "Number of extracted digests must match expected value"
1456        );
1457
1458        stark_verify.update_nondeterminism(&mut nondeterminism, &proof, &claim);
1459        encode_to_memory(
1460            &mut nondeterminism.ram,
1461            FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1462            &proof,
1463        );
1464
1465        (nondeterminism, claim)
1466    }
1467
1468    #[test]
1469    fn verify_two_proofs() {
1470        #[derive(Debug, Clone, BFieldCodec, TasmObject)]
1471        struct TwoProofs {
1472            proof1: Proof,
1473            claim1: Claim,
1474            proof2: Proof,
1475            claim2: Claim,
1476        }
1477
1478        let stark = Stark::default();
1479        let stark_snippet = StarkVerify::new_with_dynamic_layout(stark);
1480
1481        let mut library = Library::new();
1482        let stark_verify = library.import(Box::new(stark_snippet));
1483        let proof1 = field!(TwoProofs::proof1);
1484        let proof2 = field!(TwoProofs::proof2);
1485        let claim1 = field!(TwoProofs::claim1);
1486        let claim2 = field!(TwoProofs::claim2);
1487        let verify_two_proofs_program = triton_asm! {
1488
1489
1490            push {FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS}
1491            // *two_proofs
1492
1493            dup 0
1494            {&claim1}
1495
1496            dup 1
1497            {&proof1}
1498            // *two_proofs *claim1 *proof1
1499
1500            call {stark_verify}
1501
1502            dup 0
1503            {&claim2}
1504
1505            dup 1
1506            {&proof2}
1507            // *two_proofs *claim2 *proof2
1508
1509            call {stark_verify}
1510
1511            halt
1512
1513            {&library.all_imports()}
1514        };
1515
1516        let inner_input_1 = bfe_vec![3];
1517        let factorial_program = factorial_program_with_io();
1518        let (aet_1, inner_output_1) = VM::trace_execution(
1519            factorial_program.clone(),
1520            inner_input_1.clone().into(),
1521            [].into(),
1522        )
1523        .unwrap();
1524        let claim_1 = Claim::about_program(&factorial_program)
1525            .with_input(inner_input_1.clone())
1526            .with_output(inner_output_1.clone());
1527        let proof_1 = stark.prove(&claim_1, &aet_1).unwrap();
1528        let padded_height_1 = proof_1.padded_height().unwrap();
1529        println!("padded_height_1: {padded_height_1}");
1530
1531        let inner_input_2 = bfe_vec![25];
1532        let (aet_2, inner_output_2) = VM::trace_execution(
1533            factorial_program.clone(),
1534            inner_input_2.clone().into(),
1535            [].into(),
1536        )
1537        .unwrap();
1538        let claim_2 = Claim::about_program(&factorial_program)
1539            .with_input(inner_input_2.clone())
1540            .with_output(inner_output_2.clone());
1541        let proof_2 = stark.prove(&claim_2, &aet_2).unwrap();
1542        let padded_height_2 = proof_2.padded_height().unwrap();
1543        println!("padded_height_2: {padded_height_2}");
1544
1545        let two_proofs = TwoProofs {
1546            proof1: proof_1.clone(),
1547            claim1: claim_1.clone(),
1548            proof2: proof_2.clone(),
1549            claim2: claim_2.clone(),
1550        };
1551
1552        let mut memory = HashMap::<BFieldElement, BFieldElement>::new();
1553        let outer_input = vec![];
1554        encode_to_memory(
1555            &mut memory,
1556            FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1557            &two_proofs,
1558        );
1559
1560        let mut outer_nondeterminism = NonDeterminism::new(vec![]).with_ram(memory);
1561
1562        let num_nd_digests_before = outer_nondeterminism.digests.len();
1563
1564        stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_1, &claim_1);
1565        stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_2, &claim_2);
1566
1567        let num_nd_digests_after = outer_nondeterminism.digests.len();
1568
1569        assert_eq!(
1570            num_nd_digests_after - num_nd_digests_before,
1571            stark_snippet.number_of_nondeterministic_digests_consumed(&proof_1)
1572                + stark_snippet.number_of_nondeterministic_digests_consumed(&proof_2)
1573        );
1574
1575        let program = Program::new(&verify_two_proofs_program);
1576        let vm_state = VMState::new(
1577            program.clone(),
1578            outer_input.clone().into(),
1579            outer_nondeterminism.clone(),
1580        );
1581        maybe_write_debuggable_vm_state_to_disk(&vm_state);
1582        VM::run(program, outer_input.into(), outer_nondeterminism)
1583            .expect("could not verify two STARK proofs");
1584
1585        println!(
1586            "fact({}) == {} ∧ fact({}) == {}",
1587            inner_input_1[0], inner_output_1[0], inner_input_2[0], inner_output_2[0]
1588        );
1589
1590        assert_ne!(
1591            padded_height_1, padded_height_2,
1592            "proofs do not have different padded heights"
1593        );
1594    }
1595}
1596
1597#[cfg(test)]
1598mod benches {
1599    use benches::tests::factorial_program_with_io;
1600    use benches::tests::prove_and_get_non_determinism_and_claim;
1601    use num_traits::ConstZero;
1602
1603    use super::*;
1604    use crate::generate_full_profile;
1605    use crate::linker::execute_bench;
1606    use crate::memory::encode_to_memory;
1607    use crate::snippet_bencher::BenchmarkCase;
1608    use crate::snippet_bencher::NamedBenchmarkResult;
1609    use crate::snippet_bencher::write_benchmarks;
1610    use crate::test_helpers::prepend_program_with_stack_setup;
1611    use crate::verifier::claim::shared::insert_claim_into_static_memory;
1612
1613    #[ignore = "Used for profiling the verification of a proof stored on disk."]
1614    #[test]
1615    fn profile_from_stored_proof_output() {
1616        use std::fs::File;
1617        let stark = File::open("stark.json").expect("stark file should open read only");
1618        let stark: Stark = serde_json::from_reader(stark).unwrap();
1619        let claim_file = File::open("claim.json").expect("claim file should open read only");
1620        let claim_for_proof: Claim = serde_json::from_reader(claim_file).unwrap();
1621        let proof = File::open("proof.json").expect("proof file should open read only");
1622        let proof: Proof = serde_json::from_reader(proof).unwrap();
1623
1624        let snippet = StarkVerify {
1625            stark,
1626            memory_layout: MemoryLayout::conventional_static(),
1627        };
1628        let mut nondeterminism = NonDeterminism::new(vec![]);
1629        snippet.update_nondeterminism(&mut nondeterminism, &proof, &claim_for_proof);
1630
1631        let (claim_pointer, claim_size) =
1632            insert_claim_into_static_memory(&mut nondeterminism.ram, &claim_for_proof);
1633
1634        let default_proof_pointer = BFieldElement::ZERO;
1635
1636        let init_stack = [
1637            snippet.init_stack_for_isolated_run(),
1638            vec![claim_pointer, default_proof_pointer],
1639        ]
1640        .concat();
1641        let code = snippet.link_for_isolated_run_populated_static_memory(claim_size);
1642        let program = prepend_program_with_stack_setup(&init_stack, &Program::new(&code));
1643
1644        let name = snippet.entrypoint();
1645        let profile = generate_full_profile(
1646            &name,
1647            program,
1648            &PublicInput::new(claim_for_proof.input),
1649            &nondeterminism,
1650        );
1651        println!("{profile}");
1652    }
1653
1654    #[test]
1655    fn benchmark_small_default_stark_static_memory() {
1656        benchmark_verifier(
1657            3,
1658            1 << 8,
1659            Stark::default(),
1660            MemoryLayout::conventional_static(),
1661        );
1662        benchmark_verifier(
1663            40,
1664            1 << 9,
1665            Stark::default(),
1666            MemoryLayout::conventional_static(),
1667        );
1668    }
1669
1670    #[test]
1671    fn benchmark_small_default_stark_dynamic_memory() {
1672        benchmark_verifier(
1673            3,
1674            1 << 8,
1675            Stark::default(),
1676            MemoryLayout::conventional_dynamic(),
1677        );
1678        benchmark_verifier(
1679            40,
1680            1 << 9,
1681            Stark::default(),
1682            MemoryLayout::conventional_dynamic(),
1683        );
1684    }
1685
1686    #[ignore = "Takes a fairly long time. Intended to find optimal FRI expansion factor."]
1687    #[test]
1688    fn small_benchmark_different_fri_expansion_factors() {
1689        for log2_of_fri_expansion_factor in 1..=5 {
1690            let stark = Stark::new(160, log2_of_fri_expansion_factor);
1691            benchmark_verifier(10, 1 << 8, stark, MemoryLayout::conventional_static());
1692            benchmark_verifier(40, 1 << 9, stark, MemoryLayout::conventional_static());
1693            benchmark_verifier(80, 1 << 10, stark, MemoryLayout::conventional_static());
1694        }
1695    }
1696
1697    #[ignore = "Takes a very long time. Intended to find optimal FRI expansion factor. Make sure to run
1698       with `RUSTFLAGS=\"-C opt-level=3 -C debug-assertions=no\"`"]
1699    #[test]
1700    fn big_benchmark_different_fri_expansion_factors() {
1701        let mem_layout = MemoryLayout::conventional_static();
1702        for log2_of_fri_expansion_factor in 2..=3 {
1703            let stark = Stark::new(160, log2_of_fri_expansion_factor);
1704            benchmark_verifier(25600, 1 << 19, stark, mem_layout);
1705            benchmark_verifier(51200, 1 << 20, stark, mem_layout);
1706            benchmark_verifier(102400, 1 << 21, stark, mem_layout);
1707        }
1708    }
1709
1710    #[ignore = "Intended to generate data about verifier table heights as a function of inner padded
1711       height. Make sure to run with `RUSTFLAGS=\"-C opt-level=3 -C debug-assertions=no\"`"]
1712    #[test]
1713    fn benchmark_verification_as_a_function_of_inner_padded_height() {
1714        for (fact_arg, expected_inner_padded_height) in [
1715            (10, 1 << 8),
1716            (40, 1 << 9),
1717            (80, 1 << 10),
1718            (100, 1 << 11),
1719            (200, 1 << 12),
1720            (400, 1 << 13),
1721            (800, 1 << 14),
1722            (1600, 1 << 15),
1723            (3200, 1 << 16),
1724            (6400, 1 << 17),
1725            (12800, 1 << 18),
1726            (25600, 1 << 19),
1727            (51200, 1 << 20),
1728            (102400, 1 << 21),
1729        ] {
1730            benchmark_verifier(
1731                fact_arg,
1732                expected_inner_padded_height,
1733                Stark::default(),
1734                MemoryLayout::conventional_static(),
1735            );
1736        }
1737    }
1738
1739    fn benchmark_verifier(
1740        factorial_argument: u32,
1741        inner_padded_height: usize,
1742        stark: Stark,
1743        mem_layout: MemoryLayout,
1744    ) {
1745        let (mut non_determinism, claim_for_proof) = prove_and_get_non_determinism_and_claim(
1746            factorial_program_with_io(),
1747            &[bfe!(factorial_argument)],
1748            NonDeterminism::default(),
1749            &stark,
1750        );
1751
1752        let claim_pointer = BFieldElement::new(1 << 30);
1753        encode_to_memory(&mut non_determinism.ram, claim_pointer, &claim_for_proof);
1754
1755        let default_proof_pointer = BFieldElement::ZERO;
1756
1757        let snippet = StarkVerify {
1758            stark,
1759            memory_layout: mem_layout,
1760        };
1761
1762        let init_stack = [
1763            snippet.init_stack_for_isolated_run(),
1764            vec![claim_pointer, default_proof_pointer],
1765        ]
1766        .concat();
1767        let code = snippet.link_for_isolated_run();
1768        let benchmark = execute_bench(&code, &init_stack, vec![], non_determinism.clone(), None);
1769        let benchmark = NamedBenchmarkResult {
1770            name: format!(
1771                "{}_inner_padded_height_{}_fri_exp_{}",
1772                snippet.entrypoint(),
1773                inner_padded_height,
1774                stark.fri_expansion_factor
1775            ),
1776            benchmark_result: benchmark,
1777            case: BenchmarkCase::CommonCase,
1778        };
1779
1780        write_benchmarks(vec![benchmark]);
1781
1782        let program = prepend_program_with_stack_setup(&init_stack, &Program::new(&code));
1783        let name = snippet.entrypoint();
1784        let profile = generate_full_profile(
1785            &name,
1786            program,
1787            &PublicInput::new(claim_for_proof.input),
1788            &non_determinism,
1789        );
1790        println!("{profile}");
1791    }
1792}