Implement HyperNova's IVC into the FoldingScheme trait (#116)

- implement the IVC `FoldingScheme` trait for HyperNova
- refactor Nova's preprocess logic to make it simplier to use
- add to Decider trait (& Nova's DeciderEth) a preprocess method
- get rid of the `init_nova_ivc_params` and `init_ivc_and_decider_params` methods in `examples` since this is achieved with the `FS::preprocess` & `Decider::preprocess` methods
  - (update the examples code to the simplified interface using
    FS::preprocess & Decider::preprocess)
This commit is contained in:
arnaucube
2024-07-04 11:14:31 +02:00
committed by GitHub
parent 456dc9f7a1
commit b5667968f4
25 changed files with 1144 additions and 465 deletions

View File

@@ -62,12 +62,13 @@ where
GC1: CurveVar<C1, CF2<C1>> + ToConstraintFieldGadget<CF2<C1>>,
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
FC: FCircuit<C1::ScalarField>,
// CS1 is a KZG commitment, where challenge is C1::Fr elem
CS1: CommitmentScheme<
C1,
ProverChallenge = C1::ScalarField,
Challenge = C1::ScalarField,
Proof = KZGProof<C1>,
>, // KZG commitment, where challenge is C1::Fr elem
>,
// enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider
CS2: CommitmentScheme<C2, ProverParams = PedersenParams<C2>>,
S: SNARK<C1::ScalarField>,
@@ -77,20 +78,52 @@ where
<C1 as Group>::ScalarField: Absorb,
<C2 as Group>::ScalarField: Absorb,
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
for<'b> &'b GC1: GroupOpsBounds<'b, C1, GC1>,
for<'b> &'b GC2: GroupOpsBounds<'b, C2, GC2>,
// constrain FS into Nova, since this is a Decider specifically for Nova
Nova<C1, GC1, C2, GC2, FC, CS1, CS2>: From<FS>,
crate::folding::nova::ProverParams<C1, C2, CS1, CS2>:
From<<FS as FoldingScheme<C1, C2, FC>>::ProverParam>,
crate::folding::nova::VerifierParams<C1, C2, CS1, CS2>:
From<<FS as FoldingScheme<C1, C2, FC>>::VerifierParam>,
{
type PreprocessorParam = (FS::ProverParam, FS::VerifierParam);
type ProverParam = (S::ProvingKey, CS1::ProverParams);
type Proof = Proof<C1, CS1, S>;
type VerifierParam = (S::VerifyingKey, CS1::VerifierParams);
type PublicInput = Vec<C1::ScalarField>;
type CommittedInstanceWithWitness = ();
type CommittedInstance = CommittedInstance<C1>;
fn prove(
pp: Self::ProverParam,
fn preprocess(
mut rng: impl RngCore + CryptoRng,
prep_param: &Self::PreprocessorParam,
fs: FS,
) -> Result<(Self::ProverParam, Self::VerifierParam), Error> {
let circuit =
DeciderEthCircuit::<C1, GC1, C2, GC2, CS1, CS2>::from_nova::<FC>(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 Nova
#[allow(clippy::type_complexity)]
let nova_pp:
<Nova<C1, GC1, C2, GC2, FC, CS1, CS2> as FoldingScheme<C1, C2, FC>>::ProverParam =
prep_param.0.clone().into()
;
#[allow(clippy::type_complexity)]
let nova_vp:
<Nova<C1, GC1, C2, GC2, FC, CS1, CS2> as FoldingScheme<C1, C2, FC>>::VerifierParam =
prep_param.1.clone().into();
let pp = (g16_pk, nova_pp.cs_pp);
let vp = (g16_vk, nova_vp.cs_vp);
Ok((pp, vp))
}
fn prove(
mut rng: impl RngCore + CryptoRng,
pp: Self::ProverParam,
folding_scheme: FS,
) -> Result<Self::Proof, Error> {
let (snark_pk, cs_pk): (S::ProvingKey, CS1::ProverParams) = pp;
@@ -281,13 +314,13 @@ fn point2_to_eth_format(p: ark_bn254::G2Affine) -> Result<Vec<u8>, Error> {
#[cfg(test)]
pub mod tests {
use super::*;
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 ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
use std::time::Instant;
use super::*;
use crate::commitment::kzg::{ProverKey as KZGProverKey, KZG};
use crate::commitment::pedersen::Pedersen;
use crate::folding::nova::{get_cs_params_len, ProverParams};
@@ -297,7 +330,7 @@ pub mod tests {
#[test]
fn test_decider() {
// use Nova as FoldingScheme
type NOVA = Nova<
type N = Nova<
Projective,
GVar,
Projective2,
@@ -306,7 +339,7 @@ pub mod tests {
KZG<'static, Bn254>,
Pedersen<Projective2>,
>;
type DECIDER = Decider<
type D = Decider<
Projective,
GVar,
Projective2,
@@ -315,7 +348,7 @@ pub mod tests {
KZG<'static, Bn254>,
Pedersen<Projective2>,
Groth16<Bn254>, // here we define the Snark to use in the decider
NOVA, // here we define the FoldingScheme to use
N, // here we define the FoldingScheme to use
>;
let mut rng = ark_std::test_rng();
@@ -339,17 +372,17 @@ pub mod tests {
let prover_params =
ProverParams::<Projective, Projective2, KZG<Bn254>, Pedersen<Projective2>> {
poseidon_config: poseidon_config.clone(),
cs_params: kzg_pk.clone(),
cf_cs_params: cf_pedersen_params,
cs_pp: kzg_pk.clone(),
cf_cs_pp: cf_pedersen_params,
};
let start = Instant::now();
let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
println!("Nova initialized, {:?}", start.elapsed());
let start = Instant::now();
nova.prove_step(vec![]).unwrap();
nova.prove_step(&mut rng, vec![]).unwrap();
println!("prove_step, {:?}", start.elapsed());
nova.prove_step(vec![]).unwrap(); // do a 2nd step
nova.prove_step(&mut rng, vec![]).unwrap(); // do a 2nd step
// generate Groth16 setup
let circuit = DeciderEthCircuit::<
@@ -371,13 +404,13 @@ pub mod tests {
// decider proof generation
let start = Instant::now();
let decider_pp = (g16_pk, kzg_pk);
let proof = DECIDER::prove(decider_pp, rng, nova.clone()).unwrap();
let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
println!("Decider prove, {:?}", start.elapsed());
// decider proof verification
let start = Instant::now();
let decider_vp = (g16_vk, kzg_vk);
let verified = DECIDER::verify(
let verified = D::verify(
decider_vp, nova.i, nova.z_0, nova.z_i, &nova.U_i, &nova.u_i, &proof,
)
.unwrap();

View File

@@ -264,7 +264,7 @@ where
) -> Result<Self, Error> {
// compute the U_{i+1}, W_{i+1}
let (T, cmT) = NIFS::<C1, CS1>::compute_cmT(
&nova.cs_params,
&nova.cs_pp,
&nova.r1cs.clone(),
&nova.w_i.clone(),
&nova.u_i.clone(),
@@ -315,7 +315,7 @@ where
cf_E_len: nova.cf_W_i.E.len(),
r1cs: nova.r1cs,
cf_r1cs: nova.cf_r1cs,
cf_pedersen_params: nova.cf_cs_params,
cf_pedersen_params: nova.cf_cs_pp,
poseidon_config: nova.poseidon_config,
i: Some(nova.i),
z_0: Some(nova.z_0),
@@ -438,7 +438,7 @@ where
// imports here instead of at the top of the file, so we avoid having multiple
// `#[cfg(not(test))]`
use crate::commitment::pedersen::PedersenGadget;
use crate::folding::nova::cyclefold::{CycleFoldCommittedInstanceVar, CF_IO_LEN};
use crate::folding::circuits::cyclefold::{CycleFoldCommittedInstanceVar, CF_IO_LEN};
use ark_r1cs_std::ToBitsGadget;
let cf_u_dummy_native = CommittedInstance::<C2>::dummy(CF_IO_LEN);
@@ -597,7 +597,6 @@ where
#[cfg(test)]
pub mod tests {
use super::*;
use ark_crypto_primitives::crh::{
sha256::{
constraints::{Sha256Gadget, UnitVar},
@@ -611,15 +610,15 @@ pub mod tests {
use ark_std::{One, UniformRand};
use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2};
use super::*;
use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z};
use crate::ccs::r1cs::{extract_r1cs, extract_w_x};
use crate::commitment::pedersen::Pedersen;
use crate::folding::nova::{get_cs_params_len, ProverParams, VerifierParams};
use crate::frontend::tests::{CubicFCircuit, CustomFCircuit, WrapperCircuit};
use crate::transcript::poseidon::poseidon_canonical_config;
use crate::FoldingScheme;
use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z};
use crate::ccs::r1cs::{extract_r1cs, extract_w_x};
#[test]
fn test_relaxed_r1cs_small_gadget_handcrafted() {
let r1cs: R1CS<Fr> = get_test_r1cs();
@@ -786,11 +785,11 @@ pub mod tests {
let prover_params =
ProverParams::<Projective, Projective2, Pedersen<Projective>, Pedersen<Projective2>> {
poseidon_config: poseidon_config.clone(),
cs_params: pedersen_params,
cf_cs_params: cf_pedersen_params,
cs_pp: pedersen_params.clone(),
cf_cs_pp: cf_pedersen_params.clone(),
};
type NOVA = Nova<
type N = Nova<
Projective,
GVar,
Projective2,
@@ -801,16 +800,23 @@ pub mod tests {
>;
// generate a Nova instance and do a step of it
let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
nova.prove_step(vec![]).unwrap();
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
nova.prove_step(&mut rng, vec![]).unwrap();
let ivc_v = nova.clone();
let verifier_params = VerifierParams::<Projective, Projective2> {
let verifier_params = VerifierParams::<
Projective,
Projective2,
Pedersen<Projective>,
Pedersen<Projective2>,
> {
poseidon_config: poseidon_config.clone(),
r1cs: ivc_v.clone().r1cs,
cf_r1cs: ivc_v.clone().cf_r1cs,
cs_vp: pedersen_params,
cf_cs_vp: cf_pedersen_params,
};
let (running_instance, incoming_instance, cyclefold_instance) = ivc_v.instances();
NOVA::verify(
N::verify(
verifier_params,
z_0,
ivc_v.z_i,

View File

@@ -10,6 +10,7 @@ use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldG
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::fmt::Debug;
use ark_std::rand::RngCore;
use ark_std::{One, Zero};
use core::marker::PhantomData;
use std::usize;
@@ -24,7 +25,7 @@ use crate::folding::circuits::{
CF2,
};
use crate::frontend::FCircuit;
use crate::utils::vec::is_zero_vec;
use crate::utils::{get_cm_coordinates, vec::is_zero_vec};
use crate::Error;
use crate::FoldingScheme;
@@ -186,6 +187,44 @@ where
}
}
#[derive(Debug, Clone)]
pub struct PreprocessorParam<C1, C2, FC, CS1, CS2>
where
C1: CurveGroup,
C2: CurveGroup,
FC: FCircuit<C1::ScalarField>,
CS1: CommitmentScheme<C1>,
CS2: CommitmentScheme<C2>,
{
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
pub F: FC,
// cs params if not provided, will be generated at the preprocess method
pub cs_pp: Option<CS1::ProverParams>,
pub cs_vp: Option<CS1::VerifierParams>,
pub cf_cs_pp: Option<CS2::ProverParams>,
pub cf_cs_vp: Option<CS2::VerifierParams>,
}
impl<C1, C2, FC, CS1, CS2> PreprocessorParam<C1, C2, FC, CS1, CS2>
where
C1: CurveGroup,
C2: CurveGroup,
FC: FCircuit<C1::ScalarField>,
CS1: CommitmentScheme<C1>,
CS2: CommitmentScheme<C2>,
{
pub fn new(poseidon_config: PoseidonConfig<C1::ScalarField>, F: FC) -> Self {
Self {
poseidon_config,
F,
cs_pp: None,
cs_vp: None,
cf_cs_pp: None,
cf_cs_vp: None,
}
}
}
#[derive(Debug, Clone)]
pub struct ProverParams<C1, C2, CS1, CS2>
where
@@ -195,15 +234,23 @@ where
CS2: CommitmentScheme<C2>,
{
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
pub cs_params: CS1::ProverParams,
pub cf_cs_params: CS2::ProverParams,
pub cs_pp: CS1::ProverParams,
pub cf_cs_pp: CS2::ProverParams,
}
#[derive(Debug, Clone)]
pub struct VerifierParams<C1: CurveGroup, C2: CurveGroup> {
pub struct VerifierParams<C1, C2, CS1, CS2>
where
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1>,
CS2: CommitmentScheme<C2>,
{
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
pub r1cs: R1CS<C1::ScalarField>,
pub cf_r1cs: R1CS<C2::ScalarField>,
pub cs_vp: CS1::VerifierParams,
pub cf_cs_vp: CS2::VerifierParams,
}
/// Implements Nova+CycleFold's IVC, described in [Nova](https://eprint.iacr.org/2021/370.pdf) and
@@ -228,9 +275,9 @@ where
pub cf_r1cs: R1CS<C2::ScalarField>,
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
/// 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,
pub i: C1::ScalarField,
@@ -267,24 +314,50 @@ where
for<'a> &'a GC1: GroupOpsBounds<'a, C1, GC1>,
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
{
type PreprocessorParam = (Self::ProverParam, FC);
type PreprocessorParam = PreprocessorParam<C1, C2, FC, CS1, CS2>;
type ProverParam = ProverParams<C1, C2, CS1, CS2>;
type VerifierParam = VerifierParams<C1, C2>;
type CommittedInstanceWithWitness = (CommittedInstance<C1>, Witness<C1>);
type CFCommittedInstanceWithWitness = (CommittedInstance<C2>, Witness<C2>);
type VerifierParam = VerifierParams<C1, C2, CS1, CS2>;
type RunningInstance = (CommittedInstance<C1>, Witness<C1>);
type IncomingInstance = (CommittedInstance<C1>, Witness<C1>);
type CFInstance = (CommittedInstance<C2>, Witness<C2>);
fn preprocess(
mut rng: impl RngCore,
prep_param: &Self::PreprocessorParam,
) -> Result<(Self::ProverParam, Self::VerifierParam), Error> {
let (prover_params, F_circuit) = prep_param;
let (r1cs, cf_r1cs) =
get_r1cs::<C1, GC1, C2, GC2, FC>(&prover_params.poseidon_config, F_circuit.clone())?;
get_r1cs::<C1, GC1, C2, GC2, FC>(&prep_param.poseidon_config, prep_param.F.clone())?;
let verifier_params = VerifierParams::<C1, C2> {
poseidon_config: prover_params.poseidon_config.clone(),
// if cs params exist, use them, if not, generate new ones
let cs_pp: CS1::ProverParams;
let cs_vp: CS1::VerifierParams;
let cf_cs_pp: CS2::ProverParams;
let cf_cs_vp: CS2::VerifierParams;
if prep_param.cs_pp.is_some()
&& prep_param.cf_cs_pp.is_some()
&& prep_param.cs_vp.is_some()
&& prep_param.cf_cs_vp.is_some()
{
cs_pp = prep_param.clone().cs_pp.unwrap();
cs_vp = prep_param.clone().cs_vp.unwrap();
cf_cs_pp = prep_param.clone().cf_cs_pp.unwrap();
cf_cs_vp = prep_param.clone().cf_cs_vp.unwrap();
} else {
(cs_pp, cs_vp) = CS1::setup(&mut rng, r1cs.A.n_rows).unwrap();
(cf_cs_pp, cf_cs_vp) = CS2::setup(&mut rng, cf_r1cs.A.n_rows).unwrap();
}
let prover_params = ProverParams::<C1, C2, CS1, CS2> {
poseidon_config: prep_param.poseidon_config.clone(),
cs_pp: cs_pp.clone(),
cf_cs_pp: cf_cs_pp.clone(),
};
let verifier_params = VerifierParams::<C1, C2, CS1, CS2> {
poseidon_config: prep_param.poseidon_config.clone(),
r1cs,
cf_r1cs,
cs_vp: cs_vp.clone(),
cf_cs_vp: cf_cs_vp.clone(),
};
Ok((prover_params.clone(), verifier_params))
}
@@ -322,8 +395,8 @@ where
r1cs,
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,
i: C1::ScalarField::zero(),
z_0: z_0.clone(),
@@ -339,7 +412,11 @@ where
}
/// Implements IVC.P of Nova+CycleFold
fn prove_step(&mut self, external_inputs: Vec<C1::ScalarField>) -> Result<(), Error> {
fn prove_step(
&mut self,
_rng: impl RngCore,
external_inputs: Vec<C1::ScalarField>,
) -> Result<(), Error> {
let augmented_F_circuit: AugmentedFCircuit<C1, C2, GC2, FC>;
if self.z_i.len() != self.F.state_len() {
@@ -535,7 +612,7 @@ where
self.i += C1::ScalarField::one();
self.z_i = z_i1;
self.w_i = Witness::<C1>::new(w_i1, self.r1cs.A.n_rows);
self.u_i = self.w_i.commit::<CS1>(&self.cs_params, x_i1)?;
self.u_i = self.w_i.commit::<CS1>(&self.cs_pp, x_i1)?;
self.W_i = W_i1;
self.U_i = U_i1;
@@ -552,12 +629,13 @@ where
fn state(&self) -> Vec<C1::ScalarField> {
self.z_i.clone()
}
fn instances(
&self,
) -> (
Self::CommittedInstanceWithWitness,
Self::CommittedInstanceWithWitness,
Self::CFCommittedInstanceWithWitness,
Self::RunningInstance,
Self::IncomingInstance,
Self::CFInstance,
) {
(
(self.U_i.clone(), self.W_i.clone()),
@@ -566,16 +644,24 @@ where
)
}
/// Implements IVC.V of Nova+CycleFold
/// Implements IVC.V of Nova+CycleFold. Notice that this method does not include the
/// commitments verification, which is done in the Decider.
fn verify(
vp: Self::VerifierParam,
z_0: Vec<C1::ScalarField>, // initial state
z_i: Vec<C1::ScalarField>, // last state
num_steps: C1::ScalarField,
running_instance: Self::CommittedInstanceWithWitness,
incoming_instance: Self::CommittedInstanceWithWitness,
cyclefold_instance: Self::CFCommittedInstanceWithWitness,
running_instance: Self::RunningInstance,
incoming_instance: Self::IncomingInstance,
cyclefold_instance: Self::CFInstance,
) -> Result<(), Error> {
if num_steps == C1::ScalarField::zero() {
if z_0 != z_i {
return Err(Error::IVCVerificationFail);
}
return Ok(());
}
let (U_i, W_i) = running_instance;
let (u_i, w_i) = incoming_instance;
let (cf_U_i, cf_W_i) = cyclefold_instance;
@@ -631,7 +717,7 @@ where
// computes T and cmT for the AugmentedFCircuit
fn compute_cmT(&self) -> Result<(Vec<C1::ScalarField>, C1), Error> {
NIFS::<C1, CS1>::compute_cmT(
&self.cs_params,
&self.cs_pp,
&self.r1cs,
&self.w_i,
&self.u_i,
@@ -680,7 +766,7 @@ where
fold_cyclefold_circuit::<C1, GC1, C2, GC2, FC, CS1, CS2>(
&self.poseidon_config,
self.cf_r1cs.clone(),
self.cf_cs_params.clone(),
self.cf_cs_pp.clone(),
cf_W_i,
cf_U_i,
cf_u_i_x,
@@ -753,23 +839,13 @@ where
Ok((r1cs.A.n_rows, cf_r1cs.A.n_rows))
}
/// returns the coordinates of a commitment point. This is compatible with the arkworks
/// GC.to_constraint_field()[..2]
pub(crate) fn get_cm_coordinates<C: CurveGroup>(cm: &C) -> Vec<C::BaseField> {
let zero = (&C::BaseField::zero(), &C::BaseField::zero());
let cm = cm.into_affine();
let (cm_x, cm_y) = cm.xy().unwrap_or(zero);
vec![*cm_x, *cm_y]
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::commitment::kzg::{ProverKey as KZGProverKey, KZG};
use crate::commitment::kzg::KZG;
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
use super::*;
use crate::commitment::pedersen::Pedersen;
use crate::frontend::tests::CubicFCircuit;
use crate::transcript::poseidon::poseidon_canonical_config;
@@ -778,71 +854,49 @@ pub mod tests {
/// AugmentedFCircuit
#[test]
fn test_ivc() {
let mut rng = ark_std::test_rng();
let poseidon_config = poseidon_canonical_config::<Fr>();
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
let (cs_len, cf_cs_len) =
get_cs_params_len::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>>(
&poseidon_config,
F_circuit,
)
.unwrap();
let (kzg_pk, _): (KZGProverKey<Projective>, KZGVerifierKey<Bn254>) =
KZG::<Bn254>::setup(&mut rng, cs_len).unwrap();
let (pedersen_params, _) = Pedersen::<Projective>::setup(&mut rng, cs_len).unwrap();
let (cf_pedersen_params, _) = Pedersen::<Projective2>::setup(&mut rng, cf_cs_len).unwrap();
// run the test using Pedersen commitments on both sides of the curve cycle
test_ivc_opt::<Pedersen<Projective>, Pedersen<Projective2>>(
poseidon_config.clone(),
pedersen_params,
cf_pedersen_params.clone(),
F_circuit,
);
// run the test using KZG for the commitments on the main curve, and Pedersen for the
// commitments on the secondary curve
test_ivc_opt::<KZG<Bn254>, Pedersen<Projective2>>(
poseidon_config,
kzg_pk,
cf_pedersen_params,
F_circuit,
);
test_ivc_opt::<KZG<Bn254>, Pedersen<Projective2>>(poseidon_config, F_circuit);
}
// test_ivc allowing to choose the CommitmentSchemes
fn test_ivc_opt<CS1: CommitmentScheme<Projective>, CS2: CommitmentScheme<Projective2>>(
poseidon_config: PoseidonConfig<Fr>,
cs_params: CS1::ProverParams,
cf_cs_params: CS2::ProverParams,
F_circuit: CubicFCircuit<Fr>,
) {
type NOVA<CS1, CS2> =
Nova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
let mut rng = ark_std::test_rng();
type N<CS1, CS2> = Nova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
let prover_params = ProverParams::<Projective, Projective2, CS1, CS2> {
poseidon_config: poseidon_config.clone(),
cs_params,
cf_cs_params,
let prep_param = PreprocessorParam::<Projective, Projective2, CubicFCircuit<Fr>, CS1, CS2> {
poseidon_config,
F: F_circuit,
cs_pp: None,
cs_vp: None,
cf_cs_pp: None,
cf_cs_vp: None,
};
let (prover_params, verifier_params) = N::preprocess(&mut rng, &prep_param).unwrap();
let z_0 = vec![Fr::from(3_u32)];
let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
let num_steps: usize = 3;
for _ in 0..num_steps {
nova.prove_step(vec![]).unwrap();
nova.prove_step(&mut rng, vec![]).unwrap();
}
assert_eq!(Fr::from(num_steps as u32), nova.i);
let verifier_params = VerifierParams::<Projective, Projective2> {
poseidon_config,
r1cs: nova.clone().r1cs,
cf_r1cs: nova.clone().cf_r1cs,
};
let (running_instance, incoming_instance, cyclefold_instance) = nova.instances();
NOVA::<CS1, CS2>::verify(
N::<CS1, CS2>::verify(
verifier_params,
z_0,
nova.z_i,

View File

@@ -1,10 +1,3 @@
use super::{circuits::AugmentedFCircuit, Nova, ProverParams};
pub use super::{CommittedInstance, Witness};
pub use crate::folding::circuits::{cyclefold::CycleFoldCircuit, CF2};
use crate::{
ccs::r1cs::extract_r1cs, commitment::CommitmentScheme, folding::circuits::CF1,
frontend::FCircuit,
};
use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb};
use ark_ec::{CurveGroup, Group};
use ark_ff::PrimeField;
@@ -17,6 +10,14 @@ use ark_relations::r1cs::ConstraintSystem;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, SerializationError, Write};
use std::marker::PhantomData;
use super::{circuits::AugmentedFCircuit, Nova, ProverParams};
use super::{CommittedInstance, Witness};
use crate::folding::circuits::{cyclefold::CycleFoldCircuit, CF2};
use crate::{
ccs::r1cs::extract_r1cs, commitment::CommitmentScheme, folding::circuits::CF1,
frontend::FCircuit,
};
impl<C1, GC1, C2, GC2, FC, CS1, CS2> CanonicalSerialize for Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
where
C1: CurveGroup,
@@ -150,8 +151,8 @@ where
_gc1: PhantomData,
_c2: PhantomData,
_gc2: PhantomData,
cs_params: prover_params.cs_params,
cf_cs_params: prover_params.cf_cs_params,
cs_pp: prover_params.cs_pp,
cf_cs_pp: prover_params.cf_cs_pp,
i,
z_0,
z_i,
@@ -171,6 +172,12 @@ where
#[cfg(test)]
pub mod tests {
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
use ark_serialize::{CanonicalSerialize, Compress, Validate};
use std::{fs, io::Write};
use crate::{
commitment::{
kzg::{ProverKey as KZGProverKey, KZG},
@@ -182,11 +189,6 @@ pub mod tests {
transcript::poseidon::poseidon_canonical_config,
FoldingScheme,
};
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
use ark_serialize::{CanonicalSerialize, Compress, Validate};
use std::{fs, io::Write};
#[test]
fn test_serde_nova() {
@@ -204,21 +206,28 @@ pub mod tests {
let (cf_pedersen_params, _) = Pedersen::<Projective2>::setup(&mut rng, cf_cs_len).unwrap();
// Initialize nova and make multiple `prove_step()`
type NOVA<CS1, CS2> =
Nova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
type N = Nova<
Projective,
GVar,
Projective2,
GVar2,
CubicFCircuit<Fr>,
KZG<'static, Bn254>,
Pedersen<Projective2>,
>;
let prover_params =
ProverParams::<Projective, Projective2, KZG<Bn254>, Pedersen<Projective2>> {
poseidon_config: poseidon_config.clone(),
cs_params: kzg_pk.clone(),
cf_cs_params: cf_pedersen_params.clone(),
cs_pp: kzg_pk.clone(),
cf_cs_pp: cf_pedersen_params.clone(),
};
let z_0 = vec![Fr::from(3_u32)];
let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
let num_steps: usize = 3;
for _ in 0..num_steps {
nova.prove_step(vec![]).unwrap();
nova.prove_step(&mut rng, vec![]).unwrap();
}
let mut writer = vec![];
@@ -257,8 +266,8 @@ pub mod tests {
let num_steps: usize = 3;
for _ in 0..num_steps {
deserialized_nova.prove_step(vec![]).unwrap();
nova.prove_step(vec![]).unwrap();
deserialized_nova.prove_step(&mut rng, vec![]).unwrap();
nova.prove_step(&mut rng, vec![]).unwrap();
}
assert_eq!(deserialized_nova.w_i, nova.w_i);

View File

@@ -39,6 +39,7 @@ where
(w_dummy, u_dummy)
}
// notice that this method does not check the commitment correctness
fn check_instance_relation(
&self,
W: &Witness<C>,
@@ -52,6 +53,7 @@ where
self.check_relation(&Z)
}
// notice that this method does not check the commitment correctness
fn check_relaxed_instance_relation(
&self,
W: &Witness<C>,