From 46de61fef67fdb1c21d2f5aefda301718e8a76f7 Mon Sep 17 00:00:00 2001 From: M Berger <76954195+tessico@users.noreply.github.com> Date: Mon, 19 Dec 2022 16:03:59 +0100 Subject: [PATCH] Unify sponge gadget (#150) * 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 * 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` 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 with type aliases * fix local formatting after nightly update Co-authored-by: Alex Xiong --- CHANGELOG.md | 3 + plonk/src/circuit/transcript.rs | 8 +- primitives/src/circuit/commitment.rs | 5 +- .../circuit/merkle_tree/rescue_merkle_tree.rs | 11 +- primitives/src/circuit/prf.rs | 5 +- primitives/src/circuit/rescue/mod.rs | 172 ++++++- primitives/src/circuit/rescue/native.rs | 302 ++++------- primitives/src/circuit/rescue/non_native.rs | 469 ++++++++---------- primitives/src/circuit/signature/schnorr.rs | 5 +- 9 files changed, 488 insertions(+), 492 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e6deb0b98..765249409 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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`. diff --git a/plonk/src/circuit/transcript.rs b/plonk/src/circuit/transcript.rs index 263726fdd..6e3bb9a07 100644 --- a/plonk/src/circuit/transcript.rs +++ b/plonk/src/circuit/transcript.rs @@ -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::{ @@ -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::::rescue_sponge_with_padding(circuit, &input_var, STATE_SIZE) + .unwrap(); let out_var = res_var[0]; // step 2. challenge = state[0] in Fr diff --git a/primitives/src/circuit/commitment.rs b/primitives/src/circuit/commitment.rs index 5a04bd964..dd77bf032 100644 --- a/primitives/src/circuit/commitment.rs +++ b/primitives/src/circuit/commitment.rs @@ -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 @@ -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::::rescue_sponge_no_padding(self, &msg, 1)?[0]) } } diff --git a/primitives/src/circuit/merkle_tree/rescue_merkle_tree.rs b/primitives/src/circuit/merkle_tree/rescue_merkle_tree.rs index c0c85f852..d281180de 100644 --- a/primitives/src/circuit/merkle_tree/rescue_merkle_tree.rs +++ b/primitives/src/circuit/merkle_tree/rescue_merkle_tree.rs @@ -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, }, @@ -268,7 +268,11 @@ impl MerkleTreeHelperGadget for PlonkCircuit { 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::::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, @@ -279,7 +283,8 @@ impl MerkleTreeHelperGadget for PlonkCircuit { )?; // 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::::rescue_sponge_no_padding(self, &input_labels, 1)?[0]; } Ok(cur_label) } diff --git a/primitives/src/circuit/prf.rs b/primitives/src/circuit/prf.rs index b5b370afa..c2929e022 100644 --- a/primitives/src/circuit/prf.rs +++ b/primitives/src/circuit/prf.rs @@ -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 @@ -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::::rescue_full_state_keyed_sponge_no_padding(self, key, &input_vec) } } diff --git a/primitives/src/circuit/rescue/mod.rs b/primitives/src/circuit/rescue/mod.rs index e7c21f50b..f75e7b59e 100644 --- a/primitives/src/circuit/rescue/mod.rs +++ b/primitives/src/circuit/rescue/mod.rs @@ -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 { + /// 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 +where + R: SpongeStateVar, +{ + /// 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; + + /// 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; + + /// 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, 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, 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; + + /// 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, + key_var: &R, + prp_instance: &PRP, + ) -> Result, 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, + ) -> Result; + + /// 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, + keys_vars: &[R], + ) -> Result; +} + +pub(crate) trait PermutationGadget: Circuit +where + R: SpongeStateVar, + 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, + ) -> Result; + + fn add_state(&mut self, left_state_var: &R, right_state_var: &R) -> Result; + + /// 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; + + /// 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, + constant: &RescueVector, + ) -> Result; + + /// 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, + constant: &RescueVector, + ) -> Result; + + /// 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; + + /// 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, + round_keys: &[RescueVector], + ) -> Result; +} diff --git a/primitives/src/circuit/rescue/native.rs b/primitives/src/circuit/rescue/native.rs index 07b8285b2..1af1e3e67 100644 --- a/primitives/src/circuit/rescue/native.rs +++ b/primitives/src/circuit/rescue/native.rs @@ -18,10 +18,22 @@ use jf_relation::{ }; use jf_utils::compute_len_to_next_multiple; +use super::{PermutationGadget, RescueGadget, SpongeStateVar}; + #[derive(Clone, Debug)] /// Array of variables representing a Rescue state (4 field elements). pub struct RescueStateVar(pub(crate) [Variable; STATE_SIZE]); +/// Type wrapper for the RescueGadget over the native field. +pub type RescueNativeGadget = dyn RescueGadget; + +/// For the native field, there is only really one field `F`. +impl SpongeStateVar for RescueStateVar { + type Native = F; + type NonNative = F; + type Var = Variable; +} + impl From<[Variable; STATE_SIZE]> for RescueStateVar { fn from(arr: [Variable; STATE_SIZE]) -> Self { RescueStateVar(arr) @@ -97,95 +109,7 @@ impl Gate for Power5NonLinearGate { } } -/// Trait for rescue circuit over native field. -pub trait RescueGadget { - /// 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: RescueStateVar, - ) -> Result; - - /// 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: &RescueStateVar, - input_var: &RescueStateVar, - ) -> Result; - - /// 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: &[Variable], - num_output: usize, - ) -> Result, 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: &[Variable], - num_output: usize, - ) -> Result, 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: Variable, - data_vars: &[Variable], - ) -> Result; - - /// 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, - key_var: &RescueStateVar, - prp_instance: &PRP, - ) -> Result, 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, - ) -> Result; - - /// 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: &RescueStateVar, - mds: &RescueMatrix, - keys_vars: &[RescueStateVar], - ) -> Result; -} - -impl RescueGadget for PlonkCircuit +impl RescueGadget for PlonkCircuit where F: RescueParameter, { @@ -211,7 +135,8 @@ where ) -> Result { let prp_instance = PRP::::default(); let mds_states = prp_instance.mds_matrix_ref(); - let keys_vars = self.key_schedule(mds_states, key_var, &prp_instance)?; + let keys_vars = + RescueNativeGadget::::key_schedule(self, mds_states, key_var, &prp_instance)?; self.prp_with_round_keys(input_var, mds_states, &keys_vars) } @@ -229,7 +154,7 @@ where // ABSORB PHASE let mut state_var = RescueStateVar::from([data_vars[0], data_vars[1], data_vars[2], zero_var]); - state_var = self.rescue_permutation(state_var)?; + state_var = RescueNativeGadget::::rescue_permutation(self, state_var)?; for block in data_vars[rate..].chunks_exact(rate) { state_var = self.add_state( @@ -268,14 +193,14 @@ where let rate = STATE_SIZE - 1; let data_len = compute_len_to_next_multiple(data_vars.len() + 1, rate); - let data_vars = [ + let data_vars: Vec = [ data_vars, &[self.one()], vec![zero_var; data_len - data_vars.len() - 1].as_ref(), ] .concat(); - self.rescue_sponge_no_padding(&data_vars, num_output) + RescueNativeGadget::::rescue_sponge_no_padding(self, &data_vars, num_output) } fn rescue_full_state_keyed_sponge_no_padding( @@ -296,7 +221,7 @@ where for chunk in chunks { let chunk_var = RescueStateVar::from([chunk[0], chunk[1], chunk[2], chunk[3]]); state = self.add_state(&state, &chunk_var)?; - state = self.rescue_permutation(state)?; + state = RescueNativeGadget::::rescue_permutation(self, state)?; } // squeeze phase, but only a single output, can return directly from state Ok(state.0[0]) @@ -371,99 +296,7 @@ where } } -pub(crate) trait RescueHelperGadget: Circuit { - fn check_var_bound_rescue_state( - &self, - rescue_state: &RescueStateVar, - ) -> Result<(), CircuitError>; - - fn add_constant_state( - &mut self, - input_var: &RescueStateVar, - constant: &RescueVector, - ) -> Result; - - fn add_state( - &mut self, - left_state_var: &RescueStateVar, - right_state_var: &RescueStateVar, - ) -> Result; - - /// 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: &RescueStateVar, - ) -> Result; - - /// 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: &RescueStateVar, - matrix: &RescueMatrix, - constant: &RescueVector, - ) -> Result; - - /// 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: &RescueStateVar, - matrix: &RescueMatrix, - constant: &RescueVector, - ) -> Result; - - /// 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: Variable) -> Result; - - /// 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: RescueStateVar, - mds: &RescueMatrix, - round_keys: &[RescueVector], - ) -> Result { - if (round_keys.len() != 2 * ROUNDS + 1) || (mds.len() != STATE_SIZE) { - return Err(CircuitError::ParameterError("data_vars".to_string())); - } - - let mut state_var = self.add_constant_state(&input_var, &round_keys[0])?; - for (r, key) in round_keys.iter().skip(1).enumerate() { - if r % 2 == 0 { - state_var = self.pow_alpha_inv_state(&state_var)?; - state_var = self.affine_transform(&state_var, mds, key)?; - } else { - state_var = self.non_linear_transform(&state_var, mds, key)?; - } - } - Ok(state_var) - } -} - -impl RescueHelperGadget for PlonkCircuit +impl PermutationGadget for PlonkCircuit where F: RescueParameter, { @@ -505,7 +338,7 @@ where let vars: Result, CircuitError> = input_var .0 .iter() - .map(|var| self.pow_alpha_inv(*var)) + .map(|var| PermutationGadget::::pow_alpha_inv(self, *var)) .collect(); let vars = vars?; Ok(RescueStateVar::from([vars[0], vars[1], vars[2], vars[3]])) @@ -645,15 +478,40 @@ where } Ok(res) } + + fn permutation_with_const_round_keys( + &mut self, + input_var: RescueStateVar, + mds: &RescueMatrix, + round_keys: &[RescueVector], + ) -> Result { + if (round_keys.len() != 2 * ROUNDS + 1) || (mds.len() != STATE_SIZE) { + return Err(CircuitError::ParameterError("data_vars".to_string())); + } + + let mut state_var = self.add_constant_state(&input_var, &round_keys[0])?; + for (r, key) in round_keys.iter().skip(1).enumerate() { + if r % 2 == 0 { + state_var = self.pow_alpha_inv_state(&state_var)?; + state_var = self.affine_transform(&state_var, mds, key)?; + } else { + state_var = self.non_linear_transform(&state_var, mds, key)?; + } + } + Ok(state_var) + } } #[cfg(test)] mod tests { - use super::{RescueGadget, RescueHelperGadget, RescueStateVar}; - use crate::rescue::{ - sponge::{RescueCRHF, RescuePRF}, - Permutation, RescueMatrix, RescueParameter, RescueVector, CRHF_RATE, PRP, STATE_SIZE, + use super::{PermutationGadget, RescueGadget, RescueStateVar}; + use crate::{ + circuit::rescue::RescueNativeGadget, + rescue::{ + 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; @@ -973,9 +831,12 @@ mod tests { .collect_vec(); 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]; + let sponge_var = RescueNativeGadget::::rescue_sponge_no_padding( + &mut circuit, + data_vars.as_slice(), + 1, + ) + .unwrap()[0]; assert_eq!(expected_sponge, circuit.witness(sponge_var).unwrap()); @@ -994,9 +855,12 @@ mod tests { .map(|&x| circuit.create_variable(x).unwrap()) .collect_vec(); - assert!(circuit - .rescue_sponge_no_padding(data_vars.as_slice(), 1) - .is_err()); + assert!(RescueNativeGadget::::rescue_sponge_no_padding( + &mut circuit, + data_vars.as_slice(), + 1 + ) + .is_err()); } #[test] @@ -1018,9 +882,12 @@ mod tests { ]; for output_len in 1..10 { - let out_var = circuit - .rescue_sponge_no_padding(&input_var, output_len) - .unwrap(); + let out_var = RescueNativeGadget::::rescue_sponge_no_padding( + &mut circuit, + &input_var, + output_len, + ) + .unwrap(); // Check consistency between inputs for i in 0..rate { @@ -1059,7 +926,9 @@ mod tests { circuit.create_variable(input_vec[2]).unwrap(), circuit.create_variable(input_vec[3]).unwrap(), ]; - assert!(circuit.rescue_sponge_no_padding(&input_var, 1).is_err()); + assert!( + RescueNativeGadget::::rescue_sponge_no_padding(&mut circuit, &input_var, 1).is_err() + ); } #[test] @@ -1079,9 +948,12 @@ mod tests { .map(|x| circuit.create_variable(*x).unwrap()) .collect(); - let out_var = circuit - .rescue_sponge_with_padding(&input_var, output_len) - .unwrap(); + let out_var = RescueNativeGadget::::rescue_sponge_with_padding( + &mut circuit, + &input_var, + output_len, + ) + .unwrap(); // Check consistency between inputs for i in 0..input_len { @@ -1128,9 +1000,12 @@ mod tests { 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) - .unwrap(); + let fsks_var = RescueNativeGadget::::rescue_full_state_keyed_sponge_no_padding( + &mut circuit, + key_var, + &data_vars, + ) + .unwrap(); // Check prf output consistency assert_eq!(expected_fsks_output[0], circuit.witness(fsks_var).unwrap()); @@ -1143,8 +1018,13 @@ mod tests { // make data_vars of bad length let mut data_vars = data_vars; data_vars.push(circuit.zero()); - assert!(circuit - .rescue_full_state_keyed_sponge_no_padding(key_var, &data_vars) - .is_err()); + assert!( + RescueNativeGadget::::rescue_full_state_keyed_sponge_no_padding( + &mut circuit, + key_var, + &data_vars + ) + .is_err() + ); } } diff --git a/primitives/src/circuit/rescue/non_native.rs b/primitives/src/circuit/rescue/non_native.rs index 9c496d057..ddcbe9294 100644 --- a/primitives/src/circuit/rescue/non_native.rs +++ b/primitives/src/circuit/rescue/non_native.rs @@ -22,6 +22,8 @@ use jf_relation::{ }; use jf_utils::{compute_len_to_next_multiple, field_switching}; +use super::{PermutationGadget, RescueGadget, SpongeStateVar}; + /// Array of variables representing a Rescue state (4 field elements), and also /// the modulus of the non-native evaluating field. #[derive(Clone, Debug)] @@ -30,67 +32,21 @@ pub struct RescueNonNativeStateVar { pub(crate) modulus: FpElem, } -/// Trait for rescue circuit over non-native field. -pub trait RescueNonNativeGadget { - /// 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: RescueNonNativeStateVar, - ) -> Result, CircuitError>; +/// Type wrapper for the RescueGadget over the non-native field. +pub type RescueNonNativeGadget = dyn RescueGadget, T, F>; - /// 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: &RescueNonNativeStateVar, - input_var: &RescueNonNativeStateVar, - ) -> Result, 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: &[FpElemVar], - num_output: usize, - ) -> Result>, 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: &[FpElemVar], - num_output: usize, - ) -> Result>, 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: FpElemVar, - data_vars: &[FpElemVar], - ) -> Result, CircuitError>; +impl SpongeStateVar for RescueNonNativeStateVar { + type Native = T; + type NonNative = F; + type Var = FpElemVar; } -impl RescueNonNativeGadget for PlonkCircuit +impl RescueGadget, T, F> for PlonkCircuit where F: PrimeField, + T: RescueParameter, { - fn rescue_permutation( + fn rescue_permutation( &mut self, input_var: RescueNonNativeStateVar, ) -> Result, CircuitError> { @@ -105,7 +61,7 @@ where self.permutation_with_const_round_keys(input_var, mds_matrix, keys.as_slice()) } - fn prp( + fn prp( &mut self, key_var: &RescueNonNativeStateVar, input_var: &RescueNonNativeStateVar, @@ -116,7 +72,7 @@ where self.prp_with_round_keys(input_var, mds_states, &keys_vars) } - fn rescue_sponge_with_padding( + fn rescue_sponge_with_padding( &mut self, data_vars: &[FpElemVar], num_output: usize, @@ -140,10 +96,10 @@ where ] .concat(); - self.rescue_sponge_no_padding::(&data_vars, num_output) + RescueNonNativeGadget::::rescue_sponge_no_padding(self, &data_vars, num_output) } - fn rescue_sponge_no_padding( + fn rescue_sponge_no_padding( &mut self, data_vars: &[FpElemVar], num_output: usize, @@ -171,17 +127,18 @@ where state: [data_vars[0], data_vars[1], data_vars[2], zero_var], modulus, }; - state_var = self.rescue_permutation::(state_var)?; + state_var = RescueNonNativeGadget::::rescue_permutation(self, state_var)?; for block in data_vars[rate..].chunks_exact(rate) { - state_var = self.add_state( + state_var = PermutationGadget::, T, F>::add_state( + self, &state_var, &RescueNonNativeStateVar { state: [block[0], block[1], block[2], zero_var], modulus, }, )?; - state_var = self.rescue_permutation::(state_var)?; + state_var = RescueNonNativeGadget::::rescue_permutation(self, state_var)?; } // SQUEEZE PHASE let mut result = vec![]; @@ -194,13 +151,13 @@ where if remaining == 0 { break; } - state_var = self.rescue_permutation::(state_var)?; + state_var = RescueNonNativeGadget::::rescue_permutation(self, state_var)?; } Ok(result) } - fn rescue_full_state_keyed_sponge_no_padding( + fn rescue_full_state_keyed_sponge_no_padding( &mut self, key: FpElemVar, data_vars: &[FpElemVar], @@ -237,94 +194,75 @@ where state: [chunk[0], chunk[1], chunk[2], chunk[3]], modulus, }; - state = self.add_state(&state, &chunk_var)?; - state = self.rescue_permutation::(state)?; + state = PermutationGadget::, T, F>::add_state( + self, &state, &chunk_var, + )?; + state = RescueNonNativeGadget::::rescue_permutation(self, state)?; } // squeeze phase, but only a single output, can return directly from state Ok(state.state[0]) } -} -pub(crate) trait RescueNonNativeHelperGadget: Circuit { - fn check_var_bound_rescue_state( - &self, - rescue_state: &RescueNonNativeStateVar, - ) -> Result<(), CircuitError>; - - fn create_rescue_state_variable( + fn create_rescue_state_variable( &mut self, state: &RescueVector, - ) -> Result, CircuitError>; + ) -> Result, CircuitError> { + // parameter m + let m = (T::size_in_bits() / 2 / self.range_bit_len()? + 1) * self.range_bit_len()?; - fn add_constant_state( - &mut self, - input_var: &RescueNonNativeStateVar, - constant: &RescueVector, - ) -> Result, CircuitError>; + // move the modulus to the right field + let t_modulus = F::from_le_bytes_mod_order(T::Params::MODULUS.to_bytes_le().as_ref()); + let t = FpElem::new(&t_modulus, m, None)?; - fn add_state( - &mut self, - left_state_var: &RescueNonNativeStateVar, - right_state_var: &RescueNonNativeStateVar, - ) -> Result, 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/11} 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: &RescueNonNativeStateVar, - ) -> Result, 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: &RescueNonNativeStateVar, - matrix: &RescueMatrix, - constant: &RescueVector, - ) -> Result, 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: &RescueNonNativeStateVar, - matrix: &RescueMatrix, - constant: &RescueVector, - ) -> Result, CircuitError>; + // move rescue state to the plonk field + let state_f: Vec = state + .elems() + .iter() + .map(|x| field_switching::(x)) + .collect(); - /// 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: FpElemVar, - ) -> Result, CircuitError>; + // create vars for states + let mut state_split_var = [FpElemVar::::default(); STATE_SIZE]; + for (var, f) in state_split_var.iter_mut().zip(state_f.iter()) { + *var = FpElemVar::new_from_field_element(self, f, m, Some(t.two_power_m()))?; + } - /// 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( + Ok(RescueNonNativeStateVar { + state: state_split_var, + modulus: t, + }) + } + + fn key_schedule( &mut self, - mds_states: &RescueMatrix, + mds: &RescueMatrix, key_var: &RescueNonNativeStateVar, prp_instance: &PRP, - ) -> Result>, CircuitError>; + ) -> Result>, CircuitError> { + let mut aux = *prp_instance.init_vec_ref(); + let key_injection_vec = prp_instance.key_injection_vec_ref(); + + let mut key_state_var = self.add_constant_state(key_var, &aux)?; + let mut result = vec![key_state_var.clone()]; + + for (r, key_injection_item) in key_injection_vec.iter().enumerate() { + aux.linear(mds, key_injection_item); + if r % 2 == 0 { + key_state_var = + PermutationGadget::, T, F>::pow_alpha_inv_state( + self, + &key_state_var, + )?; + key_state_var = self.affine_transform(&key_state_var, mds, key_injection_item)?; + } else { + key_state_var = + self.non_linear_transform(&key_state_var, mds, key_injection_item)?; + } + result.push(key_state_var.clone()); + } + + Ok(result) + } /// Return the variable corresponding to the output of the of the Rescue /// PRP where the rounds keys have already been computed "dynamically" @@ -332,7 +270,7 @@ pub(crate) trait RescueNonNativeHelperGadget: Circuit { /// * `mds_states` - Rescue MDS matrix /// * `key_vars` - variables corresponding to the scheduled keys /// * `returns` - - fn prp_with_round_keys( + fn prp_with_round_keys( &mut self, input_var: &RescueNonNativeStateVar, mds: &RescueMatrix, @@ -343,53 +281,34 @@ pub(crate) trait RescueNonNativeHelperGadget: Circuit { } let zero_state = RescueVector::from(&[T::zero(); STATE_SIZE]); - let mut state_var = self.add_state(input_var, &keys_vars[0])?; + let mut state_var = PermutationGadget::, T, F>::add_state( + self, + input_var, + &keys_vars[0], + )?; for (r, key_var) in keys_vars.iter().skip(1).enumerate() { if r % 2 == 0 { - state_var = self.pow_alpha_inv_state::(&state_var)?; + state_var = + PermutationGadget::, T, F>::pow_alpha_inv_state( + self, &state_var, + )?; state_var = self.affine_transform(&state_var, mds, &zero_state)?; } else { state_var = self.non_linear_transform(&state_var, mds, &zero_state)?; } - state_var = self.add_state(&state_var, key_var)?; - } - Ok(state_var) - } - - /// 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: RescueNonNativeStateVar, - mds: &RescueMatrix, - round_keys: &[RescueVector], - ) -> Result, CircuitError> { - if (round_keys.len() != 2 * ROUNDS + 1) || (mds.len() != STATE_SIZE) { - return Err(CircuitError::ParameterError("data_vars".to_string())); - } - - let mut state_var = self.add_constant_state(&input_var, &round_keys[0])?; - for (r, key) in round_keys.iter().skip(1).enumerate() { - if r % 2 == 0 { - state_var = self.pow_alpha_inv_state::(&state_var)?; - state_var = self.affine_transform(&state_var, mds, key)?; - } else { - state_var = self.non_linear_transform(&state_var, mds, key)?; - } + state_var = PermutationGadget::, T, F>::add_state( + self, &state_var, key_var, + )?; } Ok(state_var) } } -impl RescueNonNativeHelperGadget for PlonkCircuit +impl PermutationGadget, T, F> for PlonkCircuit where F: PrimeField, + T: RescueParameter, { fn check_var_bound_rescue_state( &self, @@ -403,13 +322,15 @@ where Ok(()) } - fn add_constant_state( + fn add_constant_state( &mut self, input_var: &RescueNonNativeStateVar, constant: &RescueVector, ) -> Result, CircuitError> { // Check bounds for every variable - self.check_var_bound_rescue_state(input_var)?; + PermutationGadget::, T, F>::check_var_bound_rescue_state( + self, input_var, + )?; // move constant to the plonk field let constant_f: Vec = constant @@ -444,16 +365,18 @@ where }) } - fn pow_alpha_inv_state( + fn pow_alpha_inv_state( &mut self, input_var: &RescueNonNativeStateVar, ) -> Result, CircuitError> { // Check bounds for every variable - self.check_var_bound_rescue_state(input_var)?; + PermutationGadget::, T, F>::check_var_bound_rescue_state( + self, input_var, + )?; let mut state = [FpElemVar::default(); STATE_SIZE]; for (e, f) in state.iter_mut().zip(input_var.state.iter()) { - *e = self.pow_alpha_inv::(*f)?; + *e = PermutationGadget::, T, F>::pow_alpha_inv(self, *f)?; } Ok(RescueNonNativeStateVar { @@ -462,14 +385,16 @@ where }) } - fn affine_transform( + fn affine_transform( &mut self, input_var: &RescueNonNativeStateVar, matrix: &RescueMatrix, constant: &RescueVector, ) -> Result, CircuitError> { // Check bounds for every variable - self.check_var_bound_rescue_state(input_var)?; + PermutationGadget::, T, F>::check_var_bound_rescue_state( + self, input_var, + )?; let m = input_var.state[0].param_m(); @@ -548,7 +473,7 @@ where }) } - fn non_linear_transform( + fn non_linear_transform( &mut self, input_var: &RescueNonNativeStateVar, matrix: &RescueMatrix, @@ -557,7 +482,9 @@ where let m = input_var.modulus.param_m(); // Check bounds for every variable - self.check_var_bound_rescue_state(input_var)?; + PermutationGadget::, T, F>::check_var_bound_rescue_state( + self, input_var, + )?; // 1 prepare the input vector let input_fp_elem_var = input_var.state; @@ -607,10 +534,7 @@ where } } - fn pow_alpha_inv( - &mut self, - input_var: FpElemVar, - ) -> Result, CircuitError> { + fn pow_alpha_inv(&mut self, input_var: FpElemVar) -> Result, CircuitError> { self.check_var_bound(input_var.components().0)?; self.check_var_bound(input_var.components().1)?; @@ -643,43 +567,19 @@ where } } - fn create_rescue_state_variable( - &mut self, - state: &RescueVector, - ) -> Result, CircuitError> { - // parameter m - let m = (T::size_in_bits() / 2 / self.range_bit_len()? + 1) * self.range_bit_len()?; - - // move the modulus to the right field - let t_modulus = F::from_le_bytes_mod_order(T::Params::MODULUS.to_bytes_le().as_ref()); - let t = FpElem::new(&t_modulus, m, None)?; - - // move rescue state to the plonk field - let state_f: Vec = state - .elems() - .iter() - .map(|x| field_switching::(x)) - .collect(); - - // create vars for states - let mut state_split_var = [FpElemVar::::default(); STATE_SIZE]; - for (var, f) in state_split_var.iter_mut().zip(state_f.iter()) { - *var = FpElemVar::new_from_field_element(self, f, m, Some(t.two_power_m()))?; - } - - Ok(RescueNonNativeStateVar { - state: state_split_var, - modulus: t, - }) - } - fn add_state( &mut self, left_state_var: &RescueNonNativeStateVar, right_state_var: &RescueNonNativeStateVar, ) -> Result, CircuitError> { - self.check_var_bound_rescue_state(left_state_var)?; - self.check_var_bound_rescue_state(right_state_var)?; + PermutationGadget::, T, F>::check_var_bound_rescue_state( + self, + left_state_var, + )?; + PermutationGadget::, T, F>::check_var_bound_rescue_state( + self, + right_state_var, + )?; if left_state_var.modulus != right_state_var.modulus { return Err(CircuitError::ParameterError( @@ -703,41 +603,42 @@ where }) } - fn key_schedule( + fn permutation_with_const_round_keys( &mut self, + input_var: RescueNonNativeStateVar, mds: &RescueMatrix, - key_var: &RescueNonNativeStateVar, - prp_instance: &PRP, - ) -> Result>, CircuitError> { - let mut aux = *prp_instance.init_vec_ref(); - let key_injection_vec = prp_instance.key_injection_vec_ref(); - - let mut key_state_var = self.add_constant_state(key_var, &aux)?; - let mut result = vec![key_state_var.clone()]; + round_keys: &[RescueVector], + ) -> Result, CircuitError> { + if (round_keys.len() != 2 * ROUNDS + 1) || (mds.len() != STATE_SIZE) { + return Err(CircuitError::ParameterError("data_vars".to_string())); + } - for (r, key_injection_item) in key_injection_vec.iter().enumerate() { - aux.linear(mds, key_injection_item); + let mut state_var = self.add_constant_state(&input_var, &round_keys[0])?; + for (r, key) in round_keys.iter().skip(1).enumerate() { if r % 2 == 0 { - key_state_var = self.pow_alpha_inv_state::(&key_state_var)?; - key_state_var = self.affine_transform(&key_state_var, mds, key_injection_item)?; + state_var = + PermutationGadget::, T, F>::pow_alpha_inv_state( + self, &state_var, + )?; + state_var = self.affine_transform(&state_var, mds, key)?; } else { - key_state_var = - self.non_linear_transform(&key_state_var, mds, key_injection_item)?; + state_var = self.non_linear_transform(&state_var, mds, key)?; } - result.push(key_state_var.clone()); } - - Ok(result) + Ok(state_var) } } #[cfg(test)] mod tests { - use super::{RescueNonNativeGadget, RescueNonNativeHelperGadget, RescueNonNativeStateVar}; - use crate::rescue::{ - sponge::{RescueCRHF, RescuePRF}, - Permutation, RescueMatrix, RescueParameter, RescueVector, CRHF_RATE, PRP, STATE_SIZE, + use super::{PermutationGadget, RescueNonNativeGadget, RescueNonNativeStateVar}; + use crate::{ + circuit::rescue::RescueGadget, + rescue::{ + 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; @@ -853,7 +754,11 @@ mod tests { RescueVector::from(&[T::from(12u32), T::from(2u32), T::from(8u32), T::from(9u32)]); let input_var = circuit.create_rescue_state_variable(&state).unwrap(); - let out_var = circuit.pow_alpha_inv_state::(&input_var).unwrap(); + let out_var = PermutationGadget::, T, F>::pow_alpha_inv_state( + &mut circuit, + &input_var, + ) + .unwrap(); let out_value: Vec = (0..STATE_SIZE) .map(|i| state.elems()[i].pow(T::A_INV)) @@ -930,7 +835,8 @@ mod tests { let perm = Permutation::::default(); let state_out = perm.eval(&state_in); - let out_var = circuit.rescue_permutation::(state_in_var).unwrap(); + let out_var = + RescueNonNativeGadget::::rescue_permutation(&mut circuit, state_in_var).unwrap(); check_state(&circuit, &out_var, &state_out); @@ -961,7 +867,12 @@ mod tests { let input1_var = circuit.create_rescue_state_variable(&state1).unwrap(); let input2_var = circuit.create_rescue_state_variable(&state2).unwrap(); - let out_var = circuit.add_state(&input1_var, &input2_var).unwrap(); + let out_var = PermutationGadget::, T, F>::add_state( + &mut circuit, + &input1_var, + &input2_var, + ) + .unwrap(); let out_value: Vec = (0..STATE_SIZE) .map(|i| state1.elems()[i] + state2.elems()[i]) @@ -1022,7 +933,8 @@ mod tests { ]); let key_var = circuit.create_rescue_state_variable(&key_vec).unwrap(); let input_var = circuit.create_rescue_state_variable(&input_vec).unwrap(); - let out_var = circuit.prp::(&key_var, &input_var).unwrap(); + let out_var = + RescueNonNativeGadget::::prp(&mut circuit, &key_var, &input_var).unwrap(); let out_val = prp.prp(&key_vec, &input_vec); @@ -1073,9 +985,12 @@ mod tests { // sponge no padding with output length 1 let expected_sponge = RescueCRHF::sponge_no_padding(&data_t, 1).unwrap()[0]; - let sponge_var = circuit - .rescue_sponge_no_padding::(data_vars.as_slice(), 1) - .unwrap()[0]; + let sponge_var = RescueNonNativeGadget::::rescue_sponge_no_padding( + &mut circuit, + data_vars.as_slice(), + 1, + ) + .unwrap()[0]; assert_eq!( field_switching::(&expected_sponge), @@ -1092,9 +1007,12 @@ mod tests { // general sponge no padding for output_len in 1..max_output_len { let expected_sponge = RescueCRHF::sponge_no_padding(&data_t, output_len).unwrap(); - let sponge_var = circuit - .rescue_sponge_no_padding::(data_vars.as_slice(), output_len) - .unwrap(); + let sponge_var = RescueNonNativeGadget::::rescue_sponge_no_padding( + &mut circuit, + data_vars.as_slice(), + output_len, + ) + .unwrap(); for (e, f) in expected_sponge.iter().zip(sponge_var.iter()) { assert_eq!(field_switching::(e), f.witness(&circuit).unwrap()); } @@ -1118,9 +1036,12 @@ mod tests { .map(|x| FpElemVar::new_from_field_element(&mut circuit, x, m, None).unwrap()) .collect(); - assert!(circuit - .rescue_sponge_no_padding::(data_vars.as_slice(), 1) - .is_err()); + assert!(RescueNonNativeGadget::::rescue_sponge_no_padding( + &mut circuit, + data_vars.as_slice(), + 1 + ) + .is_err()); } #[test] @@ -1155,9 +1076,12 @@ mod tests { let expected_sponge = RescueCRHF::sponge_with_padding(&data_t, 1); // sponge with padding - let sponge_var = circuit - .rescue_sponge_with_padding::(data_vars.as_slice(), 1) - .unwrap()[0]; + let sponge_var = RescueNonNativeGadget::::rescue_sponge_with_padding( + &mut circuit, + data_vars.as_slice(), + 1, + ) + .unwrap()[0]; assert_eq!( field_switching::(&expected_sponge[0]), @@ -1175,9 +1099,12 @@ mod tests { for output_len in 1..max_output_len { let expected_sponge = RescueCRHF::sponge_with_padding(&data_t, output_len); - let sponge_var = circuit - .rescue_sponge_with_padding::(data_vars.as_slice(), output_len) - .unwrap(); + let sponge_var = RescueNonNativeGadget::::rescue_sponge_with_padding( + &mut circuit, + data_vars.as_slice(), + output_len, + ) + .unwrap(); for (e, f) in expected_sponge.iter().zip(sponge_var.iter()) { assert_eq!(field_switching::(e), f.witness(&circuit).unwrap()); @@ -1213,9 +1140,9 @@ mod tests { FpElemVar::new_from_field_element(&mut circuit, &input_vec_f[1], m, None).unwrap(), FpElemVar::new_from_field_element(&mut circuit, &input_vec_f[2], m, None).unwrap(), ]; - let out_var = circuit - .rescue_sponge_no_padding::(&input_var, 1) - .unwrap()[0]; + let out_var = + RescueNonNativeGadget::::rescue_sponge_no_padding(&mut circuit, &input_var, 1) + .unwrap()[0]; // Check consistency between inputs for i in 0..rate { @@ -1270,9 +1197,12 @@ mod tests { 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::(key_var, &data_vars) - .unwrap(); + let fsks_var = RescueNonNativeGadget::::rescue_full_state_keyed_sponge_no_padding( + &mut circuit, + key_var, + &data_vars, + ) + .unwrap(); // Check prf output consistency assert_eq!( @@ -1293,8 +1223,13 @@ mod tests { Some(key_var.two_power_m()), ); data_vars.push(zero_var); - assert!(circuit - .rescue_full_state_keyed_sponge_no_padding::(key_var, &data_vars) - .is_err()); + assert!( + RescueNonNativeGadget::::rescue_full_state_keyed_sponge_no_padding( + &mut circuit, + key_var, + &data_vars + ) + .is_err() + ); } } diff --git a/primitives/src/circuit/signature/schnorr.rs b/primitives/src/circuit/signature/schnorr.rs index da0264b7d..bc3083301 100644 --- a/primitives/src/circuit/signature/schnorr.rs +++ b/primitives/src/circuit/signature/schnorr.rs @@ -7,7 +7,7 @@ //! Circuit implementation of a Schnorr signature scheme. use crate::{ - circuit::rescue::RescueGadget, + circuit::rescue::RescueNativeGadget, constants::CS_ID_SCHNORR, rescue::RescueParameter, signatures::schnorr::{Signature, VerKey}, @@ -185,7 +185,8 @@ where ]; chal_input.extend(msg); - let challenge = self.rescue_sponge_with_padding(&chal_input, 1)?[0]; + let challenge = + RescueNativeGadget::::rescue_sponge_with_padding(self, &chal_input, 1)?[0]; let c_bits = self.unpack(challenge, field_bit_len::())?; Ok(c_bits[..challenge_bit_len::()].to_vec()) }