tasm_lib/hashing/sponge_hasher/
absorb.rs1use triton_vm::prelude::*;
2use twenty_first::tip5::RATE;
3
4use crate::data_type::ArrayType;
5use crate::prelude::*;
6
7#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
8pub struct Absorb;
9
10impl BasicSnippet for Absorb {
11 fn inputs(&self) -> Vec<(DataType, String)> {
12 vec![(
13 DataType::Array(Box::new(ArrayType {
14 element_type: DataType::Bfe,
15 length: RATE,
16 })),
17 "input".to_owned(),
18 )]
19 }
20
21 fn outputs(&self) -> Vec<(DataType, String)> {
22 vec![]
23 }
24
25 fn entrypoint(&self) -> String {
26 "tasmlib_hashing_sponge_hasher_absorb".to_string()
27 }
28
29 fn code(&self, _library: &mut Library) -> Vec<LabelledInstruction> {
30 assert_eq!(10, RATE, "Code assumes RATE is 10");
31
32 triton_asm!(
33 {self.entrypoint()}:
34 push 0
37 push 0
38 push 0
39 push 0
40 pick 4
41 sponge_absorb_mem
44 pop 5
47 return
50 )
51
52 }
73}
74
75#[cfg(test)]
76mod tests {
77 use arbitrary::Arbitrary;
78 use arbitrary::Unstructured;
79 use twenty_first::math::other::random_elements;
80 use twenty_first::prelude::Sponge;
81
82 use super::*;
83 use crate::empty_stack;
84 use crate::test_prelude::*;
85
86 fn init_memory_and_stack() -> (HashMap<BFieldElement, BFieldElement>, Vec<BFieldElement>) {
87 let array_pointer: BFieldElement = rand::random();
88 let init_stack = [empty_stack(), vec![array_pointer]].concat();
89 let init_memory: HashMap<BFieldElement, BFieldElement> = (0..RATE)
90 .map(|i| array_pointer + BFieldElement::new(i as u64))
91 .zip(random_elements(RATE))
92 .collect();
93
94 (init_memory, init_stack)
95 }
96
97 impl Procedure for Absorb {
98 fn rust_shadow(
99 &self,
100 stack: &mut Vec<BFieldElement>,
101 memory: &mut HashMap<BFieldElement, BFieldElement>,
102 _nondeterminism: &NonDeterminism,
103 _public_input: &[BFieldElement],
104 sponge: &mut Option<Tip5>,
105 ) -> Vec<BFieldElement> {
106 let sponge = sponge.as_mut().expect("sponge must be initialized");
107 let input_pointer: BFieldElement = stack.pop().unwrap();
108 let input: [BFieldElement; 10] = (0..10)
109 .map(|i| memory[&(BFieldElement::new(i) + input_pointer)])
110 .collect_vec()
111 .try_into()
112 .unwrap();
113 sponge.absorb(input);
114 Vec::default()
115 }
116
117 fn pseudorandom_initial_state(
118 &self,
119 seed: [u8; 32],
120 _bench_case: Option<BenchmarkCase>,
121 ) -> ProcedureInitialState {
122 let mut rng = StdRng::from_seed(seed);
123 let mut bytes = [0u8; 400];
124 rng.fill_bytes(&mut bytes);
125 let mut unstructured = Unstructured::new(&bytes);
126 let (memory, stack) = init_memory_and_stack();
127
128 ProcedureInitialState {
129 stack,
130 nondeterminism: NonDeterminism::default().with_ram(memory),
131 public_input: Vec::default(),
132 sponge: Some(Tip5::arbitrary(&mut unstructured).unwrap()),
133 }
134 }
135
136 fn corner_case_initial_states(&self) -> Vec<ProcedureInitialState> {
137 let empty_sponge = {
138 let (memory, stack) = init_memory_and_stack();
139 ProcedureInitialState {
140 stack,
141 nondeterminism: NonDeterminism::default().with_ram(memory),
142 public_input: Vec::default(),
143 sponge: Some(Tip5::init()),
144 }
145 };
146
147 vec![empty_sponge]
148 }
149 }
150
151 #[test]
152 fn absorb_test() {
153 ShadowedProcedure::new(Absorb).test();
154 }
155}
156
157#[cfg(test)]
158mod benches {
159 use super::*;
160 use crate::test_prelude::*;
161
162 #[test]
163 fn benchmark() {
164 ShadowedProcedure::new(Absorb).bench();
165 }
166}