mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-28 14:56:40 +01:00
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:
@@ -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();
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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>,
|
||||
|
||||
Reference in New Issue
Block a user