jf_rescue/
prf.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//! A rescue PRF implementation
8
9use crate::{
10    sponge::RescueSponge, Permutation, RescueError, RescueParameter, RescueVector, STATE_SIZE,
11};
12use ark_crypto_primitives::sponge::{
13    CryptographicSponge, FieldBasedCryptographicSponge, SpongeExt,
14};
15use ark_std::{borrow::Borrow, marker::PhantomData, string::ToString, vec::Vec};
16use jf_prf::PRF;
17use jf_utils::pad_with_zeros;
18
19/// Rescue PRF
20#[derive(Debug, Clone)]
21pub(crate) struct RescuePRFCore<F: RescueParameter> {
22    sponge: RescueSponge<F, STATE_SIZE>,
23}
24
25impl<F: RescueParameter> RescuePRFCore<F> {
26    /// Similar to [`Self::full_state_keyed_sponge_with_bit_padding`] except the
27    /// padding scheme are all "0" until the length of padded input is a
28    /// multiple of `STATE_SIZE`
29    pub(crate) fn full_state_keyed_sponge_with_zero_padding(
30        key: &F,
31        input: &[F],
32        num_outputs: usize,
33    ) -> Result<Vec<F>, RescueError> {
34        let mut padded = input.to_vec();
35        pad_with_zeros(&mut padded, STATE_SIZE);
36        Self::full_state_keyed_sponge_no_padding(key, padded.as_slice(), num_outputs)
37    }
38
39    /// Pseudorandom function based on rescue permutation for RATE 4. It allows
40    /// inputs with length that is a multiple of `STATE_SIZE` and returns a
41    /// vector of `num_outputs` elements.
42    pub(crate) fn full_state_keyed_sponge_no_padding(
43        key: &F,
44        input: &[F],
45        num_outputs: usize,
46    ) -> Result<Vec<F>, RescueError> {
47        if input.len() % STATE_SIZE != 0 {
48            return Err(RescueError::ParameterError(
49                "Rescue FSKS PRF Error: input to prf function is not multiple of STATE_SIZE."
50                    .to_string(),
51            ));
52        }
53        // ABSORB PHASE
54        let mut state = RescueVector::zero();
55        state.vec[STATE_SIZE - 1] = *key;
56        let mut r = Self {
57            sponge: RescueSponge::from_state(state, &Permutation::default()),
58        };
59        r.sponge.absorb(&input);
60
61        // SQUEEZE PHASE
62        Ok(r.sponge.squeeze_native_field_elements(num_outputs))
63    }
64}
65
66#[derive(Debug, Clone)]
67/// A rescue-based PRF that leverages on Full State Keyed (FSK) sponge
68/// construction
69pub struct RescuePRF<F: RescueParameter, const INPUT_LEN: usize, const OUTPUT_LEN: usize>(
70    PhantomData<F>,
71);
72
73impl<F: RescueParameter, const INPUT_LEN: usize, const OUTPUT_LEN: usize> PRF
74    for RescuePRF<F, INPUT_LEN, OUTPUT_LEN>
75{
76    type Input = [F; INPUT_LEN];
77    type Output = [F; OUTPUT_LEN];
78    type Seed = F;
79    type Error = RescueError;
80
81    fn evaluate<S: Borrow<Self::Seed>, I: Borrow<Self::Input>>(
82        seed: S,
83        input: I,
84    ) -> Result<Self::Output, Self::Error> {
85        let mut output = [F::zero(); OUTPUT_LEN];
86        output.clone_from_slice(&RescuePRFCore::full_state_keyed_sponge_with_zero_padding(
87            seed.borrow(),
88            input.borrow(),
89            OUTPUT_LEN,
90        )?);
91        Ok(output)
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use crate::{
98        crhf::RescueCRHF,
99        prf::{RescuePRF, RescuePRFCore, PRF},
100        RescueParameter,
101    };
102    use ark_bls12_377::{Fq as Fq377, Fr as Fr377};
103    use ark_bls12_381::Fr as Fr381;
104    use ark_bn254::{Fq as Fq254, Fr as Fr254};
105    use ark_ed_on_bls12_377::Fq as FqEd377;
106    use ark_ed_on_bls12_381::Fq as FqEd381;
107    use ark_ed_on_bn254::Fq as FqEd254;
108    use ark_std::{vec, UniformRand};
109    macro_rules! test_prf {
110        ($tr:tt) => {
111            let mut rng = jf_utils::test_rng();
112            let seed = $tr::rand(&mut rng);
113            let input = [$tr::from(1u8)];
114
115            assert!(RescuePRF::<$tr, 1, 15>::evaluate(&seed, &input).is_ok());
116            // check correctness
117            assert_eq!(
118                RescuePRF::<$tr, 1, 15>::evaluate(&seed, &input)
119                    .unwrap()
120                    .to_vec(),
121                RescuePRFCore::full_state_keyed_sponge_with_zero_padding(&seed, &input, 15)
122                    .unwrap()
123            );
124        };
125    }
126
127    #[test]
128    pub fn test_prf() {
129        test_prf!(FqEd254);
130        test_prf!(FqEd377);
131        test_prf!(FqEd381);
132        test_prf!(Fq377);
133        test_prf!(Fq254);
134    }
135
136    #[test]
137    fn test_fsks_no_padding_errors() {
138        test_fsks_no_padding_errors_helper::<Fq254>();
139        test_fsks_no_padding_errors_helper::<Fr254>();
140        test_fsks_no_padding_errors_helper::<Fr377>();
141        test_fsks_no_padding_errors_helper::<Fr381>();
142        test_fsks_no_padding_errors_helper::<Fq377>();
143    }
144    fn test_fsks_no_padding_errors_helper<F: RescueParameter>() {
145        let key = F::rand(&mut jf_utils::test_rng());
146        let input = vec![F::from(9u64); 4];
147        assert!(
148            RescuePRFCore::full_state_keyed_sponge_no_padding(&key, input.as_slice(), 1).is_ok()
149        );
150        let input = vec![F::from(9u64); 12];
151        assert!(
152            RescuePRFCore::full_state_keyed_sponge_no_padding(&key, input.as_slice(), 1).is_ok()
153        );
154
155        // test should panic because number of inputs is not multiple of 3
156        let input = vec![F::from(9u64); 10];
157        assert!(
158            RescuePRFCore::full_state_keyed_sponge_no_padding(&key, input.as_slice(), 1).is_err()
159        );
160        let input = vec![F::from(9u64)];
161        assert!(
162            RescuePRFCore::full_state_keyed_sponge_no_padding(&key, input.as_slice(), 1).is_err()
163        );
164
165        let input = vec![];
166        assert!(
167            RescuePRFCore::full_state_keyed_sponge_no_padding(&key, input.as_slice(), 1).is_ok()
168        );
169    }
170
171    #[test]
172    fn test_variable_output_sponge_and_fsks() {
173        test_variable_output_sponge_and_fsks_helper::<Fq254>();
174        test_variable_output_sponge_and_fsks_helper::<Fr254>();
175        test_variable_output_sponge_and_fsks_helper::<Fr377>();
176        test_variable_output_sponge_and_fsks_helper::<Fr381>();
177        test_variable_output_sponge_and_fsks_helper::<Fq377>();
178    }
179    fn test_variable_output_sponge_and_fsks_helper<F: RescueParameter>() {
180        let input = [F::zero(), F::one(), F::zero()];
181        assert_eq!(RescueCRHF::sponge_with_bit_padding(&input, 0).len(), 0);
182        assert_eq!(RescueCRHF::sponge_with_bit_padding(&input, 1).len(), 1);
183        assert_eq!(RescueCRHF::sponge_with_bit_padding(&input, 2).len(), 2);
184        assert_eq!(RescueCRHF::sponge_with_bit_padding(&input, 3).len(), 3);
185        assert_eq!(RescueCRHF::sponge_with_bit_padding(&input, 10).len(), 10);
186
187        assert_eq!(RescueCRHF::sponge_no_padding(&input, 0).unwrap().len(), 0);
188        assert_eq!(RescueCRHF::sponge_no_padding(&input, 1).unwrap().len(), 1);
189        assert_eq!(RescueCRHF::sponge_no_padding(&input, 2).unwrap().len(), 2);
190        assert_eq!(RescueCRHF::sponge_no_padding(&input, 3).unwrap().len(), 3);
191        assert_eq!(RescueCRHF::sponge_no_padding(&input, 10).unwrap().len(), 10);
192
193        let key = F::rand(&mut jf_utils::test_rng());
194        let input = [F::zero(), F::one(), F::zero(), F::zero()];
195        assert_eq!(
196            RescuePRFCore::full_state_keyed_sponge_with_zero_padding(&key, &input, 0)
197                .unwrap()
198                .len(),
199            0
200        );
201        assert_eq!(
202            RescuePRFCore::full_state_keyed_sponge_with_zero_padding(&key, &input, 1)
203                .unwrap()
204                .len(),
205            1
206        );
207        assert_eq!(
208            RescuePRFCore::full_state_keyed_sponge_with_zero_padding(&key, &input, 2)
209                .unwrap()
210                .len(),
211            2
212        );
213        assert_eq!(
214            RescuePRFCore::full_state_keyed_sponge_with_zero_padding(&key, &input, 4)
215                .unwrap()
216                .len(),
217            4
218        );
219        assert_eq!(
220            RescuePRFCore::full_state_keyed_sponge_with_zero_padding(&key, &input, 10)
221                .unwrap()
222                .len(),
223            10
224        );
225        assert_eq!(
226            RescuePRFCore::full_state_keyed_sponge_no_padding(&key, &input, 0)
227                .unwrap()
228                .len(),
229            0
230        );
231        assert_eq!(
232            RescuePRFCore::full_state_keyed_sponge_no_padding(&key, &input, 1)
233                .unwrap()
234                .len(),
235            1
236        );
237        assert_eq!(
238            RescuePRFCore::full_state_keyed_sponge_no_padding(&key, &input, 2)
239                .unwrap()
240                .len(),
241            2
242        );
243        assert_eq!(
244            RescuePRFCore::full_state_keyed_sponge_no_padding(&key, &input, 4)
245                .unwrap()
246                .len(),
247            4
248        );
249        assert_eq!(
250            RescuePRFCore::full_state_keyed_sponge_no_padding(&key, &input, 10)
251                .unwrap()
252                .len(),
253            10
254        );
255    }
256}