anemoi/ed_on_bls12_377/anemoi_4_3/
hasher.rs

1//! Sponge trait implementation for Anemoi
2
3#[cfg(not(feature = "std"))]
4use alloc::vec::Vec;
5
6use super::digest::AnemoiDigest;
7use super::{AnemoiEdOnBls12_377_4_3, Jive, Sponge};
8use super::{DIGEST_SIZE, NUM_COLUMNS, RATE_WIDTH, STATE_WIDTH};
9use crate::traits::Anemoi;
10use ark_ff::PrimeField;
11
12use super::Felt;
13use super::{One, Zero};
14
15impl Sponge<Felt> for AnemoiEdOnBls12_377_4_3 {
16    type Digest = AnemoiDigest;
17
18    fn hash(bytes: &[u8]) -> Self::Digest {
19        // Compute the number of field elements required to represent this
20        // sequence of bytes.
21        let num_elements = if bytes.len() % 31 == 0 {
22            bytes.len() / 31
23        } else {
24            bytes.len() / 31 + 1
25        };
26
27        let sigma = if num_elements % RATE_WIDTH == 0 {
28            Felt::one()
29        } else {
30            Felt::zero()
31        };
32
33        // Initialize the internal hash state to all zeroes.
34        let mut state = [Felt::zero(); STATE_WIDTH];
35
36        // Absorption phase
37
38        // Break the string into 31-byte chunks, then convert each chunk into a field element,
39        // and absorb the element into the rate portion of the state. The conversion is
40        // guaranteed to succeed as we spare one last byte to ensure this can represent a valid
41        // element encoding.
42        let mut i = 0;
43        let mut num_hashed = 0;
44        let mut buf = [0u8; 32];
45        for chunk in bytes.chunks(31) {
46            if num_hashed + i < num_elements - 1 {
47                buf[..31].copy_from_slice(chunk);
48            } else {
49                // The last chunk may be smaller than the others, which requires a special handling.
50                // In this case, we also append a byte set to 1 to the end of the string, padding the
51                // sequence in a way that adding additional trailing zeros will yield a different hash.
52                let chunk_len = chunk.len();
53                buf = [0u8; 32];
54                buf[..chunk_len].copy_from_slice(chunk);
55                // [Different to paper]: We pad the last chunk with 1 to prevent length extension attack.
56                if chunk_len < 31 {
57                    buf[chunk_len] = 1;
58                }
59            }
60
61            // Convert the bytes into a field element and absorb it into the rate portion of the
62            // state. An Anemoi permutation is applied to the internal state if all the the rate
63            // registers have been filled with additional values. We then reset the insertion index.
64            state[i] += Felt::from_le_bytes_mod_order(&buf[..]);
65            i += 1;
66            if i % RATE_WIDTH == 0 {
67                AnemoiEdOnBls12_377_4_3::permutation(&mut state);
68                i = 0;
69                num_hashed += RATE_WIDTH;
70            }
71        }
72
73        // We then add sigma to the last register of the capacity.
74        state[STATE_WIDTH - 1] += sigma;
75
76        // If the message length is not a multiple of RATE_WIDTH, we append 1 to the rate cell
77        // next to the one where we previously appended the last message element. This is
78        // guaranted to be in the rate registers (i.e. to not require an extra permutation before
79        // adding this constant) if sigma is equal to zero. We then apply a final Anemoi permutation
80        // to the whole state.
81        if sigma.is_zero() {
82            state[i] += Felt::one();
83            AnemoiEdOnBls12_377_4_3::permutation(&mut state);
84        }
85
86        // Squeezing phase
87
88        // Finally, return the first DIGEST_SIZE elements of the state.
89        Self::Digest::new(state[..DIGEST_SIZE].try_into().unwrap())
90    }
91
92    fn hash_field(elems: &[Felt]) -> Self::Digest {
93        // initialize state to all zeros
94        let mut state = [Felt::zero(); STATE_WIDTH];
95
96        let sigma = if elems.len() % RATE_WIDTH == 0 {
97            Felt::one()
98        } else {
99            Felt::zero()
100        };
101
102        let mut i = 0;
103        for &element in elems.iter() {
104            state[i] += element;
105            i += 1;
106            if i % RATE_WIDTH == 0 {
107                AnemoiEdOnBls12_377_4_3::permutation(&mut state);
108                i = 0;
109            }
110        }
111
112        // We then add sigma to the last register of the capacity.
113        state[STATE_WIDTH - 1] += sigma;
114
115        // If the message length is not a multiple of RATE_WIDTH, we append 1 to the rate cell
116        // next to the one where we previously appended the last message element. This is
117        // guaranted to be in the rate registers (i.e. to not require an extra permutation before
118        // adding this constant) if sigma is equal to zero. We then apply a final Anemoi permutation
119        // to the whole state.
120        if sigma.is_zero() {
121            state[i] += Felt::one();
122            AnemoiEdOnBls12_377_4_3::permutation(&mut state);
123        }
124
125        // Squeezing phase
126
127        Self::Digest::new(state[..DIGEST_SIZE].try_into().unwrap())
128    }
129
130    fn merge(digests: &[Self::Digest; 2]) -> Self::Digest {
131        // initialize state to all zeros
132        let mut state = [Felt::zero(); STATE_WIDTH];
133
134        // 2*DIGEST_SIZE < RATE_SIZE so we can safely store
135        // the digests into the rate registers at once
136        state[0..DIGEST_SIZE].copy_from_slice(digests[0].as_elements());
137        state[DIGEST_SIZE..2 * DIGEST_SIZE].copy_from_slice(digests[0].as_elements());
138
139        // Apply internal Anemoi permutation
140        AnemoiEdOnBls12_377_4_3::permutation(&mut state);
141
142        Self::Digest::new(state[..DIGEST_SIZE].try_into().unwrap())
143    }
144}
145
146impl Jive<Felt> for AnemoiEdOnBls12_377_4_3 {
147    fn compress(elems: &[Felt]) -> Vec<Felt> {
148        assert!(elems.len() == STATE_WIDTH);
149
150        let mut state = elems.to_vec();
151        AnemoiEdOnBls12_377_4_3::permutation(&mut state);
152
153        let mut result = [Felt::zero(); NUM_COLUMNS];
154        for (i, r) in result.iter_mut().enumerate() {
155            *r = elems[i] + elems[i + NUM_COLUMNS] + state[i] + state[i + NUM_COLUMNS];
156        }
157
158        result.to_vec()
159    }
160
161    fn compress_k(elems: &[Felt], k: usize) -> Vec<Felt> {
162        assert!(elems.len() == STATE_WIDTH);
163        assert!(STATE_WIDTH % k == 0);
164        assert!(k % 2 == 0);
165
166        let mut state = elems.to_vec();
167        AnemoiEdOnBls12_377_4_3::permutation(&mut state);
168
169        let mut result = vec![Felt::zero(); STATE_WIDTH / k];
170        let c = result.len();
171        for (i, r) in result.iter_mut().enumerate() {
172            for j in 0..k {
173                *r += elems[i + c * j] + state[i + c * j];
174            }
175        }
176
177        result
178    }
179}
180
181#[cfg(test)]
182mod tests {
183    #[cfg(not(feature = "std"))]
184    use alloc::vec;
185
186    use super::super::MontFp;
187    use super::*;
188    use ark_ff::BigInteger;
189
190    #[test]
191    fn test_anemoi_hash() {
192        // Generated from https://github.com/anemoi-hash/anemoi-hash/
193        let input_data = [
194            vec![Felt::zero(), Felt::zero(), Felt::zero(), Felt::zero()],
195            vec![Felt::one(), Felt::one(), Felt::one(), Felt::one()],
196            vec![Felt::zero(), Felt::zero(), Felt::one(), Felt::one()],
197            vec![Felt::one(), Felt::one(), Felt::zero(), Felt::zero()],
198            vec![MontFp!(
199                "3245888732545938703293848064370856564777841805765396792997613448749116772753"
200            )],
201            vec![
202                MontFp!(
203                    "7663394338249865628842769414268966392219678610153970312684440283159581613217"
204                ),
205                MontFp!(
206                    "6271904162410896908729341222426710964855145842094919193581967140936933284923"
207                ),
208            ],
209            vec![
210                MontFp!(
211                    "7969334835959175341708732577328788201615587299246107167659857871324493208835"
212                ),
213                MontFp!(
214                    "7493961423969253751307419581028383478098016292045659784917713206986998549296"
215                ),
216                MontFp!(
217                    "4026170068082212382064346783732235106988068470245368593324116477525361418264"
218                ),
219            ],
220            vec![
221                MontFp!(
222                    "2666117871319292549109278078687092690881141726197129135322956865265002280242"
223                ),
224                MontFp!(
225                    "6509697908608382218025477966055018129401065002540626665823304793770577635119"
226                ),
227                MontFp!(
228                    "1271169338579653709528628099295006826522129092665839774514071738347273016900"
229                ),
230                MontFp!(
231                    "6227043312022748939281805745739526186202679329496983601547709929059252900150"
232                ),
233            ],
234            vec![
235                MontFp!(
236                    "2909735215509804401941047549197284613681174544937466475970835246477891033436"
237                ),
238                MontFp!(
239                    "5599520051368633913843848108157638779058707144916128517158704913308108424747"
240                ),
241                MontFp!(
242                    "3432680043190079867020927346206445943703719322355884967763212834677264837833"
243                ),
244                MontFp!(
245                    "947456959501802677678449235943191631201751906080558756492421326409270025507"
246                ),
247                MontFp!(
248                    "770101993108319020437386465470482367547039566195436746871113992043063945007"
249                ),
250            ],
251            vec![
252                MontFp!(
253                    "2080443911568684752411149575349419122512153854110376483525925460103994871352"
254                ),
255                MontFp!(
256                    "6201195192392064815455731467660762987281772282324903591758021941563073326726"
257                ),
258                MontFp!(
259                    "5816509240437701961737463357848466910945009150646501054530732013884280407532"
260                ),
261                MontFp!(
262                    "364898586858423812020984816241377942240805600237616206986914820203073961940"
263                ),
264                MontFp!(
265                    "7545609520856506738146634501223899964449171533615289497205422583748185923883"
266                ),
267                MontFp!(
268                    "3267788309670351784476251074531266658544590980628771747836642182398089645088"
269                ),
270            ],
271        ];
272
273        let output_data = [
274            [MontFp!(
275                "2826852558969682283160965063399396013408991576304937928545694637519109987876"
276            )],
277            [MontFp!(
278                "715813639245542616319007380674059374635588794208688983677833596359619725647"
279            )],
280            [MontFp!(
281                "876091172931230864992957830321534820967228680519015826743030886193379751284"
282            )],
283            [MontFp!(
284                "7832641788849582971659980460374408607868841084869548467467350585852449552347"
285            )],
286            [MontFp!(
287                "1769025083902686531720248316128771525661472288104261222432854562461627706893"
288            )],
289            [MontFp!(
290                "3508965325475653084247845767237725060146495017552397552195176578350789058908"
291            )],
292            [MontFp!(
293                "1878818611437899959920600011342139010838536479547266920323586032506688840792"
294            )],
295            [MontFp!(
296                "7419422835010040190368651561187392128505524499673594534865952878287607357198"
297            )],
298            [MontFp!(
299                "3056644334375883027446266166030682099237729268530996862502216213378803940298"
300            )],
301            [MontFp!(
302                "618929239659418549046582686223990802620595245882301785085280228605376233832"
303            )],
304        ];
305
306        for (index, (input, expected)) in input_data.iter().zip(output_data).enumerate() {
307            println!("{:?}", index);
308            assert_eq!(
309                expected,
310                AnemoiEdOnBls12_377_4_3::hash_field(input).to_elements()
311            );
312        }
313    }
314
315    #[test]
316    fn test_anemoi_hash_bytes() {
317        // Generated from https://github.com/anemoi-hash/anemoi-hash/
318        let input_data = [
319            vec![Felt::zero(); 4],
320            vec![Felt::one(); 4],
321            vec![Felt::zero(), Felt::zero(), Felt::one(), Felt::one()],
322            vec![Felt::one(), Felt::one(), Felt::zero(), Felt::zero()],
323        ];
324
325        let output_data = [
326            [MontFp!(
327                "2826852558969682283160965063399396013408991576304937928545694637519109987876"
328            )],
329            [MontFp!(
330                "715813639245542616319007380674059374635588794208688983677833596359619725647"
331            )],
332            [MontFp!(
333                "876091172931230864992957830321534820967228680519015826743030886193379751284"
334            )],
335            [MontFp!(
336                "7832641788849582971659980460374408607868841084869548467467350585852449552347"
337            )],
338        ];
339
340        // The inputs can all be represented with at least 1 byte less than the field size,
341        // hence computing the Anemoi hash digest from the byte sequence yields the same
342        // result as treating the inputs as field elements.
343        for (input, expected) in input_data.iter().zip(output_data) {
344            let mut bytes = [0u8; 124];
345            bytes[0..31].copy_from_slice(&input[0].into_bigint().to_bytes_le()[0..31]);
346            bytes[31..62].copy_from_slice(&input[1].into_bigint().to_bytes_le()[0..31]);
347            bytes[62..93].copy_from_slice(&input[2].into_bigint().to_bytes_le()[0..31]);
348            bytes[93..124].copy_from_slice(&input[3].into_bigint().to_bytes_le()[0..31]);
349            assert_eq!(
350                expected,
351                AnemoiEdOnBls12_377_4_3::hash(&bytes).to_elements()
352            );
353        }
354    }
355
356    #[test]
357    fn test_anemoi_jive() {
358        // Generated from https://github.com/anemoi-hash/anemoi-hash/
359        let input_data = [
360            vec![Felt::zero(), Felt::zero(), Felt::zero(), Felt::zero()],
361            vec![Felt::one(), Felt::one(), Felt::one(), Felt::one()],
362            vec![Felt::zero(), Felt::zero(), Felt::one(), Felt::one()],
363            vec![Felt::one(), Felt::one(), Felt::zero(), Felt::zero()],
364        ];
365
366        let output_data = [
367            [
368                MontFp!(
369                    "4166825787354029787334922406033290250172572810107272783449272467370104361499"
370                ),
371                MontFp!(
372                    "443119219083466133166448152339477273242820198154691037927464243515191538965"
373                ),
374            ],
375            [
376                MontFp!(
377                    "546351612581094746909612373291868483487237596382940402109210862670055071860"
378                ),
379                MontFp!(
380                    "4683692898576499548827723194744461803813133049085680138685198838036731652343"
381                ),
382            ],
383            [
384                MontFp!(
385                    "3239548400000290705362327910139849710833184455393184789726734156259593056824"
386                ),
387                MontFp!(
388                    "429426852404684922799838349190498511339808948377701253268888394251603161550"
389                ),
390            ],
391            [
392                MontFp!(
393                    "2040858442524663883803034136807049307596283283862686075056479988745491268025"
394                ),
395                MontFp!(
396                    "8233028930313417211499327277472739989778672106814084714224282121099996419938"
397                ),
398            ],
399        ];
400
401        for (input, expected) in input_data.iter().zip(output_data) {
402            assert_eq!(expected.to_vec(), AnemoiEdOnBls12_377_4_3::compress(input));
403        }
404
405        for (input, expected) in input_data.iter().zip(output_data) {
406            assert_eq!(
407                expected.to_vec(),
408                AnemoiEdOnBls12_377_4_3::compress_k(input, 2)
409            );
410        }
411
412        let input_data = [
413            vec![Felt::zero(), Felt::zero(), Felt::zero(), Felt::zero()],
414            vec![Felt::one(), Felt::one(), Felt::one(), Felt::one()],
415            vec![Felt::zero(), Felt::zero(), Felt::one(), Felt::one()],
416            vec![Felt::one(), Felt::one(), Felt::zero(), Felt::zero()],
417        ];
418
419        let output_data = [
420            [MontFp!(
421                "4609945006437495920501370558372767523415393008261963821376736710885295900464"
422            )],
423            [MontFp!(
424                "5230044511157594295737335568036330287300370645468620540794409700706786724203"
425            )],
426            [MontFp!(
427                "3668975252404975628162166259330348222172993403770886042995622550511196218374"
428            )],
429            [MontFp!(
430                "1829425623409710671053536475498242765999056055522706961345528653928078448922"
431            )],
432        ];
433
434        for (input, expected) in input_data.iter().zip(output_data) {
435            assert_eq!(
436                expected.to_vec(),
437                AnemoiEdOnBls12_377_4_3::compress_k(input, 4)
438            );
439        }
440    }
441}