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 const LOG2_PADDED_HEIGHT_TOO_LARGE: i128 = 238;
59
60 pub fn new_with_static_layout(stark: Stark) -> Self {
61 Self {
62 stark,
63 memory_layout: MemoryLayout::conventional_static(),
64 }
65 }
66
67 pub fn new_with_dynamic_layout(stark: Stark) -> Self {
68 Self {
69 stark,
70 memory_layout: MemoryLayout::conventional_dynamic(),
71 }
72 }
73
74 pub fn number_of_nondeterministic_digests_consumed(&self, proof: &Proof) -> usize {
77 const NUM_FULL_DOMAIN_AUTH_PATHS: usize = 4;
78
79 let padded_height = proof.padded_height().unwrap();
80 let fri_params = self.stark.fri(padded_height).unwrap();
81 let num_fri_rounds = fri_params.num_rounds();
82
83 let mut j = 0;
84 let mut tree_height: usize = fri_params.domain.len().ilog2().try_into().unwrap();
85
86 let mut acc = NUM_FULL_DOMAIN_AUTH_PATHS * tree_height * fri_params.num_collinearity_checks;
87 while j < num_fri_rounds {
88 acc += fri_params.num_collinearity_checks * tree_height;
89 j += 1;
90 tree_height -= 1;
91 }
92
93 acc
94 }
95
96 pub fn number_of_nondeterministic_tokens_consumed(
100 &self,
101 _proof: &Proof,
102 _claim: &Claim,
103 ) -> usize {
104 0
105 }
106
107 pub fn update_nondeterminism(
111 &self,
112 nondeterminism: &mut NonDeterminism,
113 proof: &Proof,
114 claim: &Claim,
115 ) {
116 nondeterminism
117 .digests
118 .append(&mut self.extract_nondeterministic_digests(proof, claim));
119 }
120
121 fn extract_nondeterministic_digests(&self, proof: &Proof, claim: &Claim) -> Vec<Digest> {
122 const NUM_DEEP_CODEWORD_COMPONENTS: usize = 3;
123
124 fn extract_paths<R: BFieldCodec>(
125 indices: Vec<usize>,
126 leaf_preimages: Vec<R>,
127 tree_height: u32,
128 authentication_structure: Vec<Digest>,
129 ) -> Vec<Vec<Digest>> {
130 let indexed_leafs = indices
131 .into_iter()
132 .zip(leaf_preimages.iter().map(Tip5::hash))
133 .collect();
134 MerkleTreeInclusionProof {
135 tree_height,
136 indexed_leafs,
137 authentication_structure,
138 }
139 .into_authentication_paths()
140 .unwrap()
141 }
142
143 let mut proof_stream = ProofStream::try_from(proof).unwrap();
147 proof_stream.alter_fiat_shamir_state_with(claim);
148 let log2_padded_height = proof_stream
149 .dequeue()
150 .unwrap()
151 .try_into_log2_padded_height()
152 .unwrap();
153
154 let _main_table_root = proof_stream
156 .dequeue()
157 .unwrap()
158 .try_into_merkle_root()
159 .unwrap();
160
161 let _challenges = proof_stream.sample_scalars(Challenges::SAMPLE_COUNT);
163
164 let _aux_mt_root = proof_stream
166 .dequeue()
167 .unwrap()
168 .try_into_merkle_root()
169 .unwrap();
170
171 proof_stream.sample_scalars(MasterAuxTable::NUM_CONSTRAINTS);
173
174 let _quotient_root = proof_stream
176 .dequeue()
177 .unwrap()
178 .try_into_merkle_root()
179 .unwrap();
180
181 let _out_of_domain_point_curr_row = proof_stream.sample_scalars(1);
183
184 proof_stream
186 .dequeue()
187 .unwrap()
188 .try_into_out_of_domain_main_row()
189 .unwrap();
190 proof_stream
191 .dequeue()
192 .unwrap()
193 .try_into_out_of_domain_aux_row()
194 .unwrap();
195 proof_stream
196 .dequeue()
197 .unwrap()
198 .try_into_out_of_domain_main_row()
199 .unwrap();
200 proof_stream
201 .dequeue()
202 .unwrap()
203 .try_into_out_of_domain_aux_row()
204 .unwrap();
205 proof_stream
206 .dequeue()
207 .unwrap()
208 .try_into_out_of_domain_quot_segments()
209 .unwrap();
210
211 proof_stream.sample_scalars(
213 MasterMainTable::NUM_COLUMNS
214 + MasterAuxTable::NUM_COLUMNS
215 + NUM_QUOTIENT_SEGMENTS
216 + NUM_DEEP_CODEWORD_COMPONENTS,
217 );
218
219 let padded_height = 1 << log2_padded_height;
221 let fri = self.stark.fri(padded_height).unwrap();
222 let fri_proof_stream = proof_stream.clone();
223 let fri_verify_result = fri.verify(&mut proof_stream).unwrap();
224 let indices = fri_verify_result.iter().map(|(i, _)| *i).collect_vec();
225 let tree_height = fri.domain.len().ilog2();
226 let fri_digests =
227 FriVerify::from(fri).extract_digests_required_for_proving(&fri_proof_stream);
228
229 let main_table_rows = proof_stream
231 .dequeue()
232 .unwrap()
233 .try_into_master_main_table_rows()
234 .unwrap();
235 let main_authentication_structure = proof_stream
236 .dequeue()
237 .unwrap()
238 .try_into_authentication_structure()
239 .unwrap();
240 let main_tree_auth_paths = extract_paths(
241 indices.clone(),
242 main_table_rows,
243 tree_height,
244 main_authentication_structure,
245 );
246
247 let aux_table_rows = proof_stream
249 .dequeue()
250 .unwrap()
251 .try_into_master_aux_table_rows()
252 .unwrap();
253 let aux_authentication_structure = proof_stream
254 .dequeue()
255 .unwrap()
256 .try_into_authentication_structure()
257 .unwrap();
258 let aux_tree_auth_paths = extract_paths(
259 indices.clone(),
260 aux_table_rows,
261 tree_height,
262 aux_authentication_structure,
263 );
264
265 let quot_table_rows = proof_stream
267 .dequeue()
268 .unwrap()
269 .try_into_quot_segments_elements()
270 .unwrap();
271 let quot_authentication_structure = proof_stream
272 .dequeue()
273 .unwrap()
274 .try_into_authentication_structure()
275 .unwrap();
276 let quot_tree_auth_paths = extract_paths(
277 indices,
278 quot_table_rows,
279 tree_height,
280 quot_authentication_structure,
281 );
282
283 let stark_digests = [
284 main_tree_auth_paths,
285 aux_tree_auth_paths,
286 quot_tree_auth_paths,
287 ]
288 .concat()
289 .concat();
290
291 [fri_digests, stark_digests].concat()
292 }
293}
294
295impl BasicSnippet for StarkVerify {
296 fn parameters(&self) -> Vec<(DataType, String)> {
297 let claim_type = DataType::StructRef(claim_type());
298 vec![
299 (claim_type, "claim".to_string()),
300 (DataType::VoidPointer, "*proof".to_string()),
301 ]
302 }
303
304 fn return_values(&self) -> Vec<(DataType, String)> {
305 vec![]
306 }
307
308 fn entrypoint(&self) -> String {
309 let memory_layout_category = self.memory_layout.label_friendly_name();
310 format!("tasmlib_verifier_stark_verify_{memory_layout_category}")
311 }
312
313 fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
314 const NUM_DEEP_CODEWORD_COMPONENTS: usize = 3;
315 const NUM_OOD_ROWS_WO_QUOTIENT: u32 = 4;
316
317 fn fri_snippet() -> FriSnippet {
318 FriSnippet {
319 #[cfg(test)]
320 test_instance: FriVerify::dummy(),
321 }
322 }
323
324 let entrypoint = self.entrypoint();
325
326 let proof_to_vm_proof_iter = library.import(Box::new(New));
327 let drop_vm_proof_iter = library.import(Box::new(Drop));
328
329 let ood_curr_row_main_and_aux_value_pointer_alloc =
330 library.kmalloc(EXTENSION_DEGREE.try_into().unwrap());
331 let ood_next_row_main_and_aux_value_pointer_alloc =
332 library.kmalloc(EXTENSION_DEGREE.try_into().unwrap());
333 let ood_curr_row_quotient_segment_value_pointer_alloc =
334 library.kmalloc(EXTENSION_DEGREE.try_into().unwrap());
335
336 let out_of_domain_curr_row_quot_segments_pointer_alloc = library.kmalloc(1);
337
338 let instantiate_fiat_shamir_with_claim =
339 library.import(Box::new(InstantiateFiatShamirWithClaim));
340 let next_as_log_2_padded_height = library.import(Box::new(DequeueNextAs {
341 proof_item: ProofItemVariant::Log2PaddedHeight,
342 }));
343 let next_as_merkleroot = library.import(Box::new(DequeueNextAs {
344 proof_item: ProofItemVariant::MerkleRoot,
345 }));
346 let next_as_outofdomainmainrow = library.import(Box::new(DequeueNextAs {
347 proof_item: ProofItemVariant::OutOfDomainMainRow,
348 }));
349 let next_as_outofdomainauxrow = library.import(Box::new(DequeueNextAs {
350 proof_item: ProofItemVariant::OutOfDomainAuxRow,
351 }));
352 let next_as_outofdomainquotientsegments = library.import(Box::new(DequeueNextAs {
353 proof_item: ProofItemVariant::OutOfDomainQuotientSegments,
354 }));
355 let next_as_maintablerows = library.import(Box::new(DequeueNextAs {
356 proof_item: ProofItemVariant::MasterMainTableRows,
357 }));
358 let next_as_authentication_path = library.import(Box::new(DequeueNextAs {
359 proof_item: ProofItemVariant::AuthenticationStructure,
360 }));
361 let next_as_auxtablerows = library.import(Box::new(DequeueNextAs {
362 proof_item: ProofItemVariant::MasterAuxTableRows,
363 }));
364 let next_as_quotient_segment_elements = library.import(Box::new(DequeueNextAs {
365 proof_item: ProofItemVariant::QuotientSegmentsElements,
366 }));
367 let derive_fri_parameters =
368 library.import(Box::new(fri::derive_from_stark::DeriveFriFromStark {
369 stark: self.stark,
370 }));
371 let num_collinearity_checks_field = field!(FriVerify::num_collinearity_checks);
372 let domain_length_field = field!(FriVerify::domain_length);
373 let domain_offset_field = field!(FriVerify::domain_offset);
374 let domain_generator_field = field!(FriVerify::domain_generator);
375
376 let fri_verify = library.import(Box::new(fri_snippet()));
377
378 let get_challenges = library.import(Box::new(
379 challenges::new_generic_dyn_claim::NewGenericDynClaim::tvm_challenges(
380 self.memory_layout.challenges_pointer(),
381 ),
382 ));
383 let sample_quotient_codeword_weights =
384 library.import(Box::new(SampleScalarsStaticLengthDynMalloc {
385 num_elements: MasterAuxTable::NUM_CONSTRAINTS,
386 }));
387 let domain_generator = library.import(Box::new(PrimitiveRootOfUnity));
388 let sample_scalar_one = library.import(Box::new(SampleScalarOne));
389 let calculate_out_of_domain_points = library.import(Box::new(OutOfDomainPoints));
390 let divide_out_zerofiers = library.import(Box::new(DivideOutZerofiers));
391 let inner_product_quotient_summands = library.import(Box::new(InnerProductOfXfes {
392 length: MasterAuxTable::NUM_CONSTRAINTS,
393 }));
394 let horner_evaluation_of_ood_curr_row_quot_segments =
395 library.import(Box::new(HornerEvaluation {
396 num_coefficients: NUM_QUOTIENT_SEGMENTS,
397 }));
398 let sample_beqd_weights = library.import(Box::new(SampleScalarsStaticLengthDynMalloc {
399 num_elements: MasterMainTable::NUM_COLUMNS
400 + MasterAuxTable::NUM_COLUMNS
401 + NUM_QUOTIENT_SEGMENTS
402 + NUM_DEEP_CODEWORD_COMPONENTS,
403 }));
404 let verify_main_table_rows = library.import(Box::new(VerifyTableRows {
405 column_type: ColumnType::Main,
406 }));
407 let verify_aux_table_rows = library.import(Box::new(VerifyTableRows {
408 column_type: ColumnType::Aux,
409 }));
410 let verify_quotient_segments = library.import(Box::new(VerifyTableRows {
411 column_type: ColumnType::Quotient,
412 }));
413 let inner_product_three_rows_with_weights_bfe_main = library.import(Box::new(
414 InnerProductOfThreeRowsWithWeights::triton_vm_parameters(MainElementType::Bfe),
415 ));
416 let inner_product_three_rows_with_weights_xfe_main = library.import(Box::new(
417 InnerProductOfThreeRowsWithWeights::triton_vm_parameters(MainElementType::Xfe),
418 ));
419 let inner_product_4_xfes = library.import(Box::new(InnerProductOfXfes { length: 4 }));
420 let quotient_segment_codeword_weights_from_be_weights = triton_asm!(
421 push {(MasterMainTable::NUM_COLUMNS + MasterAuxTable::NUM_COLUMNS) * EXTENSION_DEGREE}
424 add
425 );
427 let deep_codeword_weights_read_address = |n: usize| {
428 assert!(n < NUM_DEEP_CODEWORD_COMPONENTS);
429 triton_asm!(
430 push {(MasterMainTable::NUM_COLUMNS + MasterAuxTable::NUM_COLUMNS + NUM_QUOTIENT_SEGMENTS + n) * EXTENSION_DEGREE + {EXTENSION_DEGREE - 1}}
433 add
434 )
436 };
437
438 let dequeue_four_ood_rows = triton_asm! {
439 dup 0
441 call {next_as_outofdomainmainrow}
442 hint out_of_domain_curr_main_row: Pointer = stack[0]
443
444 dup 1
445 call {next_as_outofdomainauxrow}
446 hint out_of_domain_curr_aux_row: Pointer = stack[0]
447
448 dup 2
449 call {next_as_outofdomainmainrow}
450 hint out_of_domain_next_main_row: Pointer = stack[0]
451
452 dup 3
453 call {next_as_outofdomainauxrow}
454 hint out_of_domain_next_aux_row: Pointer = stack[0]
455 };
457
458 let ood_pointers_alloc = library.kmalloc(NUM_OOD_ROWS_WO_QUOTIENT);
463 let evaluate_air_and_store_ood_pointers = match self.memory_layout {
464 MemoryLayout::Static(static_layout) => {
465 let static_eval =
466 library.import(Box::new(AirConstraintEvaluation::new_static(static_layout)));
467 triton_asm! {
468 push {ood_pointers_alloc.write_address()}
469 write_mem {ood_pointers_alloc.num_words()}
470
471 pop 2
472 call {static_eval}
475 }
477 }
478 MemoryLayout::Dynamic(dynamic_layout) => {
479 let dynamic_eval = library.import(Box::new(AirConstraintEvaluation::new_dynamic(
480 dynamic_layout,
481 )));
482 triton_asm! {
483 dup 3
485 dup 3
486 dup 3
487 dup 3
488 push {ood_pointers_alloc.write_address()}
489 write_mem {ood_pointers_alloc.num_words()}
490 pop 1
491 call {dynamic_eval}
494 pick 1 pop 1
497 }
499 }
500 };
501
502 let put_ood_row_pointers_back_on_stack = triton_asm! {
503 push {ood_pointers_alloc.read_address()}
505 read_mem {ood_pointers_alloc.num_words()}
506 pop 1
507
508 };
510
511 let challenges_ptr = self.memory_layout.challenges_pointer();
512
513 let assert_top_two_xfes_eq = triton_asm!(
514 pick 3
516 eq
517 assert error_id 230
518
519 pick 2
521 eq
522 assert error_id 231
523
524 eq
526 assert error_id 232
527
528 );
530
531 let main_loop_label = format!("{entrypoint}_main_loop");
532 let main_loop_body = triton_asm!(
533 pick 2
537 read_mem 1
538 place 3
539 dup 8
542 pow
543 dup 7
544 mul
545 push -1
546 mul
547 hint neg_fri_domain_point = stack[0]
548 dup 6
552 dup 6
553 dup 4
554 call {inner_product_three_rows_with_weights_bfe_main} hint main_and_aux_opened_row_element: Xfe = stack[0..3]
556 pick 9
560 addi {-bfe!(EXTENSION_DEGREE * MasterAuxTable::NUM_COLUMNS)}
561 place 9
562 pick 8
563 addi {-bfe!(MasterMainTable::NUM_COLUMNS)}
564 place 8
565 push -1
568 xb_mul
569 hint neg_main_and_aux_opened_row_element: Xfe = stack[0..3]
570
571 dup 4
573 {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRowPowNumSegments)}
574 dup 6
577 add
578 x_invert
581 dup 8
584 {"ient_segment_codeword_weights_from_be_weights}
585 dup 11
586 call {inner_product_4_xfes}
587 pick 13
590 addi {-bfe!(NUM_QUOTIENT_SEGMENTS * EXTENSION_DEGREE)}
591 place 13
592 push -1
595 xb_mul
596 push {ood_curr_row_quotient_segment_value_pointer_alloc.read_address()}
599 read_mem {EXTENSION_DEGREE}
600 pop 1
601 xx_add
604 xx_mul
605 hint quot_curr_row_deep_value: XFieldElement = stack[0..3]
606 dup 8
612 {&deep_codeword_weights_read_address(2)}
613 read_mem {EXTENSION_DEGREE}
614 pop 1
615 xx_mul
616 dup 7
620 {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRow)}
621 dup 9
624 add
625 x_invert
626 push {ood_curr_row_main_and_aux_value_pointer_alloc.read_address()}
629 read_mem {EXTENSION_DEGREE}
630 pop 1
631 dup 11
634 dup 11
635 dup 11
636 xx_add
637 xx_mul
640 dup 11
643 {&deep_codeword_weights_read_address(0)}
644 read_mem {EXTENSION_DEGREE} pop 1
646 xx_mul
647 xx_add
651 hint dv2_plus_dv0: XFieldElement = stack[0..3]
653
654 pick 5
655 pick 5
656 pick 5
657 push {ood_next_row_main_and_aux_value_pointer_alloc.read_address()}
660 read_mem {EXTENSION_DEGREE}
661 pop 1
662 xx_add
663 dup 7
666 {&OutOfDomainPoints::read_ood_point(OodPoint::NextRow)}
667 dup 9
670 add
671 x_invert
674 xx_mul
675 dup 8
678 {&deep_codeword_weights_read_address(1)}
679 read_mem {EXTENSION_DEGREE} pop 1
681 xx_mul
682 xx_add
686 hint deep_value: XFieldElement = stack[0..3]
687 pick 3
691 pop 1
692 pick 5
695 read_mem {EXTENSION_DEGREE}
696 place 8
697 {&assert_top_two_xfes_eq}
700
701 );
703 let main_loop = triton_asm!(
704 {main_loop_label}:
707 dup 8
709 push 0
710 eq
711 skiz
712 return
713
714 {&main_loop_body}
715
716 pick 8
718 addi -1
719 place 8
720 recurse
721 );
722
723 triton_asm!(
724 {entrypoint}:
725 sponge_init
726 call {proof_to_vm_proof_iter}
729 hint proof_iter = stack[0]
730
731 dup 1
736 call {instantiate_fiat_shamir_with_claim}
737 dup 0
742 call {next_as_log_2_padded_height}
743 read_mem 1
746 pop 1
747 push 32
751 dup 1
752 lt
753 assert error_id {Self::LOG2_PADDED_HEIGHT_TOO_LARGE}
756 push 2
759 pow
760 hint padded_height = stack[0]
761 dup 0
764 call {derive_fri_parameters}
765 hint fri = stack[0]
766 dup 2
770 call {next_as_merkleroot}
771 hint b_mr = stack[0]
772 swap 4
775 call {get_challenges}
778 push {challenges_ptr}
782 eq
783 assert error_id 233
784 dup 2
787 call {next_as_merkleroot}
788 hint e_mr = stack[0]
789 call {sample_quotient_codeword_weights}
792 hint quot_codeword_weights = stack[0]
794
795 dup 4
796 call {next_as_merkleroot}
797 hint quot_mr = stack[0]
798 push 0
803 dup 5
804 call {domain_generator}
805 hint trace_domain_generator = stack[0]
806 dup 0
809 call {sample_scalar_one}
812 call {calculate_out_of_domain_points}
815 hint out_of_domain_points = stack[0]
816 push 2
821 add
822 read_mem {EXTENSION_DEGREE}
823 push 1
824 add
825 swap 9
828 dup 10
831 {&dequeue_four_ood_rows}
832 {&evaluate_air_and_store_ood_pointers}
835 swap 5
838 call {divide_out_zerofiers}
841 {&put_ood_row_pointers_back_on_stack}
844 dup 10
847 call {next_as_outofdomainquotientsegments}
848 hint out_of_domain_quotient_segments: Pointer = stack[0]
849 dup 0
852 push {out_of_domain_curr_row_quot_segments_pointer_alloc.write_address()}
853 write_mem {out_of_domain_curr_row_quot_segments_pointer_alloc.num_words()}
854 pop 1
855
856
857 dup 10
859 {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRow)}
860 call {horner_evaluation_of_ood_curr_row_quot_segments}
863 pick 4 place 9
868 pick 3 place 6
869 pick 8 pick 6
870 call {inner_product_quotient_summands}
873 {&assert_top_two_xfes_eq}
877 call {sample_beqd_weights}
881 hint beqd_weights = stack[0]
882 swap 10
885 dup 9
891 dup 8
892 call {fri_verify}
893 hint fri_revealed = stack[0]
894 dup 10
899 call {next_as_maintablerows}
900 dup 9
904 {&num_collinearity_checks_field}
905 read_mem 1
906 pop 1
907 dup 10
910 {&domain_length_field}
911 read_mem 1
912 pop 1
913 log_2_floor
916 pick 4
919 dup 4
922 dup 4
925 call {verify_main_table_rows}
928 dup 10
933 call {next_as_authentication_path}
934 pop 1
935 swap 7
938 dup 10
943 call {next_as_auxtablerows}
944 pick 1
947 dup 9
950 {&num_collinearity_checks_field}
951 read_mem 1
952 pop 1
953 dup 10
954 {&domain_length_field}
955 read_mem 1
956 pop 1
957 log_2_floor
958 pick 2
961 dup 4
962 dup 4
963 call {verify_aux_table_rows}
966 dup 10
971 call {next_as_authentication_path}
972 pop 1
973
974 swap 5
975 dup 10
980 call {next_as_quotient_segment_elements}
981 swap 1
982 dup 9
983 {&num_collinearity_checks_field}
984 read_mem 1
985 pop 1
986 dup 10
987 {&domain_length_field}
988 read_mem 1
989 pop 1
990 log_2_floor
991 pick 2
994 dup 4
997 dup 4
998 call {verify_quotient_segments}
1001 dup 8
1006 {&num_collinearity_checks_field}
1007 read_mem 1
1008 pop 1
1009 hint num_combination_codeword_checks = stack[0]
1010 dup 2
1014 read_mem 1
1015 pop 1
1016 dup 1
1017 eq
1018 assert error_id 234
1019 dup 8
1023 read_mem 1
1024 pop 1
1025 dup 1
1026 eq
1027 assert error_id 235
1028
1029 dup 6
1031 read_mem 1
1032 pop 1
1033 dup 1
1034 eq
1035 assert error_id 236
1036
1037 dup 1
1039 read_mem 1
1040 pop 1
1041 dup 1
1042 eq
1043 assert error_id 237
1044 swap 12
1049 swap 11
1050 dup 0
1051 call {next_as_authentication_path}
1052 pop 1
1053
1054 call {drop_vm_proof_iter}
1055 dup 10
1061 swap 2
1062 swap 4
1065 swap 1
1066 swap 3
1067 swap 2
1068 call {inner_product_three_rows_with_weights_xfe_main} hint out_of_domain_curr_row_main_and_aux_value: XFieldElement = stack[0..3]
1072 push {ood_curr_row_main_and_aux_value_pointer_alloc.write_address()}
1075 write_mem {ood_curr_row_main_and_aux_value_pointer_alloc.num_words()}
1076 pop 1
1077 swap 2
1082 swap 1
1083 swap 4
1084 dup 8
1085 call {inner_product_three_rows_with_weights_xfe_main} hint out_of_domain_next_row_main_and_aux_value: XFieldElement = stack[0..3]
1089 push {ood_next_row_main_and_aux_value_pointer_alloc.write_address()}
1092 write_mem {ood_next_row_main_and_aux_value_pointer_alloc.num_words()}
1093 pop 1
1094 dup 6
1098 {"ient_segment_codeword_weights_from_be_weights}
1099 push {out_of_domain_curr_row_quot_segments_pointer_alloc.read_address()}
1102 read_mem {out_of_domain_curr_row_quot_segments_pointer_alloc.num_words()}
1103 pop 1
1104 call {inner_product_4_xfes}
1107 hint out_of_domain_curr_row_quotient_segment_value: XFieldElement = stack[0..3]
1108 push {ood_curr_row_quotient_segment_value_pointer_alloc.write_address()}
1111 write_mem {ood_curr_row_quotient_segment_value_pointer_alloc.num_words()}
1112 pop 1
1113 swap 4
1117 dup 0
1118 {&domain_offset_field}
1119 read_mem 1
1120 pop 1
1121 hint fri_domain_offset = stack[0]
1122 swap 1
1125 {&domain_generator_field}
1126 read_mem 1
1127 pop 1
1128 hint fri_domain_gen = stack[0]
1129 pick 3
1136 dup 8
1137 push {EXTENSION_DEGREE + 1} mul
1139 add
1140 hint fri_revealed_elem = stack[0]
1141 place 3
1142
1143 pick 4
1145 addi 1
1146 dup 8
1147 addi -1
1148 push {MasterMainTable::NUM_COLUMNS} mul
1150 add
1151 hint main_table_row = stack[0]
1152 place 4
1153
1154 pick 2
1156 addi 1
1157 dup 8
1158 addi -1
1159 push {MasterAuxTable::NUM_COLUMNS * EXTENSION_DEGREE} mul
1161 add
1162 hint aux_table_row = stack[0]
1163 place 2
1164
1165 pick 5
1167 addi 1
1168 dup 8
1169 addi -1
1170 push {NUM_QUOTIENT_SEGMENTS * EXTENSION_DEGREE} mul
1172 add
1173 hint quotient_segment_elem = stack[0]
1174 place 5
1175
1176 place 7
1180 place 6
1181 place 5
1182 place 4
1183 place 4
1184 place 3
1185 call {main_loop_label}
1188 pop 5 pop 4
1192
1193 return
1194
1195 {&main_loop}
1196 )
1197 }
1198}
1199
1200#[cfg(test)]
1201pub mod tests {
1202 use std::collections::HashMap;
1203
1204 use num_traits::ConstZero;
1205 use tasm_object_derive::TasmObject;
1206 use triton_vm::proof_item::ProofItem;
1207
1208 use super::*;
1209 use crate::execute_test;
1210 use crate::maybe_write_debuggable_vm_state_to_disk;
1211 use crate::memory::FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS;
1212 use crate::memory::encode_to_memory;
1213 use crate::test_helpers::maybe_write_tvm_output_to_disk;
1214 use crate::verifier::claim::shared::insert_claim_into_static_memory;
1215 use crate::verifier::master_table::air_constraint_evaluation::an_integral_but_profane_dynamic_memory_layout;
1216
1217 #[ignore = "Used for debugging when comparing two versions of the verifier"]
1218 #[test]
1219 fn verify_from_stored_proof_output() {
1220 use std::fs::File;
1221 let stark = File::open("stark.json").expect("stark file should open read only");
1222 let stark: Stark = serde_json::from_reader(stark).unwrap();
1223 let claim = File::open("claim.json").expect("claim file should open read only");
1224 let claim_for_proof: Claim = serde_json::from_reader(claim).unwrap();
1225 let proof = File::open("proof.json").expect("proof file should open read only");
1226 let proof: Proof = serde_json::from_reader(proof).unwrap();
1227
1228 let snippet = StarkVerify {
1229 stark,
1230 memory_layout: MemoryLayout::conventional_dynamic(),
1231 };
1232 let mut nondeterminism = NonDeterminism::new(vec![]);
1233 snippet.update_nondeterminism(&mut nondeterminism, &proof, &claim_for_proof);
1234
1235 let (claim_pointer, claim_size) =
1236 insert_claim_into_static_memory(&mut nondeterminism.ram, &claim_for_proof);
1237
1238 let default_proof_pointer = BFieldElement::ZERO;
1239
1240 let mut init_stack = [
1241 snippet.init_stack_for_isolated_run(),
1242 vec![claim_pointer, default_proof_pointer],
1243 ]
1244 .concat();
1245 let code = snippet.link_for_isolated_run_populated_static_memory(claim_size);
1246 let _final_tasm_state = execute_test(
1247 &code,
1248 &mut init_stack,
1249 snippet.stack_diff(),
1250 vec![],
1251 nondeterminism,
1252 None,
1253 );
1254 }
1255
1256 #[test]
1257 fn fail_on_too_big_log2_padded_height() {
1258 let mut proof_stream = ProofStream::new();
1259 proof_stream.enqueue(ProofItem::Log2PaddedHeight(32));
1260 let proof: Proof = proof_stream.into();
1261
1262 let mut nondeterminism = NonDeterminism::new(vec![]);
1263 encode_to_memory(
1264 &mut nondeterminism.ram,
1265 FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1266 &proof,
1267 );
1268 let (claim_pointer, claim_size) = insert_claim_into_static_memory(
1269 &mut nondeterminism.ram,
1270 &Claim::new(Digest::default()),
1271 );
1272
1273 let snippet = StarkVerify {
1274 stark: Stark::default(),
1275 memory_layout: MemoryLayout::conventional_static(),
1276 };
1277 let default_proof_pointer = bfe!(0);
1278 let init_stack = [
1279 snippet.init_stack_for_isolated_run(),
1280 vec![claim_pointer, default_proof_pointer],
1281 ]
1282 .concat();
1283
1284 let program =
1285 Program::new(&snippet.link_for_isolated_run_populated_static_memory(claim_size));
1286 let mut vm_state = VMState::new(program, [].into(), nondeterminism.clone());
1287 vm_state.op_stack.stack = init_stack.clone();
1288 let error = vm_state.run().unwrap_err();
1289 match error {
1290 InstructionError::AssertionFailed(assertion_error) => {
1291 assert_eq!(
1292 StarkVerify::LOG2_PADDED_HEIGHT_TOO_LARGE,
1293 assertion_error.id.unwrap()
1294 );
1295 }
1296 _ => panic!(),
1297 }
1298 }
1299
1300 fn test_verify_and_report_basic_features(
1303 inner_nondeterminism: NonDeterminism,
1304 inner_program: Program,
1305 inner_public_input: &[BFieldElement],
1306 stark: Stark,
1307 layout: MemoryLayout,
1308 ) -> (usize, usize) {
1309 let (mut non_determinism, claim_for_proof) = prove_and_get_non_determinism_and_claim(
1310 inner_program.clone(),
1311 inner_public_input,
1312 inner_nondeterminism.clone(),
1313 &stark,
1314 );
1315
1316 let (claim_pointer, claim_size) =
1317 insert_claim_into_static_memory(&mut non_determinism.ram, &claim_for_proof);
1318
1319 let default_proof_pointer = bfe!(0);
1320
1321 let snippet = StarkVerify {
1322 stark,
1323 memory_layout: layout,
1324 };
1325 let mut init_stack = [
1326 snippet.init_stack_for_isolated_run(),
1327 vec![claim_pointer, default_proof_pointer],
1328 ]
1329 .concat();
1330 let code = snippet.link_for_isolated_run_populated_static_memory(claim_size);
1331
1332 let program = Program::new(&code);
1333 let mut vm_state = VMState::new(program, [].into(), non_determinism.clone());
1334 vm_state.op_stack.stack = init_stack.clone();
1335 maybe_write_debuggable_vm_state_to_disk(&vm_state);
1336
1337 let final_tasm_state = execute_test(
1338 &code,
1339 &mut init_stack,
1340 snippet.stack_diff(),
1341 vec![],
1342 non_determinism,
1343 None,
1344 );
1345
1346 let (aet, _public_output) = VM::trace_execution(
1347 inner_program,
1348 (&claim_for_proof.input).into(),
1349 inner_nondeterminism,
1350 )
1351 .unwrap();
1352 let inner_padded_height = aet.padded_height();
1353
1354 (final_tasm_state.cycle_count as usize, inner_padded_height)
1355 }
1356
1357 #[test]
1358 fn different_fri_expansion_factors() {
1359 const FACTORIAL_ARGUMENT: u32 = 3;
1360
1361 for log2_of_fri_expansion_factor in 2..=5 {
1362 println!("log2_of_fri_expansion_factor: {log2_of_fri_expansion_factor}");
1363 let factorial_program = factorial_program_with_io();
1364 let stark = Stark::new(160, log2_of_fri_expansion_factor);
1365 let (cycle_count, inner_padded_height) = test_verify_and_report_basic_features(
1366 NonDeterminism::default(),
1367 factorial_program,
1368 &[FACTORIAL_ARGUMENT.into()],
1369 stark,
1370 MemoryLayout::conventional_static(),
1371 );
1372 println!(
1373 "TASM-verifier of factorial({FACTORIAL_ARGUMENT}):\n
1374 Fri expansion factor: {}\n
1375 clock cycle count: {}.\n
1376 Inner padded height was: {}",
1377 1 << log2_of_fri_expansion_factor,
1378 cycle_count,
1379 inner_padded_height,
1380 );
1381 }
1382 }
1383
1384 fn verify_tvm_proof_factorial_program_basic_properties(mem_layout: MemoryLayout) {
1385 const FACTORIAL_ARGUMENT: u32 = 3;
1386
1387 let factorial_program = factorial_program_with_io();
1388 let stark = Stark::default();
1389 let (cycle_count, inner_padded_height) = test_verify_and_report_basic_features(
1390 NonDeterminism::default(),
1391 factorial_program,
1392 &[FACTORIAL_ARGUMENT.into()],
1393 stark,
1394 mem_layout,
1395 );
1396
1397 println!(
1398 "TASM-verifier of factorial({FACTORIAL_ARGUMENT}):\n
1399 clock cycle count: {cycle_count}.\n
1400 Inner padded height was: {inner_padded_height}",
1401 );
1402 }
1403
1404 #[test]
1405 fn verify_tvm_proof_factorial_program_conventional_static_memlayout() {
1406 verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::conventional_static());
1407 }
1408
1409 #[test]
1410 fn verify_tvm_proof_factorial_program_conventional_dynamic_memlayout() {
1411 verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::conventional_dynamic());
1412 }
1413
1414 #[test]
1415 fn verify_tvm_proof_factorial_program_profane_dynamic_memlayout() {
1416 verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::Dynamic(
1417 an_integral_but_profane_dynamic_memory_layout(),
1418 ));
1419 }
1420
1421 pub(super) fn factorial_program_with_io() -> Program {
1422 triton_program!(
1423 read_io 1
1424 push 1 call factorial write_io 1
1427 halt
1428
1429 factorial: dup 1 push 0 eq skiz return dup 1 mul pick 1 addi -1 place 1 recurse
1443 )
1444 }
1445
1446 pub fn prove_and_get_non_determinism_and_claim(
1455 inner_program: Program,
1456 inner_public_input: &[BFieldElement],
1457 inner_nondeterminism: NonDeterminism,
1458 stark: &Stark,
1459 ) -> (NonDeterminism, Claim) {
1460 println!("Generating proof for non-determinism");
1461
1462 let inner_input = inner_public_input.to_vec();
1463 let claim = Claim::about_program(&inner_program).with_input(inner_input.clone());
1464 let (aet, inner_output) =
1465 VM::trace_execution(inner_program, inner_input.into(), inner_nondeterminism).unwrap();
1466 let claim = claim.with_output(inner_output);
1467
1468 triton_vm::profiler::start("inner program");
1469 let seed = [
1470 227, 232, 115, 183, 84, 194, 68, 59, 166, 60, 140, 218, 88, 117, 227, 129, 10, 121,
1471 108, 40, 65, 125, 143, 31, 155, 128, 202, 75, 218, 44, 120, 170,
1472 ];
1473 let prover = Prover::new(*stark).set_randomness_seed_which_may_break_zero_knowledge(seed);
1474 let proof = prover.prove(&claim, &aet).unwrap();
1475 let profile = triton_vm::profiler::finish();
1476 let padded_height = proof.padded_height().unwrap();
1477 let report = profile
1478 .with_cycle_count(aet.processor_trace.nrows())
1479 .with_padded_height(padded_height)
1480 .with_fri_domain_len(stark.fri(padded_height).unwrap().domain.len());
1481 println!("Done generating proof for non-determinism");
1482 println!("{report}");
1483
1484 assert!(
1485 stark.verify(&claim, &proof).is_ok(),
1486 "Proof from TVM must verify through TVM"
1487 );
1488
1489 maybe_write_tvm_output_to_disk(stark, &claim, &proof);
1490
1491 let mut nondeterminism = NonDeterminism::new(vec![]);
1492 let stark_verify = StarkVerify {
1493 stark: *stark,
1494 memory_layout: MemoryLayout::conventional_static(),
1495 };
1496
1497 let actual_num_extracted_digests = stark_verify
1499 .extract_nondeterministic_digests(&proof, &claim)
1500 .len();
1501 let expected_num_extracted_digests =
1502 stark_verify.number_of_nondeterministic_digests_consumed(&proof);
1503 assert_eq!(
1504 actual_num_extracted_digests, expected_num_extracted_digests,
1505 "Number of extracted digests must match expected value"
1506 );
1507
1508 stark_verify.update_nondeterminism(&mut nondeterminism, &proof, &claim);
1509 encode_to_memory(
1510 &mut nondeterminism.ram,
1511 FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1512 &proof,
1513 );
1514
1515 (nondeterminism, claim)
1516 }
1517
1518 #[test]
1519 fn verify_two_proofs() {
1520 #[derive(Debug, Clone, BFieldCodec, TasmObject)]
1521 struct TwoProofs {
1522 proof1: Proof,
1523 claim1: Claim,
1524 proof2: Proof,
1525 claim2: Claim,
1526 }
1527
1528 let stark = Stark::default();
1529 let stark_snippet = StarkVerify::new_with_dynamic_layout(stark);
1530
1531 let mut library = Library::new();
1532 let stark_verify = library.import(Box::new(stark_snippet));
1533 let proof1 = field!(TwoProofs::proof1);
1534 let proof2 = field!(TwoProofs::proof2);
1535 let claim1 = field!(TwoProofs::claim1);
1536 let claim2 = field!(TwoProofs::claim2);
1537 let verify_two_proofs_program = triton_asm! {
1538
1539
1540 push {FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS}
1541 dup 0
1544 {&claim1}
1545
1546 dup 1
1547 {&proof1}
1548 call {stark_verify}
1551
1552 dup 0
1553 {&claim2}
1554
1555 dup 1
1556 {&proof2}
1557 call {stark_verify}
1560
1561 halt
1562
1563 {&library.all_imports()}
1564 };
1565
1566 let inner_input_1 = bfe_vec![3];
1567 let factorial_program = factorial_program_with_io();
1568 let (aet_1, inner_output_1) = VM::trace_execution(
1569 factorial_program.clone(),
1570 inner_input_1.clone().into(),
1571 [].into(),
1572 )
1573 .unwrap();
1574 let claim_1 = Claim::about_program(&factorial_program)
1575 .with_input(inner_input_1.clone())
1576 .with_output(inner_output_1.clone());
1577 let proof_1 = stark.prove(&claim_1, &aet_1).unwrap();
1578 let padded_height_1 = proof_1.padded_height().unwrap();
1579 println!("padded_height_1: {padded_height_1}");
1580
1581 let inner_input_2 = bfe_vec![25];
1582 let (aet_2, inner_output_2) = VM::trace_execution(
1583 factorial_program.clone(),
1584 inner_input_2.clone().into(),
1585 [].into(),
1586 )
1587 .unwrap();
1588 let claim_2 = Claim::about_program(&factorial_program)
1589 .with_input(inner_input_2.clone())
1590 .with_output(inner_output_2.clone());
1591 let proof_2 = stark.prove(&claim_2, &aet_2).unwrap();
1592 let padded_height_2 = proof_2.padded_height().unwrap();
1593 println!("padded_height_2: {padded_height_2}");
1594
1595 let two_proofs = TwoProofs {
1596 proof1: proof_1.clone(),
1597 claim1: claim_1.clone(),
1598 proof2: proof_2.clone(),
1599 claim2: claim_2.clone(),
1600 };
1601
1602 let mut memory = HashMap::<BFieldElement, BFieldElement>::new();
1603 let outer_input = vec![];
1604 encode_to_memory(
1605 &mut memory,
1606 FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1607 &two_proofs,
1608 );
1609
1610 let mut outer_nondeterminism = NonDeterminism::new(vec![]).with_ram(memory);
1611
1612 let num_nd_digests_before = outer_nondeterminism.digests.len();
1613
1614 stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_1, &claim_1);
1615 stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_2, &claim_2);
1616
1617 let num_nd_digests_after = outer_nondeterminism.digests.len();
1618
1619 assert_eq!(
1620 num_nd_digests_after - num_nd_digests_before,
1621 stark_snippet.number_of_nondeterministic_digests_consumed(&proof_1)
1622 + stark_snippet.number_of_nondeterministic_digests_consumed(&proof_2)
1623 );
1624
1625 let program = Program::new(&verify_two_proofs_program);
1626 let vm_state = VMState::new(
1627 program.clone(),
1628 outer_input.clone().into(),
1629 outer_nondeterminism.clone(),
1630 );
1631 maybe_write_debuggable_vm_state_to_disk(&vm_state);
1632 VM::run(program, outer_input.into(), outer_nondeterminism)
1633 .expect("could not verify two STARK proofs");
1634
1635 println!(
1636 "fact({}) == {} ∧ fact({}) == {}",
1637 inner_input_1[0], inner_output_1[0], inner_input_2[0], inner_output_2[0]
1638 );
1639
1640 assert_ne!(
1641 padded_height_1, padded_height_2,
1642 "proofs do not have different padded heights"
1643 );
1644 }
1645}
1646
1647#[cfg(test)]
1648mod benches {
1649 use benches::tests::factorial_program_with_io;
1650 use benches::tests::prove_and_get_non_determinism_and_claim;
1651 use num_traits::ConstZero;
1652
1653 use super::*;
1654 use crate::generate_full_profile;
1655 use crate::linker::execute_bench;
1656 use crate::memory::encode_to_memory;
1657 use crate::snippet_bencher::BenchmarkCase;
1658 use crate::snippet_bencher::NamedBenchmarkResult;
1659 use crate::snippet_bencher::write_benchmarks;
1660 use crate::test_helpers::prepend_program_with_stack_setup;
1661 use crate::verifier::claim::shared::insert_claim_into_static_memory;
1662
1663 #[ignore = "Used for profiling the verification of a proof stored on disk."]
1664 #[test]
1665 fn profile_from_stored_proof_output() {
1666 use std::fs::File;
1667 let stark = File::open("stark.json").expect("stark file should open read only");
1668 let stark: Stark = serde_json::from_reader(stark).unwrap();
1669 let claim_file = File::open("claim.json").expect("claim file should open read only");
1670 let claim_for_proof: Claim = serde_json::from_reader(claim_file).unwrap();
1671 let proof = File::open("proof.json").expect("proof file should open read only");
1672 let proof: Proof = serde_json::from_reader(proof).unwrap();
1673
1674 let snippet = StarkVerify {
1675 stark,
1676 memory_layout: MemoryLayout::conventional_static(),
1677 };
1678 let mut nondeterminism = NonDeterminism::new(vec![]);
1679 snippet.update_nondeterminism(&mut nondeterminism, &proof, &claim_for_proof);
1680
1681 let (claim_pointer, claim_size) =
1682 insert_claim_into_static_memory(&mut nondeterminism.ram, &claim_for_proof);
1683
1684 let default_proof_pointer = BFieldElement::ZERO;
1685
1686 let init_stack = [
1687 snippet.init_stack_for_isolated_run(),
1688 vec![claim_pointer, default_proof_pointer],
1689 ]
1690 .concat();
1691 let code = snippet.link_for_isolated_run_populated_static_memory(claim_size);
1692 let program = prepend_program_with_stack_setup(&init_stack, &Program::new(&code));
1693
1694 let name = snippet.entrypoint();
1695 let profile = generate_full_profile(
1696 &name,
1697 program,
1698 &PublicInput::new(claim_for_proof.input),
1699 &nondeterminism,
1700 );
1701 println!("{profile}");
1702 }
1703
1704 #[test]
1705 fn benchmark_small_default_stark_static_memory() {
1706 benchmark_verifier(
1707 3,
1708 1 << 8,
1709 Stark::default(),
1710 MemoryLayout::conventional_static(),
1711 );
1712 benchmark_verifier(
1713 40,
1714 1 << 9,
1715 Stark::default(),
1716 MemoryLayout::conventional_static(),
1717 );
1718 }
1719
1720 #[test]
1721 fn benchmark_small_default_stark_dynamic_memory() {
1722 benchmark_verifier(
1723 3,
1724 1 << 8,
1725 Stark::default(),
1726 MemoryLayout::conventional_dynamic(),
1727 );
1728 benchmark_verifier(
1729 40,
1730 1 << 9,
1731 Stark::default(),
1732 MemoryLayout::conventional_dynamic(),
1733 );
1734 }
1735
1736 #[ignore = "Takes a fairly long time. Intended to find optimal FRI expansion factor."]
1737 #[test]
1738 fn small_benchmark_different_fri_expansion_factors() {
1739 for log2_of_fri_expansion_factor in 1..=5 {
1740 let stark = Stark::new(160, log2_of_fri_expansion_factor);
1741 benchmark_verifier(10, 1 << 8, stark, MemoryLayout::conventional_static());
1742 benchmark_verifier(40, 1 << 9, stark, MemoryLayout::conventional_static());
1743 benchmark_verifier(80, 1 << 10, stark, MemoryLayout::conventional_static());
1744 }
1745 }
1746
1747 #[ignore = "Takes a very long time. Intended to find optimal FRI expansion factor. Make sure to run
1748 with `RUSTFLAGS=\"-C opt-level=3 -C debug-assertions=no\"`"]
1749 #[test]
1750 fn big_benchmark_different_fri_expansion_factors() {
1751 let mem_layout = MemoryLayout::conventional_static();
1752 for log2_of_fri_expansion_factor in 2..=3 {
1753 let stark = Stark::new(160, log2_of_fri_expansion_factor);
1754 benchmark_verifier(25600, 1 << 19, stark, mem_layout);
1755 benchmark_verifier(51200, 1 << 20, stark, mem_layout);
1756 benchmark_verifier(102400, 1 << 21, stark, mem_layout);
1757 }
1758 }
1759
1760 #[ignore = "Intended to generate data about verifier table heights as a function of inner padded
1761 height. Make sure to run with `RUSTFLAGS=\"-C opt-level=3 -C debug-assertions=no\"`"]
1762 #[test]
1763 fn benchmark_verification_as_a_function_of_inner_padded_height() {
1764 for (fact_arg, expected_inner_padded_height) in [
1765 (10, 1 << 8),
1766 (40, 1 << 9),
1767 (80, 1 << 10),
1768 (100, 1 << 11),
1769 (200, 1 << 12),
1770 (400, 1 << 13),
1771 (800, 1 << 14),
1772 (1600, 1 << 15),
1773 (3200, 1 << 16),
1774 (6400, 1 << 17),
1775 (12800, 1 << 18),
1776 (25600, 1 << 19),
1777 (51200, 1 << 20),
1778 (102400, 1 << 21),
1779 ] {
1780 benchmark_verifier(
1781 fact_arg,
1782 expected_inner_padded_height,
1783 Stark::default(),
1784 MemoryLayout::conventional_static(),
1785 );
1786 }
1787 }
1788
1789 fn benchmark_verifier(
1790 factorial_argument: u32,
1791 inner_padded_height: usize,
1792 stark: Stark,
1793 mem_layout: MemoryLayout,
1794 ) {
1795 let (mut non_determinism, claim_for_proof) = prove_and_get_non_determinism_and_claim(
1796 factorial_program_with_io(),
1797 &[bfe!(factorial_argument)],
1798 NonDeterminism::default(),
1799 &stark,
1800 );
1801
1802 let claim_pointer = BFieldElement::new(1 << 30);
1803 encode_to_memory(&mut non_determinism.ram, claim_pointer, &claim_for_proof);
1804
1805 let default_proof_pointer = BFieldElement::ZERO;
1806
1807 let snippet = StarkVerify {
1808 stark,
1809 memory_layout: mem_layout,
1810 };
1811
1812 let init_stack = [
1813 snippet.init_stack_for_isolated_run(),
1814 vec![claim_pointer, default_proof_pointer],
1815 ]
1816 .concat();
1817 let code = snippet.link_for_isolated_run();
1818 let benchmark = execute_bench(&code, &init_stack, vec![], non_determinism.clone(), None);
1819 let benchmark = NamedBenchmarkResult {
1820 name: format!(
1821 "{}_inner_padded_height_{}_fri_exp_{}",
1822 snippet.entrypoint(),
1823 inner_padded_height,
1824 stark.fri_expansion_factor
1825 ),
1826 benchmark_result: benchmark,
1827 case: BenchmarkCase::CommonCase,
1828 };
1829
1830 write_benchmarks(vec![benchmark]);
1831
1832 let program = prepend_program_with_stack_setup(&init_stack, &Program::new(&code));
1833 let name = snippet.entrypoint();
1834 let profile = generate_full_profile(
1835 &name,
1836 program,
1837 &PublicInput::new(claim_for_proof.input),
1838 &non_determinism,
1839 );
1840 println!("{profile}");
1841 }
1842}