tasm_lib/hashing/algebraic_hasher/
hash_static_size.rs1use triton_vm::prelude::*;
2
3use crate::hashing::absorb_multiple_static_size::AbsorbMultipleStaticSize;
4use crate::prelude::*;
5
6#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
7pub struct HashStaticSize {
8 pub size: usize,
9}
10
11impl BasicSnippet for HashStaticSize {
12 fn inputs(&self) -> Vec<(DataType, String)> {
13 vec![(DataType::VoidPointer, "*addr".to_owned())]
14 }
15
16 fn outputs(&self) -> Vec<(DataType, String)> {
17 vec![
18 (DataType::Digest, "digest".to_owned()),
19 (DataType::VoidPointer, "*addr + size".to_owned()),
20 ]
21 }
22
23 fn entrypoint(&self) -> String {
24 format!(
25 "tasmlib_hashing_algebraic_hasher_hash_static_size_{}",
26 self.size
27 )
28 }
29
30 fn code(&self, library: &mut crate::library::Library) -> Vec<LabelledInstruction> {
31 let entrypoint = self.entrypoint();
32 let absorb_subroutine =
33 library.import(Box::new(AbsorbMultipleStaticSize { size: self.size }));
34
35 triton_asm!(
36 {entrypoint}:
39 sponge_init
40 call {absorb_subroutine}
41 sponge_squeeze swap 6 pop 1
43 swap 6 pop 1
44 swap 6 pop 1
45 swap 6 pop 1
46 swap 6
47 swap 1 pop 1
48 return
50 )
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use twenty_first::prelude::*;
57
58 use super::*;
59 use crate::test_prelude::*;
60
61 #[test]
62 fn hash_static_size_small_pbt() {
63 for size in 0..20 {
64 println!("Testing size {size}");
65 ShadowedProcedure::new(HashStaticSize { size }).test();
66 }
67 }
68
69 #[proptest(cases = 50)]
70 fn hash_static_size_pbt_pbt(#[strategy(arb())] size: u8) {
71 ShadowedProcedure::new(HashStaticSize {
72 size: size as usize,
73 })
74 .test();
75 }
76
77 impl Procedure for HashStaticSize {
78 fn rust_shadow(
79 &self,
80 stack: &mut Vec<BFieldElement>,
81 memory: &mut HashMap<BFieldElement, BFieldElement>,
82 nondeterminism: &NonDeterminism,
83 public_input: &[BFieldElement],
84 sponge: &mut Option<Tip5>,
85 ) -> Vec<BFieldElement> {
86 *sponge = Some(Tip5::init());
87
88 let absorb_snippet = AbsorbMultipleStaticSize { size: self.size };
89 absorb_snippet.rust_shadow(stack, memory, nondeterminism, public_input, sponge);
90
91 let mut squeezed = sponge.as_mut().unwrap().squeeze();
93 squeezed.reverse();
94 stack.extend(squeezed);
95
96 let digest = pop_encodable::<Digest>(stack);
98
99 for _ in 0..Digest::LEN {
101 stack.pop().unwrap();
102 }
103
104 let input_pointer_plus_size = stack.pop().unwrap();
106
107 stack.extend(digest.reversed().values().to_vec());
109
110 stack.push(input_pointer_plus_size);
111
112 vec![]
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 memory_start: BFieldElement = rng.random();
124 let memory: HashMap<BFieldElement, BFieldElement> = (0..self.size)
125 .map(|i| (memory_start + BFieldElement::new(i as u64), rng.random()))
126 .collect();
127
128 let nondeterminism = NonDeterminism::default().with_ram(memory);
129 ProcedureInitialState {
130 stack: [self.init_stack_for_isolated_run(), vec![memory_start]].concat(),
131 nondeterminism,
132 public_input: vec![],
133 sponge: None,
134 }
135 }
136 }
137}
138
139#[cfg(test)]
140mod benches {
141 use super::*;
142 use crate::test_prelude::*;
143
144 #[test]
146 fn hash_var_lenstatic_size_benchmark_356() {
147 ShadowedProcedure::new(HashStaticSize { size: 356 }).bench();
148 }
149
150 #[test]
152 fn hash_var_lenstatic_size_benchmark_249() {
153 ShadowedProcedure::new(HashStaticSize { size: 249 }).bench();
154 }
155
156 #[test]
158 fn hash_var_lenstatic_size_benchmark_12() {
159 ShadowedProcedure::new(HashStaticSize { size: 12 }).bench();
160 }
161
162 #[test]
164 fn hash_var_lenstatic_size_benchmark_1000() {
165 ShadowedProcedure::new(HashStaticSize { size: 1000 }).bench();
166 }
167}