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