tasm_lib/traits/
closure.rs1use rand::prelude::*;
2use triton_vm::prelude::*;
3
4use super::basic_snippet::BasicSnippet;
5use super::rust_shadow::RustShadow;
6use super::rust_shadow::RustShadowError;
7use crate::linker::execute_bench;
8use crate::prelude::Tip5;
9use crate::push_encodable;
10use crate::snippet_bencher::BenchmarkCase;
11use crate::snippet_bencher::NamedBenchmarkResult;
12use crate::snippet_bencher::write_benchmarks;
13use crate::test_helpers::test_rust_equivalence_given_complete_state;
14
15pub trait Closure: BasicSnippet {
28 type Args: BFieldCodec;
35
36 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) -> Result<(), RustShadowError>;
37
38 fn pseudorandom_args(&self, seed: [u8; 32], bench_case: Option<BenchmarkCase>) -> Self::Args;
41
42 fn corner_case_args(&self) -> Vec<Self::Args> {
43 Vec::new()
44 }
45
46 fn set_up_test_stack(&self, args: Self::Args) -> Vec<BFieldElement> {
47 let mut stack = self.init_stack_for_isolated_run();
48 push_encodable(&mut stack, &args);
49 stack
50 }
51}
52
53pub struct ShadowedClosure<C: Closure> {
54 closure: C,
55}
56
57impl<C: Closure> ShadowedClosure<C> {
58 pub fn new(closure: C) -> Self {
59 Self { closure }
60 }
61}
62
63impl<C: Closure> RustShadow for ShadowedClosure<C> {
64 fn inner(&self) -> &dyn BasicSnippet {
65 &self.closure
66 }
67
68 fn rust_shadow_wrapper(
69 &self,
70 _stdin: &[BFieldElement],
71 _nondeterminism: &NonDeterminism,
72 stack: &mut Vec<BFieldElement>,
73 _memory: &mut std::collections::HashMap<BFieldElement, BFieldElement>,
74 _sponge: &mut Option<Tip5>,
75 ) -> Result<Vec<BFieldElement>, RustShadowError> {
76 self.closure.rust_shadow(stack)?;
77
78 Ok(Vec::new())
79 }
80
81 fn test(&self) {
82 let num_states = 5;
83 let mut rng = rand::rng();
84
85 for args in self.closure.corner_case_args() {
87 test_rust_equivalence_given_complete_state(
88 self,
89 &self.closure.set_up_test_stack(args),
90 &[],
91 &NonDeterminism::default(),
92 &None,
93 None,
94 );
95 }
96
97 for _ in 0..num_states {
98 let seed: [u8; 32] = rng.random();
99 let args = self.closure.pseudorandom_args(seed, None);
100 let stack = self.closure.set_up_test_stack(args);
101
102 let stdin = vec![];
103 test_rust_equivalence_given_complete_state(
104 self,
105 &stack,
106 &stdin,
107 &NonDeterminism::default(),
108 &None,
109 None,
110 );
111 }
112 }
113
114 fn bench(&self) {
115 let mut rng = StdRng::from_seed(
116 hex::decode("73a24b6b8b32e4d7d563a4d9a85f476573a24b6b8b32e4d7d563a4d9a85f4765")
117 .unwrap()
118 .try_into()
119 .unwrap(),
120 );
121 let mut benchmarks = Vec::with_capacity(2);
122
123 for bench_case in [BenchmarkCase::CommonCase, BenchmarkCase::WorstCase] {
124 let args = self
125 .closure
126 .pseudorandom_args(rng.random(), Some(bench_case));
127 let stack = self.closure.set_up_test_stack(args);
128 let program = self.closure.link_for_isolated_run();
129 let benchmark =
130 execute_bench(&program, &stack, vec![], NonDeterminism::new(vec![]), None);
131 let benchmark = NamedBenchmarkResult {
132 name: self.closure.entrypoint(),
133 benchmark_result: benchmark,
134 case: bench_case,
135 };
136 benchmarks.push(benchmark);
137 }
138
139 write_benchmarks(benchmarks);
140 }
141}