tasm_lib/list/
set_length.rs

1use std::collections::HashMap;
2
3use triton_vm::prelude::*;
4
5use crate::prelude::*;
6use crate::traits::basic_snippet::Reviewer;
7use crate::traits::basic_snippet::SignOffFingerprint;
8
9/// Set the length of a [`BFieldCodec`]-encoded list in memory.
10///
11/// This snippet does not perform any checks. It is to be considered “unsafe”.
12///
13/// ### Behavior
14///
15/// ```text
16/// BEFORE: _ *list [list_length: u32]
17/// AFTER:  _ *list
18/// ```
19///
20/// ### Preconditions
21///
22/// - all input arguments are properly [`BFieldCodec`] encoded
23/// - the input argument `*list` is a pointer to a [`BFieldCodec`] encoded list
24///
25/// ### Postconditions
26///
27/// None.
28#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
29pub struct SetLength;
30
31impl BasicSnippet for SetLength {
32    fn inputs(&self) -> Vec<(DataType, String)> {
33        vec![
34            (DataType::VoidPointer, "*list".to_string()),
35            (DataType::U32, "list_length".to_string()),
36        ]
37    }
38
39    fn outputs(&self) -> Vec<(DataType, String)> {
40        vec![(DataType::VoidPointer, "*list".to_string())]
41    }
42
43    fn entrypoint(&self) -> String {
44        "tasmlib_list_set_length".to_string()
45    }
46
47    fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
48        triton_asm!(
49            // BEFORE: _ *list list_length
50            // AFTER:  _ *list
51            {self.entrypoint()}:
52                pick 1      // _ list_length *list
53                write_mem 1 // _ (*list + 1)
54                addi -1     // _ *list
55                return
56        )
57    }
58
59    fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
60        let mut sign_offs = HashMap::new();
61        sign_offs.insert(Reviewer("ferdinand"), 0x8306d6fa39eba00a.into());
62        sign_offs
63    }
64}
65
66#[cfg(test)]
67pub(crate) mod tests {
68    use super::*;
69    use crate::U32_TO_USIZE_ERR;
70    use crate::empty_stack;
71    use crate::rust_shadowing_helper_functions::list::list_set_length;
72    use crate::test_prelude::*;
73
74    impl Function for SetLength {
75        fn rust_shadow(
76            &self,
77            stack: &mut Vec<BFieldElement>,
78            memory: &mut HashMap<BFieldElement, BFieldElement>,
79        ) {
80            let new_length = pop_encodable::<u32>(stack);
81            let list_address = stack.pop().unwrap();
82            stack.push(list_address);
83
84            let new_length = new_length.try_into().expect(U32_TO_USIZE_ERR);
85            list_set_length(list_address, new_length, memory);
86        }
87
88        fn pseudorandom_initial_state(
89            &self,
90            seed: [u8; 32],
91            _: Option<BenchmarkCase>,
92        ) -> FunctionInitialState {
93            let mut rng = StdRng::from_seed(seed);
94
95            let mut stack = empty_stack();
96            stack.push(rng.random());
97            stack.push(bfe!(rng.next_u32()));
98
99            FunctionInitialState {
100                stack,
101                ..Default::default()
102            }
103        }
104    }
105
106    #[test]
107    fn rust_shadow() {
108        ShadowedFunction::new(SetLength).test();
109    }
110}
111
112#[cfg(test)]
113mod benches {
114    use super::*;
115    use crate::test_prelude::*;
116
117    #[test]
118    fn benchmark() {
119        ShadowedFunction::new(SetLength).bench();
120    }
121}