tasm_lib/hashing/sponge_hasher/
pad_and_absorb_all.rs1use 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 read_mem 1
31 addi {LIST_METADATA_SIZE + 1}
34 pick 1
37 call {hash_absorb_snippet_subroutine}
40 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}