tasm_lib/verifier/vm_proof_iter/
drop.rs

1use triton_vm::prelude::*;
2
3use crate::prelude::*;
4use crate::verifier::vm_proof_iter::shared::vm_proof_iter_type;
5
6/// Signals the end of the lifetime of a VmProofIter
7///
8/// This snippet crashes the VM if the VmProofIter does not end up in a sane
9/// state after a verification.
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
11pub struct Drop;
12
13impl BasicSnippet for Drop {
14    fn inputs(&self) -> Vec<(DataType, String)> {
15        vec![(
16            DataType::StructRef(vm_proof_iter_type()),
17            "vm_proof_iter".to_owned(),
18        )]
19    }
20
21    fn outputs(&self) -> Vec<(DataType, String)> {
22        vec![]
23    }
24
25    fn entrypoint(&self) -> String {
26        "tasmlib_verifier_vm_proof_iter_drop".to_owned()
27    }
28
29    fn code(&self, _library: &mut Library) -> Vec<LabelledInstruction> {
30        let entrypoint = self.entrypoint();
31
32        triton_asm!(
33            {entrypoint}:
34                // _ *vm_proof_iter
35
36                /* Assert that item count matches indicated number of items */
37                addi 4
38                read_mem 5
39                pop 1
40
41                // _ current_item_count total_item_count proof_start_pointer proof_length current_item_pointer
42
43                place 2
44                // _ current_item_count total_item_count current_item_pointer proof_start_pointer proof_length
45
46                add
47                addi 1
48                eq
49                // _ current_item_count total_item_count (current_item_pointer == proof_start_pointer + proof_length + 1)
50
51                assert error_id 50
52                // _ current_item_count total_item_count
53
54                eq
55                assert error_id 60
56                // _
57
58                return
59        )
60    }
61}
62
63#[cfg(test)]
64mod tests {
65    use arbitrary::Arbitrary;
66    use arbitrary::Unstructured;
67    use triton_vm::proof_item::ProofItemVariant;
68    use triton_vm::proof_stream::ProofStream;
69
70    use super::*;
71    use crate::test_prelude::*;
72    use crate::verifier::vm_proof_iter::dequeue_next_as::DequeueNextAs;
73    use crate::verifier::vm_proof_iter::shared::vm_proof_iter_struct::VmProofIter;
74
75    #[test]
76    fn rust_shadow() {
77        ShadowedAccessor::new(Drop).test();
78    }
79
80    #[test]
81    fn negative_test_proof_len_mismatch() {
82        let proof_ptr = bfe!(450);
83        let proof_len = 10_000u32;
84        let correct_proof_end = proof_ptr + bfe!(proof_len);
85        let bad_proof_length = VmProofIter {
86            current_item_count: 12,
87            total_item_count: 12,
88            proof_start_pointer: proof_ptr,
89            proof_length: proof_len,
90            current_item_pointer: correct_proof_end + bfe!(4),
91        };
92
93        test_assertion_failure(
94            &ShadowedAccessor::new(Drop),
95            Drop.init_state(bad_proof_length).into(),
96            &[50],
97        );
98    }
99
100    #[test]
101    fn negative_test_proof_item_count_mismatch() {
102        let proof_ptr = bfe!(450);
103        let proof_len = 10_000u32;
104        let correct_proof_end = proof_ptr + bfe!(proof_len);
105        let bad_proof_length = VmProofIter {
106            current_item_count: 16,
107            total_item_count: 12,
108            proof_start_pointer: proof_ptr,
109            proof_length: proof_len,
110            current_item_pointer: correct_proof_end,
111        };
112
113        test_assertion_failure(
114            &ShadowedAccessor::new(Drop),
115            Drop.init_state(bad_proof_length).into(),
116            &[50],
117        );
118    }
119
120    impl Drop {
121        fn init_state(&self, vm_proof_iter: VmProofIter) -> AccessorInitialState {
122            let mut memory = HashMap::default();
123            let vm_iter_ptr = bfe!(1u64 << 32);
124            encode_to_memory(&mut memory, vm_iter_ptr, &vm_proof_iter);
125
126            let stack = [self.init_stack_for_isolated_run(), vec![vm_iter_ptr]].concat();
127            AccessorInitialState { stack, memory }
128        }
129    }
130
131    impl Accessor for Drop {
132        fn rust_shadow(
133            &self,
134            stack: &mut Vec<BFieldElement>,
135            memory: &HashMap<BFieldElement, BFieldElement>,
136        ) {
137            let vm_proof_iter_ptr = stack.pop().unwrap();
138            let vm_proof_iter =
139                *VmProofIter::decode_from_memory(memory, vm_proof_iter_ptr).unwrap();
140            assert_eq!(
141                vm_proof_iter.current_item_count,
142                vm_proof_iter.total_item_count
143            );
144
145            assert_eq!(
146                vm_proof_iter.proof_start_pointer + bfe!(vm_proof_iter.proof_length + 1),
147                vm_proof_iter.current_item_pointer,
148                "{} + {} and {} must match",
149                vm_proof_iter.proof_start_pointer,
150                vm_proof_iter.proof_length,
151                vm_proof_iter.current_item_pointer
152            );
153        }
154
155        fn pseudorandom_initial_state(
156            &self,
157            seed: [u8; 32],
158            bench_case: Option<BenchmarkCase>,
159        ) -> AccessorInitialState {
160            let mut rng = StdRng::from_seed(seed);
161
162            let fake_proof_stream = match bench_case {
163                Some(BenchmarkCase::CommonCase) => {
164                    let proof_item_variants = vec![ProofItemVariant::MerkleRoot; 20];
165                    DequeueNextAs::pseudorandom_proof_stream(proof_item_variants, seed)
166                }
167                Some(BenchmarkCase::WorstCase) => {
168                    let proof_item_variants = vec![ProofItemVariant::MerkleRoot; 40];
169                    DequeueNextAs::pseudorandom_proof_stream(proof_item_variants, seed)
170                }
171                None => {
172                    let bigger_seed: Vec<u8> = (0..1_000_000).map(|_| rng.random()).collect();
173                    let unstructured = Unstructured::new(bigger_seed.as_ref());
174                    ProofStream::arbitrary_take_rest(unstructured).unwrap()
175                }
176            };
177
178            let proof_ptr = bfe!(rng.random_range(0..20u32));
179            let fake_proof = fake_proof_stream.clone().into();
180
181            // Construct `VmProofIter` as we expect to see it after verifying proof
182            let mut vm_proof_iter = VmProofIter::new(proof_ptr, &fake_proof);
183            vm_proof_iter.current_item_count = fake_proof_stream.items.len().try_into().unwrap();
184            vm_proof_iter.current_item_pointer = proof_ptr + bfe!(fake_proof.0.len() as u64 + 2);
185
186            self.init_state(vm_proof_iter)
187        }
188    }
189}
190
191#[cfg(test)]
192mod benches {
193    use super::*;
194    use crate::test_prelude::*;
195
196    #[test]
197    fn benchmark() {
198        ShadowedAccessor::new(Drop).bench();
199    }
200}