Skip to content

Commit

Permalink
Sponge API refactor (#146)
Browse files Browse the repository at this point in the history
* Implement ark-sponge for a new RescueSponge struct

* Replace all usages of Permutation::sponge with new struct

* Update primitives/src/rescue/sponge.rs

Co-authored-by: Alex Xiong <[email protected]>

* Add missing license information to sponge.rs

* use PhantomData from ark_std

* remove unused code

* Remove `_expected_size` param since impl accepts non-multiples of chunk

* Unify naming of const to CHUNK_SIZE

* Replace the hardcoded integers with appropriate constants for sponge

* enforce correct usage of CRHF and PRF

* Rename RescueSpongeCRHF -> RescueCRH, RescueSpongePRF -> RescuePRF

* Change `RescueCRH` and `PRF` from Rust types to newtype structs

* Panic with `unimplemented` on methods we don't use and don't test

* use internal `CHUNK_SIZE` instead of `RATE`

* Add a `permutation: Permutation<F>` field to the `RescueSponge` struct

* Remove unnecessary constructor, since `RescueCRH` methods are stateless

* Fill and unify `unimplemented` messages

* Rename CRH -> CRHF as per github discussion consensus

* Finally remove `sponge...` methods from the `Permutation` struct

* Rename `CHUNK_SIZE` to `RATE`

* Update public docs and code comments for sponge

* fixup! Finally remove `sponge...` methods from the `Permutation` struct

* Update CHANGELOG

* Be very explicit about supported trait functions for CryptographicSponge

+ add warning comments

Co-authored-by: Alex Xiong <[email protected]>
  • Loading branch information
tessico and alxiong authored Dec 8, 2022
1 parent 1cbf864 commit 9b7beb2
Show file tree
Hide file tree
Showing 13 changed files with 438 additions and 298 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@ and follow [semantic versioning](https://semver.org/) for our releases.
- [#144](https://github.com/EspressoSystems/jellyfish/pull/144) (`jf-primitives`) Updated append-only merkle tree gadget with the latest MT API
- [#119](https://github.com/EspressoSystems/jellyfish/pull/119) (all) Updated dependencies
- Upgraded `criterion` from `0.3.1` to `0.4.0`
- [#146](https://github.com/EspressoSystems/jellyfish/pull/146) (`jf-primitives`) Refactored Rescue sponge API:
- Remove all `.*sponge.*` methods from `Permutation`.
- Introduce `RescueCRHF` which takes over `sponge_with_padding` and `sponge_no_padding` from `Permutation`.
- Introduce `RescuePRF` which takes over `full_state_keyed_sponge_with_padding` and `full_state_keyed_sponge_no_padding` from `Permutation`.
- [#148](https://github.com/EspressoSystems/jellyfish/pull/148), [#156](https://github.com/EspressoSystems/jellyfish/pull/156) (`jf-primitives`) Refactored BLS Signature implementation
- #148 Added trait bounds on associated types of `trait SignatureScheme`
- #156 Improved BLS correctness and API compliance with IRTF standard with better doc

### Fixed

- [#76](https://github.com/EspressoSystems/jellyfish/pull/76) (`jf-plonk`) Splitting polynomials are masked to ensure zero-knowledge of Plonk
Expand Down
6 changes: 2 additions & 4 deletions plonk/src/transcript/rescue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use ark_ec::{
use ark_std::vec::Vec;
use jf_primitives::{
pcs::prelude::Commitment,
rescue::{Permutation as RescueHash, RescueParameter, STATE_SIZE},
rescue::{sponge::RescueCRHF, RescueParameter, STATE_SIZE},
};
use jf_relation::gadgets::ecc::{Point, SWToTEConParam};
use jf_utils::{bytes_to_field_elements, field_switching, fq_to_fr_with_mask};
Expand Down Expand Up @@ -176,10 +176,8 @@ where
// 2. challenge = state[0] in Fr
// 3. transcript = Vec::new()

let hasher = RescueHash::default();

let input = [self.state.as_ref(), self.transcript.as_ref()].concat();
let tmp = hasher.sponge_with_padding(&input, STATE_SIZE);
let tmp = RescueCRHF::sponge_with_padding(&input, STATE_SIZE);
let challenge = fq_to_fr_with_mask::<F, E::Fr>(&tmp[0]);
self.state.copy_from_slice(&tmp);
self.transcript = Vec::new();
Expand Down
1 change: 1 addition & 0 deletions primitives/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ ark-ed-on-bn254 = "0.3.0"
ark-ff = "0.3.0"
ark-poly = "0.3.0"
ark-serialize = "0.3.0"
ark-sponge = "0.3.0"
ark-std = { version = "0.3.0", default-features = false }
blst = "0.3.10"
crypto_box = "0.8.1"
Expand Down
4 changes: 2 additions & 2 deletions primitives/src/circuit/commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
use crate::{
circuit::rescue::RescueGadget,
rescue::{RescueParameter, RATE},
rescue::{RescueParameter, CRHF_RATE},
utils::pad_with,
};
use ark_std::vec;
Expand All @@ -33,7 +33,7 @@ where
fn commit(&mut self, input: &[Variable], blinding: Variable) -> Result<Variable, CircuitError> {
let mut msg = vec![blinding];
msg.extend_from_slice(input);
pad_with(&mut msg, RATE, self.zero());
pad_with(&mut msg, CRHF_RATE, self.zero());
Ok(self.rescue_sponge_no_padding(&msg, 1)?[0])
}
}
Expand Down
26 changes: 9 additions & 17 deletions primitives/src/circuit/rescue/native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -652,7 +652,8 @@ mod tests {

use super::{RescueGadget, RescueHelperGadget, RescueStateVar};
use crate::rescue::{
Permutation, RescueMatrix, RescueParameter, RescueVector, PRP, RATE, STATE_SIZE,
sponge::{RescueCRHF, RescuePRF},
Permutation, RescueMatrix, RescueParameter, RescueVector, CRHF_RATE, PRP, STATE_SIZE,
};
use ark_ed_on_bls12_377::Fq as FqEd377;
use ark_ed_on_bls12_381::Fq as FqEd381;
Expand Down Expand Up @@ -965,14 +966,13 @@ mod tests {
let mut circuit = PlonkCircuit::new_turbo_plonk();

let mut prng = ark_std::test_rng();
let data = (0..2 * RATE).map(|_| F::rand(&mut prng)).collect_vec();
let data = (0..2 * CRHF_RATE).map(|_| F::rand(&mut prng)).collect_vec();
let data_vars = data
.iter()
.map(|&x| circuit.create_variable(x).unwrap())
.collect_vec();

let rescue_perm = Permutation::default();
let expected_sponge = rescue_perm.sponge_no_padding(&data, 1).unwrap()[0];
let expected_sponge = RescueCRHF::sponge_no_padding(&data, 1).unwrap()[0];
let sponge_var = circuit
.rescue_sponge_no_padding(data_vars.as_slice(), 1)
.unwrap()[0];
Expand All @@ -987,7 +987,7 @@ mod tests {
// If the data length is not a multiple of RATE==3 then an error is triggered
let mut circuit = PlonkCircuit::<F>::new_turbo_plonk();

let size = 2 * RATE + 1; // Non multiple of RATE
let size = 2 * CRHF_RATE + 1; // Non multiple of RATE
let data = (0..size).map(|_| F::rand(&mut prng)).collect_vec();
let data_vars = data
.iter()
Expand Down Expand Up @@ -1022,17 +1022,13 @@ mod tests {
.rescue_sponge_no_padding(&input_var, output_len)
.unwrap();

let rescue_hash = Permutation::default();

// Check consistency between inputs
for i in 0..rate {
assert_eq!(input_vec[i], circuit.witness(input_var[i]).unwrap());
}

// Check consistency between outputs
let expected_hash = rescue_hash
.sponge_no_padding(&input_vec, output_len)
.unwrap();
let expected_hash = RescueCRHF::sponge_no_padding(&input_vec, output_len).unwrap();

for (e, f) in out_var.iter().zip(expected_hash.iter()) {
assert_eq!(*f, circuit.witness(*e).unwrap());
Expand Down Expand Up @@ -1087,15 +1083,13 @@ mod tests {
.rescue_sponge_with_padding(&input_var, output_len)
.unwrap();

let rescue_hash = Permutation::default();

// Check consistency between inputs
for i in 0..input_len {
assert_eq!(input_vec[i], circuit.witness(input_var[i]).unwrap());
}

// Check consistency between outputs
let expected_hash = rescue_hash.sponge_with_padding(&input_vec, output_len);
let expected_hash = RescueCRHF::sponge_with_padding(&input_vec, output_len);

for (&e, &f) in expected_hash.iter().zip(out_var.iter()) {
assert_eq!(e, circuit.witness(f).unwrap());
Expand Down Expand Up @@ -1131,10 +1125,8 @@ mod tests {
.map(|&x| circuit.create_variable(x).unwrap())
.collect_vec();

let perm = Permutation::default();
let expected_fsks_output = perm
.full_state_keyed_sponge_no_padding(&key, &data, 1)
.unwrap();
let expected_fsks_output =
RescuePRF::full_state_keyed_sponge_no_padding(&key, &data, 1).unwrap();

let fsks_var = circuit
.rescue_full_state_keyed_sponge_no_padding(key_var, &data_vars)
Expand Down
30 changes: 12 additions & 18 deletions primitives/src/circuit/rescue/non_native.rs
Original file line number Diff line number Diff line change
Expand Up @@ -736,7 +736,8 @@ mod tests {

use super::{RescueNonNativeGadget, RescueNonNativeHelperGadget, RescueNonNativeStateVar};
use crate::rescue::{
Permutation, RescueMatrix, RescueParameter, RescueVector, PRP, RATE, STATE_SIZE,
sponge::{RescueCRHF, RescuePRF},
Permutation, RescueMatrix, RescueParameter, RescueVector, CRHF_RATE, PRP, STATE_SIZE,
};
use ark_bls12_377::Fq as Fq377;
use ark_ed_on_bls12_377::Fq as FqEd377;
Expand Down Expand Up @@ -1063,16 +1064,15 @@ mod tests {
let mut prng = ark_std::test_rng();

// setup the inputs
let data_t: Vec<T> = (0..2 * RATE).map(|_| T::rand(&mut prng)).collect_vec();
let data_t: Vec<T> = (0..2 * CRHF_RATE).map(|_| T::rand(&mut prng)).collect_vec();
let data_f: Vec<F> = data_t.iter().map(|x| field_switching(x)).collect();
let data_vars: Vec<FpElemVar<F>> = data_f
.iter()
.map(|x| FpElemVar::new_from_field_element(&mut circuit, x, m, None).unwrap())
.collect();

// sponge no padding with output length 1
let rescue_perm = Permutation::<T>::default();
let expected_sponge = rescue_perm.sponge_no_padding(&data_t, 1).unwrap()[0];
let expected_sponge = RescueCRHF::sponge_no_padding(&data_t, 1).unwrap()[0];
let sponge_var = circuit
.rescue_sponge_no_padding::<T>(data_vars.as_slice(), 1)
.unwrap()[0];
Expand All @@ -1091,8 +1091,7 @@ mod tests {

// general sponge no padding
for output_len in 1..max_output_len {
let rescue_perm = Permutation::<T>::default();
let expected_sponge = rescue_perm.sponge_no_padding(&data_t, output_len).unwrap();
let expected_sponge = RescueCRHF::sponge_no_padding(&data_t, output_len).unwrap();
let sponge_var = circuit
.rescue_sponge_no_padding::<T>(data_vars.as_slice(), output_len)
.unwrap();
Expand All @@ -1111,7 +1110,7 @@ mod tests {
// If the data length is not a multiple of RATE==3 then an error is triggered
let mut circuit = PlonkCircuit::<F>::new_ultra_plonk(RANGE_BIT_LEN_FOR_TEST);

let size = 2 * RATE + 1; // Non multiple of RATE
let size = 2 * CRHF_RATE + 1; // Non multiple of RATE
let data_t = (0..size).map(|_| T::rand(&mut prng)).collect_vec();
let data_f: Vec<F> = data_t.iter().map(|x| field_switching(x)).collect();
let data_vars: Vec<FpElemVar<F>> = data_f
Expand Down Expand Up @@ -1153,8 +1152,7 @@ mod tests {
.map(|x| FpElemVar::new_from_field_element(&mut circuit, x, m, None).unwrap())
.collect();

let rescue_perm = Permutation::<T>::default();
let expected_sponge = rescue_perm.sponge_with_padding(&data_t, 1);
let expected_sponge = RescueCRHF::sponge_with_padding(&data_t, 1);

// sponge with padding
let sponge_var = circuit
Expand All @@ -1175,8 +1173,7 @@ mod tests {

// sponge full with padding
for output_len in 1..max_output_len {
let rescue_perm = Permutation::<T>::default();
let expected_sponge = rescue_perm.sponge_with_padding(&data_t, output_len);
let expected_sponge = RescueCRHF::sponge_with_padding(&data_t, output_len);

let sponge_var = circuit
.rescue_sponge_with_padding::<T>(data_vars.as_slice(), output_len)
Expand Down Expand Up @@ -1220,16 +1217,15 @@ mod tests {
.rescue_sponge_no_padding::<T>(&input_var, 1)
.unwrap()[0];

let rescue_hash = Permutation::<T>::default();

// Check consistency between inputs
for i in 0..rate {
assert_eq!(input_vec_f[i], input_var[i].witness(&circuit).unwrap());
}

// Check consistency between outputs
let expected_hash =
rescue_hash.hash_3_to_1(&[input_vec_t[0], input_vec_t[1], input_vec_t[2]]);
RescueCRHF::sponge_no_padding(&[input_vec_t[0], input_vec_t[1], input_vec_t[2]], 1)
.unwrap()[0];
assert_eq!(
field_switching::<T, F>(&expected_hash),
out_var.witness(&circuit).unwrap()
Expand Down Expand Up @@ -1271,10 +1267,8 @@ mod tests {
})
.collect();

let perm = Permutation::<T>::default();
let expected_fsks_output = perm
.full_state_keyed_sponge_no_padding(&key_t, &data_t, 1)
.unwrap();
let expected_fsks_output =
RescuePRF::full_state_keyed_sponge_no_padding(&key_t, &data_t, 1).unwrap();

let fsks_var = circuit
.rescue_full_state_keyed_sponge_no_padding::<T>(key_var, &data_vars)
Expand Down
12 changes: 7 additions & 5 deletions primitives/src/commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,29 @@

//! Implements a rescue hash based commitment scheme.
use ark_std::marker::PhantomData;

use crate::{
errors::PrimitivesError,
rescue::{Permutation, RescueParameter, RATE},
rescue::{sponge::RescueCRHF, RescueParameter, CRHF_RATE},
};
use ark_std::{format, string::String, vec};
use jf_utils::pad_with_zeros;

#[derive(Default)]
/// Commitment instance for user defined input size (in scalar elements)
pub struct Commitment<F: RescueParameter> {
hash: Permutation<F>,
input_len: usize,
phantom_f: PhantomData<F>,
}

impl<F: RescueParameter> Commitment<F> {
/// Create a new commitment instance for inputs of length `input_len`
pub fn new(input_len: usize) -> Commitment<F> {
assert!(input_len > 0, "input_len must be positive");
Commitment {
hash: Permutation::default(),
input_len,
phantom_f: PhantomData,
}
}
/// Commits to `input` slice using blinding `blind`. Return
Expand All @@ -44,8 +46,8 @@ impl<F: RescueParameter> Commitment<F> {
let mut msg = vec![*blind];
msg.extend_from_slice(input);
// Ok to pad with 0's since input length is fixed for the commitment instance
pad_with_zeros(&mut msg, RATE);
let result_vec = self.hash.sponge_no_padding(msg.as_slice(), 1)?;
pad_with_zeros(&mut msg, CRHF_RATE);
let result_vec = RescueCRHF::sponge_no_padding(msg.as_slice(), 1)?;
Ok(result_vec[0])
}
/// Verifies `commitment` against `input` and `blind`.
Expand Down
8 changes: 3 additions & 5 deletions primitives/src/merkle_tree/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! E.g. Sparse merkle tree with BigUInt index.
use super::{append_only::MerkleTree, prelude::RescueHash, DigestAlgorithm, Element, Index};
use crate::rescue::{Permutation, RescueParameter};
use crate::rescue::{sponge::RescueCRHF, RescueParameter};
use ark_ff::Field;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Read, SerializationError, Write};
use sha3::{Digest, Sha3_256};
Expand All @@ -21,14 +21,12 @@ pub struct Interval<F: Field>(pub F, pub F);

impl<F: RescueParameter> DigestAlgorithm<Interval<F>, u64, F> for RescueHash<F> {
fn digest(data: &[F]) -> F {
let perm = Permutation::default();
perm.sponge_no_padding(data, 1).unwrap()[0]
RescueCRHF::<F>::sponge_no_padding(data, 1).unwrap()[0]
}

fn digest_leaf(pos: &u64, elem: &Interval<F>) -> F {
let data = [F::from(*pos), elem.0, elem.1];
let perm = Permutation::default();
perm.sponge_no_padding(&data, 1).unwrap()[0]
RescueCRHF::<F>::sponge_no_padding(&data, 1).unwrap()[0]
}
}

Expand Down
14 changes: 5 additions & 9 deletions primitives/src/merkle_tree/prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub use crate::{
},
};

use crate::rescue::{Permutation, RescueParameter};
use crate::rescue::{sponge::RescueCRHF, RescueParameter};
use ark_std::marker::PhantomData;
use num_bigint::BigUint;
use typenum::U3;
Expand All @@ -28,14 +28,12 @@ pub struct RescueHash<F: RescueParameter> {

impl<F: RescueParameter> DigestAlgorithm<F, u64, F> for RescueHash<F> {
fn digest(data: &[F]) -> F {
let perm = Permutation::default();
perm.sponge_no_padding(data, 1).unwrap()[0]
RescueCRHF::<F>::sponge_no_padding(data, 1).unwrap()[0]
}

fn digest_leaf(pos: &u64, elem: &F) -> F {
let data = [F::zero(), F::from(*pos), *elem];
let perm = Permutation::default();
perm.sponge_no_padding(&data, 1).unwrap()[0]
RescueCRHF::<F>::sponge_no_padding(&data, 1).unwrap()[0]
}
}

Expand All @@ -44,14 +42,12 @@ pub type RescueMerkleTree<F> = MerkleTree<F, RescueHash<F>, u64, U3, F>;

impl<F: RescueParameter> DigestAlgorithm<F, BigUint, F> for RescueHash<F> {
fn digest(data: &[F]) -> F {
let perm = Permutation::default();
perm.sponge_no_padding(data, 1).unwrap()[0]
RescueCRHF::<F>::sponge_no_padding(data, 1).unwrap()[0]
}

fn digest_leaf(pos: &BigUint, elem: &F) -> F {
let data = [F::zero(), F::from(pos.clone()), *elem];
let perm = Permutation::default();
perm.sponge_no_padding(&data, 1).unwrap()[0]
RescueCRHF::<F>::sponge_no_padding(&data, 1).unwrap()[0]
}
}

Expand Down
Loading

0 comments on commit 9b7beb2

Please sign in to comment.