anemoi/jubjub/anemoi_2_1/
hasher.rs1#[cfg(not(feature = "std"))]
4use alloc::vec::Vec;
5
6use super::digest::AnemoiDigest;
7use super::{AnemoiJubjub_2_1, Jive, Sponge};
8use super::{DIGEST_SIZE, STATE_WIDTH};
9use crate::traits::Anemoi;
10use ark_ff::PrimeField;
11
12use super::Felt;
13use super::{One, Zero};
14
15impl Sponge<Felt> for AnemoiJubjub_2_1 {
16 type Digest = AnemoiDigest;
17
18 fn hash(bytes: &[u8]) -> Self::Digest {
19 let num_elements = if bytes.len() % 31 == 0 {
22 bytes.len() / 31
23 } else {
24 bytes.len() / 31 + 1
25 };
26
27 let mut state = [Felt::zero(); STATE_WIDTH];
29
30 let mut buf = [0u8; 32];
37 for (i, chunk) in bytes.chunks(31).enumerate() {
38 if i < num_elements - 1 {
39 buf[0..31].copy_from_slice(chunk);
40 } else {
41 let chunk_len = chunk.len();
45 buf = [0u8; 32];
46 buf[..chunk_len].copy_from_slice(chunk);
47 if chunk_len < 31 {
49 buf[chunk_len] = 1;
50 }
51 }
52
53 state[0] += Felt::from_le_bytes_mod_order(&buf[..]);
57 AnemoiJubjub_2_1::permutation(&mut state);
58 }
59 state[STATE_WIDTH - 1] += Felt::one();
60
61 Self::Digest::new(state[..DIGEST_SIZE].try_into().unwrap())
65 }
66
67 fn hash_field(elems: &[Felt]) -> Self::Digest {
68 let mut state = [Felt::zero(); STATE_WIDTH];
70
71 for &element in elems.iter() {
74 state[0] += element;
75 AnemoiJubjub_2_1::permutation(&mut state);
76 }
77
78 state[STATE_WIDTH - 1] += Felt::one();
79
80 Self::Digest::new(state[..DIGEST_SIZE].try_into().unwrap())
84 }
85
86 fn merge(digests: &[Self::Digest; 2]) -> Self::Digest {
87 let result = Self::compress(&Self::Digest::digests_to_elements(digests));
90 Self::Digest::new(result.try_into().unwrap())
91 }
92}
93
94impl Jive<Felt> for AnemoiJubjub_2_1 {
95 fn compress(elems: &[Felt]) -> Vec<Felt> {
96 assert!(elems.len() == STATE_WIDTH);
97
98 let mut state = elems.to_vec();
99 AnemoiJubjub_2_1::permutation(&mut state);
100
101 vec![state[0] + state[1] + elems[0] + elems[1]]
102 }
103
104 fn compress_k(elems: &[Felt], k: usize) -> Vec<Felt> {
105 assert!(k == 2);
107
108 Self::compress(elems)
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 #[cfg(not(feature = "std"))]
115 use alloc::vec;
116
117 use crate::jubjub::anemoi_2_1::AnemoiJubjub_2_1;
118
119 use super::super::MontFp;
120 use super::*;
121 use ark_ff::BigInteger;
122
123 #[test]
124 fn test_anemoi_hash() {
125 let input_data = [
127 vec![Felt::zero(), Felt::zero()],
128 vec![Felt::one(), Felt::one()],
129 vec![Felt::zero(), Felt::one()],
130 vec![Felt::one(), Felt::zero()],
131 vec![MontFp!(
132 "48175395693019743604712010240401407295263760496918609320567887350900617391938"
133 )],
134 vec![
135 MontFp!(
136 "40454742959619504266124780247403051250769233161218450405944303623093451986416"
137 ),
138 MontFp!(
139 "8054087401217260540119647650149067888368265718118666773108585434053496512539"
140 ),
141 ],
142 vec![
143 MontFp!(
144 "8758999781725661589943067258778898714210579746607453110171065608650902955411"
145 ),
146 MontFp!(
147 "10178224565795089103313652432250635627412560984489920086835372540455062972043"
148 ),
149 MontFp!(
150 "29925420263172396940673207520643313079312157550992489658022590098553172519229"
151 ),
152 ],
153 vec![
154 MontFp!(
155 "43810900957132973642044031022126725744779901647233666513251283506650421253719"
156 ),
157 MontFp!(
158 "13869115914274770222885665907683059789190598851587796917340886888065950179345"
159 ),
160 MontFp!(
161 "19006550950025178457226798850946071923325417837656192809920080752737539580869"
162 ),
163 MontFp!(
164 "41347464737441972873801901743357452928767385147694625932616740287115542004184"
165 ),
166 ],
167 vec![
168 MontFp!(
169 "5641061656707918290766118699473598177131260713463794396205489094250322687059"
170 ),
171 MontFp!(
172 "1762472690591903627526805710995480828874871852953217753708762291919692776669"
173 ),
174 MontFp!(
175 "5442695738609165045860698972871486100783714976905853732598284193059726137484"
176 ),
177 MontFp!(
178 "44542361587146972628762599207869936445562095976920279660028208166325239459776"
179 ),
180 MontFp!(
181 "28063805515476868299441180197710909458474770498113403830730842276622910192214"
182 ),
183 ],
184 vec![
185 MontFp!(
186 "6222884466357505240696656069181876247031182115523656595681535984457165728442"
187 ),
188 MontFp!(
189 "24237625108810802359174427858350804364244467139304282092248149414791769682836"
190 ),
191 MontFp!(
192 "51505768400040663636491631745927718349620998271409928881692372400124132380182"
193 ),
194 MontFp!(
195 "25398536888248392215715464879479309238370329411183925527848925755051761566901"
196 ),
197 MontFp!(
198 "33121696194807230645952816752132160371820263776356020452728275724510567013833"
199 ),
200 MontFp!(
201 "35999566964686704391676648398286835098210554072067856490521627625893449004755"
202 ),
203 ],
204 ];
205
206 let output_data = [
207 [MontFp!(
208 "39323781703495850903956066402464124899786304471367493625790282776944096575660"
209 )],
210 [MontFp!(
211 "4131620966514322712691579100546835054530941596511233645050286061964502598858"
212 )],
213 [MontFp!(
214 "24324273559300271396953620022426323176594027249166939337399440665091996006791"
215 )],
216 [MontFp!(
217 "42563550557900905328235558676622670923086275020825201990506124497842894441847"
218 )],
219 [MontFp!(
220 "43692645056244253091360948912521218337025407173245382000695992868011997430113"
221 )],
222 [MontFp!(
223 "48407239277773721892614795191886499809904530052733784927807524012932608104752"
224 )],
225 [MontFp!(
226 "1548462962675086445132963037144064301548201331350500682572331921762552257306"
227 )],
228 [MontFp!(
229 "19147993751018144465472900079428523048134768970599243883920905859942964907126"
230 )],
231 [MontFp!(
232 "1031442954803170480786614934433496379556692105744131745792870583811175957592"
233 )],
234 [MontFp!(
235 "41953808051964802716386912235165103363529406491121216029102398049652344033204"
236 )],
237 ];
238
239 for (input, expected) in input_data.iter().zip(output_data) {
240 assert_eq!(expected, AnemoiJubjub_2_1::hash_field(input).to_elements());
241 }
242 }
243
244 #[test]
245 fn test_anemoi_hash_bytes() {
246 let input_data = [
248 vec![Felt::zero(), Felt::zero()],
249 vec![Felt::one(), Felt::one()],
250 vec![Felt::zero(), Felt::one()],
251 vec![Felt::one(), Felt::zero()],
252 ];
253
254 let output_data = [
255 [MontFp!(
256 "39323781703495850903956066402464124899786304471367493625790282776944096575660"
257 )],
258 [MontFp!(
259 "4131620966514322712691579100546835054530941596511233645050286061964502598858"
260 )],
261 [MontFp!(
262 "24324273559300271396953620022426323176594027249166939337399440665091996006791"
263 )],
264 [MontFp!(
265 "42563550557900905328235558676622670923086275020825201990506124497842894441847"
266 )],
267 ];
268
269 for (input, expected) in input_data.iter().zip(output_data) {
273 let mut bytes = [0u8; 62];
274 bytes[0..31].copy_from_slice(&input[0].into_bigint().to_bytes_le()[0..31]);
275 bytes[31..62].copy_from_slice(&input[1].into_bigint().to_bytes_le()[0..31]);
276
277 assert_eq!(expected, AnemoiJubjub_2_1::hash(&bytes).to_elements());
278 }
279 }
280
281 #[test]
282 fn test_anemoi_jive() {
283 let input_data = [
285 vec![Felt::zero(), Felt::zero()],
286 vec![Felt::one(), Felt::one()],
287 vec![Felt::zero(), Felt::one()],
288 vec![Felt::one(), Felt::zero()],
289 ];
290
291 let output_data = [
292 [MontFp!(
293 "20387392009611881691526522206552322482509551426930619434849280967122120965518"
294 )],
295 [MontFp!(
296 "44271465307610833975255894848424514129463332778307888463652844119174793376849"
297 )],
298 [MontFp!(
299 "48081255911378449855577187903249438549252129278233190684459831383162273301317"
300 )],
301 [MontFp!(
302 "20987090084610650936759092866102729962368129813397495848982616983114798496095"
303 )],
304 ];
305
306 for (input, expected) in input_data.iter().zip(output_data) {
307 assert_eq!(expected.to_vec(), AnemoiJubjub_2_1::compress(input));
308 }
309
310 for (input, expected) in input_data.iter().zip(output_data) {
311 assert_eq!(expected.to_vec(), AnemoiJubjub_2_1::compress_k(input, 2));
312 }
313
314 for (input, expected) in input_data.iter().zip(output_data) {
315 assert_eq!(
316 expected,
317 AnemoiJubjub_2_1::merge(&[
318 AnemoiDigest::new([input[0]]),
319 AnemoiDigest::new([input[1]])
320 ])
321 .to_elements()
322 );
323 }
324 }
325}