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 const LOG2_PADDED_HEIGHT_TOO_SMALL: i128 = 239;
60
61 pub fn new_with_static_layout(stark: Stark) -> Self {
62 Self {
63 stark,
64 memory_layout: MemoryLayout::conventional_static(),
65 }
66 }
67
68 pub fn new_with_dynamic_layout(stark: Stark) -> Self {
69 Self {
70 stark,
71 memory_layout: MemoryLayout::conventional_dynamic(),
72 }
73 }
74
75 pub fn number_of_nondeterministic_digests_consumed(&self, proof: &Proof) -> usize {
78 const NUM_FULL_DOMAIN_AUTH_PATHS: usize = 4;
79
80 let padded_height = proof.padded_height().unwrap();
81 let fri_params = self.stark.fri(padded_height).unwrap();
82 let num_fri_rounds = fri_params.num_rounds();
83
84 let mut j = 0;
85 let mut tree_height: usize = fri_params.domain.len().ilog2().try_into().unwrap();
86
87 let mut acc = NUM_FULL_DOMAIN_AUTH_PATHS * tree_height * fri_params.num_collinearity_checks;
88 while j < num_fri_rounds {
89 acc += fri_params.num_collinearity_checks * tree_height;
90 j += 1;
91 tree_height -= 1;
92 }
93
94 acc
95 }
96
97 pub fn number_of_nondeterministic_tokens_consumed(
101 &self,
102 _proof: &Proof,
103 _claim: &Claim,
104 ) -> usize {
105 0
106 }
107
108 pub fn update_nondeterminism(
112 &self,
113 nondeterminism: &mut NonDeterminism,
114 proof: &Proof,
115 claim: &Claim,
116 ) {
117 nondeterminism
118 .digests
119 .append(&mut self.extract_nondeterministic_digests(proof, claim));
120 }
121
122 fn extract_nondeterministic_digests(&self, proof: &Proof, claim: &Claim) -> Vec<Digest> {
123 const NUM_DEEP_CODEWORD_COMPONENTS: usize = 3;
124
125 fn extract_paths<R: BFieldCodec>(
126 indices: Vec<usize>,
127 leaf_preimages: Vec<R>,
128 tree_height: u32,
129 authentication_structure: Vec<Digest>,
130 ) -> Vec<Vec<Digest>> {
131 let indexed_leafs = indices
132 .into_iter()
133 .zip(leaf_preimages.iter().map(Tip5::hash))
134 .collect();
135 MerkleTreeInclusionProof {
136 tree_height,
137 indexed_leafs,
138 authentication_structure,
139 }
140 .into_authentication_paths()
141 .unwrap()
142 }
143
144 let mut proof_stream = ProofStream::try_from(proof).unwrap();
148 proof_stream.alter_fiat_shamir_state_with(claim);
149 let log2_padded_height = proof_stream
150 .dequeue()
151 .unwrap()
152 .try_into_log2_padded_height()
153 .unwrap();
154
155 let _main_table_root = proof_stream
157 .dequeue()
158 .unwrap()
159 .try_into_merkle_root()
160 .unwrap();
161
162 let _challenges = proof_stream.sample_scalars(Challenges::SAMPLE_COUNT);
164
165 let _aux_mt_root = proof_stream
167 .dequeue()
168 .unwrap()
169 .try_into_merkle_root()
170 .unwrap();
171
172 proof_stream.sample_scalars(MasterAuxTable::NUM_CONSTRAINTS);
174
175 let _quotient_root = proof_stream
177 .dequeue()
178 .unwrap()
179 .try_into_merkle_root()
180 .unwrap();
181
182 let _out_of_domain_point_curr_row = proof_stream.sample_scalars(1);
184
185 proof_stream
187 .dequeue()
188 .unwrap()
189 .try_into_out_of_domain_main_row()
190 .unwrap();
191 proof_stream
192 .dequeue()
193 .unwrap()
194 .try_into_out_of_domain_aux_row()
195 .unwrap();
196 proof_stream
197 .dequeue()
198 .unwrap()
199 .try_into_out_of_domain_main_row()
200 .unwrap();
201 proof_stream
202 .dequeue()
203 .unwrap()
204 .try_into_out_of_domain_aux_row()
205 .unwrap();
206 proof_stream
207 .dequeue()
208 .unwrap()
209 .try_into_out_of_domain_quot_segments()
210 .unwrap();
211
212 proof_stream.sample_scalars(
214 MasterMainTable::NUM_COLUMNS
215 + MasterAuxTable::NUM_COLUMNS
216 + NUM_QUOTIENT_SEGMENTS
217 + NUM_DEEP_CODEWORD_COMPONENTS,
218 );
219
220 let padded_height = 1 << log2_padded_height;
222 let fri = self.stark.fri(padded_height).unwrap();
223 let fri_proof_stream = proof_stream.clone();
224 let fri_verify_result = fri.verify(&mut proof_stream).unwrap();
225 let indices = fri_verify_result.iter().map(|(i, _)| *i).collect_vec();
226 let tree_height = fri.domain.len().ilog2();
227 let fri_digests =
228 FriVerify::from(fri).extract_digests_required_for_proving(&fri_proof_stream);
229
230 let main_table_rows = proof_stream
232 .dequeue()
233 .unwrap()
234 .try_into_master_main_table_rows()
235 .unwrap();
236 let main_authentication_structure = proof_stream
237 .dequeue()
238 .unwrap()
239 .try_into_authentication_structure()
240 .unwrap();
241 let main_tree_auth_paths = extract_paths(
242 indices.clone(),
243 main_table_rows,
244 tree_height,
245 main_authentication_structure,
246 );
247
248 let aux_table_rows = proof_stream
250 .dequeue()
251 .unwrap()
252 .try_into_master_aux_table_rows()
253 .unwrap();
254 let aux_authentication_structure = proof_stream
255 .dequeue()
256 .unwrap()
257 .try_into_authentication_structure()
258 .unwrap();
259 let aux_tree_auth_paths = extract_paths(
260 indices.clone(),
261 aux_table_rows,
262 tree_height,
263 aux_authentication_structure,
264 );
265
266 let quot_table_rows = proof_stream
268 .dequeue()
269 .unwrap()
270 .try_into_quot_segments_elements()
271 .unwrap();
272 let quot_authentication_structure = proof_stream
273 .dequeue()
274 .unwrap()
275 .try_into_authentication_structure()
276 .unwrap();
277 let quot_tree_auth_paths = extract_paths(
278 indices,
279 quot_table_rows,
280 tree_height,
281 quot_authentication_structure,
282 );
283
284 let stark_digests = [
285 main_tree_auth_paths,
286 aux_tree_auth_paths,
287 quot_tree_auth_paths,
288 ]
289 .concat()
290 .concat();
291
292 [fri_digests, stark_digests].concat()
293 }
294}
295
296impl BasicSnippet for StarkVerify {
297 fn parameters(&self) -> Vec<(DataType, String)> {
298 let claim_type = DataType::StructRef(claim_type());
299 vec![
300 (claim_type, "claim".to_string()),
301 (DataType::VoidPointer, "*proof".to_string()),
302 ]
303 }
304
305 fn return_values(&self) -> Vec<(DataType, String)> {
306 vec![]
307 }
308
309 fn entrypoint(&self) -> String {
310 let memory_layout_category = self.memory_layout.label_friendly_name();
311 format!("tasmlib_verifier_stark_verify_{memory_layout_category}")
312 }
313
314 fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
315 const NUM_DEEP_CODEWORD_COMPONENTS: usize = 3;
316 const NUM_OOD_ROWS_WO_QUOTIENT: u32 = 4;
317
318 fn fri_snippet() -> FriSnippet {
319 FriSnippet {
320 #[cfg(test)]
321 test_instance: FriVerify::dummy(),
322 }
323 }
324
325 let entrypoint = self.entrypoint();
326
327 let proof_to_vm_proof_iter = library.import(Box::new(New));
328 let drop_vm_proof_iter = library.import(Box::new(Drop));
329
330 let ood_curr_row_main_and_aux_value_pointer_alloc =
331 library.kmalloc(EXTENSION_DEGREE.try_into().unwrap());
332 let ood_next_row_main_and_aux_value_pointer_alloc =
333 library.kmalloc(EXTENSION_DEGREE.try_into().unwrap());
334 let ood_curr_row_quotient_segment_value_pointer_alloc =
335 library.kmalloc(EXTENSION_DEGREE.try_into().unwrap());
336
337 let out_of_domain_curr_row_quot_segments_pointer_alloc = library.kmalloc(1);
338
339 let instantiate_fiat_shamir_with_claim =
340 library.import(Box::new(InstantiateFiatShamirWithClaim));
341 let next_as_log_2_padded_height = library.import(Box::new(DequeueNextAs {
342 proof_item: ProofItemVariant::Log2PaddedHeight,
343 }));
344 let next_as_merkleroot = library.import(Box::new(DequeueNextAs {
345 proof_item: ProofItemVariant::MerkleRoot,
346 }));
347 let next_as_outofdomainmainrow = library.import(Box::new(DequeueNextAs {
348 proof_item: ProofItemVariant::OutOfDomainMainRow,
349 }));
350 let next_as_outofdomainauxrow = library.import(Box::new(DequeueNextAs {
351 proof_item: ProofItemVariant::OutOfDomainAuxRow,
352 }));
353 let next_as_outofdomainquotientsegments = library.import(Box::new(DequeueNextAs {
354 proof_item: ProofItemVariant::OutOfDomainQuotientSegments,
355 }));
356 let next_as_maintablerows = library.import(Box::new(DequeueNextAs {
357 proof_item: ProofItemVariant::MasterMainTableRows,
358 }));
359 let next_as_authentication_path = library.import(Box::new(DequeueNextAs {
360 proof_item: ProofItemVariant::AuthenticationStructure,
361 }));
362 let next_as_auxtablerows = library.import(Box::new(DequeueNextAs {
363 proof_item: ProofItemVariant::MasterAuxTableRows,
364 }));
365 let next_as_quotient_segment_elements = library.import(Box::new(DequeueNextAs {
366 proof_item: ProofItemVariant::QuotientSegmentsElements,
367 }));
368 let derive_fri_parameters =
369 library.import(Box::new(fri::derive_from_stark::DeriveFriFromStark {
370 stark: self.stark,
371 }));
372 let num_collinearity_checks_field = field!(FriVerify::num_collinearity_checks);
373 let domain_length_field = field!(FriVerify::domain_length);
374 let domain_offset_field = field!(FriVerify::domain_offset);
375 let domain_generator_field = field!(FriVerify::domain_generator);
376
377 let fri_verify = library.import(Box::new(fri_snippet()));
378
379 let get_challenges = library.import(Box::new(
380 challenges::new_generic_dyn_claim::NewGenericDynClaim::tvm_challenges(
381 self.memory_layout.challenges_pointer(),
382 ),
383 ));
384 let sample_quotient_codeword_weights =
385 library.import(Box::new(SampleScalarsStaticLengthDynMalloc {
386 num_elements: MasterAuxTable::NUM_CONSTRAINTS,
387 }));
388 let domain_generator = library.import(Box::new(PrimitiveRootOfUnity));
389 let sample_scalar_one = library.import(Box::new(SampleScalarOne));
390 let calculate_out_of_domain_points = library.import(Box::new(OutOfDomainPoints));
391 let divide_out_zerofiers = library.import(Box::new(DivideOutZerofiers));
392 let inner_product_quotient_summands = library.import(Box::new(InnerProductOfXfes {
393 length: MasterAuxTable::NUM_CONSTRAINTS,
394 }));
395 let horner_evaluation_of_ood_curr_row_quot_segments =
396 library.import(Box::new(HornerEvaluation {
397 num_coefficients: NUM_QUOTIENT_SEGMENTS,
398 }));
399 let sample_beqd_weights = library.import(Box::new(SampleScalarsStaticLengthDynMalloc {
400 num_elements: MasterMainTable::NUM_COLUMNS
401 + MasterAuxTable::NUM_COLUMNS
402 + NUM_QUOTIENT_SEGMENTS
403 + NUM_DEEP_CODEWORD_COMPONENTS,
404 }));
405 let verify_main_table_rows = library.import(Box::new(VerifyTableRows {
406 column_type: ColumnType::Main,
407 }));
408 let verify_aux_table_rows = library.import(Box::new(VerifyTableRows {
409 column_type: ColumnType::Aux,
410 }));
411 let verify_quotient_segments = library.import(Box::new(VerifyTableRows {
412 column_type: ColumnType::Quotient,
413 }));
414 let inner_product_three_rows_with_weights_bfe_main = library.import(Box::new(
415 InnerProductOfThreeRowsWithWeights::triton_vm_parameters(MainElementType::Bfe),
416 ));
417 let inner_product_three_rows_with_weights_xfe_main = library.import(Box::new(
418 InnerProductOfThreeRowsWithWeights::triton_vm_parameters(MainElementType::Xfe),
419 ));
420 let inner_product_4_xfes = library.import(Box::new(InnerProductOfXfes { length: 4 }));
421 let quotient_segment_codeword_weights_from_be_weights = triton_asm!(
422 push {(MasterMainTable::NUM_COLUMNS + MasterAuxTable::NUM_COLUMNS) * EXTENSION_DEGREE}
425 add
426 );
428 let deep_codeword_weights_read_address = |n: usize| {
429 assert!(n < NUM_DEEP_CODEWORD_COMPONENTS);
430 triton_asm!(
431 push {(MasterMainTable::NUM_COLUMNS + MasterAuxTable::NUM_COLUMNS + NUM_QUOTIENT_SEGMENTS + n) * EXTENSION_DEGREE + {EXTENSION_DEGREE - 1}}
434 add
435 )
437 };
438
439 let dequeue_four_ood_rows = triton_asm! {
440 dup 0
442 call {next_as_outofdomainmainrow}
443 hint out_of_domain_curr_main_row: Pointer = stack[0]
444
445 dup 1
446 call {next_as_outofdomainauxrow}
447 hint out_of_domain_curr_aux_row: Pointer = stack[0]
448
449 dup 2
450 call {next_as_outofdomainmainrow}
451 hint out_of_domain_next_main_row: Pointer = stack[0]
452
453 dup 3
454 call {next_as_outofdomainauxrow}
455 hint out_of_domain_next_aux_row: Pointer = stack[0]
456 };
458
459 let ood_pointers_alloc = library.kmalloc(NUM_OOD_ROWS_WO_QUOTIENT);
464 let evaluate_air_and_store_ood_pointers = match self.memory_layout {
465 MemoryLayout::Static(static_layout) => {
466 let static_eval =
467 library.import(Box::new(AirConstraintEvaluation::new_static(static_layout)));
468 triton_asm! {
469 push {ood_pointers_alloc.write_address()}
470 write_mem {ood_pointers_alloc.num_words()}
471
472 pop 2
473 call {static_eval}
476 }
478 }
479 MemoryLayout::Dynamic(dynamic_layout) => {
480 let dynamic_eval = library.import(Box::new(AirConstraintEvaluation::new_dynamic(
481 dynamic_layout,
482 )));
483 triton_asm! {
484 dup 3
486 dup 3
487 dup 3
488 dup 3
489 push {ood_pointers_alloc.write_address()}
490 write_mem {ood_pointers_alloc.num_words()}
491 pop 1
492 call {dynamic_eval}
495 pick 1 pop 1
498 }
500 }
501 };
502
503 let put_ood_row_pointers_back_on_stack = triton_asm! {
504 push {ood_pointers_alloc.read_address()}
506 read_mem {ood_pointers_alloc.num_words()}
507 pop 1
508
509 };
511
512 let challenges_ptr = self.memory_layout.challenges_pointer();
513
514 let assert_top_two_xfes_eq = triton_asm!(
515 pick 3
517 eq
518 assert error_id 230
519
520 pick 2
522 eq
523 assert error_id 231
524
525 eq
527 assert error_id 232
528
529 );
531
532 let main_loop_label = format!("{entrypoint}_main_loop");
533 let main_loop_body = triton_asm!(
534 pick 2
538 read_mem 1
539 place 3
540 dup 8
543 pow
544 dup 7
545 mul
546 push -1
547 mul
548 hint neg_fri_domain_point = stack[0]
549 dup 6
553 dup 6
554 dup 4
555 call {inner_product_three_rows_with_weights_bfe_main} hint main_and_aux_opened_row_element: Xfe = stack[0..3]
557 pick 9
561 addi {-bfe!(EXTENSION_DEGREE * MasterAuxTable::NUM_COLUMNS)}
562 place 9
563 pick 8
564 addi {-bfe!(MasterMainTable::NUM_COLUMNS)}
565 place 8
566 push -1
569 xb_mul
570 hint neg_main_and_aux_opened_row_element: Xfe = stack[0..3]
571
572 dup 4
574 {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRowPowNumSegments)}
575 dup 6
578 add
579 x_invert
582 dup 8
585 {"ient_segment_codeword_weights_from_be_weights}
586 dup 11
587 call {inner_product_4_xfes}
588 pick 13
591 addi {-bfe!(NUM_QUOTIENT_SEGMENTS * EXTENSION_DEGREE)}
592 place 13
593 push -1
596 xb_mul
597 push {ood_curr_row_quotient_segment_value_pointer_alloc.read_address()}
600 read_mem {EXTENSION_DEGREE}
601 pop 1
602 xx_add
605 xx_mul
606 hint quot_curr_row_deep_value: XFieldElement = stack[0..3]
607 dup 8
613 {&deep_codeword_weights_read_address(2)}
614 read_mem {EXTENSION_DEGREE}
615 pop 1
616 xx_mul
617 dup 7
621 {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRow)}
622 dup 9
625 add
626 x_invert
627 push {ood_curr_row_main_and_aux_value_pointer_alloc.read_address()}
630 read_mem {EXTENSION_DEGREE}
631 pop 1
632 dup 11
635 dup 11
636 dup 11
637 xx_add
638 xx_mul
641 dup 11
644 {&deep_codeword_weights_read_address(0)}
645 read_mem {EXTENSION_DEGREE} pop 1
647 xx_mul
648 xx_add
652 hint dv2_plus_dv0: XFieldElement = stack[0..3]
654
655 pick 5
656 pick 5
657 pick 5
658 push {ood_next_row_main_and_aux_value_pointer_alloc.read_address()}
661 read_mem {EXTENSION_DEGREE}
662 pop 1
663 xx_add
664 dup 7
667 {&OutOfDomainPoints::read_ood_point(OodPoint::NextRow)}
668 dup 9
671 add
672 x_invert
675 xx_mul
676 dup 8
679 {&deep_codeword_weights_read_address(1)}
680 read_mem {EXTENSION_DEGREE} pop 1
682 xx_mul
683 xx_add
687 hint deep_value: XFieldElement = stack[0..3]
688 pick 3
692 pop 1
693 pick 5
696 read_mem {EXTENSION_DEGREE}
697 place 8
698 {&assert_top_two_xfes_eq}
701
702 );
704 let main_loop = triton_asm!(
705 {main_loop_label}:
708 dup 8
710 push 0
711 eq
712 skiz
713 return
714
715 {&main_loop_body}
716
717 pick 8
719 addi -1
720 place 8
721 recurse
722 );
723
724 triton_asm!(
725 {entrypoint}:
726 sponge_init
727 call {proof_to_vm_proof_iter}
730 hint proof_iter = stack[0]
731
732 dup 1
737 call {instantiate_fiat_shamir_with_claim}
738 dup 0
743 call {next_as_log_2_padded_height}
744 read_mem 1
747 pop 1
748 push 32
752 dup 1
753 lt
754 assert error_id {Self::LOG2_PADDED_HEIGHT_TOO_LARGE}
757 push 8
760 dup 1
761 lt
762 push 0
763 eq
764 assert error_id {Self::LOG2_PADDED_HEIGHT_TOO_SMALL}
767
768
769 push 2
770 pow
771 hint padded_height = stack[0]
772 dup 0
775 call {derive_fri_parameters}
776 hint fri = stack[0]
777 dup 2
781 call {next_as_merkleroot}
782 hint b_mr = stack[0]
783 swap 4
786 call {get_challenges}
789 push {challenges_ptr}
793 eq
794 assert error_id 233
795 dup 2
798 call {next_as_merkleroot}
799 hint e_mr = stack[0]
800 call {sample_quotient_codeword_weights}
803 hint quot_codeword_weights = stack[0]
805
806 dup 4
807 call {next_as_merkleroot}
808 hint quot_mr = stack[0]
809 push 0
814 dup 5
815 call {domain_generator}
816 hint trace_domain_generator = stack[0]
817 dup 0
820 call {sample_scalar_one}
823 call {calculate_out_of_domain_points}
826 hint out_of_domain_points = stack[0]
827 push 2
832 add
833 read_mem {EXTENSION_DEGREE}
834 push 1
835 add
836 swap 9
839 dup 10
842 {&dequeue_four_ood_rows}
843 {&evaluate_air_and_store_ood_pointers}
846 swap 5
849 call {divide_out_zerofiers}
852 {&put_ood_row_pointers_back_on_stack}
855 dup 10
858 call {next_as_outofdomainquotientsegments}
859 hint out_of_domain_quotient_segments: Pointer = stack[0]
860 dup 0
863 push {out_of_domain_curr_row_quot_segments_pointer_alloc.write_address()}
864 write_mem {out_of_domain_curr_row_quot_segments_pointer_alloc.num_words()}
865 pop 1
866
867
868 dup 10
870 {&OutOfDomainPoints::read_ood_point(OodPoint::CurrentRow)}
871 call {horner_evaluation_of_ood_curr_row_quot_segments}
874 pick 4 place 9
879 pick 3 place 6
880 pick 8 pick 6
881 call {inner_product_quotient_summands}
884 {&assert_top_two_xfes_eq}
888 call {sample_beqd_weights}
892 hint beqd_weights = stack[0]
893 swap 10
896 dup 9
902 dup 8
903 call {fri_verify}
904 hint fri_revealed = stack[0]
905 dup 10
910 call {next_as_maintablerows}
911 dup 9
915 {&num_collinearity_checks_field}
916 read_mem 1
917 pop 1
918 dup 10
921 {&domain_length_field}
922 read_mem 1
923 pop 1
924 log_2_floor
927 pick 4
930 dup 4
933 dup 4
936 call {verify_main_table_rows}
939 dup 10
944 call {next_as_authentication_path}
945 pop 1
946 swap 7
949 dup 10
954 call {next_as_auxtablerows}
955 pick 1
958 dup 9
961 {&num_collinearity_checks_field}
962 read_mem 1
963 pop 1
964 dup 10
965 {&domain_length_field}
966 read_mem 1
967 pop 1
968 log_2_floor
969 pick 2
972 dup 4
973 dup 4
974 call {verify_aux_table_rows}
977 dup 10
982 call {next_as_authentication_path}
983 pop 1
984
985 swap 5
986 dup 10
991 call {next_as_quotient_segment_elements}
992 swap 1
993 dup 9
994 {&num_collinearity_checks_field}
995 read_mem 1
996 pop 1
997 dup 10
998 {&domain_length_field}
999 read_mem 1
1000 pop 1
1001 log_2_floor
1002 pick 2
1005 dup 4
1008 dup 4
1009 call {verify_quotient_segments}
1012 dup 8
1017 {&num_collinearity_checks_field}
1018 read_mem 1
1019 pop 1
1020 hint num_combination_codeword_checks = stack[0]
1021 dup 2
1025 read_mem 1
1026 pop 1
1027 dup 1
1028 eq
1029 assert error_id 234
1030 dup 8
1034 read_mem 1
1035 pop 1
1036 dup 1
1037 eq
1038 assert error_id 235
1039
1040 dup 6
1042 read_mem 1
1043 pop 1
1044 dup 1
1045 eq
1046 assert error_id 236
1047
1048 dup 1
1050 read_mem 1
1051 pop 1
1052 dup 1
1053 eq
1054 assert error_id 237
1055 swap 12
1060 swap 11
1061 dup 0
1062 call {next_as_authentication_path}
1063 pop 1
1064
1065 call {drop_vm_proof_iter}
1066 dup 10
1072 swap 2
1073 swap 4
1076 swap 1
1077 swap 3
1078 swap 2
1079 call {inner_product_three_rows_with_weights_xfe_main} hint out_of_domain_curr_row_main_and_aux_value: XFieldElement = stack[0..3]
1083 push {ood_curr_row_main_and_aux_value_pointer_alloc.write_address()}
1086 write_mem {ood_curr_row_main_and_aux_value_pointer_alloc.num_words()}
1087 pop 1
1088 swap 2
1093 swap 1
1094 swap 4
1095 dup 8
1096 call {inner_product_three_rows_with_weights_xfe_main} hint out_of_domain_next_row_main_and_aux_value: XFieldElement = stack[0..3]
1100 push {ood_next_row_main_and_aux_value_pointer_alloc.write_address()}
1103 write_mem {ood_next_row_main_and_aux_value_pointer_alloc.num_words()}
1104 pop 1
1105 dup 6
1109 {"ient_segment_codeword_weights_from_be_weights}
1110 push {out_of_domain_curr_row_quot_segments_pointer_alloc.read_address()}
1113 read_mem {out_of_domain_curr_row_quot_segments_pointer_alloc.num_words()}
1114 pop 1
1115 call {inner_product_4_xfes}
1118 hint out_of_domain_curr_row_quotient_segment_value: XFieldElement = stack[0..3]
1119 push {ood_curr_row_quotient_segment_value_pointer_alloc.write_address()}
1122 write_mem {ood_curr_row_quotient_segment_value_pointer_alloc.num_words()}
1123 pop 1
1124 swap 4
1128 dup 0
1129 {&domain_offset_field}
1130 read_mem 1
1131 pop 1
1132 hint fri_domain_offset = stack[0]
1133 swap 1
1136 {&domain_generator_field}
1137 read_mem 1
1138 pop 1
1139 hint fri_domain_gen = stack[0]
1140 pick 3
1147 dup 8
1148 push {EXTENSION_DEGREE + 1} mul
1150 add
1151 hint fri_revealed_elem = stack[0]
1152 place 3
1153
1154 pick 4
1156 addi 1
1157 dup 8
1158 addi -1
1159 push {MasterMainTable::NUM_COLUMNS} mul
1161 add
1162 hint main_table_row = stack[0]
1163 place 4
1164
1165 pick 2
1167 addi 1
1168 dup 8
1169 addi -1
1170 push {MasterAuxTable::NUM_COLUMNS * EXTENSION_DEGREE} mul
1172 add
1173 hint aux_table_row = stack[0]
1174 place 2
1175
1176 pick 5
1178 addi 1
1179 dup 8
1180 addi -1
1181 push {NUM_QUOTIENT_SEGMENTS * EXTENSION_DEGREE} mul
1183 add
1184 hint quotient_segment_elem = stack[0]
1185 place 5
1186
1187 place 7
1191 place 6
1192 place 5
1193 place 4
1194 place 4
1195 place 3
1196 call {main_loop_label}
1199 pop 5 pop 4
1203
1204 return
1205
1206 {&main_loop}
1207 )
1208 }
1209}
1210
1211#[cfg(test)]
1212pub mod tests {
1213 use std::collections::HashMap;
1214
1215 use num_traits::ConstZero;
1216 use tasm_object_derive::TasmObject;
1217 use triton_vm::proof_item::ProofItem;
1218
1219 use super::*;
1220 use crate::execute_test;
1221 use crate::maybe_write_debuggable_vm_state_to_disk;
1222 use crate::memory::FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS;
1223 use crate::test_helpers::maybe_write_tvm_output_to_disk;
1224 use crate::test_prelude::*;
1225 use crate::verifier::claim::shared::insert_claim_into_static_memory;
1226 use crate::verifier::master_table::air_constraint_evaluation::an_integral_but_profane_dynamic_memory_layout;
1227
1228 #[ignore = "Used for debugging when comparing two versions of the verifier"]
1229 #[macro_rules_attr::apply(test)]
1230 fn verify_from_stored_proof_output() {
1231 use std::fs::File;
1232 let stark = File::open("stark.json").expect("stark file should open read only");
1233 let stark: Stark = serde_json::from_reader(stark).unwrap();
1234 let claim = File::open("claim.json").expect("claim file should open read only");
1235 let claim_for_proof: Claim = serde_json::from_reader(claim).unwrap();
1236 let proof = File::open("proof.json").expect("proof file should open read only");
1237 let proof: Proof = serde_json::from_reader(proof).unwrap();
1238
1239 let snippet = StarkVerify {
1240 stark,
1241 memory_layout: MemoryLayout::conventional_dynamic(),
1242 };
1243 let mut nondeterminism = NonDeterminism::new(vec![]);
1244 snippet.update_nondeterminism(&mut nondeterminism, &proof, &claim_for_proof);
1245
1246 let (claim_pointer, claim_size) =
1247 insert_claim_into_static_memory(&mut nondeterminism.ram, &claim_for_proof);
1248
1249 let default_proof_pointer = BFieldElement::ZERO;
1250
1251 let mut init_stack = [
1252 snippet.init_stack_for_isolated_run(),
1253 vec![claim_pointer, default_proof_pointer],
1254 ]
1255 .concat();
1256 let code = snippet.link_for_isolated_run_populated_static_memory(claim_size);
1257 let _final_tasm_state = execute_test(
1258 &code,
1259 &mut init_stack,
1260 snippet.stack_diff(),
1261 vec![],
1262 nondeterminism,
1263 None,
1264 );
1265 }
1266
1267 fn vm_state_for_log2_padded_height_proof_element(log2_padded_height: u32) -> VMState {
1268 let mut proof_stream = ProofStream::new();
1269 proof_stream.enqueue(ProofItem::Log2PaddedHeight(log2_padded_height));
1270 let proof: Proof = proof_stream.into();
1271
1272 let mut nondeterminism = NonDeterminism::new(vec![]);
1273 encode_to_memory(
1274 &mut nondeterminism.ram,
1275 FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1276 &proof,
1277 );
1278 let (claim_pointer, claim_size) = insert_claim_into_static_memory(
1279 &mut nondeterminism.ram,
1280 &Claim::new(Digest::default()),
1281 );
1282
1283 let snippet = StarkVerify {
1284 stark: Stark::default(),
1285 memory_layout: MemoryLayout::conventional_static(),
1286 };
1287 let init_stack = [
1288 snippet.init_stack_for_isolated_run(),
1289 vec![
1290 claim_pointer,
1291 FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1292 ],
1293 ]
1294 .concat();
1295
1296 let program =
1297 Program::new(&snippet.link_for_isolated_run_populated_static_memory(claim_size));
1298 let mut vm_state = VMState::new(program, [].into(), nondeterminism.clone());
1299 vm_state.op_stack.stack = init_stack.clone();
1300
1301 vm_state
1302 }
1303
1304 #[macro_rules_attr::apply(test)]
1305 fn fail_on_too_big_log2_padded_height() {
1306 for too_big_padded_height in [32, 33, 40, 41, 999] {
1307 let mut vm_state = vm_state_for_log2_padded_height_proof_element(too_big_padded_height);
1308 let error = vm_state.run().unwrap_err();
1309 match error {
1310 InstructionError::AssertionFailed(assertion_error) => {
1311 assert_eq!(
1312 StarkVerify::LOG2_PADDED_HEIGHT_TOO_LARGE,
1313 assertion_error.id.unwrap()
1314 );
1315 }
1316 _ => panic!(),
1317 }
1318 }
1319 }
1320
1321 #[macro_rules_attr::apply(test)]
1322 fn fail_on_too_small_log2_padded_height() {
1323 for too_small_padded_height in 0..8 {
1324 let mut vm_state =
1325 vm_state_for_log2_padded_height_proof_element(too_small_padded_height);
1326 let error = vm_state.run().unwrap_err();
1327 match error {
1328 InstructionError::AssertionFailed(assertion_error) => {
1329 assert_eq!(
1330 StarkVerify::LOG2_PADDED_HEIGHT_TOO_SMALL,
1331 assertion_error.id.unwrap()
1332 );
1333 }
1334 _ => panic!(),
1335 }
1336 }
1337 }
1338
1339 fn test_verify_and_report_basic_features(
1342 inner_nondeterminism: NonDeterminism,
1343 inner_program: Program,
1344 inner_public_input: &[BFieldElement],
1345 stark: Stark,
1346 layout: MemoryLayout,
1347 ) -> (usize, usize) {
1348 let (mut non_determinism, claim_for_proof) = prove_and_get_non_determinism_and_claim(
1349 inner_program.clone(),
1350 inner_public_input,
1351 inner_nondeterminism.clone(),
1352 &stark,
1353 );
1354
1355 let (claim_pointer, claim_size) =
1356 insert_claim_into_static_memory(&mut non_determinism.ram, &claim_for_proof);
1357
1358 let default_proof_pointer = bfe!(0);
1359
1360 let snippet = StarkVerify {
1361 stark,
1362 memory_layout: layout,
1363 };
1364 let mut init_stack = [
1365 snippet.init_stack_for_isolated_run(),
1366 vec![claim_pointer, default_proof_pointer],
1367 ]
1368 .concat();
1369 let code = snippet.link_for_isolated_run_populated_static_memory(claim_size);
1370
1371 let program = Program::new(&code);
1372 let mut vm_state = VMState::new(program, [].into(), non_determinism.clone());
1373 vm_state.op_stack.stack = init_stack.clone();
1374 maybe_write_debuggable_vm_state_to_disk(&vm_state);
1375
1376 let final_tasm_state = execute_test(
1377 &code,
1378 &mut init_stack,
1379 snippet.stack_diff(),
1380 vec![],
1381 non_determinism,
1382 None,
1383 )
1384 .unwrap();
1385
1386 let (aet, _public_output) = VM::trace_execution(
1387 inner_program,
1388 (&claim_for_proof.input).into(),
1389 inner_nondeterminism,
1390 )
1391 .unwrap();
1392 let inner_padded_height = aet.padded_height();
1393
1394 (final_tasm_state.cycle_count as usize, inner_padded_height)
1395 }
1396
1397 #[macro_rules_attr::apply(test)]
1398 fn different_fri_expansion_factors() {
1399 const FACTORIAL_ARGUMENT: u32 = 3;
1400
1401 for log2_of_fri_expansion_factor in 2..=5 {
1402 println!("log2_of_fri_expansion_factor: {log2_of_fri_expansion_factor}");
1403 let factorial_program = factorial_program_with_io();
1404 let stark = Stark::new(160, log2_of_fri_expansion_factor);
1405 let (cycle_count, inner_padded_height) = test_verify_and_report_basic_features(
1406 NonDeterminism::default(),
1407 factorial_program,
1408 &[FACTORIAL_ARGUMENT.into()],
1409 stark,
1410 MemoryLayout::conventional_static(),
1411 );
1412 println!(
1413 "TASM-verifier of factorial({FACTORIAL_ARGUMENT}):\n
1414 Fri expansion factor: {}\n
1415 clock cycle count: {}.\n
1416 Inner padded height was: {}",
1417 1 << log2_of_fri_expansion_factor,
1418 cycle_count,
1419 inner_padded_height,
1420 );
1421 }
1422 }
1423
1424 #[macro_rules_attr::apply(test)]
1425 fn verify_shortest_possible_execution() {
1426 let stark = Stark::default();
1427
1428 for memory_layout in [
1429 MemoryLayout::conventional_static(),
1430 MemoryLayout::conventional_dynamic(),
1431 ] {
1432 let program = triton_program!(halt);
1433 let (_, inner_padded_height) = test_verify_and_report_basic_features(
1434 NonDeterminism::default(),
1435 program,
1436 &[],
1437 stark,
1438 memory_layout,
1439 );
1440 assert_eq!(
1441 256, inner_padded_height,
1442 "This version of Triton VM has minimum padded height of 256"
1443 )
1444 }
1445 }
1446
1447 fn verify_tvm_proof_factorial_program_basic_properties(mem_layout: MemoryLayout) {
1448 const FACTORIAL_ARGUMENT: u32 = 3;
1449
1450 let factorial_program = factorial_program_with_io();
1451 let stark = Stark::default();
1452 let (cycle_count, inner_padded_height) = test_verify_and_report_basic_features(
1453 NonDeterminism::default(),
1454 factorial_program,
1455 &[FACTORIAL_ARGUMENT.into()],
1456 stark,
1457 mem_layout,
1458 );
1459
1460 println!(
1461 "TASM-verifier of factorial({FACTORIAL_ARGUMENT}):\n
1462 clock cycle count: {cycle_count}.\n
1463 Inner padded height was: {inner_padded_height}",
1464 );
1465 }
1466
1467 #[macro_rules_attr::apply(test)]
1468 fn verify_tvm_proof_factorial_program_conventional_static_memlayout() {
1469 verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::conventional_static());
1470 }
1471
1472 #[macro_rules_attr::apply(test)]
1473 fn verify_tvm_proof_factorial_program_conventional_dynamic_memlayout() {
1474 verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::conventional_dynamic());
1475 }
1476
1477 #[macro_rules_attr::apply(test)]
1478 fn verify_tvm_proof_factorial_program_profane_dynamic_memlayout() {
1479 verify_tvm_proof_factorial_program_basic_properties(MemoryLayout::Dynamic(
1480 an_integral_but_profane_dynamic_memory_layout(),
1481 ));
1482 }
1483
1484 pub(super) fn factorial_program_with_io() -> Program {
1485 triton_program!(
1486 read_io 1
1487 push 1 call factorial write_io 1
1490 halt
1491
1492 factorial: dup 1 push 0 eq skiz return dup 1 mul pick 1 addi -1 place 1 recurse
1506 )
1507 }
1508
1509 pub fn prove_and_get_non_determinism_and_claim(
1518 inner_program: Program,
1519 inner_public_input: &[BFieldElement],
1520 inner_nondeterminism: NonDeterminism,
1521 stark: &Stark,
1522 ) -> (NonDeterminism, Claim) {
1523 println!("Generating proof for non-determinism");
1524
1525 let inner_input = inner_public_input.to_vec();
1526 let claim = Claim::about_program(&inner_program).with_input(inner_input.clone());
1527 let (aet, inner_output) =
1528 VM::trace_execution(inner_program, inner_input.into(), inner_nondeterminism).unwrap();
1529 let claim = claim.with_output(inner_output);
1530
1531 triton_vm::profiler::start("inner program");
1532 let seed = [
1533 227, 232, 115, 183, 84, 194, 68, 59, 166, 60, 140, 218, 88, 117, 227, 129, 10, 121,
1534 108, 40, 65, 125, 143, 31, 155, 128, 202, 75, 218, 44, 120, 170,
1535 ];
1536 let prover = Prover::new(*stark).set_randomness_seed_which_may_break_zero_knowledge(seed);
1537 let proof = prover.prove(&claim, &aet).unwrap();
1538 let profile = triton_vm::profiler::finish();
1539 let padded_height = proof.padded_height().unwrap();
1540 let report = profile
1541 .with_cycle_count(aet.processor_trace.nrows())
1542 .with_padded_height(padded_height)
1543 .with_fri_domain_len(stark.fri(padded_height).unwrap().domain.len());
1544 println!("Done generating proof for non-determinism");
1545 println!("{report}");
1546
1547 assert!(
1548 stark.verify(&claim, &proof).is_ok(),
1549 "Proof from TVM must verify through TVM"
1550 );
1551
1552 maybe_write_tvm_output_to_disk(stark, &claim, &proof);
1553
1554 let mut nondeterminism = NonDeterminism::new(vec![]);
1555 let stark_verify = StarkVerify {
1556 stark: *stark,
1557 memory_layout: MemoryLayout::conventional_static(),
1558 };
1559
1560 let actual_num_extracted_digests = stark_verify
1562 .extract_nondeterministic_digests(&proof, &claim)
1563 .len();
1564 let expected_num_extracted_digests =
1565 stark_verify.number_of_nondeterministic_digests_consumed(&proof);
1566 assert_eq!(
1567 actual_num_extracted_digests, expected_num_extracted_digests,
1568 "Number of extracted digests must match expected value"
1569 );
1570
1571 stark_verify.update_nondeterminism(&mut nondeterminism, &proof, &claim);
1572 encode_to_memory(
1573 &mut nondeterminism.ram,
1574 FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1575 &proof,
1576 );
1577
1578 (nondeterminism, claim)
1579 }
1580
1581 #[macro_rules_attr::apply(test)]
1582 fn verify_two_proofs() {
1583 #[derive(Debug, Clone, BFieldCodec, TasmObject)]
1584 struct TwoProofs {
1585 proof1: Proof,
1586 claim1: Claim,
1587 proof2: Proof,
1588 claim2: Claim,
1589 }
1590
1591 let stark = Stark::default();
1592 let stark_snippet = StarkVerify::new_with_dynamic_layout(stark);
1593
1594 let mut library = Library::new();
1595 let stark_verify = library.import(Box::new(stark_snippet));
1596 let proof1 = field!(TwoProofs::proof1);
1597 let proof2 = field!(TwoProofs::proof2);
1598 let claim1 = field!(TwoProofs::claim1);
1599 let claim2 = field!(TwoProofs::claim2);
1600 let verify_two_proofs_program = triton_asm! {
1601
1602
1603 push {FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS}
1604 dup 0
1607 {&claim1}
1608
1609 dup 1
1610 {&proof1}
1611 call {stark_verify}
1614
1615 dup 0
1616 {&claim2}
1617
1618 dup 1
1619 {&proof2}
1620 call {stark_verify}
1623
1624 halt
1625
1626 {&library.all_imports()}
1627 };
1628
1629 let inner_input_1 = bfe_vec![3];
1630 let factorial_program = factorial_program_with_io();
1631 let (aet_1, inner_output_1) = VM::trace_execution(
1632 factorial_program.clone(),
1633 inner_input_1.clone().into(),
1634 [].into(),
1635 )
1636 .unwrap();
1637 let claim_1 = Claim::about_program(&factorial_program)
1638 .with_input(inner_input_1.clone())
1639 .with_output(inner_output_1.clone());
1640 let proof_1 = stark.prove(&claim_1, &aet_1).unwrap();
1641 let padded_height_1 = proof_1.padded_height().unwrap();
1642 println!("padded_height_1: {padded_height_1}");
1643
1644 let inner_input_2 = bfe_vec![25];
1645 let (aet_2, inner_output_2) = VM::trace_execution(
1646 factorial_program.clone(),
1647 inner_input_2.clone().into(),
1648 [].into(),
1649 )
1650 .unwrap();
1651 let claim_2 = Claim::about_program(&factorial_program)
1652 .with_input(inner_input_2.clone())
1653 .with_output(inner_output_2.clone());
1654 let proof_2 = stark.prove(&claim_2, &aet_2).unwrap();
1655 let padded_height_2 = proof_2.padded_height().unwrap();
1656 println!("padded_height_2: {padded_height_2}");
1657
1658 let two_proofs = TwoProofs {
1659 proof1: proof_1.clone(),
1660 claim1: claim_1.clone(),
1661 proof2: proof_2.clone(),
1662 claim2: claim_2.clone(),
1663 };
1664
1665 let mut memory = HashMap::<BFieldElement, BFieldElement>::new();
1666 let outer_input = vec![];
1667 encode_to_memory(
1668 &mut memory,
1669 FIRST_NON_DETERMINISTICALLY_INITIALIZED_MEMORY_ADDRESS,
1670 &two_proofs,
1671 );
1672
1673 let mut outer_nondeterminism = NonDeterminism::new(vec![]).with_ram(memory);
1674
1675 let num_nd_digests_before = outer_nondeterminism.digests.len();
1676
1677 stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_1, &claim_1);
1678 stark_snippet.update_nondeterminism(&mut outer_nondeterminism, &proof_2, &claim_2);
1679
1680 let num_nd_digests_after = outer_nondeterminism.digests.len();
1681
1682 assert_eq!(
1683 num_nd_digests_after - num_nd_digests_before,
1684 stark_snippet.number_of_nondeterministic_digests_consumed(&proof_1)
1685 + stark_snippet.number_of_nondeterministic_digests_consumed(&proof_2)
1686 );
1687
1688 let program = Program::new(&verify_two_proofs_program);
1689 let vm_state = VMState::new(
1690 program.clone(),
1691 outer_input.clone().into(),
1692 outer_nondeterminism.clone(),
1693 );
1694 maybe_write_debuggable_vm_state_to_disk(&vm_state);
1695 VM::run(program, outer_input.into(), outer_nondeterminism)
1696 .expect("could not verify two STARK proofs");
1697
1698 println!(
1699 "fact({}) == {} ∧ fact({}) == {}",
1700 inner_input_1[0], inner_output_1[0], inner_input_2[0], inner_output_2[0]
1701 );
1702
1703 assert_ne!(
1704 padded_height_1, padded_height_2,
1705 "proofs do not have different padded heights"
1706 );
1707 }
1708}
1709
1710#[cfg(test)]
1711mod benches {
1712 use benches::tests::factorial_program_with_io;
1713 use benches::tests::prove_and_get_non_determinism_and_claim;
1714 use num_traits::ConstZero;
1715
1716 use super::*;
1717 use crate::generate_full_profile;
1718 use crate::linker::execute_bench;
1719 use crate::snippet_bencher::NamedBenchmarkResult;
1720 use crate::snippet_bencher::write_benchmarks;
1721 use crate::test_helpers::prepend_program_with_stack_setup;
1722 use crate::test_prelude::*;
1723 use crate::verifier::claim::shared::insert_claim_into_static_memory;
1724
1725 #[ignore = "Used for profiling the verification of a proof stored on disk."]
1726 #[macro_rules_attr::apply(test)]
1727 fn profile_from_stored_proof_output() {
1728 use std::fs::File;
1729 let stark = File::open("stark.json").expect("stark file should open read only");
1730 let stark: Stark = serde_json::from_reader(stark).unwrap();
1731 let claim_file = File::open("claim.json").expect("claim file should open read only");
1732 let claim_for_proof: Claim = serde_json::from_reader(claim_file).unwrap();
1733 let proof = File::open("proof.json").expect("proof file should open read only");
1734 let proof: Proof = serde_json::from_reader(proof).unwrap();
1735
1736 let snippet = StarkVerify {
1737 stark,
1738 memory_layout: MemoryLayout::conventional_static(),
1739 };
1740 let mut nondeterminism = NonDeterminism::new(vec![]);
1741 snippet.update_nondeterminism(&mut nondeterminism, &proof, &claim_for_proof);
1742
1743 let (claim_pointer, claim_size) =
1744 insert_claim_into_static_memory(&mut nondeterminism.ram, &claim_for_proof);
1745
1746 let default_proof_pointer = BFieldElement::ZERO;
1747
1748 let init_stack = [
1749 snippet.init_stack_for_isolated_run(),
1750 vec![claim_pointer, default_proof_pointer],
1751 ]
1752 .concat();
1753 let code = snippet.link_for_isolated_run_populated_static_memory(claim_size);
1754 let program = prepend_program_with_stack_setup(&init_stack, &Program::new(&code));
1755
1756 let name = snippet.entrypoint();
1757 let profile = generate_full_profile(
1758 &name,
1759 program,
1760 &PublicInput::new(claim_for_proof.input),
1761 &nondeterminism,
1762 );
1763 println!("{profile}");
1764 }
1765
1766 #[macro_rules_attr::apply(test)]
1767 fn benchmark_small_default_stark_static_memory() {
1768 benchmark_verifier(
1769 3,
1770 1 << 8,
1771 Stark::default(),
1772 MemoryLayout::conventional_static(),
1773 );
1774 benchmark_verifier(
1775 40,
1776 1 << 9,
1777 Stark::default(),
1778 MemoryLayout::conventional_static(),
1779 );
1780 }
1781
1782 #[macro_rules_attr::apply(test)]
1783 fn benchmark_small_default_stark_dynamic_memory() {
1784 benchmark_verifier(
1785 3,
1786 1 << 8,
1787 Stark::default(),
1788 MemoryLayout::conventional_dynamic(),
1789 );
1790 benchmark_verifier(
1791 40,
1792 1 << 9,
1793 Stark::default(),
1794 MemoryLayout::conventional_dynamic(),
1795 );
1796 }
1797
1798 #[ignore = "Takes a fairly long time. Intended to find optimal FRI expansion factor."]
1799 #[macro_rules_attr::apply(test)]
1800 fn small_benchmark_different_fri_expansion_factors() {
1801 for log2_of_fri_expansion_factor in 1..=5 {
1802 let stark = Stark::new(160, log2_of_fri_expansion_factor);
1803 benchmark_verifier(10, 1 << 8, stark, MemoryLayout::conventional_static());
1804 benchmark_verifier(40, 1 << 9, stark, MemoryLayout::conventional_static());
1805 benchmark_verifier(80, 1 << 10, stark, MemoryLayout::conventional_static());
1806 }
1807 }
1808
1809 #[ignore = "Takes a very long time. Intended to find optimal FRI expansion factor. Make sure to run
1810 with `RUSTFLAGS=\"-C opt-level=3 -C debug-assertions=no\"`"]
1811 #[macro_rules_attr::apply(test)]
1812 fn big_benchmark_different_fri_expansion_factors() {
1813 let mem_layout = MemoryLayout::conventional_static();
1814 for log2_of_fri_expansion_factor in 2..=3 {
1815 let stark = Stark::new(160, log2_of_fri_expansion_factor);
1816 benchmark_verifier(25600, 1 << 19, stark, mem_layout);
1817 benchmark_verifier(51200, 1 << 20, stark, mem_layout);
1818 benchmark_verifier(102400, 1 << 21, stark, mem_layout);
1819 }
1820 }
1821
1822 #[ignore = "Intended to generate data about verifier table heights as a function of inner padded
1823 height. Make sure to run with `RUSTFLAGS=\"-C opt-level=3 -C debug-assertions=no\"`"]
1824 #[macro_rules_attr::apply(test)]
1825 fn benchmark_verification_as_a_function_of_inner_padded_height() {
1826 for (fact_arg, expected_inner_padded_height) in [
1827 (10, 1 << 8),
1828 (40, 1 << 9),
1829 (80, 1 << 10),
1830 (100, 1 << 11),
1831 (200, 1 << 12),
1832 (400, 1 << 13),
1833 (800, 1 << 14),
1834 (1600, 1 << 15),
1835 (3200, 1 << 16),
1836 (6400, 1 << 17),
1837 (12800, 1 << 18),
1838 (25600, 1 << 19),
1839 (51200, 1 << 20),
1840 (102400, 1 << 21),
1841 ] {
1842 benchmark_verifier(
1843 fact_arg,
1844 expected_inner_padded_height,
1845 Stark::default(),
1846 MemoryLayout::conventional_static(),
1847 );
1848 }
1849 }
1850
1851 fn benchmark_verifier(
1852 factorial_argument: u32,
1853 inner_padded_height: usize,
1854 stark: Stark,
1855 mem_layout: MemoryLayout,
1856 ) {
1857 let (mut non_determinism, claim_for_proof) = prove_and_get_non_determinism_and_claim(
1858 factorial_program_with_io(),
1859 &[bfe!(factorial_argument)],
1860 NonDeterminism::default(),
1861 &stark,
1862 );
1863
1864 let claim_pointer = BFieldElement::new(1 << 30);
1865 encode_to_memory(&mut non_determinism.ram, claim_pointer, &claim_for_proof);
1866
1867 let default_proof_pointer = BFieldElement::ZERO;
1868
1869 let snippet = StarkVerify {
1870 stark,
1871 memory_layout: mem_layout,
1872 };
1873
1874 let init_stack = [
1875 snippet.init_stack_for_isolated_run(),
1876 vec![claim_pointer, default_proof_pointer],
1877 ]
1878 .concat();
1879 let code = snippet.link_for_isolated_run();
1880 let benchmark = execute_bench(&code, &init_stack, vec![], non_determinism.clone(), None);
1881 let benchmark = NamedBenchmarkResult {
1882 name: format!(
1883 "{}_inner_padded_height_{}_fri_exp_{}",
1884 snippet.entrypoint(),
1885 inner_padded_height,
1886 stark.fri_expansion_factor
1887 ),
1888 benchmark_result: benchmark,
1889 case: BenchmarkCase::CommonCase,
1890 };
1891
1892 write_benchmarks(vec![benchmark]);
1893
1894 let program = prepend_program_with_stack_setup(&init_stack, &Program::new(&code));
1895 let name = snippet.entrypoint();
1896 let profile = generate_full_profile(
1897 &name,
1898 program,
1899 &PublicInput::new(claim_for_proof.input),
1900 &non_determinism,
1901 );
1902 println!("{profile}");
1903 }
1904}