tasm_lib/hashing/
hash_from_stack.rs1use triton_vm::prelude::*;
2use twenty_first::prelude::*;
3
4use crate::prelude::*;
5
6#[derive(Debug, Clone, Eq, PartialEq, Hash)]
7pub struct HashFromStack {
8 ty: DataType,
9 ty_len: usize,
10}
11
12impl HashFromStack {
13 pub fn new(ty: DataType) -> Self {
18 let ty_len = ty
19 .static_length()
20 .expect("data type to hash should have static length");
21 assert!(ty_len < Tip5::RATE, "type length should be small");
22
23 Self { ty, ty_len }
24 }
25}
26
27impl BasicSnippet for HashFromStack {
28 fn inputs(&self) -> Vec<(DataType, String)> {
29 vec![(self.ty.clone(), "preimage".to_string())]
30 }
31 fn outputs(&self) -> Vec<(DataType, String)> {
32 vec![(DataType::Digest, "digest".to_string())]
33 }
34
35 fn entrypoint(&self) -> String {
36 format!(
37 "tasmlib_hashing_hash_from_stack___{}",
38 self.ty.label_friendly_name()
39 )
40 }
41
42 fn code(&self, _: &mut Library) -> Vec<LabelledInstruction> {
43 let pad_single_zero = triton_asm!(
44 push 0
45 place {self.ty_len}
46 );
47
48 let num_zeros_in_pad = Tip5::RATE - self.ty_len - 1;
49 let pad_zeros = vec![pad_single_zero; num_zeros_in_pad].concat();
50
51 let entrypoint = self.entrypoint();
52 triton_asm!(
53 {entrypoint}:
54
55 {&pad_zeros}
56 push 1
59 place {self.ty_len}
60 sponge_init
64 sponge_absorb
65 sponge_squeeze
66
67 pick 9
68 pick 9
69 pick 9
70 pick 9
71 pick 9
72 pop 5
73
74 return
75 )
76 }
77}
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82 use crate::test_prelude::*;
83
84 impl Closure for HashFromStack {
85 type Args = Vec<BFieldElement>;
86
87 fn rust_shadow(&self, stack: &mut Vec<BFieldElement>) {
88 let mut preimage = vec![];
89 for _ in 0..self.ty_len {
90 preimage.push(stack.pop().unwrap());
91 }
92
93 push_encodable(stack, &Tip5::hash_varlen(&preimage));
94 }
95
96 fn pseudorandom_args(&self, seed: [u8; 32], _: Option<BenchmarkCase>) -> Self::Args {
97 self.ty.seeded_random_element(&mut StdRng::from_seed(seed))
98 }
99
100 fn set_up_test_stack(&self, args: Self::Args) -> Vec<BFieldElement> {
101 let mut stack = self.init_stack_for_isolated_run();
102 stack.extend(args.into_iter().rev());
103
104 stack
105 }
106 }
107
108 #[test]
109 fn unit() {
110 let types = [
111 DataType::Bool,
112 DataType::U32,
113 DataType::U64,
114 DataType::U128,
115 DataType::Bfe,
116 DataType::Xfe,
117 DataType::Digest,
118 ];
119 for data_type in types {
120 ShadowedClosure::new(HashFromStack::new(data_type)).test();
121 }
122 }
123}
124
125#[cfg(test)]
126mod benches {
127 use super::*;
128 use crate::test_prelude::*;
129
130 #[test]
131 fn benchmark() {
132 let types = [DataType::Bfe, DataType::Digest];
133 for data_type in types {
134 ShadowedClosure::new(HashFromStack::new(data_type)).bench();
135 }
136 }
137}