From 0ad54576ec6462d63313ebde18bb0a24669fd00e Mon Sep 17 00:00:00 2001 From: arnaucube Date: Tue, 10 Sep 2024 17:10:00 +0200 Subject: [PATCH] implement HyperNova's DeciderEth (#156) * implement HyperNova's DeciderEth * add remark about Nova's zk layer implementation and the 3 identified use cases --- examples/circom_full_flow.rs | 2 +- examples/full_flow.rs | 2 +- examples/noir_full_flow.rs | 2 +- examples/noname_full_flow.rs | 2 +- .../src/folding/hypernova/decider_eth.rs | 312 ++++++++++++++++++ .../folding/hypernova/decider_eth_circuit.rs | 2 +- folding-schemes/src/folding/hypernova/mod.rs | 25 +- .../src/folding/hypernova/nimfs.rs | 4 +- .../src/folding/nova/decider_eth.rs | 11 +- folding-schemes/src/folding/nova/zk.rs | 33 +- folding-schemes/src/lib.rs | 2 +- .../src/verifiers/nova_cyclefold.rs | 2 +- 12 files changed, 372 insertions(+), 27 deletions(-) create mode 100644 folding-schemes/src/folding/hypernova/decider_eth.rs diff --git a/examples/circom_full_flow.rs b/examples/circom_full_flow.rs index 8db4a16..10a79ba 100644 --- a/examples/circom_full_flow.rs +++ b/examples/circom_full_flow.rs @@ -89,7 +89,7 @@ fn main() { let mut nova = N::init(&nova_params, f_circuit.clone(), z_0).unwrap(); // prepare the Decider prover & verifier params - let (decider_pp, decider_vp) = D::preprocess(&mut rng, &nova_params, nova.clone()).unwrap(); + let (decider_pp, decider_vp) = D::preprocess(&mut rng, nova_params, nova.clone()).unwrap(); // run n steps of the folding iteration for (i, external_inputs_at_step) in external_inputs.iter().enumerate() { diff --git a/examples/full_flow.rs b/examples/full_flow.rs index 5c9ce18..bf1f28f 100644 --- a/examples/full_flow.rs +++ b/examples/full_flow.rs @@ -106,7 +106,7 @@ fn main() { let mut nova = N::init(&nova_params, f_circuit, z_0).unwrap(); // prepare the Decider prover & verifier params - let (decider_pp, decider_vp) = D::preprocess(&mut rng, &nova_params, nova.clone()).unwrap(); + let (decider_pp, decider_vp) = D::preprocess(&mut rng, nova_params, nova.clone()).unwrap(); // run n steps of the folding iteration for i in 0..n_steps { diff --git a/examples/noir_full_flow.rs b/examples/noir_full_flow.rs index 1d5ba52..ec5107a 100644 --- a/examples/noir_full_flow.rs +++ b/examples/noir_full_flow.rs @@ -79,7 +79,7 @@ fn main() { let mut nova = N::init(&nova_params, f_circuit.clone(), z_0).unwrap(); // prepare the Decider prover & verifier params - let (decider_pp, decider_vp) = D::preprocess(&mut rng, &nova_params, nova.clone()).unwrap(); + let (decider_pp, decider_vp) = D::preprocess(&mut rng, nova_params, nova.clone()).unwrap(); // run n steps of the folding iteration for i in 0..5 { diff --git a/examples/noname_full_flow.rs b/examples/noname_full_flow.rs index a095475..73a1a67 100644 --- a/examples/noname_full_flow.rs +++ b/examples/noname_full_flow.rs @@ -89,7 +89,7 @@ fn main() { let mut nova = N::init(&nova_params, f_circuit.clone(), z_0).unwrap(); // prepare the Decider prover & verifier params - let (decider_pp, decider_vp) = D::preprocess(&mut rng, &nova_params, nova.clone()).unwrap(); + let (decider_pp, decider_vp) = D::preprocess(&mut rng, nova_params, nova.clone()).unwrap(); // run n steps of the folding iteration for (i, external_inputs_at_step) in external_inputs.iter().enumerate() { diff --git a/folding-schemes/src/folding/hypernova/decider_eth.rs b/folding-schemes/src/folding/hypernova/decider_eth.rs new file mode 100644 index 0000000..381a6b3 --- /dev/null +++ b/folding-schemes/src/folding/hypernova/decider_eth.rs @@ -0,0 +1,312 @@ +/// This file implements the HyperNova's onchain (Ethereum's EVM) decider. +use ark_crypto_primitives::sponge::Absorb; +use ark_ec::{CurveGroup, Group}; +use ark_ff::PrimeField; +use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget}; +use ark_snark::SNARK; +use ark_std::rand::{CryptoRng, RngCore}; +use ark_std::{One, Zero}; +use core::marker::PhantomData; + +pub use super::decider_eth_circuit::DeciderEthCircuit; +use super::{lcccs::LCCCS, HyperNova}; +use crate::commitment::{ + kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme, +}; +use crate::folding::circuits::{nonnative::affine::NonNativeAffineVar, CF2}; +use crate::frontend::FCircuit; +use crate::Error; +use crate::{Decider as DeciderTrait, FoldingScheme}; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct Proof +where + C1: CurveGroup, + CS1: CommitmentScheme, + S: SNARK, +{ + snark_proof: S::Proof, + kzg_proof: CS1::Proof, + // rho used at the last fold, U_{i+1}=NIMFS.V(rho, U_i, u_i), it is checked in-circuit + rho: C1::ScalarField, + U_i1: LCCCS, // U_{i+1}, which is checked in-circuit + // the KZG challenge is provided by the prover, but in-circuit it is checked to match + // the in-circuit computed computed one. + kzg_challenge: C1::ScalarField, +} + +/// Onchain Decider, for ethereum use cases +#[derive(Clone, Debug)] +pub struct Decider { + _c1: PhantomData, + _gc1: PhantomData, + _c2: PhantomData, + _gc2: PhantomData, + _fc: PhantomData, + _cs1: PhantomData, + _cs2: PhantomData, + _s: PhantomData, + _fs: PhantomData, +} + +impl + DeciderTrait for Decider +where + C1: CurveGroup, + C2: CurveGroup, + GC1: CurveVar> + ToConstraintFieldGadget>, + GC2: CurveVar> + ToConstraintFieldGadget>, + FC: FCircuit, + // CS1 is a KZG commitment, where challenge is C1::Fr elem + CS1: CommitmentScheme< + C1, + ProverChallenge = C1::ScalarField, + Challenge = C1::ScalarField, + Proof = KZGProof, + >, + // enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider + CS2: CommitmentScheme>, + S: SNARK, + FS: FoldingScheme, + ::BaseField: PrimeField, + ::BaseField: PrimeField, + ::ScalarField: Absorb, + ::ScalarField: Absorb, + C1: CurveGroup, + for<'b> &'b GC1: GroupOpsBounds<'b, C1, GC1>, + for<'b> &'b GC2: GroupOpsBounds<'b, C2, GC2>, + // constrain FS into HyperNova, since this is a Decider specifically for HyperNova + HyperNova: From, + crate::folding::hypernova::ProverParams: + From<>::ProverParam>, + crate::folding::hypernova::VerifierParams: + From<>::VerifierParam>, +{ + type PreprocessorParam = (FS::ProverParam, FS::VerifierParam); + type ProverParam = (S::ProvingKey, CS1::ProverParams); + type Proof = Proof; + /// VerifierParam = (pp_hash, snark::vk, commitment_scheme::vk) + type VerifierParam = (C1::ScalarField, S::VerifyingKey, CS1::VerifierParams); + type PublicInput = Vec; + type CommittedInstance = (); + + fn preprocess( + mut rng: impl RngCore + CryptoRng, + prep_param: Self::PreprocessorParam, + fs: FS, + ) -> Result<(Self::ProverParam, Self::VerifierParam), Error> { + let circuit = + DeciderEthCircuit::::from_hypernova::( + fs.into(), + ) + .unwrap(); + + // get the Groth16 specific setup for the circuit + let (g16_pk, g16_vk) = S::circuit_specific_setup(circuit, &mut rng).unwrap(); + + // get the FoldingScheme prover & verifier params from HyperNova + #[allow(clippy::type_complexity)] + let hypernova_pp: as FoldingScheme< + C1, + C2, + FC, + >>::ProverParam = prep_param.0.into(); + #[allow(clippy::type_complexity)] + let hypernova_vp: as FoldingScheme< + C1, + C2, + FC, + >>::VerifierParam = prep_param.1.into(); + let pp_hash = hypernova_vp.pp_hash()?; + + let pp = (g16_pk, hypernova_pp.cs_pp); + let vp = (pp_hash, g16_vk, hypernova_vp.cs_vp); + Ok((pp, vp)) + } + + fn prove( + mut rng: impl RngCore + CryptoRng, + pp: Self::ProverParam, + folding_scheme: FS, + ) -> Result { + let (snark_pk, cs_pk): (S::ProvingKey, CS1::ProverParams) = pp; + + let circuit = DeciderEthCircuit::::from_hypernova::( + folding_scheme.into(), + )?; + + let snark_proof = S::prove(&snark_pk, circuit.clone(), &mut rng) + .map_err(|e| Error::Other(e.to_string()))?; + + // Notice that since the `circuit` has been constructed at the `from_hypernova` call, which + // in case of failure it would have returned an error there, the next two unwraps should + // never reach an error. + let rho_Fr = circuit.rho.ok_or(Error::Empty)?; + let W_i1 = circuit.W_i1.ok_or(Error::Empty)?; + + // get the challenges that have been already computed when preparing the circuit inputs in + // the above `from_hypernova` call + let challenge_W = circuit + .kzg_challenge + .ok_or(Error::MissingValue("kzg_challenge".to_string()))?; + + // generate KZG proofs + let U_cmW_proof = CS1::prove_with_challenge( + &cs_pk, + challenge_W, + &W_i1.w, + &C1::ScalarField::zero(), + None, + )?; + + Ok(Self::Proof { + snark_proof, + kzg_proof: U_cmW_proof, + rho: rho_Fr, + U_i1: circuit.U_i1.ok_or(Error::Empty)?, + kzg_challenge: challenge_W, + }) + } + + fn verify( + vp: Self::VerifierParam, + i: C1::ScalarField, + z_0: Vec, + z_i: Vec, + // we don't use the instances at the verifier level, since we check them in-circuit + _running_instance: &Self::CommittedInstance, + _incoming_instance: &Self::CommittedInstance, + proof: &Self::Proof, + ) -> Result { + if i <= C1::ScalarField::one() { + return Err(Error::NotEnoughSteps); + } + + let (pp_hash, snark_vk, cs_vk): (C1::ScalarField, S::VerifyingKey, CS1::VerifierParams) = + vp; + + // Note: the NIMFS proof is checked inside the DeciderEthCircuit, which ensures that the + // 'proof.U_i1' is correctly computed + + let (cmC_x, cmC_y) = NonNativeAffineVar::inputize(proof.U_i1.C)?; + + let public_input: Vec = [ + vec![pp_hash, i], + z_0, + z_i, + // U_i+1: + cmC_x, + cmC_y, + vec![proof.U_i1.u], + proof.U_i1.x.clone(), + proof.U_i1.r_x.clone(), + proof.U_i1.v.clone(), + vec![proof.kzg_challenge, proof.kzg_proof.eval, proof.rho], + ] + .concat(); + + let snark_v = S::verify(&snark_vk, &public_input, &proof.snark_proof) + .map_err(|e| Error::Other(e.to_string()))?; + if !snark_v { + return Err(Error::SNARKVerificationFail); + } + + // we're at the Ethereum EVM case, so the CS1 is KZG commitments + CS1::verify_with_challenge(&cs_vk, proof.kzg_challenge, &proof.U_i1.C, &proof.kzg_proof)?; + + Ok(true) + } +} + +#[cfg(test)] +pub mod tests { + use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; + use ark_groth16::Groth16; + use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use std::time::Instant; + + use super::*; + use crate::commitment::{kzg::KZG, pedersen::Pedersen}; + use crate::folding::hypernova::PreprocessorParam; + use crate::frontend::tests::CubicFCircuit; + use crate::transcript::poseidon::poseidon_canonical_config; + + #[test] + fn test_decider() { + const MU: usize = 1; + const NU: usize = 1; + // use HyperNova as FoldingScheme + type HN = HyperNova< + Projective, + GVar, + Projective2, + GVar2, + CubicFCircuit, + KZG<'static, Bn254>, + Pedersen, + MU, + NU, + false, + >; + type D = Decider< + Projective, + GVar, + Projective2, + GVar2, + CubicFCircuit, + KZG<'static, Bn254>, + Pedersen, + Groth16, // here we define the Snark to use in the decider + HN, // here we define the FoldingScheme to use + MU, + NU, + >; + + let mut rng = ark_std::test_rng(); + let poseidon_config = poseidon_canonical_config::(); + + let F_circuit = CubicFCircuit::::new(()).unwrap(); + let z_0 = vec![Fr::from(3_u32)]; + + let prep_param = PreprocessorParam::new(poseidon_config, F_circuit); + let hypernova_params = HN::preprocess(&mut rng, &prep_param).unwrap(); + + let start = Instant::now(); + let mut hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone()).unwrap(); + println!("Nova initialized, {:?}", start.elapsed()); + let start = Instant::now(); + hypernova + .prove_step(&mut rng, vec![], Some((vec![], vec![]))) + .unwrap(); + println!("prove_step, {:?}", start.elapsed()); + hypernova + .prove_step(&mut rng, vec![], Some((vec![], vec![]))) + .unwrap(); // do a 2nd step + + let mut rng = rand::rngs::OsRng; + + // prepare the Decider prover & verifier params + let (decider_pp, decider_vp) = + D::preprocess(&mut rng, hypernova_params, hypernova.clone()).unwrap(); + + // decider proof generation + let start = Instant::now(); + let proof = D::prove(rng, decider_pp, hypernova.clone()).unwrap(); + println!("Decider prove, {:?}", start.elapsed()); + + // decider proof verification + let start = Instant::now(); + let verified = D::verify( + decider_vp, + hypernova.i, + hypernova.z_0, + hypernova.z_i, + &(), + &(), + &proof, + ) + .unwrap(); + assert!(verified); + println!("Decider verify, {:?}", start.elapsed()); + } +} diff --git a/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs b/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs index ac95cbb..ec8c650 100644 --- a/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs @@ -231,7 +231,7 @@ where cf_E_len: hn.cf_W_i.E.len(), ccs: hn.ccs, cf_r1cs: hn.cf_r1cs, - cf_pedersen_params: hn.cf_cs_params, + cf_pedersen_params: hn.cf_cs_pp, poseidon_config: hn.poseidon_config, pp_hash: Some(hn.pp_hash), i: Some(hn.i), diff --git a/folding-schemes/src/folding/hypernova/mod.rs b/folding-schemes/src/folding/hypernova/mod.rs index c2656a0..fe75a9b 100644 --- a/folding-schemes/src/folding/hypernova/mod.rs +++ b/folding-schemes/src/folding/hypernova/mod.rs @@ -10,6 +10,7 @@ use ark_std::{fmt::Debug, marker::PhantomData, rand::RngCore, One, Zero}; pub mod cccs; pub mod circuits; +pub mod decider_eth; pub mod decider_eth_circuit; pub mod lcccs; pub mod nimfs; @@ -84,8 +85,8 @@ where CS2: CommitmentScheme, { pub poseidon_config: PoseidonConfig, - pub cs_params: CS1::ProverParams, - pub cf_cs_params: CS2::ProverParams, + pub cs_pp: CS1::ProverParams, + pub cf_cs_pp: CS2::ProverParams, // if ccs is set, it will be used, if not, it will be computed at runtime pub ccs: Option>, } @@ -162,9 +163,9 @@ pub struct HyperNova< pub cf_r1cs: R1CS, pub poseidon_config: PoseidonConfig, /// CommitmentScheme::ProverParams over C1 - pub cs_params: CS1::ProverParams, + pub cs_pp: CS1::ProverParams, /// CycleFold CommitmentScheme::ProverParams, over C2 - pub cf_cs_params: CS2::ProverParams, + pub cf_cs_pp: CS2::ProverParams, /// F circuit, the circuit that is being folded pub F: FC, /// public params hash @@ -221,7 +222,7 @@ where // assign them directly to w_i, u_i. let (U_i, W_i) = self .ccs - .to_lcccs::<_, _, CS1, H>(&mut rng, &self.cs_params, &r1cs_z)?; + .to_lcccs::<_, _, CS1, H>(&mut rng, &self.cs_pp, &r1cs_z)?; #[cfg(test)] U_i.check_relation(&self.ccs, &W_i)?; @@ -243,7 +244,7 @@ where // assign them directly to w_i, u_i. let (u_i, w_i) = self .ccs - .to_cccs::<_, _, CS1, H>(&mut rng, &self.cs_params, &r1cs_z)?; + .to_cccs::<_, _, CS1, H>(&mut rng, &self.cs_pp, &r1cs_z)?; #[cfg(test)] u_i.check_relation(&self.ccs, &w_i)?; @@ -426,8 +427,8 @@ where let pp = ProverParams:: { poseidon_config: prep_param.poseidon_config.clone(), - cs_params: cs_pp.clone(), - cf_cs_params: cf_cs_pp.clone(), + cs_pp, + cf_cs_pp, ccs: Some(ccs.clone()), }; let vp = VerifierParams:: { @@ -496,8 +497,8 @@ where ccs, cf_r1cs, poseidon_config: pp.poseidon_config.clone(), - cs_params: pp.cs_params.clone(), - cf_cs_params: pp.cf_cs_params.clone(), + cs_pp: pp.cs_pp.clone(), + cf_cs_pp: pp.cf_cs_pp.clone(), F, pp_hash, i: C1::ScalarField::zero(), @@ -736,7 +737,7 @@ where >( &mut transcript_p, self.cf_r1cs.clone(), - self.cf_cs_params.clone(), + self.cf_cs_pp.clone(), self.pp_hash, self.cf_W_i.clone(), // CycleFold running instance witness self.cf_U_i.clone(), // CycleFold running instance @@ -796,7 +797,7 @@ where // assign them directly to w_i, u_i. let (u_i, w_i) = self .ccs - .to_cccs::<_, C1, CS1, H>(&mut rng, &self.cs_params, &r1cs_z)?; + .to_cccs::<_, C1, CS1, H>(&mut rng, &self.cs_pp, &r1cs_z)?; self.u_i = u_i.clone(); self.w_i = w_i.clone(); diff --git a/folding-schemes/src/folding/hypernova/nimfs.rs b/folding-schemes/src/folding/hypernova/nimfs.rs index 2a70b28..6312162 100644 --- a/folding-schemes/src/folding/hypernova/nimfs.rs +++ b/folding-schemes/src/folding/hypernova/nimfs.rs @@ -23,7 +23,7 @@ use std::fmt::Debug; use std::marker::PhantomData; /// NIMFSProof defines a multifolding proof -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct NIMFSProof { pub sc_proof: SumCheckProof, pub sigmas_thetas: SigmasThetas, @@ -51,7 +51,7 @@ impl NIMFSProof { } } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct SigmasThetas(pub Vec>, pub Vec>); #[derive(Debug)] diff --git a/folding-schemes/src/folding/nova/decider_eth.rs b/folding-schemes/src/folding/nova/decider_eth.rs index 5a26813..6377b31 100644 --- a/folding-schemes/src/folding/nova/decider_eth.rs +++ b/folding-schemes/src/folding/nova/decider_eth.rs @@ -1,4 +1,4 @@ -/// This file implements the onchain (Ethereum's EVM) decider. +/// This file implements the Nova's onchain (Ethereum's EVM) decider. use ark_bn254::Bn254; use ark_crypto_primitives::sponge::Absorb; use ark_ec::{AffineRepr, CurveGroup, Group}; @@ -11,7 +11,7 @@ use ark_std::rand::{CryptoRng, RngCore}; use ark_std::{One, Zero}; use core::marker::PhantomData; -pub use super::decider_eth_circuit::{DeciderEthCircuit, KZGChallengesGadget}; +pub use super::decider_eth_circuit::DeciderEthCircuit; use super::{nifs::NIFS, CommittedInstance, Nova}; use crate::commitment::{ kzg::{Proof as KZGProof, KZG}, @@ -109,7 +109,7 @@ where fn preprocess( mut rng: impl RngCore + CryptoRng, - prep_param: &Self::PreprocessorParam, + prep_param: Self::PreprocessorParam, fs: FS, ) -> Result<(Self::ProverParam, Self::VerifierParam), Error> { let circuit = @@ -384,7 +384,7 @@ pub mod tests { println!("Nova initialized, {:?}", start.elapsed()); // prepare the Decider prover & verifier params - let (decider_pp, decider_vp) = D::preprocess(&mut rng, &nova_params, nova.clone()).unwrap(); + let (decider_pp, decider_vp) = D::preprocess(&mut rng, nova_params, nova.clone()).unwrap(); let start = Instant::now(); nova.prove_step(&mut rng, vec![], None).unwrap(); @@ -461,7 +461,8 @@ pub mod tests { println!("Nova initialized, {:?}", start.elapsed()); // prepare the Decider prover & verifier params - let (decider_pp, decider_vp) = D::preprocess(&mut rng, &nova_params, nova.clone()).unwrap(); + let (decider_pp, decider_vp) = + D::preprocess(&mut rng, nova_params.clone(), nova.clone()).unwrap(); // serialize the Nova params. These params are the trusted setup of the commitment schemes used // (ie. KZG & Pedersen in this case) diff --git a/folding-schemes/src/folding/nova/zk.rs b/folding-schemes/src/folding/nova/zk.rs index 3ec198e..ca4506f 100644 --- a/folding-schemes/src/folding/nova/zk.rs +++ b/folding-schemes/src/folding/nova/zk.rs @@ -1,4 +1,35 @@ -// Implements nova's zero-knowledge layer, as described in https://eprint.iacr.org/2023/573.pdf +/// Implements Nova's zero-knowledge layer, as described in https://eprint.iacr.org/2023/573.pdf. +/// +/// Remark: this zk layer implementation only covers a subset of the use cases: +/// +/// We identify 3 interesting places to use the nova zk-layer: one before all the folding pipeline +/// (Use-case-1), one at the end of the folding pipeline right before the final Decider SNARK +/// proof (Use-case-2), and a third one for cases where compressed SNARK proofs are not needed, and +/// just IVC proofs (bigger than SNARK proofs) suffice (Use-case-3): +/// +/// * Use-case-1: at the beginning of the folding pipeline, right when the user has their original +/// instance prior to be folded into the running instance, the user can fold it with the +/// random-satisfying-instance to then have a blinded instance that can be sent to a server that +/// will fold it with the running instance. +/// --> In this one, the user could externalize all the IVC folding and also the Decider +/// final proof generation to a server. +/// * Use-case-2: at the end of all the IVC folding steps (after n iterations of nova.prove_step), +/// to 'blind' the IVC proof so then it can be sent to a server that will generate the final +/// decider snark proof. +/// --> In this one, the user could externalize the Decider final proof generation to a +/// server. +/// * Use-case-3: the user does not care about the Decider (final compressed SNARK proof), and +/// wants to generate a zk-proof of the IVC state to an IVC verifier (without any SNARK proof +/// involved). Note that this proof will be much bigger and expensive to verify than a Decider +/// SNARK proof. +/// +/// The current implementation covers the Use-case-3. +/// Use-case-1 can be achieved directly by a simpler version of the zk IVC scheme skipping steps +/// and implemented directly at the app level by folding the original instance with a randomized +/// instance (steps 2,3,4 from section D.4 of the [HyperNova](https://eprint.iacr.org/2023/573.pdf) +/// paper). +/// And the Use-case-2 would require a modified version of the Decider circuits. +/// use crate::folding::nova::traits::NovaR1CS; use ark_crypto_primitives::sponge::CryptographicSponge; use ark_ff::{BigInteger, PrimeField}; diff --git a/folding-schemes/src/lib.rs b/folding-schemes/src/lib.rs index 9082169..e4b22ef 100644 --- a/folding-schemes/src/lib.rs +++ b/folding-schemes/src/lib.rs @@ -219,7 +219,7 @@ pub trait Decider< fn preprocess( rng: impl RngCore + CryptoRng, - prep_param: &Self::PreprocessorParam, + prep_param: Self::PreprocessorParam, fs: FS, ) -> Result<(Self::ProverParam, Self::VerifierParam), Error>; diff --git a/solidity-verifiers/src/verifiers/nova_cyclefold.rs b/solidity-verifiers/src/verifiers/nova_cyclefold.rs index 9e896bd..e82bd1f 100644 --- a/solidity-verifiers/src/verifiers/nova_cyclefold.rs +++ b/solidity-verifiers/src/verifiers/nova_cyclefold.rs @@ -346,7 +346,7 @@ mod tests { ) .unwrap(); let decider_params = - DECIDER::preprocess(&mut rng, &nova_params.clone(), nova.clone()).unwrap(); + DECIDER::preprocess(&mut rng, nova_params.clone(), nova.clone()).unwrap(); (nova_params, decider_params) }