1use ndarray::Array1;
2use triton_vm::challenges::Challenges;
3use triton_vm::constraints::dynamic_air_constraint_evaluation_tasm;
4use triton_vm::constraints::static_air_constraint_evaluation_tasm;
5use triton_vm::memory_layout::DynamicTasmConstraintEvaluationMemoryLayout;
6use triton_vm::memory_layout::IntegralMemoryLayout;
7use triton_vm::memory_layout::StaticTasmConstraintEvaluationMemoryLayout;
8use triton_vm::prelude::*;
9use triton_vm::table::auxiliary_table::Evaluable;
10use triton_vm::table::master_table::MasterAuxTable;
11use triton_vm::table::master_table::MasterMainTable;
12use twenty_first::math::x_field_element::EXTENSION_DEGREE;
13
14use crate::data_type::ArrayType;
15use crate::memory::dyn_malloc::DYN_MALLOC_ADDRESS;
16use crate::prelude::*;
17use crate::verifier::challenges::shared::conventional_challenges_pointer;
18
19#[derive(Debug, Clone, Copy)]
20pub enum MemoryLayout {
21 Dynamic(DynamicTasmConstraintEvaluationMemoryLayout),
22 Static(StaticTasmConstraintEvaluationMemoryLayout),
23}
24
25impl MemoryLayout {
26 pub fn conventional_static() -> Self {
27 const CURRENT_MAIN_ROW_PTR: u64 = 30u64;
28 const MAIN_ROW_SIZE: u64 = (MasterMainTable::NUM_COLUMNS * EXTENSION_DEGREE) as u64;
29 const AUX_ROW_SIZE: u64 = (MasterAuxTable::NUM_COLUMNS * EXTENSION_DEGREE) as u64;
30 const METADATA_SIZE_PER_PROOF_ITEM_ELEMENT: u64 = 2; let mem_layout = StaticTasmConstraintEvaluationMemoryLayout {
32 free_mem_page_ptr: BFieldElement::new(((1u64 << 32) - 3) * (1u64 << 32)),
33 curr_main_row_ptr: BFieldElement::new(CURRENT_MAIN_ROW_PTR),
34 curr_aux_row_ptr: BFieldElement::new(
35 CURRENT_MAIN_ROW_PTR + MAIN_ROW_SIZE + METADATA_SIZE_PER_PROOF_ITEM_ELEMENT,
36 ),
37 next_main_row_ptr: BFieldElement::new(
38 CURRENT_MAIN_ROW_PTR
39 + MAIN_ROW_SIZE
40 + AUX_ROW_SIZE
41 + 2 * METADATA_SIZE_PER_PROOF_ITEM_ELEMENT,
42 ),
43 next_aux_row_ptr: BFieldElement::new(
44 CURRENT_MAIN_ROW_PTR
45 + 2 * MAIN_ROW_SIZE
46 + AUX_ROW_SIZE
47 + 3 * METADATA_SIZE_PER_PROOF_ITEM_ELEMENT,
48 ),
49 challenges_ptr: conventional_challenges_pointer(),
50 };
51 assert!(mem_layout.is_integral());
52
53 Self::Static(mem_layout)
54 }
55
56 pub fn conventional_dynamic() -> Self {
59 let mem_layout = DynamicTasmConstraintEvaluationMemoryLayout {
60 free_mem_page_ptr: BFieldElement::new(((1u64 << 32) - 3) * (1u64 << 32)),
61 challenges_ptr: conventional_challenges_pointer(),
62 };
63 assert!(mem_layout.is_integral());
64
65 Self::Dynamic(mem_layout)
66 }
67
68 pub fn challenges_pointer(&self) -> BFieldElement {
69 match self {
70 MemoryLayout::Dynamic(dl) => dl.challenges_ptr,
71 MemoryLayout::Static(sl) => sl.challenges_ptr,
72 }
73 }
74
75 pub fn is_integral(&self) -> bool {
77 let memory_regions = match self {
84 MemoryLayout::Dynamic(dl) => dl.memory_regions(),
85 MemoryLayout::Static(sl) => sl.memory_regions(),
86 };
87
88 let kmalloc_region = Library::kmalloc_memory_region();
89 let kmalloc_disjoint = memory_regions
90 .iter()
91 .all(|mr| mr.disjoint_from(&kmalloc_region));
92
93 let dyn_malloc_region = DynMalloc::memory_region();
94 let dyn_malloc_disjoint = memory_regions
95 .iter()
96 .all(|mr| mr.disjoint_from(&dyn_malloc_region));
97
98 let dyn_malloc_state_disjoint = memory_regions
99 .iter()
100 .all(|mr| !mr.contains_address(DYN_MALLOC_ADDRESS));
101
102 let internally_consistent = match self {
103 MemoryLayout::Dynamic(dl) => dl.is_integral(),
104 MemoryLayout::Static(sl) => sl.is_integral(),
105 };
106
107 kmalloc_disjoint
108 && dyn_malloc_disjoint
109 && dyn_malloc_state_disjoint
110 && internally_consistent
111 }
112
113 pub fn label_friendly_name(&self) -> &str {
114 match self {
115 MemoryLayout::Dynamic(_) => "dynamic",
116 MemoryLayout::Static(_) => "static",
117 }
118 }
119}
120
121#[derive(Debug, Clone, Copy)]
122pub struct AirConstraintEvaluation {
123 pub memory_layout: MemoryLayout,
124}
125
126impl AirConstraintEvaluation {
127 pub fn new_static(static_layout: StaticTasmConstraintEvaluationMemoryLayout) -> Self {
128 Self {
129 memory_layout: MemoryLayout::Static(static_layout),
130 }
131 }
132
133 pub fn new_dynamic(static_layout: DynamicTasmConstraintEvaluationMemoryLayout) -> Self {
134 Self {
135 memory_layout: MemoryLayout::Dynamic(static_layout),
136 }
137 }
138
139 pub fn with_conventional_static_memory_layout() -> Self {
140 Self {
141 memory_layout: MemoryLayout::conventional_static(),
142 }
143 }
144
145 pub fn with_conventional_dynamic_memory_layout() -> Self {
146 Self {
147 memory_layout: MemoryLayout::conventional_dynamic(),
148 }
149 }
150
151 pub fn output_type() -> DataType {
152 DataType::Array(Box::new(ArrayType {
153 element_type: DataType::Xfe,
154 length: MasterAuxTable::NUM_CONSTRAINTS,
155 }))
156 }
157
158 pub fn host_machine_air_constraint_evaluation(
160 input_values: AirConstraintSnippetInputs,
161 ) -> Vec<XFieldElement> {
162 let current_main_row = Array1::from(input_values.current_main_row);
163 let current_aux_row = Array1::from(input_values.current_aux_row);
164 let next_main_row = Array1::from(input_values.next_main_row);
165 let next_aux_row = Array1::from(input_values.next_aux_row);
166 let evaluated_initial_constraints = MasterAuxTable::evaluate_initial_constraints(
167 current_main_row.view(),
168 current_aux_row.view(),
169 &input_values.challenges,
170 );
171 let evaluated_consistency_constraints = MasterAuxTable::evaluate_consistency_constraints(
172 current_main_row.view(),
173 current_aux_row.view(),
174 &input_values.challenges,
175 );
176 let evaluated_transition_constraints = MasterAuxTable::evaluate_transition_constraints(
177 current_main_row.view(),
178 current_aux_row.view(),
179 next_main_row.view(),
180 next_aux_row.view(),
181 &input_values.challenges,
182 );
183 let evaluated_terminal_constraints = MasterAuxTable::evaluate_terminal_constraints(
184 current_main_row.view(),
185 current_aux_row.view(),
186 &input_values.challenges,
187 );
188
189 [
190 evaluated_initial_constraints,
191 evaluated_consistency_constraints,
192 evaluated_transition_constraints,
193 evaluated_terminal_constraints,
194 ]
195 .concat()
196 }
197}
198
199impl BasicSnippet for AirConstraintEvaluation {
200 fn inputs(&self) -> Vec<(DataType, String)> {
201 match self.memory_layout {
202 MemoryLayout::Dynamic(_) => vec![
203 (DataType::VoidPointer, "*curr_main_row".to_string()),
204 (DataType::VoidPointer, "*curr_extrow".to_string()),
205 (DataType::VoidPointer, "*next_main_row".to_string()),
206 (DataType::VoidPointer, "*next_aux_row".to_string()),
207 ],
208 MemoryLayout::Static(_) => vec![],
209 }
210 }
211
212 fn outputs(&self) -> Vec<(DataType, String)> {
213 vec![(Self::output_type(), "evaluated_constraints".to_owned())]
214 }
215
216 fn entrypoint(&self) -> String {
217 assert!(
218 self.memory_layout.is_integral(),
219 "Memory layout for input values for constraint evaluation must be integral"
220 );
221
222 "tasmlib_verifier_master_table_air_constraint_evaluation".to_owned()
224 }
225
226 fn code(&self, _library: &mut Library) -> Vec<LabelledInstruction> {
227 assert!(
228 self.memory_layout.is_integral(),
229 "Memory layout for input values for constraint evaluation must be integral"
230 );
231
232 let snippet_body = match self.memory_layout {
233 MemoryLayout::Dynamic(dynamic_layout) => {
234 dynamic_air_constraint_evaluation_tasm(dynamic_layout)
235 }
236 MemoryLayout::Static(static_layout) => {
237 static_air_constraint_evaluation_tasm(static_layout)
238 }
239 };
240
241 let entrypoint = self.entrypoint();
242 let mut code = triton_asm!(
243 {entrypoint}:
244 );
245 code.extend(snippet_body);
246 code.extend(triton_asm!(return));
247
248 code
249 }
250}
251
252#[cfg(test)]
256pub fn an_integral_but_profane_static_memory_layout() -> StaticTasmConstraintEvaluationMemoryLayout
257{
258 let mem_layout = StaticTasmConstraintEvaluationMemoryLayout {
259 free_mem_page_ptr: BFieldElement::new((u32::MAX as u64 - 200) * (1u64 << 32)),
260 curr_main_row_ptr: BFieldElement::new(1u64),
261 curr_aux_row_ptr: BFieldElement::new(1u64 << 20),
262 next_main_row_ptr: BFieldElement::new(1u64 << 21),
263 next_aux_row_ptr: BFieldElement::new(1u64 << 22),
264 challenges_ptr: BFieldElement::new(1u64 << 23),
265 };
266 assert!(mem_layout.is_integral());
267
268 mem_layout
269}
270
271#[cfg(test)]
272pub fn an_integral_but_profane_dynamic_memory_layout() -> DynamicTasmConstraintEvaluationMemoryLayout
273{
274 let mem_layout = DynamicTasmConstraintEvaluationMemoryLayout {
275 free_mem_page_ptr: BFieldElement::new((u32::MAX as u64 - 100) * (1u64 << 32)),
276 challenges_ptr: BFieldElement::new(1u64 << 30),
277 };
278 assert!(mem_layout.is_integral());
279
280 mem_layout
281}
282
283#[derive(Debug, Clone)]
284pub struct AirConstraintSnippetInputs {
285 pub current_main_row: Vec<XFieldElement>,
286 pub current_aux_row: Vec<XFieldElement>,
287 pub next_main_row: Vec<XFieldElement>,
288 pub next_aux_row: Vec<XFieldElement>,
289 pub challenges: Challenges,
290}
291
292#[cfg(test)]
293mod tests {
294 use arbitrary::Arbitrary;
295 use arbitrary::Unstructured;
296 use num_traits::ConstZero;
297 use rand::distr::StandardUniform;
298 use triton_vm::proof_stream::ProofStream;
299 use triton_vm::table::master_table::MasterMainTable;
300 use twenty_first::math::x_field_element::EXTENSION_DEGREE;
301
302 use super::*;
303 use crate::execute_test;
304 use crate::library::STATIC_MEMORY_LAST_ADDRESS;
305 use crate::rust_shadowing_helper_functions::array::array_get;
306 use crate::rust_shadowing_helper_functions::array::insert_as_array;
307 use crate::structure::tasm_object::decode_from_memory_with_size;
308 use crate::test_prelude::*;
309
310 #[test]
311 fn conventional_air_constraint_memory_layouts_are_integral() {
312 assert!(MemoryLayout::conventional_static().is_integral());
313 assert!(MemoryLayout::conventional_dynamic().is_integral());
314 }
315
316 #[test]
317 fn disallow_using_kmalloc_region() {
318 let mem_layout = MemoryLayout::Dynamic(DynamicTasmConstraintEvaluationMemoryLayout {
319 free_mem_page_ptr: STATIC_MEMORY_LAST_ADDRESS,
320 challenges_ptr: BFieldElement::new(1u64 << 30),
321 });
322 assert!(!mem_layout.is_integral());
323 }
324
325 #[test]
326 fn disallow_using_dynmalloc_region() {
327 let mem_layout = MemoryLayout::Dynamic(DynamicTasmConstraintEvaluationMemoryLayout {
328 free_mem_page_ptr: BFieldElement::new(42 * (1u64 << 32)),
329 challenges_ptr: BFieldElement::new(1u64 << 30),
330 });
331 assert!(!mem_layout.is_integral());
332 }
333
334 #[test]
335 fn disallow_using_dynmalloc_state() {
336 let mem_layout = MemoryLayout::Dynamic(DynamicTasmConstraintEvaluationMemoryLayout {
337 free_mem_page_ptr: BFieldElement::new(42 * (1u64 << 32)),
338 challenges_ptr: BFieldElement::new(BFieldElement::MAX),
339 });
340 assert!(!mem_layout.is_integral());
341 }
342
343 #[test]
344 fn disallow_overlapping_regions() {
345 let mut dyn_memory_layout = DynamicTasmConstraintEvaluationMemoryLayout {
346 free_mem_page_ptr: BFieldElement::new((u32::MAX as u64 - 100) * (1u64 << 32)),
347 challenges_ptr: conventional_challenges_pointer(),
348 };
349 assert!(MemoryLayout::Dynamic(dyn_memory_layout).is_integral());
350
351 dyn_memory_layout.challenges_ptr = dyn_memory_layout.free_mem_page_ptr;
352 assert!(!MemoryLayout::Dynamic(dyn_memory_layout).is_integral());
353 }
354
355 #[test]
356 fn conventional_memory_layout_agrees_with_tvm_proof_stored_at_address_zero() {
357 let program = triton_program!(halt);
358 let claim = Claim::about_program(&program);
359
360 let proof =
361 triton_vm::prove(Stark::default(), &claim, program, NonDeterminism::default()).unwrap();
362
363 const PROOF_ADDRESS: BFieldElement = BFieldElement::ZERO;
364 let mut memory = HashMap::<BFieldElement, BFieldElement>::new();
365 let proof_stream = ProofStream::try_from(&proof).unwrap();
366 encode_to_memory(&mut memory, PROOF_ADDRESS, &proof);
367
368 let assumed_memory_layout = MemoryLayout::conventional_static();
369 let MemoryLayout::Static(assumed_memory_layout) = assumed_memory_layout else {
370 panic!()
371 };
372 const MAIN_ROW_SIZE: usize = MasterMainTable::NUM_COLUMNS * EXTENSION_DEGREE;
373 const AUX_ROW_SIZE: usize = MasterAuxTable::NUM_COLUMNS * EXTENSION_DEGREE;
374
375 let assumed_curr_main_row: [XFieldElement; MasterMainTable::NUM_COLUMNS] =
376 *decode_from_memory_with_size(
377 &memory,
378 assumed_memory_layout.curr_main_row_ptr,
379 MAIN_ROW_SIZE,
380 )
381 .unwrap();
382 let actual_curr_main_row_from_proof = proof_stream.items[4]
383 .clone()
384 .try_into_out_of_domain_main_row()
385 .unwrap();
386 assert_eq!(*actual_curr_main_row_from_proof, assumed_curr_main_row);
387
388 let assumed_curr_aux_row: [XFieldElement; MasterAuxTable::NUM_COLUMNS] =
389 *decode_from_memory_with_size(
390 &memory,
391 assumed_memory_layout.curr_aux_row_ptr,
392 AUX_ROW_SIZE,
393 )
394 .unwrap();
395 let actual_curr_aux_row_from_proof = proof_stream.items[5]
396 .clone()
397 .try_into_out_of_domain_aux_row()
398 .unwrap();
399 assert_eq!(*actual_curr_aux_row_from_proof, assumed_curr_aux_row);
400
401 let assumed_next_main_row: [XFieldElement; MasterMainTable::NUM_COLUMNS] =
402 *decode_from_memory_with_size(
403 &memory,
404 assumed_memory_layout.next_main_row_ptr,
405 MAIN_ROW_SIZE,
406 )
407 .unwrap();
408 let actual_next_main_row_from_proof = proof_stream.items[6]
409 .clone()
410 .try_into_out_of_domain_main_row()
411 .unwrap();
412 assert_eq!(*actual_next_main_row_from_proof, assumed_next_main_row);
413
414 let assumed_next_aux_row: [XFieldElement; MasterAuxTable::NUM_COLUMNS] =
415 *decode_from_memory_with_size(
416 &memory,
417 assumed_memory_layout.next_aux_row_ptr,
418 AUX_ROW_SIZE,
419 )
420 .unwrap();
421 let actual_next_aux_row_from_proof = proof_stream.items[7]
422 .clone()
423 .try_into_out_of_domain_aux_row()
424 .unwrap();
425 assert_eq!(*actual_next_aux_row_from_proof, assumed_next_aux_row);
426 }
427
428 impl Function for AirConstraintEvaluation {
429 fn rust_shadow(
430 &self,
431 _: &mut Vec<BFieldElement>,
432 _: &mut HashMap<BFieldElement, BFieldElement>,
433 ) {
434 unimplemented!()
439 }
440
441 fn pseudorandom_initial_state(
442 &self,
443 seed: [u8; 32],
444 _: Option<BenchmarkCase>,
445 ) -> FunctionInitialState {
446 let mut rng = StdRng::from_seed(seed);
448 let input_values = Self::random_input_values(&mut rng);
449 let (memory, stack) = self.prepare_tvm_memory_and_stack(input_values);
450
451 FunctionInitialState { stack, memory }
452 }
453 }
454
455 #[test]
456 fn constraint_evaluation_test() {
457 let static_snippet = AirConstraintEvaluation {
458 memory_layout: MemoryLayout::Static(an_integral_but_profane_static_memory_layout()),
459 };
460
461 let dynamic_snippet = AirConstraintEvaluation {
462 memory_layout: MemoryLayout::Dynamic(an_integral_but_profane_dynamic_memory_layout()),
463 };
464
465 let mut seed: [u8; 32] = [0u8; 32];
466 rand::rng().fill_bytes(&mut seed);
467 static_snippet.test_equivalence_with_host_machine_evaluation(seed);
468
469 rand::rng().fill_bytes(&mut seed);
470 dynamic_snippet.test_equivalence_with_host_machine_evaluation(seed);
471 }
472
473 impl AirConstraintEvaluation {
474 fn test_equivalence_with_host_machine_evaluation(&self, seed: [u8; 32]) {
475 let mut rng = StdRng::from_seed(seed);
476 let input_values = Self::random_input_values(&mut rng);
477
478 let (tasm_result, _) = self.tasm_result(input_values.clone());
479 let host_machine_result = Self::host_machine_air_constraint_evaluation(input_values);
480
481 assert_eq!(tasm_result.len(), host_machine_result.len());
482 assert_eq!(
483 tasm_result.iter().copied().sum::<XFieldElement>(),
484 host_machine_result.iter().copied().sum::<XFieldElement>()
485 );
486 assert_eq!(tasm_result, host_machine_result);
487 }
488
489 pub(crate) fn random_input_values(rng: &mut StdRng) -> AirConstraintSnippetInputs {
490 let current_main_row: Vec<XFieldElement> = rng
491 .sample_iter(StandardUniform)
492 .take(MasterMainTable::NUM_COLUMNS)
493 .collect();
494 let current_aux_row: Vec<XFieldElement> = rng
495 .sample_iter(StandardUniform)
496 .take(MasterAuxTable::NUM_COLUMNS)
497 .collect();
498 let next_main_row: Vec<XFieldElement> = rng
499 .sample_iter(StandardUniform)
500 .take(MasterMainTable::NUM_COLUMNS)
501 .collect();
502 let next_aux_row: Vec<XFieldElement> = rng
503 .sample_iter(StandardUniform)
504 .take(MasterAuxTable::NUM_COLUMNS)
505 .collect();
506
507 let mut ch_seed = [0u8; 12000];
508 rng.fill_bytes(&mut ch_seed);
509 let mut unstructured = Unstructured::new(&ch_seed);
510 let challenges: Challenges = Challenges::arbitrary(&mut unstructured).unwrap();
511
512 AirConstraintSnippetInputs {
513 current_main_row,
514 current_aux_row,
515 next_main_row,
516 next_aux_row,
517 challenges,
518 }
519 }
520
521 pub(crate) fn prepare_tvm_memory_and_stack(
522 &self,
523 input_values: AirConstraintSnippetInputs,
524 ) -> (HashMap<BFieldElement, BFieldElement>, Vec<BFieldElement>) {
525 match self.memory_layout {
526 MemoryLayout::Static(static_layout) => {
527 let mut memory: HashMap<BFieldElement, BFieldElement> = HashMap::default();
528 insert_as_array(
529 static_layout.curr_main_row_ptr,
530 &mut memory,
531 input_values.current_main_row,
532 );
533 insert_as_array(
534 static_layout.curr_aux_row_ptr,
535 &mut memory,
536 input_values.current_aux_row,
537 );
538 insert_as_array(
539 static_layout.next_main_row_ptr,
540 &mut memory,
541 input_values.next_main_row,
542 );
543 insert_as_array(
544 static_layout.next_aux_row_ptr,
545 &mut memory,
546 input_values.next_aux_row,
547 );
548 insert_as_array(
549 static_layout.challenges_ptr,
550 &mut memory,
551 input_values.challenges.challenges.to_vec(),
552 );
553
554 (memory, self.init_stack_for_isolated_run())
555 }
556 MemoryLayout::Dynamic(dynamic_layout) => {
557 let mut memory: HashMap<BFieldElement, BFieldElement> = HashMap::default();
558 let curr_main_row_ptr = dynamic_layout.challenges_ptr + bfe!(10000);
559 let curr_aux_row_ptr = curr_main_row_ptr
560 + bfe!((input_values.current_main_row.len() * EXTENSION_DEGREE + 1) as u64);
561 let next_main_row_ptr = curr_aux_row_ptr
562 + bfe!((input_values.current_aux_row.len() * EXTENSION_DEGREE + 2) as u64);
563 let next_aux_row_ptr = next_main_row_ptr
564 + bfe!((input_values.next_main_row.len() * EXTENSION_DEGREE + 3) as u64);
565
566 insert_as_array(
567 curr_main_row_ptr,
568 &mut memory,
569 input_values.current_main_row,
570 );
571 insert_as_array(curr_aux_row_ptr, &mut memory, input_values.current_aux_row);
572 insert_as_array(next_main_row_ptr, &mut memory, input_values.next_main_row);
573 insert_as_array(next_aux_row_ptr, &mut memory, input_values.next_aux_row);
574 insert_as_array(
575 dynamic_layout.challenges_ptr,
576 &mut memory,
577 input_values.challenges.challenges.to_vec(),
578 );
579
580 let mut stack = self.init_stack_for_isolated_run();
581 stack.push(curr_main_row_ptr);
582 stack.push(curr_aux_row_ptr);
583 stack.push(next_main_row_ptr);
584 stack.push(next_aux_row_ptr);
585
586 (memory, stack)
587 }
588 }
589 }
590
591 pub(crate) fn read_result_from_memory(
595 mut final_state: VMState,
596 ) -> (Vec<XFieldElement>, BFieldElement) {
597 let result_pointer = final_state.op_stack.stack.pop().unwrap();
598 let mut tasm_result: Vec<XFieldElement> = vec![];
599 for i in 0..MasterAuxTable::NUM_CONSTRAINTS {
600 tasm_result.push(XFieldElement::new(
601 array_get(result_pointer, i, &final_state.ram, EXTENSION_DEGREE)
602 .try_into()
603 .unwrap(),
604 ));
605 }
606
607 (tasm_result, result_pointer)
608 }
609
610 pub(crate) fn tasm_result(
612 &self,
613 input_values: AirConstraintSnippetInputs,
614 ) -> (Vec<XFieldElement>, BFieldElement) {
615 let (init_memory, stack) = self.prepare_tvm_memory_and_stack(input_values);
616
617 let final_state = execute_test(
618 &self.link_for_isolated_run(),
619 &mut stack.clone(),
620 self.stack_diff(),
621 vec![],
622 NonDeterminism::default().with_ram(init_memory),
623 None,
624 );
625
626 Self::read_result_from_memory(final_state)
627 }
628 }
629}
630
631#[cfg(test)]
632mod bench {
633 use super::*;
634 use crate::test_prelude::*;
635
636 #[test]
637 fn bench_air_constraint_evaluation() {
638 ShadowedFunction::new(AirConstraintEvaluation {
639 memory_layout: MemoryLayout::Static(an_integral_but_profane_static_memory_layout()),
640 })
641 .bench();
642 }
643}