Skip to main content

tasm_lib/hashing/sponge_hasher/
pad_and_absorb_all.rs

1use triton_vm::prelude::*;
2
3use crate::list::LIST_METADATA_SIZE;
4use crate::prelude::*;
5
6#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
7pub struct PadAndAbsorbAll;
8
9impl BasicSnippet for PadAndAbsorbAll {
10    fn parameters(&self) -> Vec<(DataType, String)> {
11        vec![(DataType::List(Box::new(DataType::Bfe)), "input".to_string())]
12    }
13
14    fn return_values(&self) -> Vec<(DataType, String)> {
15        vec![]
16    }
17
18    fn entrypoint(&self) -> String {
19        "tasmlib_hashing_sponge_hasher_pad_and_absorb_all".into()
20    }
21
22    fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
23        let entrypoint = self.entrypoint();
24        let hash_absorb_snippet_subroutine =
25            library.import(Box::new(crate::hashing::absorb_multiple::AbsorbMultiple));
26        triton_asm!(
27            {entrypoint}:
28                // _ *input_list
29
30                read_mem 1
31                // _ length (*input_list - 1)
32
33                addi {LIST_METADATA_SIZE + 1}
34                // _ length *first_element
35
36                pick 1
37                // _ *first_element length
38
39                call {hash_absorb_snippet_subroutine}
40                // _
41
42                return
43        )
44    }
45}
46
47#[cfg(test)]
48mod tests {
49    use arbitrary::Arbitrary;
50    use arbitrary::Unstructured;
51    use triton_vm::prelude::*;
52    use twenty_first::prelude::Sponge;
53
54    use super::*;
55    use crate::empty_stack;
56    use crate::rust_shadowing_helper_functions::list::insert_random_list;
57    use crate::test_prelude::*;
58
59    impl PadAndAbsorbAll {
60        fn init_memory_and_stack(
61            &self,
62            input_length: usize,
63        ) -> (HashMap<BFieldElement, BFieldElement>, Vec<BFieldElement>) {
64            let list_pointer: BFieldElement = rand::random();
65            let init_stack = [empty_stack(), vec![list_pointer]].concat();
66            let mut init_memory = HashMap::default();
67            insert_random_list(&DataType::Bfe, list_pointer, input_length, &mut init_memory);
68
69            (init_memory, init_stack)
70        }
71    }
72
73    impl Procedure for PadAndAbsorbAll {
74        fn rust_shadow(
75            &self,
76            stack: &mut Vec<BFieldElement>,
77            memory: &mut HashMap<BFieldElement, BFieldElement>,
78            _nondeterminism: &NonDeterminism,
79            _public_input: &[BFieldElement],
80            sponge: &mut Option<Tip5>,
81        ) -> Result<Vec<BFieldElement>, RustShadowError> {
82            let Some(sponge) = sponge.as_mut() else {
83                return Err(RustShadowError::SpongeUninitialized);
84            };
85            let input_pointer: BFieldElement =
86                stack.pop().ok_or(RustShadowError::StackUnderflow)?;
87            let first_word = input_pointer + BFieldElement::new(LIST_METADATA_SIZE as u64);
88            let input_length = memory[&input_pointer].value();
89            let input = (0..input_length)
90                .map(|i| memory[&(BFieldElement::new(i) + first_word)])
91                .collect_vec();
92            sponge.pad_and_absorb_all(&input);
93
94            Ok(Vec::new())
95        }
96
97        fn pseudorandom_initial_state(
98            &self,
99            seed: [u8; 32],
100            bench_case: Option<BenchmarkCase>,
101        ) -> ProcedureInitialState {
102            let mut rng = StdRng::from_seed(seed);
103            let mut bytes = [0u8; 400];
104            rng.fill_bytes(&mut bytes);
105            let mut unstructured = Unstructured::new(&bytes);
106            let input_length = match bench_case {
107                Some(BenchmarkCase::CommonCase) => 100,
108                Some(BenchmarkCase::WorstCase) => 10000,
109                None => rng.random_range(0..200),
110            };
111            let (memory, stack) = self.init_memory_and_stack(input_length);
112
113            ProcedureInitialState {
114                stack,
115                nondeterminism: NonDeterminism::default().with_ram(memory),
116                public_input: Vec::default(),
117                sponge: Some(Tip5::arbitrary(&mut unstructured).unwrap()),
118            }
119        }
120
121        fn corner_case_initial_states(&self) -> Vec<ProcedureInitialState> {
122            let empty_input_empty_sponge = {
123                let (memory, stack) = self.init_memory_and_stack(0);
124                ProcedureInitialState {
125                    stack,
126                    nondeterminism: NonDeterminism::default().with_ram(memory),
127                    public_input: Vec::default(),
128                    sponge: Some(Tip5::init()),
129                }
130            };
131            let empty_input_random_sponge = {
132                let (memory, stack) = self.init_memory_and_stack(0);
133                let mut rng = StdRng::from_seed([12u8; 32]);
134                let mut bytes = [0u8; 400];
135                rng.fill_bytes(&mut bytes);
136                let mut unstructured = Unstructured::new(&bytes);
137                ProcedureInitialState {
138                    stack,
139                    nondeterminism: NonDeterminism::default().with_ram(memory),
140                    public_input: Vec::default(),
141                    sponge: Some(Tip5::arbitrary(&mut unstructured).unwrap()),
142                }
143            };
144            let length_one_input_empty_sponge = {
145                let (memory, stack) = self.init_memory_and_stack(1);
146                ProcedureInitialState {
147                    stack,
148                    nondeterminism: NonDeterminism::default().with_ram(memory),
149                    public_input: Vec::default(),
150                    sponge: Some(Tip5::init()),
151                }
152            };
153            vec![
154                empty_input_empty_sponge,
155                empty_input_random_sponge,
156                length_one_input_empty_sponge,
157            ]
158        }
159    }
160
161    #[macro_rules_attr::apply(test)]
162    fn pad_and_absorb_all_test() {
163        ShadowedProcedure::new(PadAndAbsorbAll).test();
164    }
165}