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 inputs(&self) -> Vec<(DataType, String)> {
11 vec![(DataType::List(Box::new(DataType::Bfe)), "input".to_string())]
12 }
13
14 fn outputs(&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 ) -> Vec<BFieldElement> {
82 let sponge = sponge.as_mut().expect("sponge must be initialized");
83 let input_pointer: BFieldElement = stack.pop().unwrap();
84 let first_word = input_pointer + BFieldElement::new(LIST_METADATA_SIZE as u64);
85 let input_length = memory[&input_pointer].value();
86 let input = (0..input_length)
87 .map(|i| memory[&(BFieldElement::new(i) + first_word)])
88 .collect_vec();
89 sponge.pad_and_absorb_all(&input);
90
91 Vec::default()
92 }
93
94 fn pseudorandom_initial_state(
95 &self,
96 seed: [u8; 32],
97 bench_case: Option<BenchmarkCase>,
98 ) -> ProcedureInitialState {
99 let mut rng = StdRng::from_seed(seed);
100 let mut bytes = [0u8; 400];
101 rng.fill_bytes(&mut bytes);
102 let mut unstructured = Unstructured::new(&bytes);
103 let input_length = match bench_case {
104 Some(BenchmarkCase::CommonCase) => 100,
105 Some(BenchmarkCase::WorstCase) => 10000,
106 None => rng.random_range(0..200),
107 };
108 let (memory, stack) = self.init_memory_and_stack(input_length);
109
110 ProcedureInitialState {
111 stack,
112 nondeterminism: NonDeterminism::default().with_ram(memory),
113 public_input: Vec::default(),
114 sponge: Some(Tip5::arbitrary(&mut unstructured).unwrap()),
115 }
116 }
117
118 fn corner_case_initial_states(&self) -> Vec<ProcedureInitialState> {
119 let empty_input_empty_sponge = {
120 let (memory, stack) = self.init_memory_and_stack(0);
121 ProcedureInitialState {
122 stack,
123 nondeterminism: NonDeterminism::default().with_ram(memory),
124 public_input: Vec::default(),
125 sponge: Some(Tip5::init()),
126 }
127 };
128 let empty_input_random_sponge = {
129 let (memory, stack) = self.init_memory_and_stack(0);
130 let mut rng = StdRng::from_seed([12u8; 32]);
131 let mut bytes = [0u8; 400];
132 rng.fill_bytes(&mut bytes);
133 let mut unstructured = Unstructured::new(&bytes);
134 ProcedureInitialState {
135 stack,
136 nondeterminism: NonDeterminism::default().with_ram(memory),
137 public_input: Vec::default(),
138 sponge: Some(Tip5::arbitrary(&mut unstructured).unwrap()),
139 }
140 };
141 let length_one_input_empty_sponge = {
142 let (memory, stack) = self.init_memory_and_stack(1);
143 ProcedureInitialState {
144 stack,
145 nondeterminism: NonDeterminism::default().with_ram(memory),
146 public_input: Vec::default(),
147 sponge: Some(Tip5::init()),
148 }
149 };
150 vec![
151 empty_input_empty_sponge,
152 empty_input_random_sponge,
153 length_one_input_empty_sponge,
154 ]
155 }
156 }
157
158 #[test]
159 fn pad_and_absorb_all_test() {
160 ShadowedProcedure::new(PadAndAbsorbAll).test();
161 }
162}