tasm_lib/traits/
accessor.rs

1use 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
16/// An Accessor can modify that stack but only read from memory
17///
18/// An Accessor is a piece of tasm code that can read from and write to the
19/// stack but can only read from memory. Note that it cannot write to static
20/// memory. It cannot read from any inputs or write to standard out. It cannot
21/// modify the sponge state.
22/// See also: [closure], [function], [procedure], [algorithm],
23///           [read_only_algorithm], [mem_preserver]
24///
25/// [closure]: crate::traits::closure::Closure
26/// [function]: crate::traits::function::Function
27/// [procedure]: crate::traits::procedure::Procedure
28/// [algorithm]: crate::traits::algorithm::Algorithm
29/// [read_only_algorithm]: crate::traits::read_only_algorithm::ReadOnlyAlgorithm
30/// [mem_preserver]: crate::traits::mem_preserver::MemPreserver
31pub 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}