winter_crypto/hash/rescue/rp62_248/
mod.rs

1// Copyright (c) Facebook, Inc. and its affiliates.
2//
3// This source code is licensed under the MIT license found in the
4// LICENSE file in the root directory of this source tree.
5
6use math::{fields::f62::BaseElement, FieldElement, StarkField};
7
8use super::{exp_acc, Digest, ElementHasher, Hasher};
9
10mod digest;
11pub use digest::ElementDigest;
12
13#[cfg(test)]
14mod tests;
15
16// CONSTANTS
17// ================================================================================================
18
19/// Sponge state is set to 12 field elements or 93 bytes; 8 elements are reserved for rate and
20/// the remaining 4 elements are reserved for capacity.
21const STATE_WIDTH: usize = 12;
22const RATE_WIDTH: usize = 8;
23
24/// The output of the hash function is a digest which consists of 4 field elements or 31 bytes.
25const DIGEST_SIZE: usize = 4;
26
27/// The number of rounds is set to 7 to target 124-bit security level with 40% security margin;
28/// computed using algorithm 7 from <https://eprint.iacr.org/2020/1143.pdf>
29const NUM_ROUNDS: usize = 7;
30
31/// S-Box and Inverse S-Box powers;
32/// computed using algorithm 6 from <https://eprint.iacr.org/2020/1143.pdf>
33///
34/// The constants are defined for tests only because the exponentiations in the code are unrolled
35/// for efficiency reasons.
36#[cfg(test)]
37const ALPHA: u32 = 3;
38#[cfg(test)]
39const INV_ALPHA: u64 = 3074416663688030891;
40
41// HASHER IMPLEMENTATION
42// ================================================================================================
43
44/// Implementation of [Hasher] trait for Rescue Prime hash function with 248-bit output.
45///
46/// The hash function is implemented according to the Rescue Prime
47/// [specifications](https://eprint.iacr.org/2020/1143.pdf) with the following exception:
48/// * We set the number of rounds to 7, which implies a 40% security margin instead of the 50%
49///   margin used in the specifications (a 50% margin rounds up to 8 rounds). The primary motivation
50///   for this is that having the number of rounds be one less than a power of two simplifies AIR
51///   design for computations involving the hash function.
52/// * When hashing a sequence of elements, we do not append Fp(1) followed by Fp(0) elements to the
53///   end of the sequence as padding. Instead, we initialize one of the capacity elements to the
54///   number of elements to be hashed, and pad the sequence with Fp(0) elements only. This ensures
55///   consistency of hash outputs between different hashing methods (see section below). However, it
56///   also means that our instantiation of Rescue Prime cannot be used in a stream mode as the
57///   number of elements to be hashed must be known upfront.
58///
59/// The parameters used to instantiate the function are:
60/// * Field: 62-bit prime field with modulus 2^62 - 111 * 2^39 + 1.
61/// * State width: 12 field elements.
62/// * Capacity size: 4 field elements.
63/// * Number of rounds: 7.
64/// * S-Box degree: 3.
65///
66/// The above parameters target 124-bit security level. The digest consists of four field elements
67/// and it can be serialized into 31 bytes (248 bits).
68///
69/// ## Hash output consistency
70/// Functions [hash_elements()](Rp62_248::hash_elements), [merge()](Rp62_248::merge), and
71/// [merge_with_int()](Rp62_248::merge_with_int) are internally consistent. That is, computing
72/// a hash for the same set of elements using these functions will always produce the same
73/// result. For example, merging two digests using [merge()](Rp62_248::merge) will produce the
74/// same result as hashing 8 elements which make up these digests using
75/// [hash_elements()](Rp62_248::hash_elements) function.
76///
77/// However, [hash()](Rp62_248::hash) function is not consistent with functions mentioned above.
78/// For example, if we take two field elements, serialize them to bytes and hash them using
79/// [hash()](Rp62_248::hash), the result will differ from the result obtained by hashing these
80/// elements directly using [hash_elements()](Rp62_248::hash_elements) function. The reason for
81/// this difference is that [hash()](Rp62_248::hash) function needs to be able to handle
82/// arbitrary binary strings, which may or may not encode valid field elements - and thus,
83/// deserialization procedure used by this function is different from the procedure used to
84/// deserialize valid field elements.
85///
86/// Thus, if the underlying data consists of valid field elements, it might make more sense
87/// to deserialize them into field elements and then hash them using
88/// [hash_elements()](Rp62_248::hash_elements) function rather then hashing the serialized bytes
89/// using [hash()](Rp62_248::hash) function.
90pub struct Rp62_248();
91
92impl Hasher for Rp62_248 {
93    type Digest = ElementDigest;
94
95    const COLLISION_RESISTANCE: u32 = 124;
96
97    fn hash(bytes: &[u8]) -> Self::Digest {
98        // compute the number of elements required to represent the string; we will be processing
99        // the string in 7-byte chunks, thus the number of elements will be equal to the number
100        // of such chunks (including a potential partial chunk at the end).
101        let num_elements = if bytes.len() % 7 == 0 {
102            bytes.len() / 7
103        } else {
104            bytes.len() / 7 + 1
105        };
106
107        // initialize state to all zeros, except for the last element of the capacity part, which
108        // is set to the number of elements to be hashed. this is done so that adding zero elements
109        // at the end of the list always results in a different hash.
110        let mut state = [BaseElement::ZERO; STATE_WIDTH];
111        state[STATE_WIDTH - 1] = BaseElement::new(num_elements as u64);
112
113        // break the string into 7-byte chunks, convert each chunk into a field element, and
114        // absorb the element into the rate portion of the state. we use 7-byte chunks because
115        // every 7-byte chunk is guaranteed to map to some field element.
116        let mut i = 0;
117        let mut buf = [0_u8; 8];
118        for chunk in bytes.chunks(7) {
119            if i < num_elements - 1 {
120                buf[..7].copy_from_slice(chunk);
121            } else {
122                // if we are dealing with the last chunk, it may be smaller than 7 bytes long, so
123                // we need to handle it slightly differently. we also append a byte with value 1
124                // to the end of the string; this pads the string in such a way that adding
125                // trailing zeros results in different hash
126                let chunk_len = chunk.len();
127                buf = [0_u8; 8];
128                buf[..chunk_len].copy_from_slice(chunk);
129                buf[chunk_len] = 1;
130            }
131
132            // convert the bytes into a field element and absorb it into the rate portion of the
133            // state; if the rate is filled up, apply the Rescue permutation and start absorbing
134            // again from zero index.
135            state[i] += BaseElement::new(u64::from_le_bytes(buf));
136            i += 1;
137            if i % RATE_WIDTH == 0 {
138                apply_permutation(&mut state);
139                i = 0;
140            }
141        }
142
143        // if we absorbed some elements but didn't apply a permutation to them (would happen when
144        // the number of elements is not a multiple of RATE_WIDTH), apply the Rescue permutation.
145        // we don't need to apply any extra padding because we injected total number of elements
146        // in the input list into the capacity portion of the state during initialization.
147        if i > 0 {
148            apply_permutation(&mut state);
149        }
150
151        // return the first 4 elements of the state as hash result
152        ElementDigest::new(state[..DIGEST_SIZE].try_into().unwrap())
153    }
154
155    fn merge(values: &[Self::Digest; 2]) -> Self::Digest {
156        // initialize the state by copying the digest elements into the rate portion of the state
157        // (8 total elements), and set the last capacity element to 8 (the number of elements to
158        // be hashed).
159        let mut state = [BaseElement::ZERO; STATE_WIDTH];
160        state[..RATE_WIDTH].copy_from_slice(Self::Digest::digests_as_elements(values));
161        state[STATE_WIDTH - 1] = BaseElement::new(RATE_WIDTH as u64);
162
163        // apply the Rescue permutation and return the first four elements of the state
164        apply_permutation(&mut state);
165        ElementDigest::new(state[..DIGEST_SIZE].try_into().unwrap())
166    }
167
168    fn merge_many(values: &[Self::Digest]) -> Self::Digest {
169        Self::hash_elements(ElementDigest::digests_as_elements(values))
170    }
171
172    fn merge_with_int(seed: Self::Digest, value: u64) -> Self::Digest {
173        // initialize the state as follows:
174        // - seed is copied into the first 4 elements of the state.
175        // - if the value fits into a single field element, copy it into the fifth state element and
176        //   set the last capacity element to 5 (the number of elements to be hashed).
177        // - if the value doesn't fit into a single field element, split it into two field elements,
178        //   copy them into state elements 5 and 6, and set the last capacity element to 6.
179        let mut state = [BaseElement::ZERO; STATE_WIDTH];
180        state[..DIGEST_SIZE].copy_from_slice(seed.as_elements());
181        state[DIGEST_SIZE] = BaseElement::new(value);
182        if value < BaseElement::MODULUS {
183            state[STATE_WIDTH - 1] = BaseElement::new(DIGEST_SIZE as u64 + 1);
184        } else {
185            state[DIGEST_SIZE + 1] = BaseElement::new(value / BaseElement::MODULUS);
186            state[STATE_WIDTH - 1] = BaseElement::new(DIGEST_SIZE as u64 + 2);
187        }
188
189        // apply the Rescue permutation and return the first four elements of the state
190        apply_permutation(&mut state);
191        ElementDigest::new(state[..DIGEST_SIZE].try_into().unwrap())
192    }
193}
194
195impl ElementHasher for Rp62_248 {
196    type BaseField = BaseElement;
197
198    fn hash_elements<E: FieldElement<BaseField = Self::BaseField>>(elements: &[E]) -> Self::Digest {
199        // convert the elements into a list of base field elements
200        let elements = E::slice_as_base_elements(elements);
201
202        // initialize state to all zeros, except for the last element of the capacity part, which
203        // is set to the number of elements to be hashed. this is done so that adding zero elements
204        // at the end of the list always results in a different hash.
205        let mut state = [BaseElement::ZERO; STATE_WIDTH];
206        state[STATE_WIDTH - 1] = BaseElement::new(elements.len() as u64);
207
208        // absorb elements into the state one by one until the rate portion of the state is filled
209        // up; then apply the Rescue permutation and start absorbing again; repeat until all
210        // elements have been absorbed
211        let mut i = 0;
212        for &element in elements.iter() {
213            state[i] += element;
214            i += 1;
215            if i % RATE_WIDTH == 0 {
216                apply_permutation(&mut state);
217                i = 0;
218            }
219        }
220
221        // if we absorbed some elements but didn't apply a permutation to them (would happen when
222        // the number of elements is not a multiple of RATE_WIDTH), apply the Rescue permutation.
223        // we don't need to apply any extra padding because we injected total number of elements
224        // in the input list into the capacity portion of the state during initialization.
225        if i > 0 {
226            apply_permutation(&mut state);
227        }
228
229        // return the first 4 elements of the state as hash result
230        ElementDigest::new(state[..DIGEST_SIZE].try_into().unwrap())
231    }
232}
233
234// RESCUE PERMUTATION
235// ================================================================================================
236
237/// Applies Rescue-XLIX permutation to the provided state.
238///
239/// Implementation is based on algorithm 3 from <https://eprint.iacr.org/2020/1143.pdf>
240fn apply_permutation(state: &mut [BaseElement; STATE_WIDTH]) {
241    // apply round function 7 times; this provides 128-bit security with 40% security margin
242    for i in 0..NUM_ROUNDS {
243        apply_round(state, i);
244    }
245}
246
247/// Rescue-XLIX round function.
248#[inline(always)]
249fn apply_round(state: &mut [BaseElement; STATE_WIDTH], round: usize) {
250    // apply first half of Rescue round
251    apply_sbox(state);
252    apply_mds(state);
253    add_constants(state, &ARK1[round]);
254
255    // apply second half of Rescue round
256    apply_inv_sbox(state);
257    apply_mds(state);
258    add_constants(state, &ARK2[round]);
259}
260
261// HELPER FUNCTIONS
262// ================================================================================================
263
264#[inline(always)]
265fn apply_mds(state: &mut [BaseElement; STATE_WIDTH]) {
266    let mut result = [BaseElement::ZERO; STATE_WIDTH];
267    result.iter_mut().zip(MDS).for_each(|(r, mds_row)| {
268        state.iter().zip(mds_row).for_each(|(&s, m)| {
269            *r += m * s;
270        });
271    });
272    *state = result
273}
274
275#[inline(always)]
276fn add_constants(state: &mut [BaseElement; STATE_WIDTH], ark: &[BaseElement; STATE_WIDTH]) {
277    state.iter_mut().zip(ark).for_each(|(s, &k)| *s += k);
278}
279
280#[inline(always)]
281fn apply_sbox(state: &mut [BaseElement; STATE_WIDTH]) {
282    state.iter_mut().for_each(|v| *v = v.cube())
283}
284
285#[inline(always)]
286fn apply_inv_sbox(state: &mut [BaseElement; STATE_WIDTH]) {
287    // compute base^3074416663688030891 using 69 multiplications per array element
288    // 3074416663688030891 = b10101010101010100001011010101010101010101010101010101010101011
289
290    // compute base^10
291    let mut t1 = *state;
292    t1.iter_mut().for_each(|t1| *t1 = t1.square());
293
294    // compute base^1010
295    let t2 = exp_acc::<BaseElement, STATE_WIDTH, 2>(t1, t1);
296
297    // compute base^10101010
298    let t4 = exp_acc::<BaseElement, STATE_WIDTH, 4>(t2, t2);
299
300    // compute base^1010101010101010
301    let t8 = exp_acc::<BaseElement, STATE_WIDTH, 8>(t4, t4);
302
303    // compute base^10101010101010100001010
304    let acc = exp_acc::<BaseElement, STATE_WIDTH, 7>(t8, t2);
305
306    // compute base^10101010101010100001011010101010101010
307    let acc = exp_acc::<BaseElement, STATE_WIDTH, 15>(acc, t8);
308
309    // compute base^101010101010101000010110101010101010101010101010101010
310    let acc = exp_acc::<BaseElement, STATE_WIDTH, 16>(acc, t8);
311
312    // compute base^10101010101010100001011010101010101010101010101010101010101010
313    let acc = exp_acc::<BaseElement, STATE_WIDTH, 8>(acc, t4);
314
315    // compute base^10101010101010100001011010101010101010101010101010101010101011
316    state.iter_mut().zip(acc).for_each(|(s, a)| *s *= a);
317}
318
319// MDS
320// ================================================================================================
321/// Rescue MDS matrix
322/// Computed using algorithm 4 from <https://eprint.iacr.org/2020/1143.pdf>
323const MDS: [[BaseElement; STATE_WIDTH]; STATE_WIDTH] = [
324    [
325        BaseElement::new(3950144678237376122),
326        BaseElement::new(2690153189131774333),
327        BaseElement::new(936645784682382348),
328        BaseElement::new(3107191214132265415),
329        BaseElement::new(2603209838230440664),
330        BaseElement::new(1199396433148647196),
331        BaseElement::new(1282983482067326228),
332        BaseElement::new(461437407589395643),
333        BaseElement::new(2214977176974126410),
334        BaseElement::new(360795585898440),
335        BaseElement::new(4611624977880333167),
336        BaseElement::new(265720),
337    ],
338    [
339        BaseElement::new(3536793164176604955),
340        BaseElement::new(1911503332938627860),
341        BaseElement::new(3418675122760523340),
342        BaseElement::new(1504989930332511353),
343        BaseElement::new(2722575982003138843),
344        BaseElement::new(1431609872573058051),
345        BaseElement::new(1192456656548488631),
346        BaseElement::new(545546930229576032),
347        BaseElement::new(945223199513254881),
348        BaseElement::new(1241455355734630133),
349        BaseElement::new(4607295377894412377),
350        BaseElement::new(52955405230),
351    ],
352    [
353        BaseElement::new(4170851182034451356),
354        BaseElement::new(4049722115827050441),
355        BaseElement::new(2592958603203603955),
356        BaseElement::new(1591126261909367400),
357        BaseElement::new(1258275846807863107),
358        BaseElement::new(1998950167196902314),
359        BaseElement::new(3042201191319512244),
360        BaseElement::new(543039388605157758),
361        BaseElement::new(1398996793391337371),
362        BaseElement::new(4366181202594792993),
363        BaseElement::new(2647705527662157444),
364        BaseElement::new(9741692640081640),
365    ],
366    [
367        BaseElement::new(2734904247639408359),
368        BaseElement::new(4279587509601476247),
369        BaseElement::new(4485482368008952587),
370        BaseElement::new(3891839128198288856),
371        BaseElement::new(3605615068318190226),
372        BaseElement::new(4481033712623965820),
373        BaseElement::new(4511906145686918697),
374        BaseElement::new(3379942354449020806),
375        BaseElement::new(3990599459674901680),
376        BaseElement::new(3930378924631282611),
377        BaseElement::new(2736309679810514295),
378        BaseElement::new(4088651356677543187),
379    ],
380    [
381        BaseElement::new(842258110397353220),
382        BaseElement::new(3379876823114508085),
383        BaseElement::new(1075495666387844288),
384        BaseElement::new(2308322198399190449),
385        BaseElement::new(535073101119307124),
386        BaseElement::new(2549013922555968548),
387        BaseElement::new(2089967165864721761),
388        BaseElement::new(1833259538539094178),
389        BaseElement::new(1286299364399671252),
390        BaseElement::new(3116429868056012525),
391        BaseElement::new(3765145590440791140),
392        BaseElement::new(276983628385769116),
393    ],
394    [
395        BaseElement::new(1299560456850023050),
396        BaseElement::new(4414989737001639740),
397        BaseElement::new(627780834867342283),
398        BaseElement::new(1711770898052004155),
399        BaseElement::new(1979604523493335895),
400        BaseElement::new(33488920757262988),
401        BaseElement::new(3296083413419576217),
402        BaseElement::new(716111559512999319),
403        BaseElement::new(1748727787185165915),
404        BaseElement::new(2725007460252215875),
405        BaseElement::new(2185047820717910109),
406        BaseElement::new(2319951565550756140),
407    ],
408    [
409        BaseElement::new(4184625686841861769),
410        BaseElement::new(1784981074793151883),
411        BaseElement::new(502457291852703062),
412        BaseElement::new(345570060311611630),
413        BaseElement::new(2471821400707240604),
414        BaseElement::new(2133038110899525730),
415        BaseElement::new(939120245208093777),
416        BaseElement::new(4151312447988641414),
417        BaseElement::new(210626922136569504),
418        BaseElement::new(2121768124528492214),
419        BaseElement::new(3469035391047007665),
420        BaseElement::new(743768221345332434),
421    ],
422    [
423        BaseElement::new(2145694559473526100),
424        BaseElement::new(1632268183143575659),
425        BaseElement::new(440280249850363795),
426        BaseElement::new(1074260737240252344),
427        BaseElement::new(434235372443698697),
428        BaseElement::new(4579079558834190297),
429        BaseElement::new(507988595809300562),
430        BaseElement::new(746255436130103157),
431        BaseElement::new(1959107915115263608),
432        BaseElement::new(4030330146733953284),
433        BaseElement::new(3748621471482452510),
434        BaseElement::new(1760002751403551673),
435    ],
436    [
437        BaseElement::new(2299194066166806303),
438        BaseElement::new(2406031288159683129),
439        BaseElement::new(3724303300393675060),
440        BaseElement::new(3136303930848425791),
441        BaseElement::new(842217609243732235),
442        BaseElement::new(2433222065782096659),
443        BaseElement::new(1853915347332186193),
444        BaseElement::new(3565339054535487990),
445        BaseElement::new(3159752035320462032),
446        BaseElement::new(1001592926358592140),
447        BaseElement::new(1070575826169209928),
448        BaseElement::new(2177302522881920563),
449    ],
450    [
451        BaseElement::new(2207526749486243134),
452        BaseElement::new(4032720262691072240),
453        BaseElement::new(1260214313840482146),
454        BaseElement::new(3621152551536391331),
455        BaseElement::new(1609693674346558276),
456        BaseElement::new(1076797379868177960),
457        BaseElement::new(1050224695423079188),
458        BaseElement::new(1679887683779537233),
459        BaseElement::new(1053394941293588429),
460        BaseElement::new(2176319632402176708),
461        BaseElement::new(807051555764923088),
462        BaseElement::new(2483141537228001953),
463    ],
464    [
465        BaseElement::new(873986056056007361),
466        BaseElement::new(2985158312969304104),
467        BaseElement::new(2082576071668149043),
468        BaseElement::new(1607709264834493266),
469        BaseElement::new(1027130385873843589),
470        BaseElement::new(3876861839368848637),
471        BaseElement::new(2999813843878199730),
472        BaseElement::new(3252530728916107838),
473        BaseElement::new(4464640832314938694),
474        BaseElement::new(1978539358398864357),
475        BaseElement::new(3425590232595452442),
476        BaseElement::new(3706838041850115299),
477    ],
478    [
479        BaseElement::new(3407508207732360664),
480        BaseElement::new(2899952415584588394),
481        BaseElement::new(282047285293952955),
482        BaseElement::new(4147714396995528527),
483        BaseElement::new(1141786266584343815),
484        BaseElement::new(3523991864183271024),
485        BaseElement::new(1659008334442446407),
486        BaseElement::new(2857663046861472404),
487        BaseElement::new(1954265424153359502),
488        BaseElement::new(4018750979872307732),
489        BaseElement::new(494911809436924696),
490        BaseElement::new(1282149942051721903),
491    ],
492];
493
494// ROUND CONSTANTS
495// ================================================================================================
496
497/// Rescue round constants;
498/// computed using algorithm 5 from <https://eprint.iacr.org/2020/1143.pdf>
499///
500/// The constants are broken up into two arrays ARK1 and ARK2; ARK1 contains the constants for the
501/// first half of Rescue round, and ARK2 contains constants for the second half of Rescue round.
502pub const ARK1: [[BaseElement; STATE_WIDTH]; NUM_ROUNDS] = [
503    [
504        BaseElement::new(2066114551762569441),
505        BaseElement::new(3806895469920197238),
506        BaseElement::new(4101271467144175579),
507        BaseElement::new(597783788093439290),
508        BaseElement::new(3459529549731874958),
509        BaseElement::new(3361732357449281221),
510        BaseElement::new(4510044102131299796),
511        BaseElement::new(2674251637583411151),
512        BaseElement::new(4589456981709905074),
513        BaseElement::new(97204927704726530),
514        BaseElement::new(3366467278170867590),
515        BaseElement::new(1661995649761352250),
516    ],
517    [
518        BaseElement::new(2552080730515318124),
519        BaseElement::new(4551129269607279176),
520        BaseElement::new(3896238353185798118),
521        BaseElement::new(4378451547412130464),
522        BaseElement::new(1120678946404787820),
523        BaseElement::new(3392815550656692052),
524        BaseElement::new(3397267446269039551),
525        BaseElement::new(2148161493216445570),
526        BaseElement::new(449851947043698998),
527        BaseElement::new(2745778316253333994),
528        BaseElement::new(3247100729373266485),
529        BaseElement::new(1474512661374883327),
530    ],
531    [
532        BaseElement::new(3875405236566248698),
533        BaseElement::new(3509172052827303011),
534        BaseElement::new(232674088014396347),
535        BaseElement::new(4189609763147780999),
536        BaseElement::new(3106901133683704323),
537        BaseElement::new(592695797873090171),
538        BaseElement::new(266738566669046215),
539        BaseElement::new(2668509039085882180),
540        BaseElement::new(950720373611234910),
541        BaseElement::new(1192091586747406812),
542        BaseElement::new(2245360993531047612),
543        BaseElement::new(2031514636218081872),
544    ],
545    [
546        BaseElement::new(2291456653144584105),
547        BaseElement::new(869259464485808552),
548        BaseElement::new(1154055231930493301),
549        BaseElement::new(1843073679205946182),
550        BaseElement::new(1748748883129851856),
551        BaseElement::new(4085632850766581010),
552        BaseElement::new(2907511654177734852),
553        BaseElement::new(1563252740420931271),
554        BaseElement::new(57166044462862224),
555        BaseElement::new(3237323403752048612),
556        BaseElement::new(4563484427236835576),
557        BaseElement::new(2956709587309713553),
558    ],
559    [
560        BaseElement::new(2157779262561212790),
561        BaseElement::new(2452020513593893218),
562        BaseElement::new(3051597722203497560),
563        BaseElement::new(3131962147511514023),
564        BaseElement::new(194930663253195526),
565        BaseElement::new(930794074695110797),
566        BaseElement::new(3616451697350340387),
567        BaseElement::new(1493869649774878568),
568        BaseElement::new(2790579710588613698),
569        BaseElement::new(4552593272704308029),
570        BaseElement::new(931863165972727433),
571        BaseElement::new(2628222466499909093),
572    ],
573    [
574        BaseElement::new(628982718083809865),
575        BaseElement::new(3809487906119235546),
576        BaseElement::new(1412055838972795717),
577        BaseElement::new(2702758340764464061),
578        BaseElement::new(643165380746471120),
579        BaseElement::new(1755475976486779630),
580        BaseElement::new(4322584783908582556),
581        BaseElement::new(2377752666356883186),
582        BaseElement::new(3806838324704149861),
583        BaseElement::new(3978620600887524391),
584        BaseElement::new(2546609133879704944),
585        BaseElement::new(3704323050566652251),
586    ],
587    [
588        BaseElement::new(364418616620607840),
589        BaseElement::new(557500673241722848),
590        BaseElement::new(2838167312179774894),
591        BaseElement::new(919171238566781484),
592        BaseElement::new(1810286722734245651),
593        BaseElement::new(2647811277753845608),
594        BaseElement::new(1083073358474695843),
595        BaseElement::new(2087740333294235353),
596        BaseElement::new(3237593972479805167),
597        BaseElement::new(2979012086287276314),
598        BaseElement::new(4247318354894968843),
599        BaseElement::new(4339035876293932168),
600    ],
601];
602
603pub const ARK2: [[BaseElement; STATE_WIDTH]; NUM_ROUNDS] = [
604    [
605        BaseElement::new(3819036781602939606),
606        BaseElement::new(887046499825451011),
607        BaseElement::new(2129644207518417092),
608        BaseElement::new(2927054444958183703),
609        BaseElement::new(3938394192009721127),
610        BaseElement::new(4350492790583122386),
611        BaseElement::new(3932489874389553135),
612        BaseElement::new(2187735113981662094),
613        BaseElement::new(2707268329521558754),
614        BaseElement::new(1672475830798880457),
615        BaseElement::new(577661991381759440),
616        BaseElement::new(4202413457369478629),
617    ],
618    [
619        BaseElement::new(2386138289504492057),
620        BaseElement::new(3614836749985123032),
621        BaseElement::new(1959364639655691456),
622        BaseElement::new(3952161783467742979),
623        BaseElement::new(2113797503569123694),
624        BaseElement::new(2706761515468719677),
625        BaseElement::new(1408899580454624727),
626        BaseElement::new(1752562999883762712),
627        BaseElement::new(2699036399761024947),
628        BaseElement::new(2111974313315470120),
629        BaseElement::new(1945634303007041433),
630        BaseElement::new(603680138767490486),
631    ],
632    [
633        BaseElement::new(216541366065294490),
634        BaseElement::new(1663917238463860974),
635        BaseElement::new(3681161841551456227),
636        BaseElement::new(1463044976083347872),
637        BaseElement::new(4293067359825676566),
638        BaseElement::new(3701547299239100959),
639        BaseElement::new(2198012560927400476),
640        BaseElement::new(924090339017537873),
641        BaseElement::new(4592565695695653575),
642        BaseElement::new(2568652539159558382),
643        BaseElement::new(2556673802560280889),
644        BaseElement::new(2055200673419696274),
645    ],
646    [
647        BaseElement::new(675825972975288687),
648        BaseElement::new(157304917963529210),
649        BaseElement::new(2874195676109427150),
650        BaseElement::new(400733584567227315),
651        BaseElement::new(982698402204661622),
652        BaseElement::new(820183842893732317),
653        BaseElement::new(301881572013037058),
654        BaseElement::new(1963857632534980766),
655        BaseElement::new(4091993061963419897),
656        BaseElement::new(4102179200035343013),
657        BaseElement::new(886874507443125118),
658        BaseElement::new(1900379595653484868),
659    ],
660    [
661        BaseElement::new(663951223276314056),
662        BaseElement::new(3247862347650141921),
663        BaseElement::new(2405853211128575753),
664        BaseElement::new(2313821214725089833),
665        BaseElement::new(892865509580640652),
666        BaseElement::new(3786801988137677226),
667        BaseElement::new(1708051655041482785),
668        BaseElement::new(413367975786665969),
669        BaseElement::new(4184177931828745920),
670        BaseElement::new(1902978742415691889),
671        BaseElement::new(3457684352259258126),
672        BaseElement::new(2092600929857819767),
673    ],
674    [
675        BaseElement::new(3616150808336931771),
676        BaseElement::new(3206846600545625539),
677        BaseElement::new(3830153390371624940),
678        BaseElement::new(2654199900015314333),
679        BaseElement::new(783490214003335242),
680        BaseElement::new(3730076606034436027),
681        BaseElement::new(3784919641869206369),
682        BaseElement::new(2204748845493012644),
683        BaseElement::new(448185939031874189),
684        BaseElement::new(435945873799083567),
685        BaseElement::new(695310862494154666),
686        BaseElement::new(2112586212508747422),
687    ],
688    [
689        BaseElement::new(1802926915815728451),
690        BaseElement::new(2057340163436909216),
691        BaseElement::new(982232855844273391),
692        BaseElement::new(1559347186127685318),
693        BaseElement::new(1420221884912541505),
694        BaseElement::new(4213862187371016442),
695        BaseElement::new(476828620219460093),
696        BaseElement::new(4518037022029400598),
697        BaseElement::new(186346377116487094),
698        BaseElement::new(4479404873270208061),
699        BaseElement::new(3269764362972891817),
700        BaseElement::new(2929967273325723272),
701    ],
702];