Browse Source

Nova parameters & decider parameters and proofs serialization (#151)

* Add nova's decider serialization & deserialization to proof, verifier_params and public inputs

* polish

* add serialization for nova's ivc proverparams & verifierparams
main
arnaucube 2 months ago
committed by GitHub
parent
commit
1f7bf0462b
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
11 changed files with 402 additions and 38 deletions
  1. +1
    -1
      folding-schemes/Cargo.toml
  2. +8
    -0
      folding-schemes/src/arith/r1cs.rs
  3. +2
    -1
      folding-schemes/src/commitment/ipa.rs
  4. +1
    -1
      folding-schemes/src/commitment/kzg.rs
  5. +2
    -2
      folding-schemes/src/commitment/mod.rs
  6. +1
    -1
      folding-schemes/src/commitment/pedersen.rs
  7. +214
    -16
      folding-schemes/src/folding/nova/decider_eth.rs
  8. +140
    -5
      folding-schemes/src/folding/nova/mod.rs
  9. +1
    -1
      folding-schemes/src/frontend/noir/mod.rs
  10. +7
    -0
      folding-schemes/src/utils/vec.rs
  11. +25
    -10
      solidity-verifiers/src/verifiers/nova_cyclefold.rs

+ 1
- 1
folding-schemes/Cargo.toml

@ -30,7 +30,7 @@ noname = { git = "https://github.com/dmpierre/noname" }
serde_json = "1.0.85" # to (de)serialize JSON serde_json = "1.0.85" # to (de)serialize JSON
serde = "1.0.203" serde = "1.0.203"
acvm = { git = "https://github.com/noir-lang/noir", rev="2b4853e", default-features = false } acvm = { git = "https://github.com/noir-lang/noir", rev="2b4853e", default-features = false }
arkworks_backend = { git = "https://github.com/dmpierre/arkworks_backend", branch = "feat/sonobe-integration" }
noir_arkworks_backend = { package="arkworks_backend", git = "https://github.com/dmpierre/arkworks_backend", branch = "feat/sonobe-integration" }
log = "0.4" log = "0.4"
# tmp import for espresso's sumcheck # tmp import for espresso's sumcheck

+ 8
- 0
folding-schemes/src/arith/r1cs.rs

@ -44,6 +44,14 @@ impl Arith for R1CS {
} }
impl<F: PrimeField> R1CS<F> { impl<F: PrimeField> R1CS<F> {
pub fn empty() -> Self {
R1CS {
l: 0,
A: SparseMatrix::empty(),
B: SparseMatrix::empty(),
C: SparseMatrix::empty(),
}
}
pub fn rand<R: Rng>(rng: &mut R, n_rows: usize, n_cols: usize) -> Self { pub fn rand<R: Rng>(rng: &mut R, n_rows: usize, n_cols: usize) -> Self {
Self { Self {
l: 1, l: 1,

+ 2
- 1
folding-schemes/src/commitment/ipa.rs

@ -18,6 +18,7 @@ use ark_r1cs_std::{
ToBitsGadget, ToBitsGadget,
}; };
use ark_relations::r1cs::{Namespace, SynthesisError}; use ark_relations::r1cs::{Namespace, SynthesisError};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_std::{cfg_iter, rand::RngCore, UniformRand, Zero}; use ark_std::{cfg_iter, rand::RngCore, UniformRand, Zero};
use core::{borrow::Borrow, marker::PhantomData}; use core::{borrow::Borrow, marker::PhantomData};
use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator};
@ -30,7 +31,7 @@ use crate::utils::{
}; };
use crate::Error; use crate::Error;
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Proof<C: CurveGroup> { pub struct Proof<C: CurveGroup> {
a: C::ScalarField, a: C::ScalarField,
l: Vec<C::ScalarField>, l: Vec<C::ScalarField>,

+ 1
- 1
folding-schemes/src/commitment/kzg.rs

@ -70,7 +70,7 @@ impl<'a, C: CurveGroup> Valid for ProverKey<'a, C> {
} }
} }
#[derive(Debug, Clone, Default, Eq, PartialEq)]
#[derive(Debug, Clone, Default, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Proof<C: CurveGroup> { pub struct Proof<C: CurveGroup> {
pub eval: C::ScalarField, pub eval: C::ScalarField,
pub proof: C, pub proof: C,

+ 2
- 2
folding-schemes/src/commitment/mod.rs

@ -13,9 +13,9 @@ pub mod pedersen;
/// CommitmentScheme defines the vector commitment scheme trait. Where `H` indicates if to use the /// CommitmentScheme defines the vector commitment scheme trait. Where `H` indicates if to use the
/// commitment in hiding mode or not. /// commitment in hiding mode or not.
pub trait CommitmentScheme<C: CurveGroup, const H: bool = false>: Clone + Debug { pub trait CommitmentScheme<C: CurveGroup, const H: bool = false>: Clone + Debug {
type ProverParams: Clone + Debug;
type ProverParams: Clone + Debug + CanonicalSerialize + CanonicalDeserialize;
type VerifierParams: Clone + Debug + CanonicalSerialize + CanonicalDeserialize; type VerifierParams: Clone + Debug + CanonicalSerialize + CanonicalDeserialize;
type Proof: Clone + Debug;
type Proof: Clone + Debug + CanonicalSerialize + CanonicalDeserialize;
type ProverChallenge: Clone + Debug; type ProverChallenge: Clone + Debug;
type Challenge: Clone + Debug; type Challenge: Clone + Debug;

+ 1
- 1
folding-schemes/src/commitment/pedersen.rs

@ -12,7 +12,7 @@ use crate::transcript::Transcript;
use crate::utils::vec::{vec_add, vec_scalar_mul}; use crate::utils::vec::{vec_add, vec_scalar_mul};
use crate::Error; use crate::Error;
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Proof<C: CurveGroup> { pub struct Proof<C: CurveGroup> {
pub R: C, pub R: C,
pub u: Vec<C::ScalarField>, pub u: Vec<C::ScalarField>,

+ 214
- 16
folding-schemes/src/folding/nova/decider_eth.rs

@ -5,6 +5,7 @@ use ark_ec::{AffineRepr, CurveGroup, Group};
use ark_ff::{BigInteger, PrimeField}; use ark_ff::{BigInteger, PrimeField};
use ark_groth16::Groth16; use ark_groth16::Groth16;
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget}; use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_snark::SNARK; use ark_snark::SNARK;
use ark_std::rand::{CryptoRng, RngCore}; use ark_std::rand::{CryptoRng, RngCore};
use ark_std::{One, Zero}; use ark_std::{One, Zero};
@ -22,7 +23,7 @@ use crate::frontend::FCircuit;
use crate::Error; use crate::Error;
use crate::{Decider as DeciderTrait, FoldingScheme}; use crate::{Decider as DeciderTrait, FoldingScheme};
#[derive(Debug, Clone, Eq, PartialEq)]
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct Proof<C1, CS1, S> pub struct Proof<C1, CS1, S>
where where
C1: CurveGroup, C1: CurveGroup,
@ -40,6 +41,18 @@ where
kzg_challenges: [C1::ScalarField; 2], kzg_challenges: [C1::ScalarField; 2],
} }
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
pub struct VerifierParam<C1, CS_VerifyingKey, S_VerifyingKey>
where
C1: CurveGroup,
CS_VerifyingKey: Clone + CanonicalSerialize + CanonicalDeserialize,
S_VerifyingKey: Clone + CanonicalSerialize + CanonicalDeserialize,
{
pub pp_hash: C1::ScalarField,
pub snark_vp: S_VerifyingKey,
pub cs_vp: CS_VerifyingKey,
}
/// Onchain Decider, for ethereum use cases /// Onchain Decider, for ethereum use cases
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub struct Decider<C1, GC1, C2, GC2, FC, CS1, CS2, S, FS> { pub struct Decider<C1, GC1, C2, GC2, FC, CS1, CS2, S, FS> {
@ -90,8 +103,7 @@ where
type PreprocessorParam = (FS::ProverParam, FS::VerifierParam); type PreprocessorParam = (FS::ProverParam, FS::VerifierParam);
type ProverParam = (S::ProvingKey, CS1::ProverParams); type ProverParam = (S::ProvingKey, CS1::ProverParams);
type Proof = Proof<C1, CS1, S>; type Proof = Proof<C1, CS1, S>;
/// VerifierParam = (pp_hash, snark::vk, commitment_scheme::vk)
type VerifierParam = (C1::ScalarField, S::VerifyingKey, CS1::VerifierParams);
type VerifierParam = VerifierParam<C1, CS1::VerifierParams, S::VerifyingKey>;
type PublicInput = Vec<C1::ScalarField>; type PublicInput = Vec<C1::ScalarField>;
type CommittedInstance = CommittedInstance<C1>; type CommittedInstance = CommittedInstance<C1>;
@ -122,7 +134,11 @@ where
let pp_hash = nova_vp.pp_hash()?; let pp_hash = nova_vp.pp_hash()?;
let pp = (g16_pk, nova_pp.cs_pp); let pp = (g16_pk, nova_pp.cs_pp);
let vp = (pp_hash, g16_vk, nova_vp.cs_vp);
let vp = Self::VerifierParam {
pp_hash,
snark_vp: g16_vk,
cs_vp: nova_vp.cs_vp,
};
Ok((pp, vp)) Ok((pp, vp))
} }
@ -191,9 +207,6 @@ where
return Err(Error::NotEnoughSteps); return Err(Error::NotEnoughSteps);
} }
let (pp_hash, snark_vk, cs_vk): (C1::ScalarField, S::VerifyingKey, CS1::VerifierParams) =
vp;
// compute U = U_{d+1}= NIFS.V(U_d, u_d, cmT) // compute U = U_{d+1}= NIFS.V(U_d, u_d, cmT)
let U = NIFS::<C1, CS1>::verify(proof.r, running_instance, incoming_instance, &proof.cmT); let U = NIFS::<C1, CS1>::verify(proof.r, running_instance, incoming_instance, &proof.cmT);
@ -202,7 +215,7 @@ where
let (cmT_x, cmT_y) = NonNativeAffineVar::inputize(proof.cmT)?; let (cmT_x, cmT_y) = NonNativeAffineVar::inputize(proof.cmT)?;
let public_input: Vec<C1::ScalarField> = [ let public_input: Vec<C1::ScalarField> = [
vec![pp_hash, i],
vec![vp.pp_hash, i],
z_0, z_0,
z_i, z_i,
vec![U.u], vec![U.u],
@ -222,7 +235,7 @@ where
] ]
.concat(); .concat();
let snark_v = S::verify(&snark_vk, &public_input, &proof.snark_proof)
let snark_v = S::verify(&vp.snark_vp, &public_input, &proof.snark_proof)
.map_err(|e| Error::Other(e.to_string()))?; .map_err(|e| Error::Other(e.to_string()))?;
if !snark_v { if !snark_v {
return Err(Error::SNARKVerificationFail); return Err(Error::SNARKVerificationFail);
@ -230,13 +243,13 @@ where
// we're at the Ethereum EVM case, so the CS1 is KZG commitments // we're at the Ethereum EVM case, so the CS1 is KZG commitments
CS1::verify_with_challenge( CS1::verify_with_challenge(
&cs_vk,
&vp.cs_vp,
proof.kzg_challenges[0], proof.kzg_challenges[0],
&U.cmW, &U.cmW,
&proof.kzg_proofs[0], &proof.kzg_proofs[0],
)?; )?;
CS1::verify_with_challenge( CS1::verify_with_challenge(
&cs_vk,
&vp.cs_vp,
proof.kzg_challenges[1], proof.kzg_challenges[1],
&U.cmE, &U.cmE,
&proof.kzg_proofs[1], &proof.kzg_proofs[1],
@ -326,7 +339,9 @@ pub mod tests {
use super::*; use super::*;
use crate::commitment::pedersen::Pedersen; use crate::commitment::pedersen::Pedersen;
use crate::folding::nova::PreprocessorParam;
use crate::folding::nova::{
PreprocessorParam, ProverParams as NovaProverParams, VerifierParams as NovaVerifierParams,
};
use crate::frontend::tests::CubicFCircuit; use crate::frontend::tests::CubicFCircuit;
use crate::transcript::poseidon::poseidon_canonical_config; use crate::transcript::poseidon::poseidon_canonical_config;
@ -355,28 +370,140 @@ pub mod tests {
N, // here we define the FoldingScheme to use N, // here we define the FoldingScheme to use
>; >;
let mut rng = ark_std::test_rng();
let mut rng = rand::rngs::OsRng;
let poseidon_config = poseidon_canonical_config::<Fr>(); let poseidon_config = poseidon_canonical_config::<Fr>();
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap(); let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
let z_0 = vec![Fr::from(3_u32)]; let z_0 = vec![Fr::from(3_u32)];
let prep_param = PreprocessorParam::new(poseidon_config, F_circuit);
let nova_params = N::preprocess(&mut rng, &prep_param).unwrap();
let preprocessor_param = PreprocessorParam::new(poseidon_config, F_circuit);
let nova_params = N::preprocess(&mut rng, &preprocessor_param).unwrap();
let start = Instant::now(); let start = Instant::now();
let mut nova = N::init(&nova_params, F_circuit, z_0.clone()).unwrap(); let mut nova = N::init(&nova_params, F_circuit, z_0.clone()).unwrap();
println!("Nova initialized, {:?}", start.elapsed()); 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 start = Instant::now(); let start = Instant::now();
nova.prove_step(&mut rng, vec![], None).unwrap(); nova.prove_step(&mut rng, vec![], None).unwrap();
println!("prove_step, {:?}", start.elapsed()); println!("prove_step, {:?}", start.elapsed());
nova.prove_step(&mut rng, vec![], None).unwrap(); // do a 2nd step nova.prove_step(&mut rng, vec![], None).unwrap(); // do a 2nd step
// decider proof generation
let start = Instant::now();
let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
println!("Decider prove, {:?}", start.elapsed());
// decider proof verification
let start = Instant::now();
let verified = D::verify(
decider_vp.clone(),
nova.i.clone(),
nova.z_0.clone(),
nova.z_i.clone(),
&nova.U_i,
&nova.u_i,
&proof,
)
.unwrap();
assert!(verified);
println!("Decider verify, {:?}", start.elapsed());
// decider proof verification using the deserialized data
let verified = D::verify(
decider_vp, nova.i, nova.z_0, nova.z_i, &nova.U_i, &nova.u_i, &proof,
)
.unwrap();
assert!(verified);
}
// Test to check the serialization and deserialization of diverse Decider related parameters.
// This test is the same test as `test_decider` but it serializes values and then uses the
// deserialized values to continue the checks.
#[test]
fn test_decider_serialization() {
// use Nova as FoldingScheme
type N = Nova<
Projective,
GVar,
Projective2,
GVar2,
CubicFCircuit<Fr>,
KZG<'static, Bn254>,
Pedersen<Projective2>,
false,
>;
type D = Decider<
Projective,
GVar,
Projective2,
GVar2,
CubicFCircuit<Fr>,
KZG<'static, Bn254>,
Pedersen<Projective2>,
Groth16<Bn254>, // here we define the Snark to use in the decider
N, // here we define the FoldingScheme to use
>;
let mut rng = rand::rngs::OsRng; let mut rng = rand::rngs::OsRng;
let poseidon_config = poseidon_canonical_config::<Fr>();
let F_circuit = CubicFCircuit::<Fr>::new(()).unwrap();
let z_0 = vec![Fr::from(3_u32)];
let preprocessor_param = PreprocessorParam::new(poseidon_config, F_circuit);
let nova_params = N::preprocess(&mut rng, &preprocessor_param).unwrap();
let start = Instant::now();
let nova = N::init(&nova_params, F_circuit, z_0.clone()).unwrap();
println!("Nova initialized, {:?}", start.elapsed());
// prepare the Decider prover & verifier params // 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();
// serialize the Nova params. These params are the trusted setup of the commitment schemes used
// (ie. KZG & Pedersen in this case)
let mut nova_pp_serialized = vec![];
nova_params
.0
.serialize_compressed(&mut nova_pp_serialized)
.unwrap();
let mut nova_vp_serialized = vec![];
nova_params
.1
.serialize_compressed(&mut nova_vp_serialized)
.unwrap();
// deserialize the Nova params. This would be done by the client reading from a file
let nova_pp_deserialized = NovaProverParams::<
Projective,
Projective2,
KZG<'static, Bn254>,
Pedersen<Projective2>,
>::deserialize_compressed(
&mut nova_pp_serialized.as_slice()
)
.unwrap();
let nova_vp_deserialized = NovaVerifierParams::<
Projective,
Projective2,
KZG<'static, Bn254>,
Pedersen<Projective2>,
>::deserialize_compressed(
&mut nova_vp_serialized.as_slice()
)
.unwrap();
// initialize nova again, but from the deserialized parameters
let nova_params = (nova_pp_deserialized, nova_vp_deserialized);
let mut nova = N::init(&nova_params, F_circuit, z_0).unwrap();
let start = Instant::now();
nova.prove_step(&mut rng, vec![], None).unwrap();
println!("prove_step, {:?}", start.elapsed());
nova.prove_step(&mut rng, vec![], None).unwrap(); // do a 2nd step
// decider proof generation // decider proof generation
let start = Instant::now(); let start = Instant::now();
let proof = D::prove(rng, decider_pp, nova.clone()).unwrap(); let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
@ -385,10 +512,81 @@ pub mod tests {
// decider proof verification // decider proof verification
let start = Instant::now(); let start = Instant::now();
let verified = D::verify( let verified = D::verify(
decider_vp, nova.i, nova.z_0, nova.z_i, &nova.U_i, &nova.u_i, &proof,
decider_vp.clone(),
nova.i.clone(),
nova.z_0.clone(),
nova.z_i.clone(),
&nova.U_i,
&nova.u_i,
&proof,
) )
.unwrap(); .unwrap();
assert!(verified); assert!(verified);
println!("Decider verify, {:?}", start.elapsed()); println!("Decider verify, {:?}", start.elapsed());
// The rest of this test will serialize the data and deserialize it back, and use it to
// verify the proof:
// serialize the verifier_params, proof and public inputs
let mut decider_vp_serialized = vec![];
decider_vp
.serialize_compressed(&mut decider_vp_serialized)
.unwrap();
let mut proof_serialized = vec![];
proof.serialize_compressed(&mut proof_serialized).unwrap();
// serialize the public inputs in a single packet
let mut public_inputs_serialized = vec![];
nova.i
.serialize_compressed(&mut public_inputs_serialized)
.unwrap();
nova.z_0
.serialize_compressed(&mut public_inputs_serialized)
.unwrap();
nova.z_i
.serialize_compressed(&mut public_inputs_serialized)
.unwrap();
nova.U_i
.serialize_compressed(&mut public_inputs_serialized)
.unwrap();
nova.u_i
.serialize_compressed(&mut public_inputs_serialized)
.unwrap();
// deserialize back the verifier_params, proof and public inputs
let decider_vp_deserialized =
VerifierParam::<
Projective,
<KZG<'static, Bn254> as CommitmentScheme<Projective>>::VerifierParams,
<Groth16<Bn254> as SNARK<Fr>>::VerifyingKey,
>::deserialize_compressed(&mut decider_vp_serialized.as_slice())
.unwrap();
let proof_deserialized =
Proof::<Projective, KZG<'static, Bn254>, Groth16<Bn254>>::deserialize_compressed(
&mut proof_serialized.as_slice(),
)
.unwrap();
// deserialize the public inputs from the single packet 'public_inputs_serialized'
let mut reader = public_inputs_serialized.as_slice();
let i_deserialized = Fr::deserialize_compressed(&mut reader).unwrap();
let z_0_deserialized = Vec::<Fr>::deserialize_compressed(&mut reader).unwrap();
let z_i_deserialized = Vec::<Fr>::deserialize_compressed(&mut reader).unwrap();
let U_i_deserialized =
CommittedInstance::<Projective>::deserialize_compressed(&mut reader).unwrap();
let u_i_deserialized =
CommittedInstance::<Projective>::deserialize_compressed(&mut reader).unwrap();
// decider proof verification using the deserialized data
let verified = D::verify(
decider_vp_deserialized,
i_deserialized,
z_0_deserialized,
z_i_deserialized,
&U_i_deserialized,
&u_i_deserialized,
&proof_deserialized,
)
.unwrap();
assert!(verified);
} }
} }

+ 140
- 5
folding-schemes/src/folding/nova/mod.rs

@ -8,7 +8,7 @@ use ark_ec::{CurveGroup, Group};
use ark_ff::{BigInteger, PrimeField}; use ark_ff::{BigInteger, PrimeField};
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget}; use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget};
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Valid};
use ark_std::fmt::Debug; use ark_std::fmt::Debug;
use ark_std::rand::RngCore; use ark_std::rand::RngCore;
use ark_std::{One, UniformRand, Zero}; use ark_std::{One, UniformRand, Zero};
@ -21,7 +21,7 @@ use crate::folding::circuits::cyclefold::{
}; };
use crate::folding::circuits::CF2; use crate::folding::circuits::CF2;
use crate::frontend::FCircuit; use crate::frontend::FCircuit;
use crate::transcript::{AbsorbNonNative, Transcript};
use crate::transcript::{poseidon::poseidon_canonical_config, AbsorbNonNative, Transcript};
use crate::utils::vec::is_zero_vec; use crate::utils::vec::is_zero_vec;
use crate::Error; use crate::Error;
use crate::FoldingScheme; use crate::FoldingScheme;
@ -190,7 +190,7 @@ where
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PreprocessorParam<C1, C2, FC, CS1, CS2, const H: bool>
pub struct PreprocessorParam<C1, C2, FC, CS1, CS2, const H: bool = false>
where where
C1: CurveGroup, C1: CurveGroup,
C2: CurveGroup, C2: CurveGroup,
@ -228,7 +228,7 @@ where
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ProverParams<C1, C2, CS1, CS2, const H: bool>
pub struct ProverParams<C1, C2, CS1, CS2, const H: bool = false>
where where
C1: CurveGroup, C1: CurveGroup,
C2: CurveGroup, C2: CurveGroup,
@ -240,8 +240,70 @@ where
pub cf_cs_pp: CS2::ProverParams, pub cf_cs_pp: CS2::ProverParams,
} }
impl<C1, C2, CS1, CS2, const H: bool> Valid for ProverParams<C1, C2, CS1, CS2, H>
where
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
{
fn check(&self) -> Result<(), ark_serialize::SerializationError> {
self.poseidon_config.full_rounds.check()?;
self.poseidon_config.partial_rounds.check()?;
self.poseidon_config.alpha.check()?;
self.poseidon_config.ark.check()?;
self.poseidon_config.mds.check()?;
self.poseidon_config.rate.check()?;
self.poseidon_config.capacity.check()?;
self.cs_pp.check()?;
self.cf_cs_pp.check()?;
Ok(())
}
}
impl<C1, C2, CS1, CS2, const H: bool> CanonicalSerialize for ProverParams<C1, C2, CS1, CS2, H>
where
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
{
fn serialize_with_mode<W: std::io::prelude::Write>(
&self,
mut writer: W,
compress: ark_serialize::Compress,
) -> Result<(), ark_serialize::SerializationError> {
self.cs_pp.serialize_with_mode(&mut writer, compress)?;
self.cf_cs_pp.serialize_with_mode(&mut writer, compress)
}
fn serialized_size(&self, compress: ark_serialize::Compress) -> usize {
self.cs_pp.serialized_size(compress) + self.cf_cs_pp.serialized_size(compress)
}
}
impl<C1, C2, CS1, CS2, const H: bool> CanonicalDeserialize for ProverParams<C1, C2, CS1, CS2, H>
where
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
{
fn deserialize_with_mode<R: std::io::prelude::Read>(
mut reader: R,
compress: ark_serialize::Compress,
validate: ark_serialize::Validate,
) -> Result<Self, ark_serialize::SerializationError> {
let cs_pp = CS1::ProverParams::deserialize_with_mode(&mut reader, compress, validate)?;
let cf_cs_pp = CS2::ProverParams::deserialize_with_mode(&mut reader, compress, validate)?;
Ok(ProverParams {
poseidon_config: poseidon_canonical_config::<C1::ScalarField>(),
cs_pp,
cf_cs_pp,
})
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct VerifierParams<C1, C2, CS1, CS2, const H: bool>
pub struct VerifierParams<C1, C2, CS1, CS2, const H: bool = false>
where where
C1: CurveGroup, C1: CurveGroup,
C2: CurveGroup, C2: CurveGroup,
@ -255,6 +317,79 @@ where
pub cf_cs_vp: CS2::VerifierParams, pub cf_cs_vp: CS2::VerifierParams,
} }
impl<C1, C2, CS1, CS2, const H: bool> Valid for VerifierParams<C1, C2, CS1, CS2, H>
where
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
{
fn check(&self) -> Result<(), ark_serialize::SerializationError> {
self.poseidon_config.full_rounds.check()?;
self.poseidon_config.partial_rounds.check()?;
self.poseidon_config.alpha.check()?;
self.poseidon_config.ark.check()?;
self.poseidon_config.mds.check()?;
self.poseidon_config.rate.check()?;
self.poseidon_config.capacity.check()?;
self.r1cs.check()?;
self.cf_r1cs.check()?;
self.cs_vp.check()?;
self.cf_cs_vp.check()?;
Ok(())
}
}
impl<C1, C2, CS1, CS2, const H: bool> CanonicalSerialize for VerifierParams<C1, C2, CS1, CS2, H>
where
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
{
fn serialize_with_mode<W: std::io::prelude::Write>(
&self,
mut writer: W,
compress: ark_serialize::Compress,
) -> Result<(), ark_serialize::SerializationError> {
self.r1cs.serialize_with_mode(&mut writer, compress)?;
self.cf_r1cs.serialize_with_mode(&mut writer, compress)?;
self.cs_vp.serialize_with_mode(&mut writer, compress)?;
self.cf_cs_vp.serialize_with_mode(&mut writer, compress)
}
fn serialized_size(&self, compress: ark_serialize::Compress) -> usize {
self.r1cs.serialized_size(compress)
+ self.cf_r1cs.serialized_size(compress)
+ self.cs_vp.serialized_size(compress)
+ self.cf_cs_vp.serialized_size(compress)
}
}
impl<C1, C2, CS1, CS2, const H: bool> CanonicalDeserialize for VerifierParams<C1, C2, CS1, CS2, H>
where
C1: CurveGroup,
C2: CurveGroup,
CS1: CommitmentScheme<C1, H>,
CS2: CommitmentScheme<C2, H>,
{
fn deserialize_with_mode<R: std::io::prelude::Read>(
mut reader: R,
compress: ark_serialize::Compress,
validate: ark_serialize::Validate,
) -> Result<Self, ark_serialize::SerializationError> {
let r1cs = R1CS::deserialize_with_mode(&mut reader, compress, validate)?;
let cf_r1cs = R1CS::deserialize_with_mode(&mut reader, compress, validate)?;
let cs_vp = CS1::VerifierParams::deserialize_with_mode(&mut reader, compress, validate)?;
let cf_cs_vp = CS2::VerifierParams::deserialize_with_mode(&mut reader, compress, validate)?;
Ok(VerifierParams {
poseidon_config: poseidon_canonical_config::<C1::ScalarField>(),
r1cs,
cf_r1cs,
cs_vp,
cf_cs_vp,
})
}
}
impl<C1, C2, CS1, CS2, const H: bool> VerifierParams<C1, C2, CS1, CS2, H> impl<C1, C2, CS1, CS2, const H: bool> VerifierParams<C1, C2, CS1, CS2, H>
where where
C1: CurveGroup, C1: CurveGroup,

+ 1
- 1
folding-schemes/src/frontend/noir/mod.rs

@ -16,7 +16,7 @@ use ark_ff::PrimeField;
use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar}; use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar};
use ark_relations::r1cs::ConstraintSynthesizer; use ark_relations::r1cs::ConstraintSynthesizer;
use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
use arkworks_backend::{
use noir_arkworks_backend::{
read_program_from_binary, read_program_from_file, sonobe_bridge::AcirCircuitSonobe, read_program_from_binary, read_program_from_file, sonobe_bridge::AcirCircuitSonobe,
}; };

+ 7
- 0
folding-schemes/src/utils/vec.rs

@ -20,6 +20,13 @@ pub struct SparseMatrix {
} }
impl<F: PrimeField> SparseMatrix<F> { impl<F: PrimeField> SparseMatrix<F> {
pub fn empty() -> Self {
Self {
n_rows: 0,
n_cols: 0,
coeffs: vec![],
}
}
pub fn rand<R: Rng>(rng: &mut R, n_rows: usize, n_cols: usize) -> Self { pub fn rand<R: Rng>(rng: &mut R, n_rows: usize, n_cols: usize) -> Self {
const ZERO_VAL_PROBABILITY: f64 = 0.8f64; const ZERO_VAL_PROBABILITY: f64 = 0.8f64;

+ 25
- 10
solidity-verifiers/src/verifiers/nova_cyclefold.rs

@ -2,13 +2,14 @@
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(clippy::upper_case_acronyms)] #![allow(clippy::upper_case_acronyms)]
use ark_bn254::{Bn254, Fq, Fr, G1Affine};
use ark_bn254::{Bn254, Fq, Fr, G1Affine, G1Projective};
use ark_groth16::VerifyingKey as ArkG16VerifierKey; use ark_groth16::VerifyingKey as ArkG16VerifierKey;
use ark_poly_commit::kzg10::VerifierKey as ArkKZG10VerifierKey; use ark_poly_commit::kzg10::VerifierKey as ArkKZG10VerifierKey;
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
use askama::Template; use askama::Template;
use folding_schemes::folding::circuits::nonnative::uint::NonNativeUintVar; use folding_schemes::folding::circuits::nonnative::uint::NonNativeUintVar;
use folding_schemes::folding::nova::decider_eth::VerifierParam as DeciderVerifierParam;
use super::g16::Groth16Verifier; use super::g16::Groth16Verifier;
use super::kzg::KZG10Verifier; use super::kzg::KZG10Verifier;
@ -92,22 +93,26 @@ impl From<(Fr, Groth16VerifierKey, KZG10VerifierKey, usize)> for NovaCycleFoldVe
// in the NovaCycleFoldDecider verifier contract // in the NovaCycleFoldDecider verifier contract
impl impl
From<( From<(
(Fr, ArkG16VerifierKey<Bn254>, ArkKZG10VerifierKey<Bn254>),
DeciderVerifierParam<G1Projective, ArkKZG10VerifierKey<Bn254>, ArkG16VerifierKey<Bn254>>,
usize, usize,
)> for NovaCycleFoldVerifierKey )> for NovaCycleFoldVerifierKey
{ {
fn from( fn from(
value: ( value: (
(Fr, ArkG16VerifierKey<Bn254>, ArkKZG10VerifierKey<Bn254>),
DeciderVerifierParam<
G1Projective,
ArkKZG10VerifierKey<Bn254>,
ArkG16VerifierKey<Bn254>,
>,
usize, usize,
), ),
) -> Self { ) -> Self {
let decider_vp = value.0; let decider_vp = value.0;
let g16_vk = Groth16VerifierKey::from(decider_vp.1);
let g16_vk = Groth16VerifierKey::from(decider_vp.snark_vp);
// pass `Vec::new()` since batchCheck will not be used // pass `Vec::new()` since batchCheck will not be used
let kzg_vk = KZG10VerifierKey::from((decider_vp.2, Vec::new()));
let kzg_vk = KZG10VerifierKey::from((decider_vp.cs_vp, Vec::new()));
Self { Self {
pp_hash: decider_vp.0,
pp_hash: decider_vp.pp_hash,
g16_vk, g16_vk,
kzg_vk, kzg_vk,
z_len: value.1, z_len: value.1,
@ -157,7 +162,7 @@ mod tests {
Decider, Error, FoldingScheme, Decider, Error, FoldingScheme,
}; };
use super::NovaCycleFoldDecider;
use super::{DeciderVerifierParam, NovaCycleFoldDecider};
use crate::verifiers::tests::{setup, DEFAULT_SETUP_LEN}; use crate::verifiers::tests::{setup, DEFAULT_SETUP_LEN};
use crate::{ use crate::{
evm::{compile_solidity, save_solidity, Evm}, evm::{compile_solidity, save_solidity, Evm},
@ -286,9 +291,14 @@ mod tests {
fn nova_cyclefold_vk_serde_roundtrip() { fn nova_cyclefold_vk_serde_roundtrip() {
let (pp_hash, _, kzg_vk, _, g16_vk, _) = setup(DEFAULT_SETUP_LEN); let (pp_hash, _, kzg_vk, _, g16_vk, _) = setup(DEFAULT_SETUP_LEN);
let mut bytes = vec![];
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from(((pp_hash, g16_vk, kzg_vk), 1));
let decider_vp = DeciderVerifierParam {
pp_hash,
snark_vp: g16_vk,
cs_vp: kzg_vk,
};
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((decider_vp, 1));
let mut bytes = vec![];
nova_cyclefold_vk nova_cyclefold_vk
.serialize_protocol_verifier_key(&mut bytes) .serialize_protocol_verifier_key(&mut bytes)
.unwrap(); .unwrap();
@ -301,7 +311,12 @@ mod tests {
#[test] #[test]
fn nova_cyclefold_decider_template_renders() { fn nova_cyclefold_decider_template_renders() {
let (pp_hash, _, kzg_vk, _, g16_vk, _) = setup(DEFAULT_SETUP_LEN); let (pp_hash, _, kzg_vk, _, g16_vk, _) = setup(DEFAULT_SETUP_LEN);
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from(((pp_hash, g16_vk, kzg_vk), 1));
let decider_vp = DeciderVerifierParam {
pp_hash,
snark_vp: g16_vk,
cs_vp: kzg_vk,
};
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((decider_vp, 1));
let decider_solidity_code = HeaderInclusion::<NovaCycleFoldDecider>::builder() let decider_solidity_code = HeaderInclusion::<NovaCycleFoldDecider>::builder()
.template(nova_cyclefold_vk) .template(nova_cyclefold_vk)

Loading…
Cancel
Save