tasm_lib/hashing/algebraic_hasher/
hash_varlen.rs1use std::collections::HashMap;
2
3use triton_vm::prelude::*;
4
5use crate::hashing::absorb_multiple::AbsorbMultiple;
6use crate::prelude::*;
7use crate::traits::basic_snippet::Reviewer;
8use crate::traits::basic_snippet::SignOffFingerprint;
9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
27pub struct HashVarlen;
28
29impl BasicSnippet for HashVarlen {
30 fn inputs(&self) -> Vec<(DataType, String)> {
31 vec![
32 (DataType::VoidPointer, "*addr".to_owned()),
33 (DataType::U32, "length".to_owned()),
34 ]
35 }
36
37 fn outputs(&self) -> Vec<(DataType, String)> {
38 vec![(DataType::Digest, "digest".to_owned())]
39 }
40
41 fn entrypoint(&self) -> String {
42 "tasmlib_hashing_algebraic_hasher_hash_varlen".to_owned()
43 }
44
45 fn code(&self, library: &mut Library) -> Vec<LabelledInstruction> {
46 let absorb_subroutine = library.import(Box::new(AbsorbMultiple));
47
48 triton_asm!(
49 {self.entrypoint()}:
52 sponge_init
53 call {absorb_subroutine}
54 sponge_squeeze pick 9
56 pick 9
57 pick 9
58 pick 9
59 pick 9
60 pop 5 return
62 )
63 }
64
65 fn sign_offs(&self) -> HashMap<Reviewer, SignOffFingerprint> {
66 let mut sign_offs = HashMap::new();
67 sign_offs.insert(Reviewer("ferdinand"), 0xc34a81b899f207ec.into());
68 sign_offs
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use std::collections::VecDeque;
75
76 use twenty_first::prelude::*;
77
78 use super::*;
79 use crate::empty_stack;
80 use crate::test_prelude::*;
81
82 impl MemPreserver for HashVarlen {
83 fn rust_shadow(
84 &self,
85 stack: &mut Vec<BFieldElement>,
86 memory: &HashMap<BFieldElement, BFieldElement>,
87 nd_tokens: VecDeque<BFieldElement>,
88 nd_digests: VecDeque<Digest>,
89 stdin: VecDeque<BFieldElement>,
90 sponge: &mut Option<Tip5>,
91 ) -> Vec<BFieldElement> {
92 *sponge = Some(Tip5::init());
93
94 AbsorbMultiple.rust_shadow(stack, memory, nd_tokens, nd_digests, stdin, sponge);
95 let [d0, d1, d2, d3, d4, ..] = sponge.as_mut().unwrap().squeeze();
96 push_encodable(stack, &Digest::new([d0, d1, d2, d3, d4]));
97
98 vec![]
99 }
100
101 fn pseudorandom_initial_state(
102 &self,
103 seed: [u8; 32],
104 bench_case: Option<BenchmarkCase>,
105 ) -> MemPreserverInitialState {
106 let mut rng = StdRng::from_seed(seed);
107 let length = match bench_case {
108 Some(BenchmarkCase::CommonCase) => 25,
109 Some(BenchmarkCase::WorstCase) => 1000,
110 None => rng.random_range(0..400),
111 };
112
113 let address = rng.random::<BFieldElement>();
114 let ram: HashMap<_, _> = (0..length)
115 .map(|i| (address + bfe!(i), rng.random()))
116 .collect();
117
118 MemPreserverInitialState {
119 stack: [empty_stack(), bfe_vec![address, length]].concat(),
120 nondeterminism: NonDeterminism::default().with_ram(ram),
121 ..MemPreserverInitialState::default()
122 }
123 }
124 }
125
126 #[test]
127 fn test() {
128 ShadowedMemPreserver::new(HashVarlen).test();
129 }
130}
131
132#[cfg(test)]
133mod benches {
134 use super::*;
135 use crate::test_prelude::*;
136
137 #[test]
138 fn benchmark() {
139 ShadowedMemPreserver::new(HashVarlen).bench();
140 }
141}