jf_rescue/
lib.rs

1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the Jellyfish library.
3
4// You should have received a copy of the MIT License
5// along with the Jellyfish library. If not, see <https://mit-license.org/>.
6
7//! This module implements Rescue hash function over the following fields
8//! - bls12_377 base field
9//! - ed_on_bls12_377 base field
10//! - ed_on_bls12_381 base field
11//! - ed_on_bn254 base field
12//!
13//! It also has place holders for
14//! - bls12_381 base field
15//! - bn254 base field
16//! - bw6_761 base field
17//!
18//! Those three place holders should never be used.
19
20#![cfg_attr(not(feature = "std"), no_std)]
21// Temporarily allow warning for nightly compilation with [`displaydoc`].
22#![allow(warnings)]
23#![deny(missing_docs)]
24#[cfg(test)]
25extern crate std;
26
27#[cfg(any(not(feature = "std"), target_has_atomic = "ptr"))]
28#[doc(hidden)]
29extern crate alloc;
30
31pub mod commitment;
32pub mod crhf;
33#[cfg(feature = "gadgets")]
34pub mod gadgets;
35pub mod prf;
36mod rescue_constants;
37pub mod sponge;
38
39use ark_crypto_primitives::sponge::Absorb;
40use ark_ff::{PrimeField, Zero};
41use ark_std::{string::String, vec, vec::Vec};
42use displaydoc::Display;
43
44/// Rescue error type
45#[derive(Debug, Display, Eq, PartialEq)]
46pub enum RescueError {
47    /// Bad parameter in function call, {0}
48    ParameterError(String),
49}
50
51impl ark_std::error::Error for RescueError {}
52
53/// The state size of rescue hash.
54pub const STATE_SIZE: usize = 4;
55/// The rate of the sponge used in RescueCRHF.
56pub const CRHF_RATE: usize = 3;
57
58/// The # of rounds of rescue hash.
59// In the paper, to derive ROUND:
60//  sage: m = 4
61//  sage: for N in range (13):
62//  ....:     t = m*N*3+3+2
63//  ....:     b = m*N + 3
64//  ....:     sec = factorial(t)/factorial(b)/factorial(t-b)
65//  ....:     print (N, RR(log(sec^2,2)))
66//
67// for alpha = 5, (i.e., BLS12-381 and BN254)
68//      10 224.672644456021
69//      11 246.589942930803
70//      12 268.516687541633
71// set ROUND = 12, we have 134 bits security
72//
73// for alpha = 11, (i.e. BLS12-377) we have l1 =
74//      7 227.364142668101
75//      8 258.421493926570
76//      9 289.491120346551
77//      10 320.571247089962
78//      11 351.660410749737
79//      12 382.757409540148
80// The smallest possible round number will be max(10, l1), which
81// means round = 10 gives 160 bits security
82//
83// There is also the script from
84//  https://github.com/EspressoSystems/Marvellous
85//
86// For unknown reasons, for all alpha >=5, the ROUND number is taken as if alpha
87// = 5. This parameter choice does not seem to be optimal
88//
89//  if (self.alpha == 3):
90//      self.Nb = max(10, 2*ceil((1.0 * security_level + 2) / (4*m)))
91//  elif (self.alpha == 5):
92//      self.Nb = max(10, 2*ceil((1.0 * security_level + 3) / (5.5*m)))
93//  else :
94//      self.Nb = max(10, 2*ceil((1.0 * security_level + 3) / (5.5*m)))
95//  # where m = 4
96//
97// For conservative purpose, we are setting ROUNDS = 12 for now.
98// We may consider to use ROUNDS = 10 for BLS12-377 (alpha = 11) in futures.
99pub const ROUNDS: usize = 12;
100
101/// This trait defines constants that are used for rescue hash functions.
102pub trait RescueParameter: PrimeField + Absorb {
103    /// parameter A, a.k.a., alpha
104    const A: u64;
105    /// parameter A^-1
106    const A_INV: &'static [u64];
107    /// MDS matrix
108    const MDS_LE: [[&'static [u8]; STATE_SIZE]; STATE_SIZE];
109    /// Initial vector.
110    const INIT_VEC_LE: [&'static [u8]; STATE_SIZE];
111    /// Injected keys for each round.
112    const KEY_INJECTION_LE: [[&'static [u8]; 4]; 2 * ROUNDS];
113    /// Permutation keys.
114    const PERMUTATION_ROUND_KEYS: [[&'static [u8]; 4]; 25];
115}
116
117#[derive(Clone, Debug, Eq, PartialEq, Copy, Default)]
118/// Data type for rescue prp inputs, keys and internal data
119pub struct RescueVector<F> {
120    pub(crate) vec: [F; STATE_SIZE],
121}
122
123// Public functions
124impl<F: PrimeField> RescueVector<F> {
125    /// zero vector
126    pub fn zero() -> RescueVector<F> {
127        RescueVector {
128            vec: [F::zero(); STATE_SIZE],
129        }
130    }
131
132    /// Return vector of the field elements
133    /// WARNING: may expose the internal state.
134    pub fn elems(&self) -> Vec<F> {
135        self.vec.to_vec()
136    }
137
138    /// Perform a linear transform of the vector.
139    /// Function needs to be public for circuits generation..
140    pub fn linear(&mut self, matrix: &RescueMatrix<F>, vector: &RescueVector<F>) {
141        let mut aux = matrix.mul_vec(self);
142        aux.add_assign(vector);
143        *self = aux
144    }
145}
146
147// Private functions
148impl<F: PrimeField> RescueVector<F> {
149    fn from_elems_le_bytes(e0: &[u8], e1: &[u8], e2: &[u8], e3: &[u8]) -> RescueVector<F> {
150        RescueVector {
151            vec: [
152                F::from_le_bytes_mod_order(e0),
153                F::from_le_bytes_mod_order(e1),
154                F::from_le_bytes_mod_order(e2),
155                F::from_le_bytes_mod_order(e3),
156            ],
157        }
158    }
159
160    fn pow(&mut self, exp: &[u64]) {
161        self.vec.iter_mut().for_each(|elem| {
162            *elem = elem.pow(exp);
163        });
164    }
165
166    fn add_assign(&mut self, vector: &RescueVector<F>) {
167        for (a, b) in self.vec.iter_mut().zip(vector.vec.iter()) {
168            a.add_assign(b);
169        }
170    }
171
172    fn add(&self, vector: &RescueVector<F>) -> RescueVector<F> {
173        let mut aux = *self;
174        aux.add_assign(vector);
175        aux
176    }
177
178    fn add_assign_elems(&mut self, elems: &[F]) {
179        self.vec
180            .iter_mut()
181            .zip(elems.iter())
182            .for_each(|(a, b)| a.add_assign(b));
183    }
184
185    fn dot_product(&self, vector: &RescueVector<F>) -> F {
186        let mut r = F::zero();
187        for (a, b) in self.vec.iter().zip(vector.vec.iter()) {
188            r.add_assign(&a.mul(b));
189        }
190        r
191    }
192}
193
194impl<F: RescueParameter> RescueVector<F> {
195    /// Helper function to compute f(M,x,c) = Mx^a + c.
196    /// Function needs to be public for circuits generation..
197    pub fn non_linear(&mut self, matrix: &RescueMatrix<F>, vector: &RescueVector<F>) {
198        let mut self_aux = *self;
199        self_aux.pow(&[F::A]);
200        let mut aux = matrix.mul_vec(&self_aux);
201        aux.add_assign(vector);
202        *self = aux;
203    }
204}
205
206impl<F: Copy> From<&[F]> for RescueVector<F> {
207    fn from(field_elems: &[F]) -> RescueVector<F> {
208        assert_eq!(field_elems.len(), STATE_SIZE);
209        RescueVector {
210            vec: [
211                field_elems[0],
212                field_elems[1],
213                field_elems[2],
214                field_elems[3],
215            ],
216        }
217    }
218}
219
220impl<F: Copy> From<&[F; STATE_SIZE]> for RescueVector<F> {
221    fn from(field_elems: &[F; STATE_SIZE]) -> RescueVector<F> {
222        RescueVector { vec: *field_elems }
223    }
224}
225
226/// A matrix that consists of `STATE_SIZE` number of rescue vectors.
227#[derive(Debug, Clone)]
228pub struct RescueMatrix<F> {
229    matrix: [RescueVector<F>; STATE_SIZE],
230}
231
232impl<F: PrimeField> From<&[RescueVector<F>; STATE_SIZE]> for RescueMatrix<F> {
233    fn from(vectors: &[RescueVector<F>; STATE_SIZE]) -> Self {
234        Self { matrix: *vectors }
235    }
236}
237
238impl<F: PrimeField> RescueMatrix<F> {
239    fn mul_vec(&self, vector: &RescueVector<F>) -> RescueVector<F> {
240        let mut result = [F::zero(); STATE_SIZE];
241        self.matrix
242            .iter()
243            .enumerate()
244            .for_each(|(i, row)| result[i] = row.dot_product(vector));
245        RescueVector { vec: result }
246    }
247
248    /// Accessing the i-th vector of the matrix.    
249    /// Function needs to be public for circuits generation..
250    /// WARNING: may expose the internal state.
251    pub fn vec(&self, i: usize) -> RescueVector<F> {
252        self.matrix[i]
253    }
254
255    /// Check if the matrix is empty.
256    pub fn is_empty(&self) -> bool {
257        self.matrix.is_empty()
258    }
259
260    /// Return the number of columns of the matrix.
261    pub fn len(&self) -> usize {
262        self.matrix.len()
263    }
264}
265
266// Rescue Pseudorandom Permutation (PRP) implementation for the BLS12_381 Scalar
267// field with 4 elements as key and input size. From the PRP it derives 3 hash
268// functions: 1. Sponge construction with arbitrary input and output length
269// 2. Sponge construction with input length multiple of the RATE (3) (no padding
270// needed) 3. 3 to 1 hashing (same construction as 1 and 2, but limiting the
271// input to 3 and output to 1
272//
273
274#[derive(Debug, Clone)]
275#[allow(clippy::upper_case_acronyms)]
276/// Rescue pseudo-random permutation (PRP) instance
277pub struct PRP<F> {
278    mds: RescueMatrix<F>,      // rescue permutation MDS matrix
279    init_vec: RescueVector<F>, // rescue permutation initial constants
280    key_injection: Vec<RescueVector<F>>, /* rescue permutation key injection constants to compute
281                                * round keys */
282}
283
284impl<F: RescueParameter> Default for PRP<F> {
285    fn default() -> Self {
286        let mut key_injection = Vec::with_capacity(2 * ROUNDS);
287        for bytes in F::KEY_INJECTION_LE.iter() {
288            key_injection.push(RescueVector::from_elems_le_bytes(
289                bytes[0], bytes[1], bytes[2], bytes[3],
290            ));
291        }
292        PRP {
293            mds: RescueMatrix::from(&[
294                RescueVector::from_elems_le_bytes(
295                    F::MDS_LE[0][0],
296                    F::MDS_LE[0][1],
297                    F::MDS_LE[0][2],
298                    F::MDS_LE[0][3],
299                ),
300                RescueVector::from_elems_le_bytes(
301                    F::MDS_LE[1][0],
302                    F::MDS_LE[1][1],
303                    F::MDS_LE[1][2],
304                    F::MDS_LE[1][3],
305                ),
306                RescueVector::from_elems_le_bytes(
307                    F::MDS_LE[2][0],
308                    F::MDS_LE[2][1],
309                    F::MDS_LE[2][2],
310                    F::MDS_LE[2][3],
311                ),
312                RescueVector::from_elems_le_bytes(
313                    F::MDS_LE[3][0],
314                    F::MDS_LE[3][1],
315                    F::MDS_LE[3][2],
316                    F::MDS_LE[3][3],
317                ),
318            ]),
319            init_vec: RescueVector::from_elems_le_bytes(
320                F::INIT_VEC_LE[0],
321                F::INIT_VEC_LE[1],
322                F::INIT_VEC_LE[2],
323                F::INIT_VEC_LE[3],
324            ),
325            key_injection,
326        }
327    }
328}
329
330impl<F: RescueParameter> PRP<F> {
331    /// Rescue pseudorandom permutation for Bls12381 scalars vectors of size 4
332    /// without key scheduled keys (scheduling occurs online)
333    pub fn prp(&self, key: &RescueVector<F>, input: &RescueVector<F>) -> RescueVector<F> {
334        let round_keys = self.key_schedule(key);
335        self.prp_with_round_keys(round_keys.as_slice(), input)
336    }
337
338    /// Rescue pseudorandom permutation for Bls12381 scalars vectors of size 4
339    /// using scheduled keys
340    pub fn prp_with_round_keys(
341        &self,
342        round_keys: &[RescueVector<F>],
343        input: &RescueVector<F>,
344    ) -> RescueVector<F> {
345        assert_eq!(round_keys.len(), 2 * ROUNDS + 1);
346        let mut perm_state = input.add(&round_keys[0]);
347        round_keys[1..].iter().enumerate().for_each(|(round, key)| {
348            if (round % 2).is_zero() {
349                perm_state.pow(F::A_INV);
350            } else {
351                perm_state.pow(&[F::A]);
352            }
353            perm_state.linear(&self.mds, key)
354        });
355        perm_state
356    }
357
358    /// Key scheduling for rescue based PRP for Bls12_381 scalars vector of size
359    /// 4
360    pub fn key_schedule(&self, key: &RescueVector<F>) -> Vec<RescueVector<F>> {
361        let mut aux = key.add(&self.init_vec);
362        let mut round_keys = vec![aux];
363        (0..2 * ROUNDS).for_each(|i| {
364            let exp = if (i % 2).is_zero() { F::A_INV } else { &[F::A] };
365            aux.pow(exp);
366            aux.linear(&self.mds, &self.key_injection[i]);
367            round_keys.push(aux);
368        });
369        round_keys
370    }
371
372    /// Return a pointer to the mds matrix.
373    /// Does not expose secret states.
374    #[inline]
375    pub fn mds_matrix_ref(&self) -> &RescueMatrix<F> {
376        &self.mds
377    }
378
379    /// Return a pointer to the key injection vectors.
380    /// Function needs to be public for circuits generation..
381    /// WARNING!!! May expose secret state if keys are supposed to be secret.
382    #[inline]
383    pub fn key_injection_vec_ref(&self) -> &[RescueVector<F>] {
384        &self.key_injection
385    }
386
387    /// Return a pointer to the initial vectors.
388    /// Does not expose secret states.
389    #[inline]
390    pub fn init_vec_ref(&self) -> &RescueVector<F> {
391        &self.init_vec
392    }
393}
394
395/// Instance of a unkeyed cryptographic permutation to be used for instantiation
396/// hashing, pseudo-random function, and other cryptographic primitives
397#[derive(Debug, Clone)]
398pub struct Permutation<F> {
399    rescue_prp: PRP<F>,
400    round_keys: Vec<RescueVector<F>>,
401}
402
403impl<F: RescueParameter> From<PRP<F>> for Permutation<F> {
404    fn from(rescue: PRP<F>) -> Self {
405        let mut keys: Vec<RescueVector<F>> = Vec::with_capacity(2 * ROUNDS + 1);
406        for key in F::PERMUTATION_ROUND_KEYS.iter() {
407            keys.push(RescueVector::from_elems_le_bytes(
408                key[0], key[1], key[2], key[3],
409            ))
410        }
411        Permutation {
412            rescue_prp: rescue,
413            round_keys: keys,
414        }
415    }
416}
417
418impl<F: RescueParameter> Default for Permutation<F> {
419    fn default() -> Self {
420        Permutation::from(PRP::default())
421    }
422}
423
424impl<F: RescueParameter> Permutation<F> {
425    /// Return a pointer to the round key.
426    /// Does not expose secret states.
427    #[inline]
428    pub fn round_keys_ref(&self) -> &[RescueVector<F>] {
429        self.round_keys.as_slice()
430    }
431
432    /// Return a pointer to the mds matrix.
433    /// Does not expose secret states.
434    #[inline]
435    pub fn mds_matrix_ref(&self) -> &RescueMatrix<F> {
436        self.rescue_prp.mds_matrix_ref()
437    }
438    /// Compute the permutation on RescueVector `input`
439    pub fn eval(&self, input: &RescueVector<F>) -> RescueVector<F> {
440        self.rescue_prp
441            .prp_with_round_keys(self.round_keys.as_slice(), input)
442    }
443}
444
445#[cfg(test)]
446mod test_prp {
447    use crate::{RescueVector, PRP};
448    use ark_bls12_377::Fq as Fq377;
449    use ark_bn254::Fq as Fq254;
450    use ark_ed_on_bls12_377::Fq as Fr377;
451    use ark_ed_on_bls12_381::Fq as Fr381;
452    use ark_ed_on_bn254::Fq as Fr254;
453
454    // hash output on vector [0, 0, 0, 0]
455    // this value is cross checked with sage script
456    // rescue761.Sponge([0,0,0,0], 4)
457    const OUTPUT761: [[u8; 48]; 4] = [
458        [
459            0x37, 0xBE, 0x12, 0x7E, 0xDF, 0x9C, 0xBF, 0xCE, 0x78, 0xE1, 0x4F, 0xEB, 0x69, 0xAC,
460            0x89, 0x53, 0xE7, 0xC4, 0x8D, 0x89, 0x90, 0x77, 0x64, 0x0D, 0xD0, 0x87, 0x42, 0xDD,
461            0x1F, 0x98, 0x30, 0xC8, 0x0F, 0x12, 0x6D, 0x7A, 0x49, 0xD3, 0x22, 0x2E, 0x12, 0xBA,
462            0x5B, 0x0E, 0x29, 0xB7, 0x2C, 0x01,
463        ],
464        [
465            0x68, 0xFE, 0x2E, 0x95, 0x57, 0xDA, 0x2E, 0x36, 0xEC, 0xC1, 0xC5, 0x8A, 0x19, 0x50,
466            0xD7, 0xBE, 0x11, 0x00, 0x3D, 0x5B, 0xAA, 0x8C, 0xF8, 0x45, 0x6F, 0xDC, 0xE4, 0x1F,
467            0xF0, 0x35, 0xC7, 0x62, 0x6A, 0xC2, 0x33, 0xE7, 0x98, 0x9F, 0x26, 0x2A, 0x6E, 0x89,
468            0xD5, 0x43, 0x21, 0xF8, 0x67, 0x01,
469        ],
470        [
471            0x84, 0xB4, 0x93, 0x04, 0x3B, 0x23, 0x3A, 0x1B, 0x43, 0xC3, 0x61, 0x61, 0x1B, 0xA0,
472            0x59, 0xFB, 0x2E, 0x88, 0x76, 0x62, 0x28, 0xBB, 0x32, 0x6F, 0x27, 0x1C, 0xA9, 0xCA,
473            0x60, 0xC1, 0xE0, 0x7A, 0x7D, 0x37, 0x2F, 0x95, 0x75, 0xDD, 0x37, 0x2A, 0x70, 0xD1,
474            0xE4, 0x55, 0xDB, 0x50, 0x2F, 0x00,
475        ],
476        [
477            0x4E, 0x01, 0x9E, 0x8A, 0x7F, 0x6F, 0x3B, 0xDE, 0x7F, 0xF5, 0x58, 0x0B, 0x1A, 0x34,
478            0x95, 0x8D, 0xBC, 0x94, 0x88, 0xD8, 0x5D, 0x25, 0x7A, 0xB0, 0xCC, 0x72, 0xFE, 0x36,
479            0xC3, 0x13, 0xCB, 0x1B, 0x7A, 0x69, 0xCF, 0xCC, 0xAB, 0x2B, 0x55, 0x11, 0x1E, 0xC5,
480            0x7C, 0xFC, 0x47, 0x7D, 0x9D, 0x01,
481        ],
482    ];
483
484    // hash output on vector [0, 0, 0, 0]
485    // this value is cross checked with sage script
486    // rescue381.Sponge([0,0,0,0], 4)
487    const OUTPUT381: [[u8; 32]; 4] = [
488        [
489            0x12, 0x53, 0x24, 0x66, 0x84, 0xA2, 0x4D, 0x2B, 0xC7, 0x28, 0x3E, 0x0F, 0x80, 0xDF,
490            0x1A, 0xC3, 0x5B, 0xA1, 0xA9, 0x5B, 0x46, 0x60, 0xBD, 0xED, 0xA6, 0xD1, 0x43, 0xB7,
491            0x60, 0xCA, 0x59, 0x0D,
492        ],
493        [
494            0x1B, 0xBE, 0xAB, 0x6C, 0xAB, 0x62, 0xB7, 0xAB, 0x19, 0xDF, 0xFF, 0x4D, 0x73, 0xB5,
495            0x78, 0x30, 0x72, 0xC0, 0xC6, 0xDA, 0x1F, 0x10, 0xAD, 0xD1, 0x28, 0x65, 0xB4, 0x94,
496            0x6F, 0xAC, 0xE5, 0x4B,
497        ],
498        [
499            0x07, 0x86, 0xBD, 0x9A, 0xB3, 0x35, 0x96, 0x22, 0xF0, 0xE5, 0xEA, 0xCC, 0x9C, 0x79,
500            0x89, 0x1F, 0x9D, 0x1D, 0x43, 0x44, 0xCC, 0xA9, 0x9A, 0xB0, 0x0E, 0xC0, 0x57, 0x6B,
501            0x07, 0xF8, 0x53, 0x06,
502        ],
503        [
504            0x9C, 0x23, 0x34, 0xB3, 0x0A, 0xCD, 0x94, 0x11, 0x49, 0xC0, 0x9D, 0x90, 0x7E, 0x7E,
505            0xC8, 0x51, 0x42, 0xD3, 0xCD, 0x5D, 0x05, 0x13, 0x31, 0x66, 0x4D, 0x36, 0x98, 0xCE,
506            0xAC, 0x44, 0x5C, 0x60,
507        ],
508    ];
509    // this value is cross checked with sage script
510    // rescue377.Sponge([0,0,0,0], 4)
511    const OUTPUT377: [[u8; 32]; 4] = [
512        [
513            0x65, 0xF2, 0xF2, 0x74, 0x15, 0x7A, 0x5A, 0xB5, 0xE0, 0x86, 0x46, 0x9D, 0xAE, 0x27,
514            0x29, 0xE0, 0x08, 0x39, 0x0D, 0xA6, 0x44, 0x5E, 0x20, 0x76, 0x23, 0x42, 0xDA, 0xF0,
515            0x49, 0xA3, 0x51, 0x02,
516        ],
517        [
518            0x67, 0xB5, 0x6A, 0xBA, 0x4B, 0xB8, 0x0F, 0xE2, 0xFC, 0x3D, 0x7E, 0xFC, 0x70, 0xCA,
519            0x3D, 0x1D, 0xAC, 0xDD, 0xEA, 0x62, 0x81, 0xD7, 0x08, 0x0B, 0x38, 0x5F, 0x0A, 0x68,
520            0xEC, 0xED, 0x53, 0x02,
521        ],
522        [
523            0x10, 0xC5, 0xA0, 0xA1, 0x8E, 0x8D, 0xBC, 0xAD, 0x99, 0xC3, 0xB4, 0xE9, 0x22, 0xC9,
524            0xB1, 0xCF, 0x35, 0x46, 0xE3, 0x52, 0x99, 0x5B, 0xBE, 0x6E, 0x08, 0xFF, 0x4B, 0x2F,
525            0xCE, 0xF0, 0xCB, 0x0A,
526        ],
527        [
528            0x33, 0xB0, 0xD0, 0x58, 0xE9, 0x25, 0x15, 0xB2, 0x8A, 0x9D, 0x16, 0x04, 0xEB, 0x26,
529            0xC4, 0x0E, 0x3F, 0xBF, 0xCF, 0x49, 0x20, 0xA8, 0x89, 0xE2, 0x16, 0x2D, 0x76, 0x19,
530            0xDF, 0x01, 0x02, 0x09,
531        ],
532    ];
533
534    // this value is cross checked with sage script
535    // rescue254.Sponge([0,0,0,0], 4)
536    const OUTPUT254: [[u8; 32]; 4] = [
537        [
538            0xDD, 0xE7, 0x55, 0x8E, 0x14, 0xF9, 0x4C, 0xEE, 0x9F, 0xCC, 0xB2, 0x02, 0xFC, 0x0E,
539            0x54, 0x21, 0xF2, 0xAA, 0xB8, 0x48, 0x05, 0xDB, 0x9B, 0x7A, 0xD2, 0x36, 0xA5, 0xF1,
540            0x49, 0x77, 0xB4, 0x17,
541        ],
542        [
543            0x43, 0x5F, 0x99, 0x3C, 0xB7, 0xB3, 0x84, 0x74, 0x4E, 0x80, 0x83, 0xFF, 0x73, 0x20,
544            0x07, 0xD9, 0x7B, 0xEC, 0x4B, 0x90, 0x48, 0x1D, 0xFD, 0x72, 0x4C, 0xF0, 0xA5, 0x7C,
545            0xDC, 0x68, 0xC0, 0x25,
546        ],
547        [
548            0x2C, 0x7B, 0x21, 0x09, 0x9D, 0x10, 0xE9, 0x5C, 0x36, 0x3E, 0x6D, 0x20, 0x28, 0xBB,
549            0xDB, 0x1E, 0xED, 0xF4, 0x22, 0x9B, 0x3A, 0xEE, 0x1E, 0x6F, 0x89, 0x13, 0x3D, 0x1E,
550            0x4C, 0xA0, 0xA6, 0x23,
551        ],
552        [
553            0x25, 0x9B, 0x47, 0xA2, 0x29, 0xFD, 0xC1, 0x08, 0xA9, 0xD1, 0x44, 0x71, 0x15, 0x8A,
554            0x5A, 0x1A, 0x55, 0x5B, 0x88, 0xAE, 0xD6, 0xF6, 0x57, 0xD3, 0x33, 0x07, 0xE1, 0x5B,
555            0x71, 0x5F, 0x12, 0x25,
556        ],
557    ];
558
559    // this value is cross checked with sage script
560    // rescue254.Sponge([0,0,0,0], 4)
561    const OUTPUTFQ254: [[u8; 32]; 4] = [
562        [
563            0xC9, 0xAC, 0x42, 0x08, 0x04, 0x18, 0xFC, 0x10, 0xA4, 0x41, 0xF4, 0xF9, 0x06, 0x2B,
564            0xE2, 0x87, 0xB7, 0x7A, 0xC4, 0x65, 0x8C, 0xE0, 0xE9, 0x78, 0xB0, 0x48, 0x39, 0xB6,
565            0x96, 0x9B, 0x60, 0x1B,
566        ],
567        [
568            0x00, 0xC2, 0xF9, 0x07, 0x54, 0x25, 0xF2, 0xC6, 0x75, 0x21, 0x01, 0x14, 0xF6, 0xD1,
569            0xAF, 0xE1, 0x0D, 0xD4, 0xFC, 0xEC, 0x15, 0xF3, 0x7D, 0x9A, 0x91, 0x26, 0x51, 0xDE,
570            0xC8, 0x8A, 0x19, 0x09,
571        ],
572        [
573            0x78, 0xDB, 0xB7, 0xEA, 0xD4, 0x35, 0x5E, 0xED, 0xAE, 0x14, 0xD6, 0xB1, 0xE8, 0x0D,
574            0xB4, 0xA7, 0x29, 0x9B, 0xBA, 0x6F, 0xBD, 0xA4, 0xEB, 0x52, 0x7D, 0xD5, 0x9B, 0x03,
575            0x17, 0x83, 0x06, 0x1D,
576        ],
577        [
578            0x72, 0xC6, 0xB8, 0xF9, 0x9E, 0xF3, 0xDA, 0x20, 0xED, 0x3D, 0xE4, 0x39, 0x87, 0x28,
579            0xE9, 0x25, 0x0D, 0x8D, 0x57, 0xCE, 0xEE, 0xCA, 0x35, 0xFB, 0x8E, 0x7E, 0xE3, 0x32,
580            0xDA, 0x03, 0x3F, 0x1B,
581        ],
582    ];
583
584    #[test]
585    fn test_rescue_perm_on_0_vec() {
586        test_rescue_perm_on_0_vec_fq254();
587        test_rescue_perm_on_0_vec_254();
588        test_rescue_perm_on_0_vec_377();
589        test_rescue_perm_on_0_vec_381();
590        test_rescue_perm_on_0_vec_761();
591    }
592
593    fn test_rescue_perm_on_0_vec_fq254() {
594        let rescue = PRP::<Fq254>::default();
595        let key = RescueVector::zero();
596        let input = RescueVector::zero();
597        let expected = RescueVector::from_elems_le_bytes(
598            &OUTPUTFQ254[0],
599            &OUTPUTFQ254[1],
600            &OUTPUTFQ254[2],
601            &OUTPUTFQ254[3],
602        );
603        let real_output = rescue.prp(&key, &input);
604        let round_keys = rescue.key_schedule(&key);
605
606        let real_output_with_round_keys = rescue.prp_with_round_keys(&round_keys, &input);
607        assert_eq!(real_output, real_output_with_round_keys);
608        assert_eq!(real_output, expected);
609    }
610
611    fn test_rescue_perm_on_0_vec_254() {
612        let rescue = PRP::<Fr254>::default();
613        let key = RescueVector::zero();
614        let input = RescueVector::zero();
615        let expected = RescueVector::from_elems_le_bytes(
616            &OUTPUT254[0],
617            &OUTPUT254[1],
618            &OUTPUT254[2],
619            &OUTPUT254[3],
620        );
621        let real_output = rescue.prp(&key, &input);
622        let round_keys = rescue.key_schedule(&key);
623        let real_output_with_round_keys = rescue.prp_with_round_keys(&round_keys, &input);
624        assert_eq!(real_output, real_output_with_round_keys);
625        assert_eq!(real_output, expected);
626    }
627
628    fn test_rescue_perm_on_0_vec_381() {
629        let rescue = PRP::<Fr381>::default();
630        let key = RescueVector::zero();
631        let input = RescueVector::zero();
632        let expected = RescueVector::from_elems_le_bytes(
633            &OUTPUT381[0],
634            &OUTPUT381[1],
635            &OUTPUT381[2],
636            &OUTPUT381[3],
637        );
638        let real_output = rescue.prp(&key, &input);
639        let round_keys = rescue.key_schedule(&key);
640        let real_output_with_round_keys = rescue.prp_with_round_keys(&round_keys, &input);
641
642        assert_eq!(real_output, real_output_with_round_keys);
643        assert_eq!(real_output, expected);
644    }
645
646    fn test_rescue_perm_on_0_vec_377() {
647        let rescue = PRP::<Fr377>::default();
648        let key = RescueVector::zero();
649        let input = RescueVector::zero();
650        let expected = RescueVector::from_elems_le_bytes(
651            &OUTPUT377[0],
652            &OUTPUT377[1],
653            &OUTPUT377[2],
654            &OUTPUT377[3],
655        );
656        let real_output = rescue.prp(&key, &input);
657        let round_keys = rescue.key_schedule(&key);
658        let real_output_with_round_keys = rescue.prp_with_round_keys(&round_keys, &input);
659        assert_eq!(real_output, real_output_with_round_keys);
660        assert_eq!(real_output, expected);
661    }
662
663    fn test_rescue_perm_on_0_vec_761() {
664        let rescue = PRP::<Fq377>::default();
665        let key = RescueVector::zero();
666        let input = RescueVector::zero();
667        let expected = RescueVector::from_elems_le_bytes(
668            &OUTPUT761[0],
669            &OUTPUT761[1],
670            &OUTPUT761[2],
671            &OUTPUT761[3],
672        );
673        let real_output = rescue.prp(&key, &input);
674        let round_keys = rescue.key_schedule(&key);
675        let real_output_with_round_keys = rescue.prp_with_round_keys(&round_keys, &input);
676        assert_eq!(real_output, real_output_with_round_keys);
677        assert_eq!(real_output, expected);
678    }
679
680    // printing vectors as hex bytes little endian
681    // use ark_ff::{BigInteger, PrimeField};
682    // use ark_std::{format, println, string::String, vec::Vec};
683    // #[test]
684    // fn print() {
685    //     let rescue_hash = PRP::<Fq254>::default();
686    //     println!("KeySchedule:");
687    //     let keys = rescue_hash.key_schedule(&RescueVector::zero());
688    //     println!("[");
689    //     for key in keys {
690    //         for elem in key.vec.iter() {
691    //             let str: Vec<String> = elem
692    //                 .into_bigint()
693    //                 .to_bytes_le()
694    //                 .iter()
695    //                 .map(|b| format!("0x{:02X},", b))
696    //                 .collect();
697    //             println!("&[{}],", str.join(" "));
698    //         }
699    //         println!("],[");
700    //     }
701    // }
702}
703
704#[cfg(test)]
705mod test_permutation {
706    use crate::{crhf::RescueCRHF, Permutation, RescueParameter, RescueVector, PRP};
707    use ark_bls12_377::Fq as Fq377;
708    use ark_bn254::Fq as Fq254;
709    use ark_ed_on_bls12_377::Fq as Fr377;
710    use ark_ed_on_bls12_381::Fq as Fr381;
711    use ark_ed_on_bn254::Fq as Fr254;
712    use ark_ff::PrimeField;
713    use ark_std::{vec, Zero};
714
715    #[test]
716    fn test_round_keys() {
717        test_round_keys_helper::<Fq254>();
718        test_round_keys_helper::<Fr254>();
719        test_round_keys_helper::<Fr377>();
720        test_round_keys_helper::<Fr381>();
721        test_round_keys_helper::<Fq377>();
722    }
723
724    fn test_round_keys_helper<F: RescueParameter>() {
725        let rescue_perm = PRP::<F>::default();
726        let rescue_hash = Permutation::default();
727        let zero = RescueVector::zero();
728        let keys2 = rescue_perm.key_schedule(&zero);
729
730        // // the following code is used to dump the key schedule to screen
731        // // in a sage friendly format
732        // for e in keys2.iter() {
733        //     for f in e.vec.iter() {
734        //         ark_std::println!("permutation_round_key.append({})",
735        // f.into_bigint());     }
736        // }
737        // assert!(false);
738
739        assert_eq!(rescue_hash.round_keys, keys2);
740    }
741
742    // hash output on vector [0, 0, 0, 0]
743    // this value is cross checked with sage script
744    // first three vectors of rescue761.Sponge([0,0,0,0], 4)
745    const OUTPUT761: [[u8; 48]; 3] = [
746        [
747            0x37, 0xBE, 0x12, 0x7E, 0xDF, 0x9C, 0xBF, 0xCE, 0x78, 0xE1, 0x4F, 0xEB, 0x69, 0xAC,
748            0x89, 0x53, 0xE7, 0xC4, 0x8D, 0x89, 0x90, 0x77, 0x64, 0x0D, 0xD0, 0x87, 0x42, 0xDD,
749            0x1F, 0x98, 0x30, 0xC8, 0x0F, 0x12, 0x6D, 0x7A, 0x49, 0xD3, 0x22, 0x2E, 0x12, 0xBA,
750            0x5B, 0x0E, 0x29, 0xB7, 0x2C, 0x01,
751        ],
752        [
753            0x68, 0xFE, 0x2E, 0x95, 0x57, 0xDA, 0x2E, 0x36, 0xEC, 0xC1, 0xC5, 0x8A, 0x19, 0x50,
754            0xD7, 0xBE, 0x11, 0x00, 0x3D, 0x5B, 0xAA, 0x8C, 0xF8, 0x45, 0x6F, 0xDC, 0xE4, 0x1F,
755            0xF0, 0x35, 0xC7, 0x62, 0x6A, 0xC2, 0x33, 0xE7, 0x98, 0x9F, 0x26, 0x2A, 0x6E, 0x89,
756            0xD5, 0x43, 0x21, 0xF8, 0x67, 0x01,
757        ],
758        [
759            0x84, 0xB4, 0x93, 0x04, 0x3B, 0x23, 0x3A, 0x1B, 0x43, 0xC3, 0x61, 0x61, 0x1B, 0xA0,
760            0x59, 0xFB, 0x2E, 0x88, 0x76, 0x62, 0x28, 0xBB, 0x32, 0x6F, 0x27, 0x1C, 0xA9, 0xCA,
761            0x60, 0xC1, 0xE0, 0x7A, 0x7D, 0x37, 0x2F, 0x95, 0x75, 0xDD, 0x37, 0x2A, 0x70, 0xD1,
762            0xE4, 0x55, 0xDB, 0x50, 0x2F, 0x00,
763        ],
764    ];
765
766    // hash output on vector [0, 0, 0, 0]
767    // this value is cross checked with sage script
768    // first three vectors of rescue254.Sponge([0,0,0,0], 4)
769    const OUTPUT254: [[u8; 32]; 3] = [
770        [
771            0xDD, 0xE7, 0x55, 0x8E, 0x14, 0xF9, 0x4C, 0xEE, 0x9F, 0xCC, 0xB2, 0x02, 0xFC, 0x0E,
772            0x54, 0x21, 0xF2, 0xAA, 0xB8, 0x48, 0x05, 0xDB, 0x9B, 0x7A, 0xD2, 0x36, 0xA5, 0xF1,
773            0x49, 0x77, 0xB4, 0x17,
774        ],
775        [
776            0x43, 0x5F, 0x99, 0x3C, 0xB7, 0xB3, 0x84, 0x74, 0x4E, 0x80, 0x83, 0xFF, 0x73, 0x20,
777            0x07, 0xD9, 0x7B, 0xEC, 0x4B, 0x90, 0x48, 0x1D, 0xFD, 0x72, 0x4C, 0xF0, 0xA5, 0x7C,
778            0xDC, 0x68, 0xC0, 0x25,
779        ],
780        [
781            0x2C, 0x7B, 0x21, 0x09, 0x9D, 0x10, 0xE9, 0x5C, 0x36, 0x3E, 0x6D, 0x20, 0x28, 0xBB,
782            0xDB, 0x1E, 0xED, 0xF4, 0x22, 0x9B, 0x3A, 0xEE, 0x1E, 0x6F, 0x89, 0x13, 0x3D, 0x1E,
783            0x4C, 0xA0, 0xA6, 0x23,
784        ],
785    ];
786    // hash output on vector [0, 0, 0, 0]
787    // this value is cross checked with sage script
788    // first three vectors of rescue377.Sponge([0,0,0,0], 4)
789    const OUTPUT377: [[u8; 32]; 3] = [
790        [
791            0x65, 0xF2, 0xF2, 0x74, 0x15, 0x7A, 0x5A, 0xB5, 0xE0, 0x86, 0x46, 0x9D, 0xAE, 0x27,
792            0x29, 0xE0, 0x08, 0x39, 0x0D, 0xA6, 0x44, 0x5E, 0x20, 0x76, 0x23, 0x42, 0xDA, 0xF0,
793            0x49, 0xA3, 0x51, 0x02,
794        ],
795        [
796            0x67, 0xB5, 0x6A, 0xBA, 0x4B, 0xB8, 0x0F, 0xE2, 0xFC, 0x3D, 0x7E, 0xFC, 0x70, 0xCA,
797            0x3D, 0x1D, 0xAC, 0xDD, 0xEA, 0x62, 0x81, 0xD7, 0x08, 0x0B, 0x38, 0x5F, 0x0A, 0x68,
798            0xEC, 0xED, 0x53, 0x02,
799        ],
800        [
801            0x10, 0xC5, 0xA0, 0xA1, 0x8E, 0x8D, 0xBC, 0xAD, 0x99, 0xC3, 0xB4, 0xE9, 0x22, 0xC9,
802            0xB1, 0xCF, 0x35, 0x46, 0xE3, 0x52, 0x99, 0x5B, 0xBE, 0x6E, 0x08, 0xFF, 0x4B, 0x2F,
803            0xCE, 0xF0, 0xCB, 0x0A,
804        ],
805    ];
806
807    // hash output on vector [0, 0, 0, 0]
808    // this value is cross checked with sage script
809    // first three vectors of rescue381.Sponge([0,0,0,0], 4)
810    const OUTPUT381: [[u8; 32]; 3] = [
811        [
812            0x12, 0x53, 0x24, 0x66, 0x84, 0xA2, 0x4D, 0x2B, 0xC7, 0x28, 0x3E, 0x0F, 0x80, 0xDF,
813            0x1A, 0xC3, 0x5B, 0xA1, 0xA9, 0x5B, 0x46, 0x60, 0xBD, 0xED, 0xA6, 0xD1, 0x43, 0xB7,
814            0x60, 0xCA, 0x59, 0x0D,
815        ],
816        [
817            0x1B, 0xBE, 0xAB, 0x6C, 0xAB, 0x62, 0xB7, 0xAB, 0x19, 0xDF, 0xFF, 0x4D, 0x73, 0xB5,
818            0x78, 0x30, 0x72, 0xC0, 0xC6, 0xDA, 0x1F, 0x10, 0xAD, 0xD1, 0x28, 0x65, 0xB4, 0x94,
819            0x6F, 0xAC, 0xE5, 0x4B,
820        ],
821        [
822            0x07, 0x86, 0xBD, 0x9A, 0xB3, 0x35, 0x96, 0x22, 0xF0, 0xE5, 0xEA, 0xCC, 0x9C, 0x79,
823            0x89, 0x1F, 0x9D, 0x1D, 0x43, 0x44, 0xCC, 0xA9, 0x9A, 0xB0, 0x0E, 0xC0, 0x57, 0x6B,
824            0x07, 0xF8, 0x53, 0x06,
825        ],
826    ];
827
828    // this value is cross checked with sage script
829    // rescue254.Sponge([0,0,0,0], 4)
830    const OUTPUTFQ254: [[u8; 32]; 4] = [
831        [
832            0xC9, 0xAC, 0x42, 0x08, 0x04, 0x18, 0xFC, 0x10, 0xA4, 0x41, 0xF4, 0xF9, 0x06, 0x2B,
833            0xE2, 0x87, 0xB7, 0x7A, 0xC4, 0x65, 0x8C, 0xE0, 0xE9, 0x78, 0xB0, 0x48, 0x39, 0xB6,
834            0x96, 0x9B, 0x60, 0x1B,
835        ],
836        [
837            0x00, 0xC2, 0xF9, 0x07, 0x54, 0x25, 0xF2, 0xC6, 0x75, 0x21, 0x01, 0x14, 0xF6, 0xD1,
838            0xAF, 0xE1, 0x0D, 0xD4, 0xFC, 0xEC, 0x15, 0xF3, 0x7D, 0x9A, 0x91, 0x26, 0x51, 0xDE,
839            0xC8, 0x8A, 0x19, 0x09,
840        ],
841        [
842            0x78, 0xDB, 0xB7, 0xEA, 0xD4, 0x35, 0x5E, 0xED, 0xAE, 0x14, 0xD6, 0xB1, 0xE8, 0x0D,
843            0xB4, 0xA7, 0x29, 0x9B, 0xBA, 0x6F, 0xBD, 0xA4, 0xEB, 0x52, 0x7D, 0xD5, 0x9B, 0x03,
844            0x17, 0x83, 0x06, 0x1D,
845        ],
846        [
847            0x72, 0xC6, 0xB8, 0xF9, 0x9E, 0xF3, 0xDA, 0x20, 0xED, 0x3D, 0xE4, 0x39, 0x87, 0x28,
848            0xE9, 0x25, 0x0D, 0x8D, 0x57, 0xCE, 0xEE, 0xCA, 0x35, 0xFB, 0x8E, 0x7E, 0xE3, 0x32,
849            0xDA, 0x03, 0x3F, 0x1B,
850        ],
851    ];
852
853    #[test]
854    fn test_sponge() {
855        test_sponge_helper::<Fq254>();
856        test_sponge_helper::<Fr254>();
857        test_sponge_helper::<Fr377>();
858        test_sponge_helper::<Fr381>();
859        test_sponge_helper::<Fq377>();
860    }
861
862    fn test_sponge_helper<F: RescueParameter>() {
863        let rescue_prp = PRP::default();
864        let mut prng = jf_utils::test_rng();
865        let e0 = F::rand(&mut prng);
866        let e1 = F::rand(&mut prng);
867        let e2 = F::rand(&mut prng);
868        let e3 = F::rand(&mut prng);
869        let e4 = F::rand(&mut prng);
870        let e5 = F::rand(&mut prng);
871
872        let input = [e0, e1, e2, e3, e4, e5];
873
874        let output = RescueCRHF::<F>::sponge_no_padding(&input, 1).unwrap()[0];
875
876        let zero = RescueVector::zero();
877        let mut state = RescueVector {
878            vec: [input[0], input[1], input[2], F::zero()],
879        };
880        state = rescue_prp.prp(&zero, &state);
881        state.add_assign_elems(&input[3..6]);
882        state = rescue_prp.prp(&zero, &state);
883        assert_eq!(output, state.vec[0]);
884    }
885
886    #[test]
887    fn test_rescue_hash_on_0_vec() {
888        test_rescue_hash_on_0_vec_fq254();
889        test_rescue_hash_on_0_vec_254();
890        test_rescue_hash_on_0_vec_377();
891        test_rescue_hash_on_0_vec_381();
892        test_rescue_hash_on_0_vec_761()
893    }
894
895    fn test_rescue_hash_on_0_vec_fq254() {
896        let input = [Fq254::zero(); 3];
897        let expected = vec![
898            Fq254::from_le_bytes_mod_order(&OUTPUTFQ254[0]),
899            Fq254::from_le_bytes_mod_order(&OUTPUTFQ254[1]),
900            Fq254::from_le_bytes_mod_order(&OUTPUTFQ254[2]),
901        ];
902        let real_output = RescueCRHF::sponge_no_padding(&input, 3).unwrap();
903        assert_eq!(real_output, expected);
904    }
905
906    fn test_rescue_hash_on_0_vec_254() {
907        let input = [Fr254::zero(); 3];
908        let expected = vec![
909            Fr254::from_le_bytes_mod_order(&OUTPUT254[0]),
910            Fr254::from_le_bytes_mod_order(&OUTPUT254[1]),
911            Fr254::from_le_bytes_mod_order(&OUTPUT254[2]),
912        ];
913        let real_output = RescueCRHF::sponge_no_padding(&input, 3).unwrap();
914        assert_eq!(real_output, expected);
915    }
916
917    fn test_rescue_hash_on_0_vec_377() {
918        let input = [Fr377::zero(); 3];
919        let expected = vec![
920            Fr377::from_le_bytes_mod_order(&OUTPUT377[0]),
921            Fr377::from_le_bytes_mod_order(&OUTPUT377[1]),
922            Fr377::from_le_bytes_mod_order(&OUTPUT377[2]),
923        ];
924        let real_output = RescueCRHF::sponge_no_padding(&input, 3).unwrap();
925        assert_eq!(real_output, expected);
926    }
927
928    fn test_rescue_hash_on_0_vec_381() {
929        let input = [Fr381::zero(); 3];
930        let expected = vec![
931            Fr381::from_le_bytes_mod_order(&OUTPUT381[0]),
932            Fr381::from_le_bytes_mod_order(&OUTPUT381[1]),
933            Fr381::from_le_bytes_mod_order(&OUTPUT381[2]),
934        ];
935        let real_output = RescueCRHF::sponge_no_padding(&input, 3).unwrap();
936        assert_eq!(real_output, expected);
937    }
938
939    fn test_rescue_hash_on_0_vec_761() {
940        let input = [Fq377::zero(); 3];
941        let expected = vec![
942            Fq377::from_le_bytes_mod_order(&OUTPUT761[0]),
943            Fq377::from_le_bytes_mod_order(&OUTPUT761[1]),
944            Fq377::from_le_bytes_mod_order(&OUTPUT761[2]),
945        ];
946        let real_output = RescueCRHF::sponge_no_padding(&input, 3).unwrap();
947        assert_eq!(real_output, expected);
948    }
949}