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::test_helpers::maybe_write_tvm_output_to_disk;
1213 use crate::test_prelude::*;
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 #[macro_rules_attr::apply(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 #[macro_rules_attr::apply(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 .unwrap();
1346
1347 let (aet, _public_output) = VM::trace_execution(
1348 inner_program,
1349 (&claim_for_proof.input).into(),
1350 inner_nondeterminism,
1351 )
1352 .unwrap();
1353 let inner_padded_height = aet.padded_height();
1354
1355 (final_tasm_state.cycle_count as usize, inner_padded_height)
1356 }
1357
1358 #[macro_rules_attr::apply(test)]
1359 fn different_fri_expansion_factors() {
1360 const FACTORIAL_ARGUMENT: u32 = 3;
1361
1362 for log2_of_fri_expansion_factor in 2..=5 {
1363 println!("log2_of_fri_expansion_factor: {log2_of_fri_expansion_factor}");
1364 let factorial_program = factorial_program_with_io();
1365 let stark = Stark::new(160, log2_of_fri_expansion_factor);
1366 let (cycle_count, inner_padded_height) = test_verify_and_report_basic_features(
1367 NonDeterminism::default(),
1368 factorial_program,
1369 &[FACTORIAL_ARGUMENT.into()],
1370 stark,
1371 MemoryLayout::conventional_static(),
1372 );
1373 println!(
1374 "TASM-verifier of factorial({FACTORIAL_ARGUMENT}):\n
1375 Fri expansion factor: {}\n
1376 clock cycle count: {}.\n
1377 Inner padded height was: {}",
1378 1 << log2_of_fri_expansion_factor,
1379 cycle_count,
1380 inner_padded_height,
1381 );
1382 }
1383 }
1384
1385 fn verify_tvm_proof_factorial_program_basic_properties(mem_layout: MemoryLayout) {
1386 const FACTORIAL_ARGUMENT: u32 = 3;
1387
1388 let factorial_program = factorial_program_with_io();
1389 let stark = Stark::default();
1390 let (cycle_count, inner_padded_height) = test_verify_and_report_basic_features(
1391 NonDeterminism::default(),
1392 factorial_program,
1393 &[FACTORIAL_ARGUMENT.into()],
1394 stark,
1395 mem_layout,
1396 );
1397
1398 println!(
1399 "TASM-verifier of factorial({FACTORIAL_ARGUMENT}):\n
1400 clock cycle count: {cycle_count}.\n
1401 Inner padded height was: {inner_padded_height}",
1402 );
1403 }
1404
1405 #[macro_rules_attr::apply(test)]
1406 fn verify_tvm_proof_factorial_program_conventional_static_memlayout() {
1407 verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::conventional_static());
1408 }
1409
1410 #[macro_rules_attr::apply(test)]
1411 fn verify_tvm_proof_factorial_program_conventional_dynamic_memlayout() {
1412 verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::conventional_dynamic());
1413 }
1414
1415 #[macro_rules_attr::apply(test)]
1416 fn verify_tvm_proof_factorial_program_profane_dynamic_memlayout() {
1417 verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::Dynamic(
1418 an_integral_but_profane_dynamic_memory_layout(),
1419 ));
1420 }
1421
1422 pub(super) fn factorial_program_with_io() -> Program {
1423 triton_program!(
1424 read_io 1
1425 push 1 call factorial write_io 1
1428 halt
1429
1430 factorial: dup 1 push 0 eq skiz return dup 1 mul pick 1 addi -1 place 1 recurse
1444 )
1445 }
1446
1447 pub fn prove_and_get_non_determinism_and_claim(
1456 inner_program: Program,
1457 inner_public_input: &[BFieldElement],
1458 inner_nondeterminism: NonDeterminism,
1459 stark: &Stark,
1460 ) -> (NonDeterminism, Claim) {
1461 println!("Generating proof for non-determinism");
1462
1463 let inner_input = inner_public_input.to_vec();
1464 let claim = Claim::about_program(&inner_program).with_input(inner_input.clone());
1465 let (aet, inner_output) =
1466 VM::trace_execution(inner_program, inner_input.into(), inner_nondeterminism).unwrap();
1467 let claim = claim.with_output(inner_output);
1468
1469 triton_vm::profiler::start("inner program");
1470 let seed = [
1471 227, 232, 115, 183, 84, 194, 68, 59, 166, 60, 140, 218, 88, 117, 227, 129, 10, 121,
1472 108, 40, 65, 125, 143, 31, 155, 128, 202, 75, 218, 44, 120, 170,
1473 ];
1474 let prover = Prover::new(*stark).set_randomness_seed_which_may_break_zero_knowledge(seed);
1475 let proof = prover.prove(&claim, &aet).unwrap();
1476 let profile = triton_vm::profiler::finish();
1477 let padded_height = proof.padded_height().unwrap();
1478 let report = profile
1479 .with_cycle_count(aet.processor_trace.nrows())
1480 .with_padded_height(padded_height)
1481 .with_fri_domain_len(stark.fri(padded_height).unwrap().domain.len());
1482 println!("Done generating proof for non-determinism");
1483 println!("{report}");
1484
1485 assert!(
1486 stark.verify(&claim, &proof).is_ok(),
1487 "Proof from TVM must verify through TVM"
1488 );
1489
1490 maybe_write_tvm_output_to_disk(stark, &claim, &proof);
1491
1492 let mut nondeterminism = NonDeterminism::new(vec![]);
1493 let stark_verify = StarkVerify {
1494 stark: *stark,
1495 memory_layout: MemoryLayout::conventional_static(),
1496 };
1497
1498 let actual_num_extracted_digests = stark_verify
1500 .extract_nondeterministic_digests(&proof, &claim)
1501 .len();
1502 let expected_num_extracted_digests =
1503 stark_verify.number_of_nondeterministic_digests_consumed(&proof);
1504 assert_eq!(
1505 actual_num_extracted_digests, expected_num_extracted_digests,
1506 "Number of extracted digests must match expected value"
1507 );
1508
1509 stark_verify.update_nondeterminism(&mut nondeterminism, &proof, &claim);
1510 encode_to_memory(
1511 &mut nondeterminism.ram,
1512 FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1513 &proof,
1514 );
1515
1516 (nondeterminism, claim)
1517 }
1518
1519 #[macro_rules_attr::apply(test)]
1520 fn verify_two_proofs() {
1521 #[derive(Debug, Clone, BFieldCodec, TasmObject)]
1522 struct TwoProofs {
1523 proof1: Proof,
1524 claim1: Claim,
1525 proof2: Proof,
1526 claim2: Claim,
1527 }
1528
1529 let stark = Stark::default();
1530 let stark_snippet = StarkVerify::new_with_dynamic_layout(stark);
1531
1532 let mut library = Library::new();
1533 let stark_verify = library.import(Box::new(stark_snippet));
1534 let proof1 = field!(TwoProofs::proof1);
1535 let proof2 = field!(TwoProofs::proof2);
1536 let claim1 = field!(TwoProofs::claim1);
1537 let claim2 = field!(TwoProofs::claim2);
1538 let verify_two_proofs_program = triton_asm! {
1539
1540
1541 push {FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS}
1542 dup 0
1545 {&claim1}
1546
1547 dup 1
1548 {&proof1}
1549 call {stark_verify}
1552
1553 dup 0
1554 {&claim2}
1555
1556 dup 1
1557 {&proof2}
1558 call {stark_verify}
1561
1562 halt
1563
1564 {&library.all_imports()}
1565 };
1566
1567 let inner_input_1 = bfe_vec![3];
1568 let factorial_program = factorial_program_with_io();
1569 let (aet_1, inner_output_1) = VM::trace_execution(
1570 factorial_program.clone(),
1571 inner_input_1.clone().into(),
1572 [].into(),
1573 )
1574 .unwrap();
1575 let claim_1 = Claim::about_program(&factorial_program)
1576 .with_input(inner_input_1.clone())
1577 .with_output(inner_output_1.clone());
1578 let proof_1 = stark.prove(&claim_1, &aet_1).unwrap();
1579 let padded_height_1 = proof_1.padded_height().unwrap();
1580 println!("padded_height_1: {padded_height_1}");
1581
1582 let inner_input_2 = bfe_vec![25];
1583 let (aet_2, inner_output_2) = VM::trace_execution(
1584 factorial_program.clone(),
1585 inner_input_2.clone().into(),
1586 [].into(),
1587 )
1588 .unwrap();
1589 let claim_2 = Claim::about_program(&factorial_program)
1590 .with_input(inner_input_2.clone())
1591 .with_output(inner_output_2.clone());
1592 let proof_2 = stark.prove(&claim_2, &aet_2).unwrap();
1593 let padded_height_2 = proof_2.padded_height().unwrap();
1594 println!("padded_height_2: {padded_height_2}");
1595
1596 let two_proofs = TwoProofs {
1597 proof1: proof_1.clone(),
1598 claim1: claim_1.clone(),
1599 proof2: proof_2.clone(),
1600 claim2: claim_2.clone(),
1601 };
1602
1603 let mut memory = HashMap::<BFieldElement, BFieldElement>::new();
1604 let outer_input = vec![];
1605 encode_to_memory(
1606 &mut memory,
1607 FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1608 &two_proofs,
1609 );
1610
1611 let mut outer_nondeterminism = NonDeterminism::new(vec![]).with_ram(memory);
1612
1613 let num_nd_digests_before = outer_nondeterminism.digests.len();
1614
1615 stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_1, &claim_1);
1616 stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_2, &claim_2);
1617
1618 let num_nd_digests_after = outer_nondeterminism.digests.len();
1619
1620 assert_eq!(
1621 num_nd_digests_after - num_nd_digests_before,
1622 stark_snippet.number_of_nondeterministic_digests_consumed(&proof_1)
1623 + stark_snippet.number_of_nondeterministic_digests_consumed(&proof_2)
1624 );
1625
1626 let program = Program::new(&verify_two_proofs_program);
1627 let vm_state = VMState::new(
1628 program.clone(),
1629 outer_input.clone().into(),
1630 outer_nondeterminism.clone(),
1631 );
1632 maybe_write_debuggable_vm_state_to_disk(&vm_state);
1633 VM::run(program, outer_input.into(), outer_nondeterminism)
1634 .expect("could not verify two STARK proofs");
1635
1636 println!(
1637 "fact({}) == {} ∧ fact({}) == {}",
1638 inner_input_1[0], inner_output_1[0], inner_input_2[0], inner_output_2[0]
1639 );
1640
1641 assert_ne!(
1642 padded_height_1, padded_height_2,
1643 "proofs do not have different padded heights"
1644 );
1645 }
1646}
1647
1648#[cfg(test)]
1649mod benches {
1650 use benches::tests::factorial_program_with_io;
1651 use benches::tests::prove_and_get_non_determinism_and_claim;
1652 use num_traits::ConstZero;
1653
1654 use super::*;
1655 use crate::generate_full_profile;
1656 use crate::linker::execute_bench;
1657 use crate::snippet_bencher::NamedBenchmarkResult;
1658 use crate::snippet_bencher::write_benchmarks;
1659 use crate::test_helpers::prepend_program_with_stack_setup;
1660 use crate::test_prelude::*;
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 #[macro_rules_attr::apply(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 #[macro_rules_attr::apply(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 #[macro_rules_attr::apply(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 #[macro_rules_attr::apply(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 #[macro_rules_attr::apply(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 #[macro_rules_attr::apply(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}