jf_rescue/
sponge.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 file contains the APIs wrappers for ark-sponge
8
9use super::{Permutation, RescueParameter, RescueVector};
10use ark_crypto_primitives::sponge::{
11    Absorb, CryptographicSponge, FieldBasedCryptographicSponge, FieldElementSize, SpongeExt,
12};
13use ark_ff::PrimeField;
14use ark_std::{vec, vec::Vec};
15
16#[derive(Clone, Default, Debug)]
17/// A rescue hash function consists of a permutation function and
18/// an internal state.
19pub struct RescueSponge<F: RescueParameter, const RATE: usize> {
20    pub(crate) state: RescueVector<F>,
21    pub(crate) permutation: Permutation<F>,
22}
23
24impl<F: RescueParameter, const RATE: usize> SpongeExt for RescueSponge<F, RATE> {
25    type State = RescueVector<F>;
26
27    fn from_state(state: Self::State, permutation: &Self::Config) -> Self {
28        Self {
29            state,
30            permutation: permutation.clone(),
31        }
32    }
33
34    fn into_state(self) -> Self::State {
35        self.state
36    }
37}
38
39impl<T: RescueParameter + PrimeField, const RATE: usize> CryptographicSponge
40    for RescueSponge<T, RATE>
41{
42    /// Config used by the sponge.
43    type Config = Permutation<T>;
44
45    /// Initialize a new instance of the sponge.
46    fn new(permutation: &Self::Config) -> Self {
47        Self {
48            state: RescueVector::default(),
49            permutation: permutation.clone(),
50        }
51    }
52
53    /// Absorb an input into the sponge.
54    /// This function will absorb the entire input, in chunks of `RATE`,
55    /// even if the input length is not a multiple of `RATE`.
56    fn absorb(&mut self, input: &impl Absorb) {
57        let input_field_elements = input.to_sponge_field_elements_as_vec();
58
59        // Absorb input.
60        input_field_elements.chunks(RATE).for_each(|chunk| {
61            self.state.add_assign_elems(chunk);
62            self.state = self.permutation.eval(&self.state)
63        });
64    }
65
66    /// WARNING! This trait method is unimplemented and should not be used.
67    /// Only use the `CryptographicSponge` for squeezing native field elements.
68    fn squeeze_bytes(&mut self, _num_bytes: usize) -> Vec<u8> {
69        unimplemented!("Currently we only support squeezing native field elements!")
70    }
71
72    /// WARNING! This trait method is unimplemented and should not be used.
73    /// Only use the `CryptographicSponge` for squeezing native field elements.
74    fn squeeze_bits(&mut self, _num_bits: usize) -> Vec<bool> {
75        unimplemented!("Currently we only support squeezing native field elements!")
76    }
77
78    /// WARNING! This trait method is unimplemented and should not be used.
79    /// Use `squeeze_native_field_elements` instead.
80    fn squeeze_field_elements_with_sizes<F: PrimeField>(
81        &mut self,
82        _sizes: &[FieldElementSize],
83    ) -> Vec<F> {
84        unimplemented!("Currently we only support squeezing native field elements!")
85    }
86
87    /// WARNING! This trait method is unimplemented and should not be used.
88    /// Use `squeeze_native_field_elements` instead.
89    fn squeeze_field_elements<F: PrimeField>(&mut self, _num_elements: usize) -> Vec<F> {
90        unimplemented!("Currently we only support squeezing native field elements!")
91    }
92
93    /// Creates a new sponge with applied domain separation.
94    fn fork(&self, domain: &[u8]) -> Self {
95        let mut new_sponge = self.clone();
96
97        let mut input = Absorb::to_sponge_bytes_as_vec(&domain.len());
98        input.extend_from_slice(domain);
99        new_sponge.absorb(&input);
100
101        new_sponge
102    }
103}
104
105/// The interface for field-based cryptographic sponge.
106/// `T` is the native field used by the cryptographic sponge implementation.
107impl<T: RescueParameter, const RATE: usize> FieldBasedCryptographicSponge<T>
108    for RescueSponge<T, RATE>
109{
110    /// Squeeze `num_elements` field elements from the sponge.
111    fn squeeze_native_field_elements(&mut self, num_elements: usize) -> Vec<T> {
112        // SQUEEZE PHASE
113        let mut result = vec![];
114        let mut remaining = num_elements;
115        // extract current rate before calling PRP again
116        loop {
117            let extract = remaining.min(RATE);
118            result.extend_from_slice(&self.state.vec[0..extract]);
119            remaining -= extract;
120            if remaining == 0 {
121                break;
122            }
123            self.state = self.permutation.eval(&self.state)
124        }
125        result
126    }
127
128    /// WARNING! This trait method is unimplemented and should not be used.
129    /// Use `squeeze_native_field_elements` instead.
130    fn squeeze_native_field_elements_with_sizes(&mut self, _sizes: &[FieldElementSize]) -> Vec<T> {
131        unimplemented!("Currently we only support squeezing native field elements!")
132    }
133}
134
135#[cfg(test)]
136mod test {
137    use super::*;
138    use ark_bls12_381::Fr;
139    use ark_crypto_primitives::{
140        absorb, collect_sponge_bytes, collect_sponge_field_elements, sponge::AbsorbWithLength,
141    };
142    use ark_ff::{One, UniformRand};
143    use jf_utils::test_rng;
144
145    fn assert_different_encodings<F: RescueParameter, A: Absorb>(a: &A, b: &A) {
146        let bytes1 = a.to_sponge_bytes_as_vec();
147        let bytes2 = b.to_sponge_bytes_as_vec();
148        assert_ne!(bytes1, bytes2);
149
150        let sponge_param = Permutation::default();
151        let mut sponge1 = RescueSponge::<F, 3>::new(&sponge_param);
152        let mut sponge2 = RescueSponge::<F, 3>::new(&sponge_param);
153
154        sponge1.absorb(&a);
155        sponge2.absorb(&b);
156
157        assert_ne!(
158            sponge1.squeeze_native_field_elements(3),
159            sponge2.squeeze_native_field_elements(3)
160        );
161    }
162
163    #[test]
164    fn single_field_element() {
165        let mut rng = test_rng();
166        let elem1 = Fr::rand(&mut rng);
167        let elem2 = elem1 + Fr::one();
168
169        assert_different_encodings::<Fr, _>(&elem1, &elem2)
170    }
171
172    #[test]
173    fn list_with_constant_size_element() {
174        let mut rng = test_rng();
175        let lst1: Vec<_> = (0..1024 * 8).map(|_| Fr::rand(&mut rng)).collect();
176        let mut lst2 = lst1.to_vec();
177        lst2[3] += Fr::one();
178
179        assert_different_encodings::<Fr, _>(&lst1, &lst2)
180    }
181
182    struct VariableSizeList(Vec<u8>);
183
184    impl Absorb for VariableSizeList {
185        fn to_sponge_bytes(&self, dest: &mut Vec<u8>) {
186            self.0.to_sponge_bytes_with_length(dest)
187        }
188
189        fn to_sponge_field_elements<F: PrimeField>(&self, dest: &mut Vec<F>) {
190            self.0.to_sponge_field_elements_with_length(dest)
191        }
192    }
193
194    #[test]
195    fn list_with_nonconstant_size_element() {
196        let lst1 = vec![
197            VariableSizeList(vec![1u8, 2, 3, 4]),
198            VariableSizeList(vec![5, 6]),
199        ];
200        let lst2 = vec![
201            VariableSizeList(vec![1u8, 2]),
202            VariableSizeList(vec![3, 4, 5, 6]),
203        ];
204
205        assert_different_encodings::<Fr, _>(&lst1, &lst2);
206    }
207
208    #[test]
209    fn test_macros() {
210        let sponge_param = Permutation::default();
211        let mut sponge1 = RescueSponge::<Fr, 3>::new(&sponge_param);
212        sponge1.absorb(&vec![1u8, 2, 3, 4, 5, 6]);
213        sponge1.absorb(&Fr::from(114514u128));
214
215        let mut sponge2 = RescueSponge::<Fr, 3>::new(&sponge_param);
216        absorb!(&mut sponge2, vec![1u8, 2, 3, 4, 5, 6], Fr::from(114514u128));
217
218        let expected = sponge1.squeeze_native_field_elements(3);
219        let actual = sponge2.squeeze_native_field_elements(3);
220
221        assert_eq!(actual, expected);
222
223        let mut expected = Vec::new();
224        vec![6u8, 5, 4, 3, 2, 1].to_sponge_bytes(&mut expected);
225        Fr::from(42u8).to_sponge_bytes(&mut expected);
226
227        let actual = collect_sponge_bytes!(vec![6u8, 5, 4, 3, 2, 1], Fr::from(42u8));
228
229        assert_eq!(actual, expected);
230
231        let mut expected: Vec<Fr> = Vec::new();
232        vec![6u8, 5, 4, 3, 2, 1].to_sponge_field_elements(&mut expected);
233        Fr::from(42u8).to_sponge_field_elements(&mut expected);
234
235        let actual: Vec<Fr> =
236            collect_sponge_field_elements!(vec![6u8, 5, 4, 3, 2, 1], Fr::from(42u8));
237
238        assert_eq!(actual, expected);
239    }
240}