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#[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 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 pub fn number_of_nondeterministic_tokens_consumed(
98 &self,
99 _proof: &Proof,
100 _claim: &Claim,
101 ) -> usize {
102 0
103 }
104
105 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 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 let _main_table_root = proof_stream
154 .dequeue()
155 .unwrap()
156 .try_into_merkle_root()
157 .unwrap();
158
159 let _challenges = proof_stream.sample_scalars(Challenges::SAMPLE_COUNT);
161
162 let _aux_mt_root = proof_stream
164 .dequeue()
165 .unwrap()
166 .try_into_merkle_root()
167 .unwrap();
168
169 proof_stream.sample_scalars(MasterAuxTable::NUM_CONSTRAINTS);
171
172 let _quotient_root = proof_stream
174 .dequeue()
175 .unwrap()
176 .try_into_merkle_root()
177 .unwrap();
178
179 let _out_of_domain_point_curr_row = proof_stream.sample_scalars(1);
181
182 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 proof_stream.sample_scalars(
211 MasterMainTable::NUM_COLUMNS
212 + MasterAuxTable::NUM_COLUMNS
213 + NUM_QUOTIENT_SEGMENTS
214 + NUM_DEEP_CODEWORD_COMPONENTS,
215 );
216
217 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 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 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 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 push {(MasterMainTable::NUM_COLUMNS + MasterAuxTable::NUM_COLUMNS) * EXTENSION_DEGREE}
428 add
429 );
431 let deep_codeword_weights_read_address = |n: usize| {
432 assert!(n < NUM_DEEP_CODEWORD_COMPONENTS);
433 triton_asm!(
434 push {(MasterMainTable::NUM_COLUMNS + MasterAuxTable::NUM_COLUMNS + NUM_QUOTIENT_SEGMENTS + n) * EXTENSION_DEGREE + {EXTENSION_DEGREE - 1}}
437 add
438 )
440 };
441
442 let dequeue_four_ood_rows = triton_asm! {
443 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 };
461
462 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 call {static_eval}
479 }
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 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 call {dynamic_eval}
498 pick 1 pop 1
501 }
503 }
504 };
505
506 let put_ood_row_pointers_back_on_stack = triton_asm! {
507 push {ood_pointers_alloc.read_address()}
509 read_mem {ood_pointers_alloc.num_words()}
510 pop 1
511
512 };
514
515 let challenges_ptr = self.memory_layout.challenges_pointer();
516
517 let assert_top_two_xfes_eq = triton_asm!(
518 pick 3
520 eq
521 assert error_id 230
522
523 pick 2
525 eq
526 assert error_id 231
527
528 eq
530 assert error_id 232
531
532 );
534
535 let main_loop_label = format!("{entrypoint}_main_loop");
536 let main_loop_body = triton_asm!(
537 pick 2
541 read_mem 1
542 place 3
543 dup 8
546 pow
547 dup 7
548 mul
549 push -1
550 mul
551 hint neg_fri_domain_point = stack[0]
552 dup 6
556 dup 6
557 dup 4
558 call {inner_product_three_rows_with_weights_bfe_main} hint main_and_aux_opened_row_element: Xfe = stack[0..3]
560 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 push -1
572 xb_mul
573 hint neg_main_and_aux_opened_row_element: Xfe = stack[0..3]
574
575 dup 4
577 {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRowPowNumSegments)}
578 dup 6
581 add
582 x_invert
585 dup 8
588 {"ient_segment_codeword_weights_from_be_weights}
589 dup 11
590 call {inner_product_4_xfes}
591 pick 13
594 addi {-bfe!(NUM_QUOTIENT_SEGMENTS * EXTENSION_DEGREE)}
595 place 13
596 push -1
599 xb_mul
600 push {ood_curr_row_quotient_segment_value_pointer_alloc.read_address()}
603 read_mem {EXTENSION_DEGREE}
604 pop 1
605 xx_add
608 xx_mul
609 hint quot_curr_row_deep_value: XFieldElement = stack[0..3]
610 dup 8
616 {&deep_codeword_weights_read_address(2)}
617 read_mem {EXTENSION_DEGREE}
618 pop 1
619 xx_mul
620 dup 7
624 {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRow)}
625 dup 9
628 add
629 x_invert
630 push {ood_curr_row_main_and_aux_value_pointer_alloc.read_address()}
633 read_mem {EXTENSION_DEGREE}
634 pop 1
635 dup 11
638 dup 11
639 dup 11
640 xx_add
641 xx_mul
644 dup 11
647 {&deep_codeword_weights_read_address(0)}
648 read_mem {EXTENSION_DEGREE} pop 1
650 xx_mul
651 xx_add
655 hint dv2_plus_dv0: XFieldElement = stack[0..3]
657
658 pick 5
659 pick 5
660 pick 5
661 push {ood_next_row_main_and_aux_value_pointer_alloc.read_address()}
664 read_mem {EXTENSION_DEGREE}
665 pop 1
666 xx_add
667 dup 7
670 {&OutOfDomainPoints::read_ood_point(OodPoint::NextRow)}
671 dup 9
674 add
675 x_invert
678 xx_mul
679 dup 8
682 {&deep_codeword_weights_read_address(1)}
683 read_mem {EXTENSION_DEGREE} pop 1
685 xx_mul
686 xx_add
690 hint deep_value: XFieldElement = stack[0..3]
691 pick 3
695 pop 1
696 pick 5
699 read_mem {EXTENSION_DEGREE}
700 place 8
701 {&assert_top_two_xfes_eq}
704
705 );
707 let main_loop = triton_asm!(
708 {main_loop_label}:
711 dup 8
713 push 0
714 eq
715 skiz
716 return
717
718 {&main_loop_body}
719
720 pick 8
722 addi -1
723 place 8
724 recurse
725 );
726
727 triton_asm!(
728 {entrypoint}:
729 sponge_init
730 call {proof_to_vm_proof_iter}
733 hint proof_iter = stack[0]
734
735 dup 1
740 call {instantiate_fiat_shamir_with_claim}
741 dup 0
746 call {next_as_log_2_padded_height}
747 read_mem 1
750 pop 1
751 push 2
754 pow
755 hint padded_height = stack[0]
756 dup 0
759 call {derive_fri_parameters}
760 hint fri = stack[0]
761 dup 2
765 call {next_as_merkleroot}
766 hint b_mr = stack[0]
767 swap 4
770 call {get_challenges}
773 push {challenges_ptr}
777 eq
778 assert error_id 233
779 dup 2
782 call {next_as_merkleroot}
783 hint e_mr = stack[0]
784 call {sample_quotient_codeword_weights}
787 hint quot_codeword_weights = stack[0]
789
790 dup 4
791 call {next_as_merkleroot}
792 hint quot_mr = stack[0]
793 push 0
798 dup 5
799 call {domain_generator}
800 hint trace_domain_generator = stack[0]
801 dup 0
804 call {sample_scalar_one}
807 call {calculate_out_of_domain_points}
810 hint out_of_domain_points = stack[0]
811 push 2
816 add
817 read_mem {EXTENSION_DEGREE}
818 push 1
819 add
820 swap 9
823 dup 10
826 {&dequeue_four_ood_rows}
827 {&evaluate_air_and_store_ood_pointers}
830 swap 5
833 call {divide_out_zerofiers}
836 {&put_ood_row_pointers_back_on_stack}
839 dup 10
842 call {next_as_outofdomainquotientsegments}
843 hint out_of_domain_quotient_segments: Pointer = stack[0]
844 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 dup 10
854 {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRow)}
855 call {horner_evaluation_of_ood_curr_row_quot_segments}
858 pick 4 place 9
863 pick 3 place 6
864 pick 8 pick 6
865 call {inner_product_quotient_summands}
868 {&assert_top_two_xfes_eq}
872 call {sample_beqd_weights}
876 hint beqd_weights = stack[0]
877 swap 10
880 dup 9
886 dup 8
887 call {fri_verify}
888 hint fri_revealed = stack[0]
889 dup 10
894 call {next_as_maintablerows}
895 dup 9
899 {&num_collinearity_checks_field}
900 read_mem 1
901 pop 1
902 dup 10
905 {&domain_length_field}
906 read_mem 1
907 pop 1
908 log_2_floor
911 pick 4
914 dup 4
917 dup 4
920 call {verify_main_table_rows}
923 dup 10
928 call {next_as_authentication_path}
929 pop 1
930 swap 7
933 dup 10
938 call {next_as_auxtablerows}
939 pick 1
942 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 pick 2
956 dup 4
957 dup 4
958 call {verify_aux_table_rows}
961 dup 10
966 call {next_as_authentication_path}
967 pop 1
968
969 swap 5
970 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 pick 2
989 dup 4
992 dup 4
993 call {verify_quotient_segments}
996 dup 8
1001 {&num_collinearity_checks_field}
1002 read_mem 1
1003 pop 1
1004 hint num_combination_codeword_checks = stack[0]
1005 dup 2
1009 read_mem 1
1010 pop 1
1011 dup 1
1012 eq
1013 assert error_id 234
1014 dup 8
1018 read_mem 1
1019 pop 1
1020 dup 1
1021 eq
1022 assert error_id 235
1023
1024 dup 6
1026 read_mem 1
1027 pop 1
1028 dup 1
1029 eq
1030 assert error_id 236
1031
1032 dup 1
1034 read_mem 1
1035 pop 1
1036 dup 1
1037 eq
1038 assert error_id 237
1039 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 dup 10
1056 swap 2
1057 swap 4
1060 swap 1
1061 swap 3
1062 swap 2
1063 call {inner_product_three_rows_with_weights_xfe_main} hint out_of_domain_curr_row_main_and_aux_value: XFieldElement = stack[0..3]
1067 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 swap 2
1077 swap 1
1078 swap 4
1079 dup 8
1080 call {inner_product_three_rows_with_weights_xfe_main} hint out_of_domain_next_row_main_and_aux_value: XFieldElement = stack[0..3]
1084 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 dup 6
1093 {"ient_segment_codeword_weights_from_be_weights}
1094 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 call {inner_product_4_xfes}
1102 hint out_of_domain_curr_row_quotient_segment_value: XFieldElement = stack[0..3]
1103 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 swap 4
1112 dup 0
1113 {&domain_offset_field}
1114 read_mem 1
1115 pop 1
1116 hint fri_domain_offset = stack[0]
1117 swap 1
1120 {&domain_generator_field}
1121 read_mem 1
1122 pop 1
1123 hint fri_domain_gen = stack[0]
1124 pick 3
1131 dup 8
1132 push {EXTENSION_DEGREE + 1} mul
1134 add
1135 hint fri_revealed_elem = stack[0]
1136 place 3
1137
1138 pick 4
1140 addi 1
1141 dup 8
1142 addi -1
1143 push {MasterMainTable::NUM_COLUMNS} mul
1145 add
1146 hint main_table_row = stack[0]
1147 place 4
1148
1149 pick 2
1151 addi 1
1152 dup 8
1153 addi -1
1154 push {MasterAuxTable::NUM_COLUMNS * EXTENSION_DEGREE} mul
1156 add
1157 hint aux_table_row = stack[0]
1158 place 2
1159
1160 pick 5
1162 addi 1
1163 dup 8
1164 addi -1
1165 push {NUM_QUOTIENT_SEGMENTS * EXTENSION_DEGREE} mul
1167 add
1168 hint quotient_segment_elem = stack[0]
1169 place 5
1170
1171 place 7
1175 place 6
1176 place 5
1177 place 4
1178 place 4
1179 place 3
1180 call {main_loop_label}
1183 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 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 call factorial write_io 1
1377 halt
1378
1379 factorial: dup 1 push 0 eq skiz return dup 1 mul pick 1 addi -1 place 1 recurse
1393 )
1394 }
1395
1396 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 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 dup 0
1494 {&claim1}
1495
1496 dup 1
1497 {&proof1}
1498 call {stark_verify}
1501
1502 dup 0
1503 {&claim2}
1504
1505 dup 1
1506 {&proof2}
1507 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}