Skip to content

Commit

Permalink
Unify sponge gadget (#150)
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

* Unify native & non-native traits: native done

* sync non-native traits to match native (sponge vs permutation gadgtets)

* Use fully qualified calls for the RescueGadget

* Implement RescueGadget for non native

* Extract `PermutationGadget` to mod.rs and implement for native & non

* Add docs to `RescueStateVarGen` struct

* Rename RescueStateVarGen -> SpongeStateVar

as per PR review suggestion

* Add CHANGELOG entry

* Add type wrappers for native and non-native rescue gadgets

* Replace usages of RescueGadget<SpongeStateVar, F, F> with type aliases

* fix local formatting after nightly update

Co-authored-by: Alex Xiong <[email protected]>
  • Loading branch information
tessico and alxiong authored Dec 19, 2022
1 parent b47a284 commit 46de61f
Show file tree
Hide file tree
Showing 9 changed files with 488 additions and 492 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ and follow [semantic versioning](https://semver.org/) for our releases.
- [#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
- [#150](https://github.com/EspressoSystems/jellyfish/pull/150) (`jf-primitives`) Refactor `RescueGadget`
- Introduce `SpongeStateVar` to abstract over `RescueStateVar` and `RescueNonNativeStateVar` structs.
- Unify `RescueGadget` and `RescueNonNativeGadget` traits into `RescueGadget`.
- [#158](https://github.com/EspressoSystems/jellyfish/pull/158) (`jf-primitives`) Refactored `MerkleTreeGadget` API:
- Generic only over `MerkleTreeScheme`.
- New methods for allocating variables: `create_leaf_variable`, `create_membership_proof_variable`, `create_root_variable`.
Expand Down
8 changes: 4 additions & 4 deletions plonk/src/circuit/transcript.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use ark_ff::PrimeField;
use ark_std::{string::ToString, vec::Vec};
use core::marker::PhantomData;
use jf_primitives::{
circuit::rescue::RescueGadget,
circuit::rescue::RescueNativeGadget,
rescue::{RescueParameter, STATE_SIZE},
};
use jf_relation::{
Expand Down Expand Up @@ -208,9 +208,9 @@ where

// step 1. state: [F: STATE_SIZE] = hash(state|transcript)
let input_var = [self.state_var.as_ref(), self.transcript_var.as_ref()].concat();
let res_var = circuit
.rescue_sponge_with_padding(&input_var, STATE_SIZE)
.unwrap();
let res_var =
RescueNativeGadget::<F>::rescue_sponge_with_padding(circuit, &input_var, STATE_SIZE)
.unwrap();
let out_var = res_var[0];

// step 2. challenge = state[0] in Fr
Expand Down
5 changes: 3 additions & 2 deletions primitives/src/circuit/commitment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@
//! Circuit implementation of the commitment scheme.
use crate::{
circuit::rescue::RescueGadget,
rescue::{RescueParameter, CRHF_RATE},
utils::pad_with,
};
use ark_std::vec;
use jf_relation::{errors::CircuitError, Circuit, PlonkCircuit, Variable};

use super::rescue::RescueNativeGadget;

/// Circuit implementation of the commitment scheme.
pub trait CommitmentGadget {
// Commitment scheme
Expand All @@ -34,7 +35,7 @@ where
let mut msg = vec![blinding];
msg.extend_from_slice(input);
pad_with(&mut msg, CRHF_RATE, self.zero());
Ok(self.rescue_sponge_no_padding(&msg, 1)?[0])
Ok(RescueNativeGadget::<F>::rescue_sponge_no_padding(self, &msg, 1)?[0])
}
}

Expand Down
11 changes: 8 additions & 3 deletions primitives/src/circuit/merkle_tree/rescue_merkle_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
//! with a Rescue hash function.
use crate::{
circuit::rescue::RescueGadget,
circuit::rescue::RescueNativeGadget,
merkle_tree::{
internal::MerkleNode, prelude::RescueMerkleTree, MerkleTreeScheme, ToTraversalPath,
},
Expand Down Expand Up @@ -268,7 +268,11 @@ impl<F: RescueParameter> MerkleTreeHelperGadget<F> for PlonkCircuit<F> {
let zero_var = self.zero();

// leaf label = H(0, uid, arc)
let mut cur_label = self.rescue_sponge_no_padding(&[zero_var, elem.uid, elem.elem], 1)?[0];
let mut cur_label = RescueNativeGadget::<F>::rescue_sponge_no_padding(
self,
&[zero_var, elem.uid, elem.elem],
1,
)?[0];
for cur_node in path_vars.nodes.iter() {
let input_labels = self.permute(
cur_label,
Expand All @@ -279,7 +283,8 @@ impl<F: RescueParameter> MerkleTreeHelperGadget<F> for PlonkCircuit<F> {
)?;
// check that the left child's label is non-zero
self.non_zero_gate(input_labels[0])?;
cur_label = self.rescue_sponge_no_padding(&input_labels, 1)?[0];
cur_label =
RescueNativeGadget::<F>::rescue_sponge_no_padding(self, &input_labels, 1)?[0];
}
Ok(cur_label)
}
Expand Down
5 changes: 3 additions & 2 deletions primitives/src/circuit/prf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@
//! Circuit implementation of a PRF.
use crate::{
circuit::rescue::RescueGadget,
rescue::{RescueParameter, STATE_SIZE},
utils::pad_with,
};
use jf_relation::{errors::CircuitError, Circuit, PlonkCircuit, Variable};

use super::rescue::RescueNativeGadget;

/// Circuit implementation of a PRF.
pub trait PrfGadget {
/// PRF many to one
Expand All @@ -32,7 +33,7 @@ where

let mut input_vec = input.to_vec();
pad_with(&mut input_vec, STATE_SIZE, self.zero());
self.rescue_full_state_keyed_sponge_no_padding(key, &input_vec)
RescueNativeGadget::<F>::rescue_full_state_keyed_sponge_no_padding(self, key, &input_vec)
}
}

Expand Down
172 changes: 171 additions & 1 deletion primitives/src/circuit/rescue/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,175 @@
mod native;
mod non_native;

pub use native::{RescueGadget, RescueStateVar};
use ark_ff::PrimeField;
use ark_std::vec::Vec;
use jf_relation::{errors::CircuitError, Circuit};
pub use native::{RescueNativeGadget, RescueStateVar};
pub use non_native::{RescueNonNativeGadget, RescueNonNativeStateVar};

use crate::rescue::{RescueMatrix, RescueVector, PRP};

/// Variable to represent the state of the sponge.
pub trait SpongeStateVar<T, F> {
/// The native field.
type Native;
/// Non-native field.
type NonNative;
/// How variable is represented in this Rescue(NonNative)StateVar.
type Var;
}

/// Trait for rescue circuit over native field.
pub trait RescueGadget<R, T, F>
where
R: SpongeStateVar<T, F>,
{
/// Given an input state st_0 and an output state st_1, ensure that st_1 =
/// rescue_permutation(st_0) where rescue_permutation is the instance
/// of the Rescue permutation defined by its respective constants
/// * `input_var` - variables corresponding to the input state
/// * `returns` - variables corresponding to the output state
fn rescue_permutation(&mut self, input_var: R) -> Result<R, CircuitError>;

/// Rescue based Pseudo Random Permutation (PRP)
/// * `key_var` - rescue state variable corresponding to the cipher key
/// * `input_var` - rescue state variable corresponding to the plaintext
/// * `returns` - state variable corresponding to the cipher text
fn prp(&mut self, key_var: &R, input_var: &R) -> Result<R, CircuitError>;

/// Sponge-based hashes from Rescue permutations
/// * `data_vars` - sponge input variables, `data_vars.len()` should be a
/// positive integer that is a multiple of the sponge rate (i.e. 3)
/// * `num_output` - number of output variables
/// * `returns` - a vector of variables that refers to the sponge hash
/// output
fn rescue_sponge_no_padding(
&mut self,
data_vars: &[R::Var],
num_output: usize,
) -> Result<Vec<R::Var>, CircuitError>;

/// Sponge-based hashes from Rescue permutations
/// * `data_vars` - sponge input variables,
/// * `num_output` - number of output variables
/// * `returns` - a vector of variables that refers to the sponge hash
/// output
fn rescue_sponge_with_padding(
&mut self,
data_vars: &[R::Var],
num_output: usize,
) -> Result<Vec<R::Var>, CircuitError>;

/// Full-State-Keyed-Sponge with a single output
/// * `key` - key variable
/// * `input` - input variables,
/// * `returns` a variable that refers to the output
fn rescue_full_state_keyed_sponge_no_padding(
&mut self,
key: R::Var,
data_vars: &[R::Var],
) -> Result<R::Var, CircuitError>;

/// Return the round keys variables for the Rescue block cipher
/// * `mds_states` - Rescue MDS matrix
/// * `key_var` - state variable representing the cipher key
/// * `returns` - state variables corresponding to the scheduled keys
fn key_schedule(
&mut self,
mds_states: &RescueMatrix<R::Native>,
key_var: &R,
prp_instance: &PRP<R::Native>,
) -> Result<Vec<R>, CircuitError>;

/// Create a variable representing a rescue state
/// * `state` - Rescue state
/// * `returns` - state variables corresponding to the state
fn create_rescue_state_variable(
&mut self,
state: &RescueVector<R::Native>,
) -> Result<R, CircuitError>;

/// Return the variable corresponding to the output of the of the Rescue
/// PRP where the rounds keys have already been computed "dynamically"
/// * `input_var` - variable corresponding to the plain text
/// * `mds_states` - Rescue MDS matrix
/// * `key_vars` - variables corresponding to the scheduled keys
/// * `returns` -
fn prp_with_round_keys(
&mut self,
input_var: &R,
mds: &RescueMatrix<R::Native>,
keys_vars: &[R],
) -> Result<R, CircuitError>;
}

pub(crate) trait PermutationGadget<R, T, F>: Circuit<F>
where
R: SpongeStateVar<T, F>,
F: PrimeField,
{
fn check_var_bound_rescue_state(&self, rescue_state: &R) -> Result<(), CircuitError>;

fn add_constant_state(
&mut self,
input_var: &R,
constant: &RescueVector<R::Native>,
) -> Result<R, CircuitError>;

fn add_state(&mut self, left_state_var: &R, right_state_var: &R) -> Result<R, CircuitError>;

/// Given a state st_0=(x_1,...,x_w) and st_1=(y_1,...,y_w),
/// add the constraints that ensure we have y_i=x_i ^{1/5} for i in
/// [1,...,w]
/// * `input_var` - rescue state variables st_0
/// * `returns` - rescue state variables st_1
fn pow_alpha_inv_state(&mut self, input_var: &R) -> Result<R, CircuitError>;

/// Given an input state st_0 and an output state st_1, ensure that st_1 = M
/// st_0 + C where M is a Rescue matrix and c is a constant vector
/// * `input_var` - variables corresponding to the input state
/// * `matrix` - matrix M in the description above
/// * `constant` - constant c in the description above
/// * `returns` - variables corresponding to the output state
fn affine_transform(
&mut self,
input_var: &R,
matrix: &RescueMatrix<R::Native>,
constant: &RescueVector<R::Native>,
) -> Result<R, CircuitError>;

/// Given an input state st_0=(x_1,...,x_w) and an output state
/// st_1=(y_1,...,y_m) y_i = \sum_{j=1}^w M_{i,j}x_j^alpha+c_i for all i in
/// [1,..,w] where M is a Rescue matrix and c=(c_1,...,c_w) is a
/// constant vector
/// * `input_var` - variables corresponding to the input state
/// * `matrix` - matrix M in the description above
/// * `constant` - constant c in the description above
/// * `returns` - variables corresponding to the output state
fn non_linear_transform(
&mut self,
input_var: &R,
matrix: &RescueMatrix<R::Native>,
constant: &RescueVector<R::Native>,
) -> Result<R, CircuitError>;

/// Define a constraint such that y = x^(1/alpha).
/// It is implemented by setting q_{H1} y^alpha = q_O x
/// * `input_var` - variable id corresponding to x in the equation above
/// * `returns` - the variable id corresponding to y
fn pow_alpha_inv(&mut self, input_var: R::Var) -> Result<R::Var, CircuitError>;

/// Given an input state st_0 and an output state st_1, ensure that st_1 is
/// obtained by applying the rescue permutation with a specific list of
/// round keys (i.e. the keys are constants) and a matrix
/// * `input_var` - variables corresponding to the input state
/// * `mds` - Rescue matrix
/// * `round_keys` - list of round keys
/// * `returns` - variables corresponding to the output state
fn permutation_with_const_round_keys(
&mut self,
input_var: R,
mds: &RescueMatrix<R::Native>,
round_keys: &[RescueVector<R::Native>],
) -> Result<R, CircuitError>;
}
Loading

0 comments on commit 46de61f

Please sign in to comment.