mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-09 07:21:28 +01:00
add hash of public params for Nova & HyperNova (#118)
- implement hash of public params for Nova & HyperNova - abstract pp_hash computation for folding schemes - add pp_hash to solidity contract generator to verify the decider proof
This commit is contained in:
@@ -82,13 +82,13 @@ fn main() {
|
|||||||
|
|
||||||
// prepare the Nova prover & verifier params
|
// prepare the Nova prover & verifier params
|
||||||
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, f_circuit.clone());
|
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, f_circuit.clone());
|
||||||
let (fs_pp, fs_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
let nova_params = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
||||||
|
|
||||||
// initialize the folding scheme engine, in our case we use Nova
|
// initialize the folding scheme engine, in our case we use Nova
|
||||||
let mut nova = N::init(&fs_pp, f_circuit.clone(), z_0).unwrap();
|
let mut nova = N::init(nova_params.clone(), f_circuit.clone(), z_0).unwrap();
|
||||||
|
|
||||||
// prepare the Decider prover & verifier params
|
// prepare the Decider prover & verifier params
|
||||||
let (decider_pp, decider_vp) = D::preprocess(&mut rng, &(fs_pp, fs_vp), nova.clone()).unwrap();
|
let (decider_pp, decider_vp) = D::preprocess(&mut rng, &nova_params, nova.clone()).unwrap();
|
||||||
|
|
||||||
// run n steps of the folding iteration
|
// run n steps of the folding iteration
|
||||||
for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
|
for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
|
||||||
|
|||||||
@@ -187,10 +187,11 @@ fn main() {
|
|||||||
|
|
||||||
println!("Prepare Nova's ProverParams & VerifierParams");
|
println!("Prepare Nova's ProverParams & VerifierParams");
|
||||||
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit.clone());
|
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit.clone());
|
||||||
let (nova_pp, nova_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
let nova_params = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
||||||
|
|
||||||
println!("Initialize FoldingScheme");
|
println!("Initialize FoldingScheme");
|
||||||
let mut folding_scheme = N::init(&nova_pp, F_circuit, initial_state.clone()).unwrap();
|
let mut folding_scheme =
|
||||||
|
N::init(nova_params.clone(), F_circuit, initial_state.clone()).unwrap();
|
||||||
|
|
||||||
// compute a step of the IVC
|
// compute a step of the IVC
|
||||||
for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
|
for (i, external_inputs_at_step) in external_inputs.iter().enumerate() {
|
||||||
@@ -210,7 +211,7 @@ fn main() {
|
|||||||
|
|
||||||
println!("Run the Nova's IVC verifier");
|
println!("Run the Nova's IVC verifier");
|
||||||
N::verify(
|
N::verify(
|
||||||
nova_vp,
|
nova_params.1,
|
||||||
initial_state.clone(),
|
initial_state.clone(),
|
||||||
folding_scheme.state(), // latest state
|
folding_scheme.state(), // latest state
|
||||||
Fr::from(num_steps as u32),
|
Fr::from(num_steps as u32),
|
||||||
|
|||||||
@@ -99,13 +99,13 @@ fn main() {
|
|||||||
|
|
||||||
// prepare the Nova prover & verifier params
|
// prepare the Nova prover & verifier params
|
||||||
let nova_preprocess_params = PreprocessorParam::new(poseidon_config.clone(), f_circuit);
|
let nova_preprocess_params = PreprocessorParam::new(poseidon_config.clone(), f_circuit);
|
||||||
let (fs_pp, fs_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
let nova_params = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
||||||
|
|
||||||
// initialize the folding scheme engine, in our case we use Nova
|
// initialize the folding scheme engine, in our case we use Nova
|
||||||
let mut nova = N::init(&fs_pp, f_circuit, z_0).unwrap();
|
let mut nova = N::init(nova_params.clone(), f_circuit, z_0).unwrap();
|
||||||
|
|
||||||
// prepare the Decider prover & verifier params
|
// prepare the Decider prover & verifier params
|
||||||
let (decider_pp, decider_vp) = D::preprocess(&mut rng, &(fs_pp, fs_vp), nova.clone()).unwrap();
|
let (decider_pp, decider_vp) = D::preprocess(&mut rng, &nova_params, nova.clone()).unwrap();
|
||||||
|
|
||||||
// run n steps of the folding iteration
|
// run n steps of the folding iteration
|
||||||
for i in 0..n_steps {
|
for i in 0..n_steps {
|
||||||
|
|||||||
@@ -141,10 +141,11 @@ fn main() {
|
|||||||
|
|
||||||
println!("Prepare Nova ProverParams & VerifierParams");
|
println!("Prepare Nova ProverParams & VerifierParams");
|
||||||
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit);
|
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit);
|
||||||
let (nova_pp, nova_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
let nova_params = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
||||||
|
|
||||||
println!("Initialize FoldingScheme");
|
println!("Initialize FoldingScheme");
|
||||||
let mut folding_scheme = N::init(&nova_pp, F_circuit, initial_state.clone()).unwrap();
|
let mut folding_scheme =
|
||||||
|
N::init(nova_params.clone(), F_circuit, initial_state.clone()).unwrap();
|
||||||
|
|
||||||
// compute a step of the IVC
|
// compute a step of the IVC
|
||||||
for i in 0..num_steps {
|
for i in 0..num_steps {
|
||||||
@@ -157,7 +158,7 @@ fn main() {
|
|||||||
|
|
||||||
println!("Run the Nova's IVC verifier");
|
println!("Run the Nova's IVC verifier");
|
||||||
N::verify(
|
N::verify(
|
||||||
nova_vp,
|
nova_params.1,
|
||||||
initial_state.clone(),
|
initial_state.clone(),
|
||||||
folding_scheme.state(), // latest state
|
folding_scheme.state(), // latest state
|
||||||
Fr::from(num_steps as u32),
|
Fr::from(num_steps as u32),
|
||||||
|
|||||||
@@ -126,10 +126,11 @@ fn main() {
|
|||||||
|
|
||||||
println!("Prepare Nova ProverParams & VerifierParams");
|
println!("Prepare Nova ProverParams & VerifierParams");
|
||||||
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit);
|
let nova_preprocess_params = PreprocessorParam::new(poseidon_config, F_circuit);
|
||||||
let (nova_pp, nova_vp) = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
let nova_params = N::preprocess(&mut rng, &nova_preprocess_params).unwrap();
|
||||||
|
|
||||||
println!("Initialize FoldingScheme");
|
println!("Initialize FoldingScheme");
|
||||||
let mut folding_scheme = N::init(&nova_pp, F_circuit, initial_state.clone()).unwrap();
|
let mut folding_scheme =
|
||||||
|
N::init(nova_params.clone(), F_circuit, initial_state.clone()).unwrap();
|
||||||
// compute a step of the IVC
|
// compute a step of the IVC
|
||||||
for i in 0..num_steps {
|
for i in 0..num_steps {
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
@@ -141,7 +142,7 @@ fn main() {
|
|||||||
|
|
||||||
println!("Run the Nova's IVC verifier");
|
println!("Run the Nova's IVC verifier");
|
||||||
N::verify(
|
N::verify(
|
||||||
nova_vp,
|
nova_params.1,
|
||||||
initial_state,
|
initial_state,
|
||||||
folding_scheme.state(), // latest state
|
folding_scheme.state(), // latest state
|
||||||
Fr::from(num_steps as u32),
|
Fr::from(num_steps as u32),
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ num-integer = "0.1"
|
|||||||
color-eyre = "=0.6.2"
|
color-eyre = "=0.6.2"
|
||||||
ark-bn254 = {version="0.4.0"}
|
ark-bn254 = {version="0.4.0"}
|
||||||
ark-groth16 = { version = "^0.4.0" }
|
ark-groth16 = { version = "^0.4.0" }
|
||||||
|
sha3 = "0.10"
|
||||||
|
|
||||||
# tmp imports for espresso's sumcheck
|
# tmp imports for espresso's sumcheck
|
||||||
espresso_subroutines = {git="https://github.com/EspressoSystems/hyperplonk", package="subroutines"}
|
espresso_subroutines = {git="https://github.com/EspressoSystems/hyperplonk", package="subroutines"}
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ use ark_std::log2;
|
|||||||
use crate::utils::vec::{hadamard, mat_vec_mul, vec_add, vec_scalar_mul, SparseMatrix};
|
use crate::utils::vec::{hadamard, mat_vec_mul, vec_add, vec_scalar_mul, SparseMatrix};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|
||||||
pub mod r1cs;
|
use super::{r1cs::R1CS, Arith};
|
||||||
use r1cs::R1CS;
|
|
||||||
|
|
||||||
/// CCS represents the Customizable Constraint Systems structure defined in
|
/// CCS represents the Customizable Constraint Systems structure defined in
|
||||||
/// the [CCS paper](https://eprint.iacr.org/2023/552)
|
/// the [CCS paper](https://eprint.iacr.org/2023/552)
|
||||||
@@ -36,9 +35,9 @@ pub struct CCS<F: PrimeField> {
|
|||||||
pub c: Vec<F>,
|
pub c: Vec<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: PrimeField> CCS<F> {
|
impl<F: PrimeField> Arith<F> for CCS<F> {
|
||||||
/// check that a CCS structure is satisfied by a z vector. Only for testing.
|
/// check that a CCS structure is satisfied by a z vector. Only for testing.
|
||||||
pub fn check_relation(&self, z: &[F]) -> Result<(), Error> {
|
fn check_relation(&self, z: &[F]) -> Result<(), Error> {
|
||||||
let mut result = vec![F::zero(); self.m];
|
let mut result = vec![F::zero(); self.m];
|
||||||
|
|
||||||
for i in 0..self.q {
|
for i in 0..self.q {
|
||||||
@@ -67,6 +66,18 @@ impl<F: PrimeField> CCS<F> {
|
|||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn params_to_bytes(&self) -> Vec<u8> {
|
||||||
|
[
|
||||||
|
self.l.to_le_bytes(),
|
||||||
|
self.m.to_le_bytes(),
|
||||||
|
self.n.to_le_bytes(),
|
||||||
|
self.t.to_le_bytes(),
|
||||||
|
self.q.to_le_bytes(),
|
||||||
|
self.d.to_le_bytes(),
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: PrimeField> CCS<F> {
|
impl<F: PrimeField> CCS<F> {
|
||||||
@@ -102,7 +113,7 @@ impl<F: PrimeField> CCS<F> {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z as r1cs_get_test_z};
|
use crate::arith::r1cs::tests::{get_test_r1cs, get_test_z as r1cs_get_test_z};
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
use ark_pallas::Fr;
|
use ark_pallas::Fr;
|
||||||
|
|
||||||
15
folding-schemes/src/arith/mod.rs
Normal file
15
folding-schemes/src/arith/mod.rs
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
use ark_ff::PrimeField;
|
||||||
|
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
|
pub mod ccs;
|
||||||
|
pub mod r1cs;
|
||||||
|
|
||||||
|
pub trait Arith<F: PrimeField> {
|
||||||
|
/// Checks that the given Arith structure is satisfied by a z vector. Used only for testing.
|
||||||
|
fn check_relation(&self, z: &[F]) -> Result<(), Error>;
|
||||||
|
|
||||||
|
/// Returns the bytes that represent the parameters, that is, the matrices sizes, the amount of
|
||||||
|
/// public inputs, etc, without the matrices/polynomials values.
|
||||||
|
fn params_to_bytes(&self) -> Vec<u8>;
|
||||||
|
}
|
||||||
@@ -1,10 +1,11 @@
|
|||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
use ark_relations::r1cs::ConstraintSystem;
|
use ark_relations::r1cs::ConstraintSystem;
|
||||||
|
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||||
use ark_std::rand::Rng;
|
use ark_std::rand::Rng;
|
||||||
|
|
||||||
|
use super::Arith;
|
||||||
use crate::utils::vec::{hadamard, mat_vec_mul, vec_add, vec_scalar_mul, SparseMatrix};
|
use crate::utils::vec::{hadamard, mat_vec_mul, vec_add, vec_scalar_mul, SparseMatrix};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
|
#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
|
||||||
pub struct R1CS<F: PrimeField> {
|
pub struct R1CS<F: PrimeField> {
|
||||||
@@ -14,6 +15,29 @@ pub struct R1CS<F: PrimeField> {
|
|||||||
pub C: SparseMatrix<F>,
|
pub C: SparseMatrix<F>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<F: PrimeField> Arith<F> for R1CS<F> {
|
||||||
|
/// check that a R1CS structure is satisfied by a z vector. Only for testing.
|
||||||
|
fn check_relation(&self, z: &[F]) -> Result<(), Error> {
|
||||||
|
let Az = mat_vec_mul(&self.A, z)?;
|
||||||
|
let Bz = mat_vec_mul(&self.B, z)?;
|
||||||
|
let Cz = mat_vec_mul(&self.C, z)?;
|
||||||
|
let AzBz = hadamard(&Az, &Bz)?;
|
||||||
|
if AzBz != Cz {
|
||||||
|
return Err(Error::NotSatisfied);
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn params_to_bytes(&self) -> Vec<u8> {
|
||||||
|
[
|
||||||
|
self.l.to_le_bytes(),
|
||||||
|
self.A.n_rows.to_le_bytes(),
|
||||||
|
self.A.n_cols.to_le_bytes(),
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<F: PrimeField> R1CS<F> {
|
impl<F: PrimeField> R1CS<F> {
|
||||||
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 {
|
||||||
@@ -29,19 +53,6 @@ impl<F: PrimeField> R1CS<F> {
|
|||||||
(z[self.l + 1..].to_vec(), z[1..self.l + 1].to_vec())
|
(z[self.l + 1..].to_vec(), z[1..self.l + 1].to_vec())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// check that a R1CS structure is satisfied by a z vector. Only for testing.
|
|
||||||
pub fn check_relation(&self, z: &[F]) -> Result<(), Error> {
|
|
||||||
let Az = mat_vec_mul(&self.A, z)?;
|
|
||||||
let Bz = mat_vec_mul(&self.B, z)?;
|
|
||||||
let Cz = mat_vec_mul(&self.C, z)?;
|
|
||||||
let AzBz = hadamard(&Az, &Bz)?;
|
|
||||||
if AzBz != Cz {
|
|
||||||
return Err(Error::NotSatisfied);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// converts the R1CS instance into a RelaxedR1CS as described in
|
/// converts the R1CS instance into a RelaxedR1CS as described in
|
||||||
/// [Nova](https://eprint.iacr.org/2021/370.pdf) section 4.1.
|
/// [Nova](https://eprint.iacr.org/2021/370.pdf) section 4.1.
|
||||||
pub fn relax(self) -> RelaxedR1CS<F> {
|
pub fn relax(self) -> RelaxedR1CS<F> {
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
use ark_ec::CurveGroup;
|
use ark_ec::CurveGroup;
|
||||||
|
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||||
use ark_std::fmt::Debug;
|
use ark_std::fmt::Debug;
|
||||||
use ark_std::rand::RngCore;
|
use ark_std::rand::RngCore;
|
||||||
|
|
||||||
@@ -13,7 +14,7 @@ pub mod pedersen;
|
|||||||
/// 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;
|
||||||
type VerifierParams: Clone + Debug;
|
type VerifierParams: Clone + Debug + CanonicalSerialize + CanonicalDeserialize;
|
||||||
type Proof: Clone + Debug;
|
type Proof: Clone + Debug;
|
||||||
type ProverChallenge: Clone + Debug;
|
type ProverChallenge: Clone + Debug;
|
||||||
type Challenge: Clone + Debug;
|
type Challenge: Clone + Debug;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ use ark_std::{One, Zero};
|
|||||||
use core::{borrow::Borrow, marker::PhantomData};
|
use core::{borrow::Borrow, marker::PhantomData};
|
||||||
|
|
||||||
use super::{nonnative::uint::NonNativeUintVar, CF2};
|
use super::{nonnative::uint::NonNativeUintVar, CF2};
|
||||||
use crate::ccs::r1cs::{extract_w_x, R1CS};
|
use crate::arith::r1cs::{extract_w_x, R1CS};
|
||||||
use crate::commitment::CommitmentScheme;
|
use crate::commitment::CommitmentScheme;
|
||||||
use crate::constants::N_BITS_RO;
|
use crate::constants::N_BITS_RO;
|
||||||
use crate::folding::nova::{nifs::NIFS, CommittedInstance, Witness};
|
use crate::folding::nova::{nifs::NIFS, CommittedInstance, Witness};
|
||||||
@@ -127,9 +127,13 @@ where
|
|||||||
pub fn hash(
|
pub fn hash(
|
||||||
self,
|
self,
|
||||||
crh_params: &CRHParametersVar<CF2<C>>,
|
crh_params: &CRHParametersVar<CF2<C>>,
|
||||||
|
pp_hash: FpVar<CF2<C>>, // public params hash
|
||||||
) -> Result<(FpVar<CF2<C>>, Vec<FpVar<CF2<C>>>), SynthesisError> {
|
) -> Result<(FpVar<CF2<C>>, Vec<FpVar<CF2<C>>>), SynthesisError> {
|
||||||
let U_vec = self.to_constraint_field()?;
|
let U_vec = self.to_constraint_field()?;
|
||||||
Ok((CRHGadget::evaluate(crh_params, &U_vec)?, U_vec))
|
Ok((
|
||||||
|
CRHGadget::evaluate(crh_params, &[vec![pp_hash], U_vec.clone()].concat())?,
|
||||||
|
U_vec,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -252,6 +256,7 @@ where
|
|||||||
{
|
{
|
||||||
pub fn get_challenge_native(
|
pub fn get_challenge_native(
|
||||||
poseidon_config: &PoseidonConfig<C::BaseField>,
|
poseidon_config: &PoseidonConfig<C::BaseField>,
|
||||||
|
pp_hash: C::BaseField, // public params hash
|
||||||
U_i: CommittedInstance<C>,
|
U_i: CommittedInstance<C>,
|
||||||
u_i: CommittedInstance<C>,
|
u_i: CommittedInstance<C>,
|
||||||
cmT: C,
|
cmT: C,
|
||||||
@@ -276,7 +281,7 @@ where
|
|||||||
// to save constraints for sponge.squeeze_bits in the corresponding circuit
|
// to save constraints for sponge.squeeze_bits in the corresponding circuit
|
||||||
let is_inf = U_cm_is_inf * CF2::<C>::from(8u8) + u_cm_is_inf.double() + cmT_is_inf;
|
let is_inf = U_cm_is_inf * CF2::<C>::from(8u8) + u_cm_is_inf.double() + cmT_is_inf;
|
||||||
|
|
||||||
let input = [U_vec, u_vec, vec![cmT_x, cmT_y, is_inf]].concat();
|
let input = [vec![pp_hash], U_vec, u_vec, vec![cmT_x, cmT_y, is_inf]].concat();
|
||||||
sponge.absorb(&input);
|
sponge.absorb(&input);
|
||||||
let bits = sponge.squeeze_bits(N_BITS_RO);
|
let bits = sponge.squeeze_bits(N_BITS_RO);
|
||||||
Ok(bits)
|
Ok(bits)
|
||||||
@@ -286,6 +291,7 @@ where
|
|||||||
pub fn get_challenge_gadget(
|
pub fn get_challenge_gadget(
|
||||||
cs: ConstraintSystemRef<C::BaseField>,
|
cs: ConstraintSystemRef<C::BaseField>,
|
||||||
poseidon_config: &PoseidonConfig<C::BaseField>,
|
poseidon_config: &PoseidonConfig<C::BaseField>,
|
||||||
|
pp_hash: FpVar<C::BaseField>, // public params hash
|
||||||
mut U_i_vec: Vec<FpVar<C::BaseField>>,
|
mut U_i_vec: Vec<FpVar<C::BaseField>>,
|
||||||
u_i: CycleFoldCommittedInstanceVar<C, GC>,
|
u_i: CycleFoldCommittedInstanceVar<C, GC>,
|
||||||
cmT: GC,
|
cmT: GC,
|
||||||
@@ -303,7 +309,7 @@ where
|
|||||||
// to save constraints for sponge.squeeze_bits
|
// to save constraints for sponge.squeeze_bits
|
||||||
let is_inf = U_cm_is_inf * CF2::<C>::from(8u8) + u_cm_is_inf.double()? + cmT_is_inf;
|
let is_inf = U_cm_is_inf * CF2::<C>::from(8u8) + u_cm_is_inf.double()? + cmT_is_inf;
|
||||||
|
|
||||||
let input = [U_i_vec, u_i_vec, cmT_vec, vec![is_inf]].concat();
|
let input = [vec![pp_hash], U_i_vec, u_i_vec, cmT_vec, vec![is_inf]].concat();
|
||||||
sponge.absorb(&input)?;
|
sponge.absorb(&input)?;
|
||||||
let bits = sponge.squeeze_bits(N_BITS_RO)?;
|
let bits = sponge.squeeze_bits(N_BITS_RO)?;
|
||||||
Ok(bits)
|
Ok(bits)
|
||||||
@@ -372,13 +378,15 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Folds the given cyclefold circuit and its instances. This method is isolated from any folding
|
/// Folds the given cyclefold circuit and its instances. This method is abstracted from any folding
|
||||||
/// scheme struct because it is used both by Nova & HyperNova's CycleFold.
|
/// scheme struct because it is used both by Nova & HyperNova's CycleFold.
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
pub fn fold_cyclefold_circuit<C1, GC1, C2, GC2, FC, CS1, CS2>(
|
pub fn fold_cyclefold_circuit<C1, GC1, C2, GC2, FC, CS1, CS2>(
|
||||||
poseidon_config: &PoseidonConfig<C1::ScalarField>,
|
poseidon_config: &PoseidonConfig<C1::ScalarField>,
|
||||||
cf_r1cs: R1CS<C2::ScalarField>,
|
cf_r1cs: R1CS<C2::ScalarField>,
|
||||||
cf_cs_params: CS2::ProverParams,
|
cf_cs_params: CS2::ProverParams,
|
||||||
|
pp_hash: C1::ScalarField, // public params hash
|
||||||
cf_W_i: Witness<C2>, // witness of the running instance
|
cf_W_i: Witness<C2>, // witness of the running instance
|
||||||
cf_U_i: CommittedInstance<C2>, // running instance
|
cf_U_i: CommittedInstance<C2>, // running instance
|
||||||
cf_u_i_x: Vec<C2::ScalarField>,
|
cf_u_i_x: Vec<C2::ScalarField>,
|
||||||
@@ -438,6 +446,7 @@ where
|
|||||||
|
|
||||||
let cf_r_bits = CycleFoldChallengeGadget::<C2, GC2>::get_challenge_native(
|
let cf_r_bits = CycleFoldChallengeGadget::<C2, GC2>::get_challenge_native(
|
||||||
poseidon_config,
|
poseidon_config,
|
||||||
|
pp_hash,
|
||||||
cf_U_i.clone(),
|
cf_U_i.clone(),
|
||||||
cf_u_i.clone(),
|
cf_u_i.clone(),
|
||||||
cf_cmT,
|
cf_cmT,
|
||||||
@@ -594,8 +603,10 @@ pub mod tests {
|
|||||||
let cmT = Projective::rand(&mut rng);
|
let cmT = Projective::rand(&mut rng);
|
||||||
|
|
||||||
// compute the challenge natively
|
// compute the challenge natively
|
||||||
|
let pp_hash = Fq::from(42u32); // only for test
|
||||||
let r_bits = CycleFoldChallengeGadget::<Projective, GVar>::get_challenge_native(
|
let r_bits = CycleFoldChallengeGadget::<Projective, GVar>::get_challenge_native(
|
||||||
&poseidon_config,
|
&poseidon_config,
|
||||||
|
pp_hash,
|
||||||
U_i.clone(),
|
U_i.clone(),
|
||||||
u_i.clone(),
|
u_i.clone(),
|
||||||
cmT,
|
cmT,
|
||||||
@@ -615,9 +626,11 @@ pub mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let cmTVar = GVar::new_witness(cs.clone(), || Ok(cmT)).unwrap();
|
let cmTVar = GVar::new_witness(cs.clone(), || Ok(cmT)).unwrap();
|
||||||
|
|
||||||
|
let pp_hashVar = FpVar::<Fq>::new_witness(cs.clone(), || Ok(pp_hash)).unwrap();
|
||||||
let r_bitsVar = CycleFoldChallengeGadget::<Projective, GVar>::get_challenge_gadget(
|
let r_bitsVar = CycleFoldChallengeGadget::<Projective, GVar>::get_challenge_gadget(
|
||||||
cs.clone(),
|
cs.clone(),
|
||||||
&poseidon_config,
|
&poseidon_config,
|
||||||
|
pp_hashVar,
|
||||||
U_iVar.to_constraint_field().unwrap(),
|
U_iVar.to_constraint_field().unwrap(),
|
||||||
u_iVar,
|
u_iVar,
|
||||||
cmTVar,
|
cmTVar,
|
||||||
@@ -645,7 +658,8 @@ pub mod tests {
|
|||||||
.take(CF_IO_LEN)
|
.take(CF_IO_LEN)
|
||||||
.collect(),
|
.collect(),
|
||||||
};
|
};
|
||||||
let h = U_i.hash_cyclefold(&poseidon_config).unwrap();
|
let pp_hash = Fq::from(42u32); // only for test
|
||||||
|
let h = U_i.hash_cyclefold(&poseidon_config, pp_hash).unwrap();
|
||||||
|
|
||||||
let cs = ConstraintSystem::<Fq>::new_ref();
|
let cs = ConstraintSystem::<Fq>::new_ref();
|
||||||
let U_iVar =
|
let U_iVar =
|
||||||
@@ -653,8 +667,12 @@ pub mod tests {
|
|||||||
Ok(U_i.clone())
|
Ok(U_i.clone())
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let pp_hashVar = FpVar::<Fq>::new_witness(cs.clone(), || Ok(pp_hash)).unwrap();
|
||||||
let (hVar, _) = U_iVar
|
let (hVar, _) = U_iVar
|
||||||
.hash(&CRHParametersVar::new_constant(cs.clone(), poseidon_config).unwrap())
|
.hash(
|
||||||
|
&CRHParametersVar::new_constant(cs.clone(), poseidon_config).unwrap(),
|
||||||
|
pp_hashVar,
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
hVar.enforce_equal(&FpVar::new_witness(cs.clone(), || Ok(h)).unwrap())
|
hVar.enforce_equal(&FpVar::new_witness(cs.clone(), || Ok(h)).unwrap())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use std::sync::Arc;
|
|||||||
use ark_std::rand::Rng;
|
use ark_std::rand::Rng;
|
||||||
|
|
||||||
use super::Witness;
|
use super::Witness;
|
||||||
use crate::ccs::CCS;
|
use crate::arith::{ccs::CCS, Arith};
|
||||||
use crate::commitment::CommitmentScheme;
|
use crate::commitment::CommitmentScheme;
|
||||||
use crate::utils::mle::dense_vec_to_dense_mle;
|
use crate::utils::mle::dense_vec_to_dense_mle;
|
||||||
use crate::utils::vec::mat_vec_mul;
|
use crate::utils::vec::mat_vec_mul;
|
||||||
@@ -125,7 +125,7 @@ pub mod tests {
|
|||||||
use ark_std::UniformRand;
|
use ark_std::UniformRand;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ccs::tests::{get_test_ccs, get_test_z};
|
use crate::arith::ccs::tests::{get_test_ccs, get_test_z};
|
||||||
use crate::utils::hypercube::BooleanHypercube;
|
use crate::utils::hypercube::BooleanHypercube;
|
||||||
|
|
||||||
/// Do some sanity checks on q(x). It's a multivariable polynomial and it should evaluate to zero inside the
|
/// Do some sanity checks on q(x). It's a multivariable polynomial and it should evaluate to zero inside the
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ use crate::frontend::FCircuit;
|
|||||||
use crate::utils::virtual_polynomial::VPAuxInfo;
|
use crate::utils::virtual_polynomial::VPAuxInfo;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use crate::{
|
use crate::{
|
||||||
ccs::{r1cs::extract_r1cs, CCS},
|
arith::{ccs::CCS, r1cs::extract_r1cs},
|
||||||
transcript::{
|
transcript::{
|
||||||
poseidon::{PoseidonTranscript, PoseidonTranscriptVar},
|
poseidon::{PoseidonTranscript, PoseidonTranscriptVar},
|
||||||
Transcript, TranscriptVar,
|
Transcript, TranscriptVar,
|
||||||
@@ -143,6 +143,7 @@ where
|
|||||||
pub fn hash(
|
pub fn hash(
|
||||||
self,
|
self,
|
||||||
crh_params: &CRHParametersVar<CF1<C>>,
|
crh_params: &CRHParametersVar<CF1<C>>,
|
||||||
|
pp_hash: FpVar<CF1<C>>,
|
||||||
i: FpVar<CF1<C>>,
|
i: FpVar<CF1<C>>,
|
||||||
z_0: Vec<FpVar<CF1<C>>>,
|
z_0: Vec<FpVar<CF1<C>>>,
|
||||||
z_i: Vec<FpVar<CF1<C>>>,
|
z_i: Vec<FpVar<CF1<C>>>,
|
||||||
@@ -155,7 +156,7 @@ where
|
|||||||
self.v,
|
self.v,
|
||||||
]
|
]
|
||||||
.concat();
|
.concat();
|
||||||
let input = [vec![i], z_0, z_i, U_vec.clone()].concat();
|
let input = [vec![pp_hash, i], z_0, z_i, U_vec.clone()].concat();
|
||||||
Ok((
|
Ok((
|
||||||
CRHGadget::<C::ScalarField>::evaluate(crh_params, &input)?,
|
CRHGadget::<C::ScalarField>::evaluate(crh_params, &input)?,
|
||||||
U_vec,
|
U_vec,
|
||||||
@@ -455,6 +456,7 @@ pub struct AugmentedFCircuit<
|
|||||||
pub _gc2: PhantomData<GC2>,
|
pub _gc2: PhantomData<GC2>,
|
||||||
pub poseidon_config: PoseidonConfig<CF1<C1>>,
|
pub poseidon_config: PoseidonConfig<CF1<C1>>,
|
||||||
pub ccs: CCS<C1::ScalarField>, // CCS of the AugmentedFCircuit
|
pub ccs: CCS<C1::ScalarField>, // CCS of the AugmentedFCircuit
|
||||||
|
pub pp_hash: Option<CF1<C1>>,
|
||||||
pub i: Option<CF1<C1>>,
|
pub i: Option<CF1<C1>>,
|
||||||
pub i_usize: Option<usize>,
|
pub i_usize: Option<usize>,
|
||||||
pub z_0: Option<Vec<C1::ScalarField>>,
|
pub z_0: Option<Vec<C1::ScalarField>>,
|
||||||
@@ -497,6 +499,7 @@ where
|
|||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config: poseidon_config.clone(),
|
||||||
ccs,
|
ccs,
|
||||||
|
pp_hash: None,
|
||||||
i: None,
|
i: None,
|
||||||
i_usize: None,
|
i_usize: None,
|
||||||
z_0: None,
|
z_0: None,
|
||||||
@@ -559,6 +562,7 @@ where
|
|||||||
|
|
||||||
let mut transcript_p: PoseidonTranscript<C1> =
|
let mut transcript_p: PoseidonTranscript<C1> =
|
||||||
PoseidonTranscript::<C1>::new(&self.poseidon_config.clone());
|
PoseidonTranscript::<C1>::new(&self.poseidon_config.clone());
|
||||||
|
// since this is only for the number of constraints, no need to absorb the pp_hash here
|
||||||
let (nimfs_proof, U_i1, _, _) = NIMFS::<C1, PoseidonTranscript<C1>>::prove(
|
let (nimfs_proof, U_i1, _, _) = NIMFS::<C1, PoseidonTranscript<C1>>::prove(
|
||||||
&mut transcript_p,
|
&mut transcript_p,
|
||||||
&ccs,
|
&ccs,
|
||||||
@@ -573,6 +577,7 @@ where
|
|||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
poseidon_config: self.poseidon_config.clone(),
|
poseidon_config: self.poseidon_config.clone(),
|
||||||
ccs: ccs.clone(),
|
ccs: ccs.clone(),
|
||||||
|
pp_hash: Some(C1::ScalarField::zero()),
|
||||||
i: Some(C1::ScalarField::zero()),
|
i: Some(C1::ScalarField::zero()),
|
||||||
i_usize: Some(0),
|
i_usize: Some(0),
|
||||||
z_0: Some(z_0.clone()),
|
z_0: Some(z_0.clone()),
|
||||||
@@ -624,6 +629,9 @@ where
|
|||||||
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
|
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
|
||||||
{
|
{
|
||||||
fn generate_constraints(self, cs: ConstraintSystemRef<CF1<C1>>) -> Result<(), SynthesisError> {
|
fn generate_constraints(self, cs: ConstraintSystemRef<CF1<C1>>) -> Result<(), SynthesisError> {
|
||||||
|
let pp_hash = FpVar::<CF1<C1>>::new_witness(cs.clone(), || {
|
||||||
|
Ok(self.pp_hash.unwrap_or_else(CF1::<C1>::zero))
|
||||||
|
})?;
|
||||||
let i = FpVar::<CF1<C1>>::new_witness(cs.clone(), || {
|
let i = FpVar::<CF1<C1>>::new_witness(cs.clone(), || {
|
||||||
Ok(self.i.unwrap_or_else(CF1::<C1>::zero))
|
Ok(self.i.unwrap_or_else(CF1::<C1>::zero))
|
||||||
})?;
|
})?;
|
||||||
@@ -680,11 +688,15 @@ where
|
|||||||
// Primary Part
|
// Primary Part
|
||||||
// P.1. Compute u_i.x
|
// P.1. Compute u_i.x
|
||||||
// u_i.x[0] = H(i, z_0, z_i, U_i)
|
// u_i.x[0] = H(i, z_0, z_i, U_i)
|
||||||
let (u_i_x, _) = U_i
|
let (u_i_x, _) = U_i.clone().hash(
|
||||||
.clone()
|
&crh_params,
|
||||||
.hash(&crh_params, i.clone(), z_0.clone(), z_i.clone())?;
|
pp_hash.clone(),
|
||||||
|
i.clone(),
|
||||||
|
z_0.clone(),
|
||||||
|
z_i.clone(),
|
||||||
|
)?;
|
||||||
// u_i.x[1] = H(cf_U_i)
|
// u_i.x[1] = H(cf_U_i)
|
||||||
let (cf_u_i_x, cf_U_i_vec) = cf_U_i.clone().hash(&crh_params)?;
|
let (cf_u_i_x, cf_U_i_vec) = cf_U_i.clone().hash(&crh_params, pp_hash.clone())?;
|
||||||
|
|
||||||
// P.2. Construct u_i
|
// P.2. Construct u_i
|
||||||
let u_i = CCCSVar::<C1> {
|
let u_i = CCCSVar::<C1> {
|
||||||
@@ -700,8 +712,9 @@ where
|
|||||||
// Notice that NIMFSGadget::fold_committed_instance does not fold C. We set `U_i1.C` to
|
// Notice that NIMFSGadget::fold_committed_instance does not fold C. We set `U_i1.C` to
|
||||||
// unconstrained witnesses `U_i1_C` respectively. Its correctness will be checked on the
|
// unconstrained witnesses `U_i1_C` respectively. Its correctness will be checked on the
|
||||||
// other curve.
|
// other curve.
|
||||||
let transcript =
|
let mut transcript =
|
||||||
PoseidonTranscriptVar::<C1::ScalarField>::new(cs.clone(), &self.poseidon_config);
|
PoseidonTranscriptVar::<C1::ScalarField>::new(cs.clone(), &self.poseidon_config);
|
||||||
|
transcript.absorb(pp_hash.clone())?;
|
||||||
let (mut U_i1, rho_bits) = NIMFSGadget::<C1>::verify(
|
let (mut U_i1, rho_bits) = NIMFSGadget::<C1>::verify(
|
||||||
cs.clone(),
|
cs.clone(),
|
||||||
&self.ccs.clone(),
|
&self.ccs.clone(),
|
||||||
@@ -716,12 +729,14 @@ where
|
|||||||
// P.4.a compute and check the first output of F'
|
// P.4.a compute and check the first output of F'
|
||||||
let (u_i1_x, _) = U_i1.clone().hash(
|
let (u_i1_x, _) = U_i1.clone().hash(
|
||||||
&crh_params,
|
&crh_params,
|
||||||
|
pp_hash.clone(),
|
||||||
i + FpVar::<CF1<C1>>::one(),
|
i + FpVar::<CF1<C1>>::one(),
|
||||||
z_0.clone(),
|
z_0.clone(),
|
||||||
z_i1.clone(),
|
z_i1.clone(),
|
||||||
)?;
|
)?;
|
||||||
let (u_i1_x_base, _) = LCCCSVar::new_constant(cs.clone(), U_dummy)?.hash(
|
let (u_i1_x_base, _) = LCCCSVar::new_constant(cs.clone(), U_dummy)?.hash(
|
||||||
&crh_params,
|
&crh_params,
|
||||||
|
pp_hash.clone(),
|
||||||
FpVar::<CF1<C1>>::one(),
|
FpVar::<CF1<C1>>::one(),
|
||||||
z_0.clone(),
|
z_0.clone(),
|
||||||
z_i1.clone(),
|
z_i1.clone(),
|
||||||
@@ -763,6 +778,7 @@ where
|
|||||||
let cf_r_bits = CycleFoldChallengeGadget::<C2, GC2>::get_challenge_gadget(
|
let cf_r_bits = CycleFoldChallengeGadget::<C2, GC2>::get_challenge_gadget(
|
||||||
cs.clone(),
|
cs.clone(),
|
||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
|
pp_hash.clone(),
|
||||||
cf_U_i_vec,
|
cf_U_i_vec,
|
||||||
cf_u_i.clone(),
|
cf_u_i.clone(),
|
||||||
cf_cmT.clone(),
|
cf_cmT.clone(),
|
||||||
@@ -786,10 +802,10 @@ where
|
|||||||
// P.4.b compute and check the second output of F'
|
// P.4.b compute and check the second output of F'
|
||||||
// Base case: u_{i+1}.x[1] == H(cf_U_{\bot})
|
// Base case: u_{i+1}.x[1] == H(cf_U_{\bot})
|
||||||
// Non-base case: u_{i+1}.x[1] == H(cf_U_{i+1})
|
// Non-base case: u_{i+1}.x[1] == H(cf_U_{i+1})
|
||||||
let (cf_u_i1_x, _) = cf_U_i1.clone().hash(&crh_params)?;
|
let (cf_u_i1_x, _) = cf_U_i1.clone().hash(&crh_params, pp_hash.clone())?;
|
||||||
let (cf_u_i1_x_base, _) =
|
let (cf_u_i1_x_base, _) =
|
||||||
CycleFoldCommittedInstanceVar::new_constant(cs.clone(), cf_u_dummy)?
|
CycleFoldCommittedInstanceVar::new_constant(cs.clone(), cf_u_dummy)?
|
||||||
.hash(&crh_params)?;
|
.hash(&crh_params, pp_hash)?;
|
||||||
let cf_x = FpVar::new_input(cs.clone(), || {
|
let cf_x = FpVar::new_input(cs.clone(), || {
|
||||||
Ok(self.cf_x.unwrap_or(cf_u_i1_x_base.value()?))
|
Ok(self.cf_x.unwrap_or(cf_u_i1_x_base.value()?))
|
||||||
})?;
|
})?;
|
||||||
@@ -810,10 +826,12 @@ mod tests {
|
|||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
ccs::{
|
arith::{
|
||||||
|
ccs::{
|
||||||
|
tests::{get_test_ccs, get_test_z},
|
||||||
|
CCS,
|
||||||
|
},
|
||||||
r1cs::extract_w_x,
|
r1cs::extract_w_x,
|
||||||
tests::{get_test_ccs, get_test_z},
|
|
||||||
CCS,
|
|
||||||
},
|
},
|
||||||
commitment::{pedersen::Pedersen, CommitmentScheme},
|
commitment::{pedersen::Pedersen, CommitmentScheme},
|
||||||
folding::{
|
folding::{
|
||||||
@@ -1049,6 +1067,7 @@ mod tests {
|
|||||||
|
|
||||||
let (pedersen_params, _) =
|
let (pedersen_params, _) =
|
||||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||||
|
let pp_hash = Fr::from(42u32); // only for test
|
||||||
|
|
||||||
let i = Fr::from(3_u32);
|
let i = Fr::from(3_u32);
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
@@ -1058,19 +1077,26 @@ mod tests {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let h = lcccs
|
let h = lcccs
|
||||||
.clone()
|
.clone()
|
||||||
.hash(&poseidon_config, i, z_0.clone(), z_i.clone())
|
.hash(&poseidon_config, pp_hash, i, z_0.clone(), z_i.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
|
|
||||||
let crh_params = CRHParametersVar::<Fr>::new_constant(cs.clone(), poseidon_config).unwrap();
|
let crh_params = CRHParametersVar::<Fr>::new_constant(cs.clone(), poseidon_config).unwrap();
|
||||||
|
let pp_hashVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(pp_hash)).unwrap();
|
||||||
let iVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(i)).unwrap();
|
let iVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(i)).unwrap();
|
||||||
let z_0Var = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_0.clone())).unwrap();
|
let z_0Var = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_0.clone())).unwrap();
|
||||||
let z_iVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_i.clone())).unwrap();
|
let z_iVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_i.clone())).unwrap();
|
||||||
let lcccsVar = LCCCSVar::<Projective>::new_witness(cs.clone(), || Ok(lcccs)).unwrap();
|
let lcccsVar = LCCCSVar::<Projective>::new_witness(cs.clone(), || Ok(lcccs)).unwrap();
|
||||||
let (hVar, _) = lcccsVar
|
let (hVar, _) = lcccsVar
|
||||||
.clone()
|
.clone()
|
||||||
.hash(&crh_params, iVar.clone(), z_0Var.clone(), z_iVar.clone())
|
.hash(
|
||||||
|
&crh_params,
|
||||||
|
pp_hashVar,
|
||||||
|
iVar.clone(),
|
||||||
|
z_0Var.clone(),
|
||||||
|
z_iVar.clone(),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert!(cs.is_satisfied().unwrap());
|
assert!(cs.is_satisfied().unwrap());
|
||||||
|
|
||||||
@@ -1112,6 +1138,9 @@ mod tests {
|
|||||||
let (cf_pedersen_params, _) =
|
let (cf_pedersen_params, _) =
|
||||||
Pedersen::<Projective2>::setup(&mut rng, cf_r1cs.A.n_cols - cf_r1cs.l - 1).unwrap();
|
Pedersen::<Projective2>::setup(&mut rng, cf_r1cs.A.n_cols - cf_r1cs.l - 1).unwrap();
|
||||||
|
|
||||||
|
// public params hash
|
||||||
|
let pp_hash = Fr::from(42u32); // only for test
|
||||||
|
|
||||||
// first step
|
// first step
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
let mut z_i = z_0.clone();
|
let mut z_i = z_0.clone();
|
||||||
@@ -1132,9 +1161,15 @@ mod tests {
|
|||||||
let mut cf_W_i = cf_W_dummy.clone();
|
let mut cf_W_i = cf_W_dummy.clone();
|
||||||
let mut cf_U_i = cf_U_dummy.clone();
|
let mut cf_U_i = cf_U_dummy.clone();
|
||||||
u_i.x = vec![
|
u_i.x = vec![
|
||||||
U_i.hash(&poseidon_config, Fr::zero(), z_0.clone(), z_i.clone())
|
U_i.hash(
|
||||||
.unwrap(),
|
&poseidon_config,
|
||||||
cf_U_i.hash_cyclefold(&poseidon_config).unwrap(),
|
pp_hash,
|
||||||
|
Fr::zero(),
|
||||||
|
z_0.clone(),
|
||||||
|
z_i.clone(),
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
cf_U_i.hash_cyclefold(&poseidon_config, pp_hash).unwrap(),
|
||||||
];
|
];
|
||||||
|
|
||||||
let n_steps: usize = 4;
|
let n_steps: usize = 4;
|
||||||
@@ -1151,12 +1186,18 @@ mod tests {
|
|||||||
U_i1 = LCCCS::dummy(ccs.l, ccs.t, ccs.s);
|
U_i1 = LCCCS::dummy(ccs.l, ccs.t, ccs.s);
|
||||||
|
|
||||||
let u_i1_x = U_i1
|
let u_i1_x = U_i1
|
||||||
.hash(&poseidon_config, Fr::one(), z_0.clone(), z_i1.clone())
|
.hash(
|
||||||
|
&poseidon_config,
|
||||||
|
pp_hash,
|
||||||
|
Fr::one(),
|
||||||
|
z_0.clone(),
|
||||||
|
z_i1.clone(),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
||||||
// input in the AugmentedFCircuit
|
// input in the AugmentedFCircuit
|
||||||
let cf_u_i1_x = cf_U_i.hash_cyclefold(&poseidon_config).unwrap();
|
let cf_u_i1_x = cf_U_i.hash_cyclefold(&poseidon_config, pp_hash).unwrap();
|
||||||
|
|
||||||
augmented_f_circuit =
|
augmented_f_circuit =
|
||||||
AugmentedFCircuit::<Projective, Projective2, GVar2, CubicFCircuit<Fr>> {
|
AugmentedFCircuit::<Projective, Projective2, GVar2, CubicFCircuit<Fr>> {
|
||||||
@@ -1164,6 +1205,7 @@ mod tests {
|
|||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config: poseidon_config.clone(),
|
||||||
ccs: ccs.clone(),
|
ccs: ccs.clone(),
|
||||||
|
pp_hash: Some(pp_hash),
|
||||||
i: Some(Fr::zero()),
|
i: Some(Fr::zero()),
|
||||||
i_usize: Some(0),
|
i_usize: Some(0),
|
||||||
z_0: Some(z_0.clone()),
|
z_0: Some(z_0.clone()),
|
||||||
@@ -1185,6 +1227,7 @@ mod tests {
|
|||||||
} else {
|
} else {
|
||||||
let mut transcript_p: PoseidonTranscript<Projective> =
|
let mut transcript_p: PoseidonTranscript<Projective> =
|
||||||
PoseidonTranscript::<Projective>::new(&poseidon_config.clone());
|
PoseidonTranscript::<Projective>::new(&poseidon_config.clone());
|
||||||
|
transcript_p.absorb(&pp_hash);
|
||||||
let (rho_bits, nimfs_proof);
|
let (rho_bits, nimfs_proof);
|
||||||
(nimfs_proof, U_i1, W_i1, rho_bits) =
|
(nimfs_proof, U_i1, W_i1, rho_bits) =
|
||||||
NIMFS::<Projective, PoseidonTranscript<Projective>>::prove(
|
NIMFS::<Projective, PoseidonTranscript<Projective>>::prove(
|
||||||
@@ -1201,7 +1244,13 @@ mod tests {
|
|||||||
U_i1.check_relation(&ccs, &W_i1).unwrap();
|
U_i1.check_relation(&ccs, &W_i1).unwrap();
|
||||||
|
|
||||||
let u_i1_x = U_i1
|
let u_i1_x = U_i1
|
||||||
.hash(&poseidon_config, iFr + Fr::one(), z_0.clone(), z_i1.clone())
|
.hash(
|
||||||
|
&poseidon_config,
|
||||||
|
pp_hash,
|
||||||
|
iFr + Fr::one(),
|
||||||
|
z_0.clone(),
|
||||||
|
z_i1.clone(),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let rho_Fq = Fq::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap();
|
let rho_Fq = Fq::from_bigint(BigInteger::from_bits_le(&rho_bits)).unwrap();
|
||||||
@@ -1236,6 +1285,7 @@ mod tests {
|
|||||||
&poseidon_config,
|
&poseidon_config,
|
||||||
cf_r1cs.clone(),
|
cf_r1cs.clone(),
|
||||||
cf_pedersen_params.clone(),
|
cf_pedersen_params.clone(),
|
||||||
|
pp_hash,
|
||||||
cf_W_i.clone(), // CycleFold running instance witness
|
cf_W_i.clone(), // CycleFold running instance witness
|
||||||
cf_U_i.clone(), // CycleFold running instance
|
cf_U_i.clone(), // CycleFold running instance
|
||||||
cf_u_i_x, // CycleFold incoming instance
|
cf_u_i_x, // CycleFold incoming instance
|
||||||
@@ -1245,7 +1295,7 @@ mod tests {
|
|||||||
|
|
||||||
// hash the CycleFold folded instance, which is used as the 2nd public input in the
|
// hash the CycleFold folded instance, which is used as the 2nd public input in the
|
||||||
// AugmentedFCircuit
|
// AugmentedFCircuit
|
||||||
let cf_u_i1_x = cf_U_i1.hash_cyclefold(&poseidon_config).unwrap();
|
let cf_u_i1_x = cf_U_i1.hash_cyclefold(&poseidon_config, pp_hash).unwrap();
|
||||||
|
|
||||||
augmented_f_circuit =
|
augmented_f_circuit =
|
||||||
AugmentedFCircuit::<Projective, Projective2, GVar2, CubicFCircuit<Fr>> {
|
AugmentedFCircuit::<Projective, Projective2, GVar2, CubicFCircuit<Fr>> {
|
||||||
@@ -1253,6 +1303,7 @@ mod tests {
|
|||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config: poseidon_config.clone(),
|
||||||
ccs: ccs.clone(),
|
ccs: ccs.clone(),
|
||||||
|
pp_hash: Some(pp_hash),
|
||||||
i: Some(iFr),
|
i: Some(iFr),
|
||||||
i_usize: Some(i),
|
i_usize: Some(i),
|
||||||
z_0: Some(z_0.clone()),
|
z_0: Some(z_0.clone()),
|
||||||
@@ -1296,9 +1347,15 @@ mod tests {
|
|||||||
assert_eq!(u_i.x[0], augmented_f_circuit.x.unwrap());
|
assert_eq!(u_i.x[0], augmented_f_circuit.x.unwrap());
|
||||||
assert_eq!(u_i.x[1], augmented_f_circuit.cf_x.unwrap());
|
assert_eq!(u_i.x[1], augmented_f_circuit.cf_x.unwrap());
|
||||||
let expected_u_i1_x = U_i1
|
let expected_u_i1_x = U_i1
|
||||||
.hash(&poseidon_config, iFr + Fr::one(), z_0.clone(), z_i1.clone())
|
.hash(
|
||||||
|
&poseidon_config,
|
||||||
|
pp_hash,
|
||||||
|
iFr + Fr::one(),
|
||||||
|
z_0.clone(),
|
||||||
|
z_i1.clone(),
|
||||||
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let expected_cf_U_i1_x = cf_U_i.hash_cyclefold(&poseidon_config).unwrap();
|
let expected_cf_U_i1_x = cf_U_i.hash_cyclefold(&poseidon_config, pp_hash).unwrap();
|
||||||
// u_i is already u_i1 at this point, check that has the expected value at x[0]
|
// u_i is already u_i1 at this point, check that has the expected value at x[0]
|
||||||
assert_eq!(u_i.x[0], expected_u_i1_x);
|
assert_eq!(u_i.x[0], expected_u_i1_x);
|
||||||
assert_eq!(u_i.x[1], expected_cf_U_i1_x);
|
assert_eq!(u_i.x[1], expected_cf_U_i1_x);
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use ark_std::rand::Rng;
|
|||||||
use ark_std::Zero;
|
use ark_std::Zero;
|
||||||
|
|
||||||
use super::Witness;
|
use super::Witness;
|
||||||
use crate::ccs::CCS;
|
use crate::arith::ccs::CCS;
|
||||||
use crate::commitment::CommitmentScheme;
|
use crate::commitment::CommitmentScheme;
|
||||||
use crate::folding::circuits::nonnative::affine::nonnative_affine_to_field_elements;
|
use crate::folding::circuits::nonnative::affine::nonnative_affine_to_field_elements;
|
||||||
use crate::utils::mle::dense_vec_to_dense_mle;
|
use crate::utils::mle::dense_vec_to_dense_mle;
|
||||||
@@ -129,6 +129,7 @@ where
|
|||||||
pub fn hash(
|
pub fn hash(
|
||||||
&self,
|
&self,
|
||||||
poseidon_config: &PoseidonConfig<C::ScalarField>,
|
poseidon_config: &PoseidonConfig<C::ScalarField>,
|
||||||
|
pp_hash: C::ScalarField,
|
||||||
i: C::ScalarField,
|
i: C::ScalarField,
|
||||||
z_0: Vec<C::ScalarField>,
|
z_0: Vec<C::ScalarField>,
|
||||||
z_i: Vec<C::ScalarField>,
|
z_i: Vec<C::ScalarField>,
|
||||||
@@ -138,7 +139,7 @@ where
|
|||||||
CRH::<C::ScalarField>::evaluate(
|
CRH::<C::ScalarField>::evaluate(
|
||||||
poseidon_config,
|
poseidon_config,
|
||||||
vec![
|
vec![
|
||||||
vec![i],
|
vec![pp_hash, i],
|
||||||
z_0,
|
z_0,
|
||||||
z_i,
|
z_i,
|
||||||
C_x,
|
C_x,
|
||||||
@@ -164,9 +165,10 @@ pub mod tests {
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ccs::{
|
use crate::arith::{
|
||||||
|
ccs::tests::{get_test_ccs, get_test_z},
|
||||||
r1cs::R1CS,
|
r1cs::R1CS,
|
||||||
tests::{get_test_ccs, get_test_z},
|
Arith,
|
||||||
};
|
};
|
||||||
use crate::commitment::pedersen::Pedersen;
|
use crate::commitment::pedersen::Pedersen;
|
||||||
use crate::utils::hypercube::BooleanHypercube;
|
use crate::utils::hypercube::BooleanHypercube;
|
||||||
|
|||||||
@@ -24,16 +24,17 @@ use crate::folding::circuits::{
|
|||||||
CF2,
|
CF2,
|
||||||
};
|
};
|
||||||
use crate::folding::nova::{
|
use crate::folding::nova::{
|
||||||
get_r1cs_from_cs, traits::NovaR1CS, CommittedInstance, Witness as NovaWitness,
|
get_r1cs_from_cs, traits::NovaR1CS, CommittedInstance, PreprocessorParam,
|
||||||
|
Witness as NovaWitness,
|
||||||
};
|
};
|
||||||
use crate::frontend::FCircuit;
|
use crate::frontend::FCircuit;
|
||||||
use crate::utils::get_cm_coordinates;
|
use crate::utils::{get_cm_coordinates, pp_hash};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use crate::FoldingScheme;
|
use crate::FoldingScheme;
|
||||||
use crate::{
|
use crate::{
|
||||||
ccs::{
|
arith::{
|
||||||
|
ccs::CCS,
|
||||||
r1cs::{extract_w_x, R1CS},
|
r1cs::{extract_w_x, R1CS},
|
||||||
CCS,
|
|
||||||
},
|
},
|
||||||
transcript::{poseidon::PoseidonTranscript, Transcript},
|
transcript::{poseidon::PoseidonTranscript, Transcript},
|
||||||
};
|
};
|
||||||
@@ -56,22 +57,6 @@ impl<F: PrimeField> Witness<F> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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 & cf_cs_params: if not provided, will be generated at the preprocess method
|
|
||||||
pub cs_params: Option<CS1::ProverParams>,
|
|
||||||
pub cf_cs_params: Option<CS2::ProverParams>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ProverParams<C1, C2, CS1, CS2>
|
pub struct ProverParams<C1, C2, CS1, CS2>
|
||||||
where
|
where
|
||||||
@@ -97,8 +82,27 @@ pub struct VerifierParams<
|
|||||||
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||||
pub ccs: CCS<C1::ScalarField>,
|
pub ccs: CCS<C1::ScalarField>,
|
||||||
pub cf_r1cs: R1CS<C2::ScalarField>,
|
pub cf_r1cs: R1CS<C2::ScalarField>,
|
||||||
pub cs_params: CS1::ProverParams,
|
pub cs_vp: CS1::VerifierParams,
|
||||||
pub cf_cs_params: CS2::ProverParams,
|
pub cf_cs_vp: CS2::VerifierParams,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C1, C2, CS1, CS2> VerifierParams<C1, C2, CS1, CS2>
|
||||||
|
where
|
||||||
|
C1: CurveGroup,
|
||||||
|
C2: CurveGroup,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
{
|
||||||
|
/// returns the hash of the public parameters of HyperNova
|
||||||
|
pub fn pp_hash(&self) -> Result<C1::ScalarField, Error> {
|
||||||
|
pp_hash::<C1, C2, CS1, CS2>(
|
||||||
|
&self.ccs,
|
||||||
|
&self.cf_r1cs,
|
||||||
|
&self.cs_vp,
|
||||||
|
&self.cf_cs_vp,
|
||||||
|
&self.poseidon_config,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Implements HyperNova+CycleFold's IVC, described in
|
/// Implements HyperNova+CycleFold's IVC, described in
|
||||||
@@ -130,6 +134,8 @@ where
|
|||||||
pub cf_cs_params: CS2::ProverParams,
|
pub cf_cs_params: CS2::ProverParams,
|
||||||
/// F circuit, the circuit that is being folded
|
/// F circuit, the circuit that is being folded
|
||||||
pub F: FC,
|
pub F: FC,
|
||||||
|
/// public params hash
|
||||||
|
pub pp_hash: C1::ScalarField,
|
||||||
pub i: C1::ScalarField,
|
pub i: C1::ScalarField,
|
||||||
/// initial state
|
/// initial state
|
||||||
pub z_0: Vec<C1::ScalarField>,
|
pub z_0: Vec<C1::ScalarField>,
|
||||||
@@ -185,35 +191,49 @@ where
|
|||||||
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty();
|
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty();
|
||||||
let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?;
|
let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?;
|
||||||
|
|
||||||
// if cs_params & cf_cs_params exist, use them, if not, generate new ones
|
// if cs params exist, use them, if not, generate new ones
|
||||||
let cs_params: CS1::ProverParams;
|
let cs_pp: CS1::ProverParams;
|
||||||
let cf_cs_params: CS2::ProverParams;
|
let cs_vp: CS1::VerifierParams;
|
||||||
if prep_param.cs_params.is_some() && prep_param.cf_cs_params.is_some() {
|
let cf_cs_pp: CS2::ProverParams;
|
||||||
cs_params = prep_param.clone().cs_params.unwrap();
|
let cf_cs_vp: CS2::VerifierParams;
|
||||||
cf_cs_params = prep_param.clone().cf_cs_params.unwrap();
|
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 {
|
} else {
|
||||||
(cs_params, _) = CS1::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
(cs_pp, cs_vp) = CS1::setup(&mut rng, ccs.n - ccs.l - 1)?;
|
||||||
(cf_cs_params, _) = CS2::setup(&mut rng, cf_r1cs.A.n_cols - cf_r1cs.l - 1).unwrap();
|
(cf_cs_pp, cf_cs_vp) = CS2::setup(&mut rng, cf_r1cs.A.n_cols - cf_r1cs.l - 1)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pp = ProverParams::<C1, C2, CS1, CS2> {
|
let pp = ProverParams::<C1, C2, CS1, CS2> {
|
||||||
poseidon_config: prep_param.poseidon_config.clone(),
|
poseidon_config: prep_param.poseidon_config.clone(),
|
||||||
cs_params: cs_params.clone(),
|
cs_params: cs_pp.clone(),
|
||||||
cf_cs_params: cf_cs_params.clone(),
|
cf_cs_params: cf_cs_pp.clone(),
|
||||||
ccs: Some(ccs.clone()),
|
ccs: Some(ccs.clone()),
|
||||||
};
|
};
|
||||||
let vp = VerifierParams::<C1, C2, CS1, CS2> {
|
let vp = VerifierParams::<C1, C2, CS1, CS2> {
|
||||||
poseidon_config: prep_param.poseidon_config.clone(),
|
poseidon_config: prep_param.poseidon_config.clone(),
|
||||||
ccs,
|
ccs,
|
||||||
cf_r1cs,
|
cf_r1cs,
|
||||||
cs_params: cs_params.clone(),
|
cs_vp: cs_vp.clone(),
|
||||||
cf_cs_params: cf_cs_params.clone(),
|
cf_cs_vp: cf_cs_vp.clone(),
|
||||||
};
|
};
|
||||||
Ok((pp, vp))
|
Ok((pp, vp))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes the HyperNova+CycleFold's IVC for the given parameters and initial state `z_0`.
|
/// Initializes the HyperNova+CycleFold's IVC for the given parameters and initial state `z_0`.
|
||||||
fn init(pp: &Self::ProverParam, F: FC, z_0: Vec<C1::ScalarField>) -> Result<Self, Error> {
|
fn init(
|
||||||
|
params: (Self::ProverParam, Self::VerifierParam),
|
||||||
|
F: FC,
|
||||||
|
z_0: Vec<C1::ScalarField>,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let (pp, vp) = params;
|
||||||
|
|
||||||
// prepare the HyperNova's AugmentedFCircuit and CycleFold's circuits and obtain its CCS
|
// prepare the HyperNova's AugmentedFCircuit and CycleFold's circuits and obtain its CCS
|
||||||
// and R1CS respectively
|
// and R1CS respectively
|
||||||
let augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC>::empty(
|
let augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC>::empty(
|
||||||
@@ -226,6 +246,9 @@ where
|
|||||||
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty();
|
let cf_circuit = CycleFoldCircuit::<C1, GC1>::empty();
|
||||||
let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?;
|
let cf_r1cs = get_r1cs_from_cs::<C2::ScalarField>(cf_circuit)?;
|
||||||
|
|
||||||
|
// compute the public params hash
|
||||||
|
let pp_hash = vp.pp_hash()?;
|
||||||
|
|
||||||
// setup the dummy instances
|
// setup the dummy instances
|
||||||
let W_dummy = Witness::<C1::ScalarField>::dummy(&ccs);
|
let W_dummy = Witness::<C1::ScalarField>::dummy(&ccs);
|
||||||
let U_dummy = LCCCS::<C1>::dummy(ccs.l, ccs.t, ccs.s);
|
let U_dummy = LCCCS::<C1>::dummy(ccs.l, ccs.t, ccs.s);
|
||||||
@@ -236,11 +259,12 @@ where
|
|||||||
u_dummy.x = vec![
|
u_dummy.x = vec![
|
||||||
U_dummy.hash(
|
U_dummy.hash(
|
||||||
&pp.poseidon_config,
|
&pp.poseidon_config,
|
||||||
|
pp_hash,
|
||||||
C1::ScalarField::zero(),
|
C1::ScalarField::zero(),
|
||||||
z_0.clone(),
|
z_0.clone(),
|
||||||
z_0.clone(),
|
z_0.clone(),
|
||||||
)?,
|
)?,
|
||||||
cf_U_dummy.hash_cyclefold(&pp.poseidon_config)?,
|
cf_U_dummy.hash_cyclefold(&pp.poseidon_config, pp_hash)?,
|
||||||
];
|
];
|
||||||
|
|
||||||
// W_dummy=W_0 is a 'dummy witness', all zeroes, but with the size corresponding to the
|
// W_dummy=W_0 is a 'dummy witness', all zeroes, but with the size corresponding to the
|
||||||
@@ -255,6 +279,7 @@ where
|
|||||||
cs_params: pp.cs_params.clone(),
|
cs_params: pp.cs_params.clone(),
|
||||||
cf_cs_params: pp.cf_cs_params.clone(),
|
cf_cs_params: pp.cf_cs_params.clone(),
|
||||||
F,
|
F,
|
||||||
|
pp_hash,
|
||||||
i: C1::ScalarField::zero(),
|
i: C1::ScalarField::zero(),
|
||||||
z_0: z_0.clone(),
|
z_0: z_0.clone(),
|
||||||
z_i: z_0,
|
z_i: z_0,
|
||||||
@@ -315,6 +340,7 @@ where
|
|||||||
|
|
||||||
let u_i1_x = U_i1.hash(
|
let u_i1_x = U_i1.hash(
|
||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
|
self.pp_hash,
|
||||||
C1::ScalarField::one(),
|
C1::ScalarField::one(),
|
||||||
self.z_0.clone(),
|
self.z_0.clone(),
|
||||||
z_i1.clone(),
|
z_i1.clone(),
|
||||||
@@ -322,13 +348,16 @@ where
|
|||||||
|
|
||||||
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
// hash the initial (dummy) CycleFold instance, which is used as the 2nd public
|
||||||
// input in the AugmentedFCircuit
|
// input in the AugmentedFCircuit
|
||||||
cf_u_i1_x = self.cf_U_i.hash_cyclefold(&self.poseidon_config)?;
|
cf_u_i1_x = self
|
||||||
|
.cf_U_i
|
||||||
|
.hash_cyclefold(&self.poseidon_config, self.pp_hash)?;
|
||||||
|
|
||||||
augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
||||||
_c2: PhantomData,
|
_c2: PhantomData,
|
||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
poseidon_config: self.poseidon_config.clone(),
|
poseidon_config: self.poseidon_config.clone(),
|
||||||
ccs: self.ccs.clone(),
|
ccs: self.ccs.clone(),
|
||||||
|
pp_hash: Some(self.pp_hash),
|
||||||
i: Some(C1::ScalarField::zero()),
|
i: Some(C1::ScalarField::zero()),
|
||||||
i_usize: Some(0),
|
i_usize: Some(0),
|
||||||
z_0: Some(self.z_0.clone()),
|
z_0: Some(self.z_0.clone()),
|
||||||
@@ -350,6 +379,7 @@ where
|
|||||||
} else {
|
} else {
|
||||||
let mut transcript_p: PoseidonTranscript<C1> =
|
let mut transcript_p: PoseidonTranscript<C1> =
|
||||||
PoseidonTranscript::<C1>::new(&self.poseidon_config);
|
PoseidonTranscript::<C1>::new(&self.poseidon_config);
|
||||||
|
transcript_p.absorb(&self.pp_hash);
|
||||||
let (rho_bits, nimfs_proof);
|
let (rho_bits, nimfs_proof);
|
||||||
(nimfs_proof, U_i1, W_i1, rho_bits) = NIMFS::<C1, PoseidonTranscript<C1>>::prove(
|
(nimfs_proof, U_i1, W_i1, rho_bits) = NIMFS::<C1, PoseidonTranscript<C1>>::prove(
|
||||||
&mut transcript_p,
|
&mut transcript_p,
|
||||||
@@ -366,6 +396,7 @@ where
|
|||||||
|
|
||||||
let u_i1_x = U_i1.hash(
|
let u_i1_x = U_i1.hash(
|
||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
|
self.pp_hash,
|
||||||
self.i + C1::ScalarField::one(),
|
self.i + C1::ScalarField::one(),
|
||||||
self.z_0.clone(),
|
self.z_0.clone(),
|
||||||
z_i1.clone(),
|
z_i1.clone(),
|
||||||
@@ -397,19 +428,21 @@ where
|
|||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
self.cf_r1cs.clone(),
|
self.cf_r1cs.clone(),
|
||||||
self.cf_cs_params.clone(),
|
self.cf_cs_params.clone(),
|
||||||
|
self.pp_hash,
|
||||||
self.cf_W_i.clone(), // CycleFold running instance witness
|
self.cf_W_i.clone(), // CycleFold running instance witness
|
||||||
self.cf_U_i.clone(), // CycleFold running instance
|
self.cf_U_i.clone(), // CycleFold running instance
|
||||||
cf_u_i_x,
|
cf_u_i_x,
|
||||||
cf_circuit,
|
cf_circuit,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
cf_u_i1_x = cf_U_i1.hash_cyclefold(&self.poseidon_config)?;
|
cf_u_i1_x = cf_U_i1.hash_cyclefold(&self.poseidon_config, self.pp_hash)?;
|
||||||
|
|
||||||
augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
augmented_f_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
||||||
_c2: PhantomData,
|
_c2: PhantomData,
|
||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
poseidon_config: self.poseidon_config.clone(),
|
poseidon_config: self.poseidon_config.clone(),
|
||||||
ccs: self.ccs.clone(),
|
ccs: self.ccs.clone(),
|
||||||
|
pp_hash: Some(self.pp_hash),
|
||||||
i: Some(self.i),
|
i: Some(self.i),
|
||||||
i_usize: Some(i_usize),
|
i_usize: Some(i_usize),
|
||||||
z_0: Some(self.z_0.clone()),
|
z_0: Some(self.z_0.clone()),
|
||||||
@@ -516,14 +549,16 @@ where
|
|||||||
return Err(Error::IVCVerificationFail);
|
return Err(Error::IVCVerificationFail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pp_hash = vp.pp_hash()?;
|
||||||
|
|
||||||
// check that u_i's output points to the running instance
|
// check that u_i's output points to the running instance
|
||||||
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
||||||
let expected_u_i_x = U_i.hash(&vp.poseidon_config, num_steps, z_0, z_i.clone())?;
|
let expected_u_i_x = U_i.hash(&vp.poseidon_config, pp_hash, num_steps, z_0, z_i.clone())?;
|
||||||
if expected_u_i_x != u_i.x[0] {
|
if expected_u_i_x != u_i.x[0] {
|
||||||
return Err(Error::IVCVerificationFail);
|
return Err(Error::IVCVerificationFail);
|
||||||
}
|
}
|
||||||
// u_i.X[1] == H(cf_U_i)
|
// u_i.X[1] == H(cf_U_i)
|
||||||
let expected_cf_u_i_x = cf_U_i.hash_cyclefold(&vp.poseidon_config)?;
|
let expected_cf_u_i_x = cf_U_i.hash_cyclefold(&vp.poseidon_config, pp_hash)?;
|
||||||
if expected_cf_u_i_x != u_i.x[1] {
|
if expected_cf_u_i_x != u_i.x[1] {
|
||||||
return Err(Error::IVCVerificationFail);
|
return Err(Error::IVCVerificationFail);
|
||||||
}
|
}
|
||||||
@@ -578,16 +613,20 @@ mod tests {
|
|||||||
type HN<CS1, CS2> =
|
type HN<CS1, CS2> =
|
||||||
HyperNova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
|
HyperNova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
|
||||||
|
|
||||||
let prep_param = PreprocessorParam::<Projective, Projective2, CubicFCircuit<Fr>, CS1, CS2> {
|
let prep_param =
|
||||||
poseidon_config,
|
PreprocessorParam::<Projective, Projective2, CubicFCircuit<Fr>, CS1, CS2>::new(
|
||||||
F: F_circuit,
|
poseidon_config.clone(),
|
||||||
cs_params: None,
|
F_circuit,
|
||||||
cf_cs_params: None,
|
);
|
||||||
};
|
|
||||||
let (prover_params, verifier_params) = HN::preprocess(&mut rng, &prep_param).unwrap();
|
let (prover_params, verifier_params) = HN::preprocess(&mut rng, &prep_param).unwrap();
|
||||||
|
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
let mut hypernova = HN::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
let mut hypernova = HN::init(
|
||||||
|
(prover_params, verifier_params.clone()),
|
||||||
|
F_circuit,
|
||||||
|
z_0.clone(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let num_steps: usize = 3;
|
let num_steps: usize = 3;
|
||||||
for _ in 0..num_steps {
|
for _ in 0..num_steps {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use super::{
|
|||||||
utils::{compute_c, compute_g, compute_sigmas_thetas},
|
utils::{compute_c, compute_g, compute_sigmas_thetas},
|
||||||
Witness,
|
Witness,
|
||||||
};
|
};
|
||||||
use crate::ccs::CCS;
|
use crate::arith::ccs::CCS;
|
||||||
use crate::constants::N_BITS_RO;
|
use crate::constants::N_BITS_RO;
|
||||||
use crate::folding::circuits::nonnative::affine::nonnative_affine_to_field_elements;
|
use crate::folding::circuits::nonnative::affine::nonnative_affine_to_field_elements;
|
||||||
use crate::transcript::Transcript;
|
use crate::transcript::Transcript;
|
||||||
@@ -408,7 +408,10 @@ where
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub mod tests {
|
pub mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ccs::tests::{get_test_ccs, get_test_z};
|
use crate::arith::{
|
||||||
|
ccs::tests::{get_test_ccs, get_test_z},
|
||||||
|
Arith,
|
||||||
|
};
|
||||||
use crate::transcript::poseidon::poseidon_canonical_config;
|
use crate::transcript::poseidon::poseidon_canonical_config;
|
||||||
use crate::transcript::poseidon::PoseidonTranscript;
|
use crate::transcript::poseidon::PoseidonTranscript;
|
||||||
use ark_std::test_rng;
|
use ark_std::test_rng;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use super::lcccs::LCCCS;
|
use super::lcccs::LCCCS;
|
||||||
use super::nimfs::SigmasThetas;
|
use super::nimfs::SigmasThetas;
|
||||||
use crate::ccs::CCS;
|
use crate::arith::ccs::CCS;
|
||||||
use crate::utils::mle::dense_vec_to_dense_mle;
|
use crate::utils::mle::dense_vec_to_dense_mle;
|
||||||
use crate::utils::vec::mat_vec_mul;
|
use crate::utils::vec::mat_vec_mul;
|
||||||
use crate::utils::virtual_polynomial::{build_eq_x_r_vec, eq_eval, VirtualPolynomial};
|
use crate::utils::virtual_polynomial::{build_eq_x_r_vec, eq_eval, VirtualPolynomial};
|
||||||
@@ -167,7 +167,10 @@ pub mod tests {
|
|||||||
use ark_std::Zero;
|
use ark_std::Zero;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ccs::tests::{get_test_ccs, get_test_z};
|
use crate::arith::{
|
||||||
|
ccs::tests::{get_test_ccs, get_test_z},
|
||||||
|
Arith,
|
||||||
|
};
|
||||||
use crate::commitment::{pedersen::Pedersen, CommitmentScheme};
|
use crate::commitment::{pedersen::Pedersen, CommitmentScheme};
|
||||||
use crate::folding::hypernova::lcccs::tests::compute_Ls;
|
use crate::folding::hypernova::lcccs::tests::compute_Ls;
|
||||||
use crate::utils::hypercube::BooleanHypercube;
|
use crate::utils::hypercube::BooleanHypercube;
|
||||||
|
|||||||
@@ -94,6 +94,7 @@ where
|
|||||||
pub fn hash(
|
pub fn hash(
|
||||||
self,
|
self,
|
||||||
crh_params: &CRHParametersVar<CF1<C>>,
|
crh_params: &CRHParametersVar<CF1<C>>,
|
||||||
|
pp_hash: FpVar<CF1<C>>,
|
||||||
i: FpVar<CF1<C>>,
|
i: FpVar<CF1<C>>,
|
||||||
z_0: Vec<FpVar<CF1<C>>>,
|
z_0: Vec<FpVar<CF1<C>>>,
|
||||||
z_i: Vec<FpVar<CF1<C>>>,
|
z_i: Vec<FpVar<CF1<C>>>,
|
||||||
@@ -105,7 +106,7 @@ where
|
|||||||
self.cmW.to_constraint_field()?,
|
self.cmW.to_constraint_field()?,
|
||||||
]
|
]
|
||||||
.concat();
|
.concat();
|
||||||
let input = [vec![i], z_0, z_i, U_vec.clone()].concat();
|
let input = [vec![pp_hash, i], z_0, z_i, U_vec.clone()].concat();
|
||||||
Ok((
|
Ok((
|
||||||
CRHGadget::<C::ScalarField>::evaluate(crh_params, &input)?,
|
CRHGadget::<C::ScalarField>::evaluate(crh_params, &input)?,
|
||||||
U_vec,
|
U_vec,
|
||||||
@@ -175,6 +176,7 @@ where
|
|||||||
{
|
{
|
||||||
pub fn get_challenge_native(
|
pub fn get_challenge_native(
|
||||||
poseidon_config: &PoseidonConfig<C::ScalarField>,
|
poseidon_config: &PoseidonConfig<C::ScalarField>,
|
||||||
|
pp_hash: C::ScalarField, // public params hash
|
||||||
U_i: CommittedInstance<C>,
|
U_i: CommittedInstance<C>,
|
||||||
u_i: CommittedInstance<C>,
|
u_i: CommittedInstance<C>,
|
||||||
cmT: C,
|
cmT: C,
|
||||||
@@ -187,6 +189,7 @@ where
|
|||||||
|
|
||||||
let mut sponge = PoseidonSponge::<C::ScalarField>::new(poseidon_config);
|
let mut sponge = PoseidonSponge::<C::ScalarField>::new(poseidon_config);
|
||||||
let input = vec![
|
let input = vec![
|
||||||
|
vec![pp_hash],
|
||||||
vec![U_i.u],
|
vec![U_i.u],
|
||||||
U_i.x.clone(),
|
U_i.x.clone(),
|
||||||
U_cmE_x,
|
U_cmE_x,
|
||||||
@@ -212,6 +215,7 @@ where
|
|||||||
pub fn get_challenge_gadget(
|
pub fn get_challenge_gadget(
|
||||||
cs: ConstraintSystemRef<C::ScalarField>,
|
cs: ConstraintSystemRef<C::ScalarField>,
|
||||||
poseidon_config: &PoseidonConfig<C::ScalarField>,
|
poseidon_config: &PoseidonConfig<C::ScalarField>,
|
||||||
|
pp_hash: FpVar<CF1<C>>, // public params hash
|
||||||
U_i_vec: Vec<FpVar<CF1<C>>>, // apready processed input, so we don't have to recompute these values
|
U_i_vec: Vec<FpVar<CF1<C>>>, // apready processed input, so we don't have to recompute these values
|
||||||
u_i: CommittedInstanceVar<C>,
|
u_i: CommittedInstanceVar<C>,
|
||||||
cmT: NonNativeAffineVar<C>,
|
cmT: NonNativeAffineVar<C>,
|
||||||
@@ -219,6 +223,7 @@ where
|
|||||||
let mut sponge = PoseidonSpongeVar::<C::ScalarField>::new(cs, poseidon_config);
|
let mut sponge = PoseidonSpongeVar::<C::ScalarField>::new(cs, poseidon_config);
|
||||||
|
|
||||||
let input: Vec<FpVar<C::ScalarField>> = [
|
let input: Vec<FpVar<C::ScalarField>> = [
|
||||||
|
vec![pp_hash],
|
||||||
U_i_vec,
|
U_i_vec,
|
||||||
vec![u_i.u.clone()],
|
vec![u_i.u.clone()],
|
||||||
u_i.x.clone(),
|
u_i.x.clone(),
|
||||||
@@ -247,6 +252,7 @@ pub struct AugmentedFCircuit<
|
|||||||
{
|
{
|
||||||
pub _gc2: PhantomData<GC2>,
|
pub _gc2: PhantomData<GC2>,
|
||||||
pub poseidon_config: PoseidonConfig<CF1<C1>>,
|
pub poseidon_config: PoseidonConfig<CF1<C1>>,
|
||||||
|
pub pp_hash: Option<CF1<C1>>,
|
||||||
pub i: Option<CF1<C1>>,
|
pub i: Option<CF1<C1>>,
|
||||||
pub i_usize: Option<usize>,
|
pub i_usize: Option<usize>,
|
||||||
pub z_0: Option<Vec<C1::ScalarField>>,
|
pub z_0: Option<Vec<C1::ScalarField>>,
|
||||||
@@ -280,6 +286,7 @@ where
|
|||||||
Self {
|
Self {
|
||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
poseidon_config: poseidon_config.clone(),
|
poseidon_config: poseidon_config.clone(),
|
||||||
|
pp_hash: None,
|
||||||
i: None,
|
i: None,
|
||||||
i_usize: None,
|
i_usize: None,
|
||||||
z_0: None,
|
z_0: None,
|
||||||
@@ -317,6 +324,9 @@ where
|
|||||||
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
|
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
|
||||||
{
|
{
|
||||||
fn generate_constraints(self, cs: ConstraintSystemRef<CF1<C1>>) -> Result<(), SynthesisError> {
|
fn generate_constraints(self, cs: ConstraintSystemRef<CF1<C1>>) -> Result<(), SynthesisError> {
|
||||||
|
let pp_hash = FpVar::<CF1<C1>>::new_witness(cs.clone(), || {
|
||||||
|
Ok(self.pp_hash.unwrap_or_else(CF1::<C1>::zero))
|
||||||
|
})?;
|
||||||
let i = FpVar::<CF1<C1>>::new_witness(cs.clone(), || {
|
let i = FpVar::<CF1<C1>>::new_witness(cs.clone(), || {
|
||||||
Ok(self.i.unwrap_or_else(CF1::<C1>::zero))
|
Ok(self.i.unwrap_or_else(CF1::<C1>::zero))
|
||||||
})?;
|
})?;
|
||||||
@@ -373,11 +383,15 @@ where
|
|||||||
// Primary Part
|
// Primary Part
|
||||||
// P.1. Compute u_i.x
|
// P.1. Compute u_i.x
|
||||||
// u_i.x[0] = H(i, z_0, z_i, U_i)
|
// u_i.x[0] = H(i, z_0, z_i, U_i)
|
||||||
let (u_i_x, U_i_vec) =
|
let (u_i_x, U_i_vec) = U_i.clone().hash(
|
||||||
U_i.clone()
|
&crh_params,
|
||||||
.hash(&crh_params, i.clone(), z_0.clone(), z_i.clone())?;
|
pp_hash.clone(),
|
||||||
|
i.clone(),
|
||||||
|
z_0.clone(),
|
||||||
|
z_i.clone(),
|
||||||
|
)?;
|
||||||
// u_i.x[1] = H(cf_U_i)
|
// u_i.x[1] = H(cf_U_i)
|
||||||
let (cf_u_i_x, cf_U_i_vec) = cf_U_i.clone().hash(&crh_params)?;
|
let (cf_u_i_x, cf_U_i_vec) = cf_U_i.clone().hash(&crh_params, pp_hash.clone())?;
|
||||||
|
|
||||||
// P.2. Construct u_i
|
// P.2. Construct u_i
|
||||||
let u_i = CommittedInstanceVar {
|
let u_i = CommittedInstanceVar {
|
||||||
@@ -399,6 +413,7 @@ where
|
|||||||
let r_bits = ChallengeGadget::<C1>::get_challenge_gadget(
|
let r_bits = ChallengeGadget::<C1>::get_challenge_gadget(
|
||||||
cs.clone(),
|
cs.clone(),
|
||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
|
pp_hash.clone(),
|
||||||
U_i_vec,
|
U_i_vec,
|
||||||
u_i.clone(),
|
u_i.clone(),
|
||||||
cmT.clone(),
|
cmT.clone(),
|
||||||
@@ -424,12 +439,14 @@ where
|
|||||||
// Non-base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{i+1})
|
// Non-base case: u_{i+1}.x[0] == H((i+1, z_0, z_{i+1}, U_{i+1})
|
||||||
let (u_i1_x, _) = U_i1.clone().hash(
|
let (u_i1_x, _) = U_i1.clone().hash(
|
||||||
&crh_params,
|
&crh_params,
|
||||||
|
pp_hash.clone(),
|
||||||
i + FpVar::<CF1<C1>>::one(),
|
i + FpVar::<CF1<C1>>::one(),
|
||||||
z_0.clone(),
|
z_0.clone(),
|
||||||
z_i1.clone(),
|
z_i1.clone(),
|
||||||
)?;
|
)?;
|
||||||
let (u_i1_x_base, _) = CommittedInstanceVar::new_constant(cs.clone(), u_dummy)?.hash(
|
let (u_i1_x_base, _) = CommittedInstanceVar::new_constant(cs.clone(), u_dummy)?.hash(
|
||||||
&crh_params,
|
&crh_params,
|
||||||
|
pp_hash.clone(),
|
||||||
FpVar::<CF1<C1>>::one(),
|
FpVar::<CF1<C1>>::one(),
|
||||||
z_0.clone(),
|
z_0.clone(),
|
||||||
z_i1.clone(),
|
z_i1.clone(),
|
||||||
@@ -484,6 +501,7 @@ where
|
|||||||
let cf1_r_bits = CycleFoldChallengeGadget::<C2, GC2>::get_challenge_gadget(
|
let cf1_r_bits = CycleFoldChallengeGadget::<C2, GC2>::get_challenge_gadget(
|
||||||
cs.clone(),
|
cs.clone(),
|
||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
|
pp_hash.clone(),
|
||||||
cf_U_i_vec,
|
cf_U_i_vec,
|
||||||
cf1_u_i.clone(),
|
cf1_u_i.clone(),
|
||||||
cf1_cmT.clone(),
|
cf1_cmT.clone(),
|
||||||
@@ -507,6 +525,7 @@ where
|
|||||||
let cf2_r_bits = CycleFoldChallengeGadget::<C2, GC2>::get_challenge_gadget(
|
let cf2_r_bits = CycleFoldChallengeGadget::<C2, GC2>::get_challenge_gadget(
|
||||||
cs.clone(),
|
cs.clone(),
|
||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
|
pp_hash.clone(),
|
||||||
cf1_U_i1.to_constraint_field()?,
|
cf1_U_i1.to_constraint_field()?,
|
||||||
cf2_u_i.clone(),
|
cf2_u_i.clone(),
|
||||||
cf2_cmT.clone(),
|
cf2_cmT.clone(),
|
||||||
@@ -528,10 +547,10 @@ where
|
|||||||
// P.4.b compute and check the second output of F'
|
// P.4.b compute and check the second output of F'
|
||||||
// Base case: u_{i+1}.x[1] == H(cf_U_{\bot})
|
// Base case: u_{i+1}.x[1] == H(cf_U_{\bot})
|
||||||
// Non-base case: u_{i+1}.x[1] == H(cf_U_{i+1})
|
// Non-base case: u_{i+1}.x[1] == H(cf_U_{i+1})
|
||||||
let (cf_u_i1_x, _) = cf_U_i1.clone().hash(&crh_params)?;
|
let (cf_u_i1_x, _) = cf_U_i1.clone().hash(&crh_params, pp_hash.clone())?;
|
||||||
let (cf_u_i1_x_base, _) =
|
let (cf_u_i1_x_base, _) =
|
||||||
CycleFoldCommittedInstanceVar::new_constant(cs.clone(), cf_u_dummy)?
|
CycleFoldCommittedInstanceVar::new_constant(cs.clone(), cf_u_dummy)?
|
||||||
.hash(&crh_params)?;
|
.hash(&crh_params, pp_hash)?;
|
||||||
let cf_x = FpVar::new_input(cs.clone(), || {
|
let cf_x = FpVar::new_input(cs.clone(), || {
|
||||||
Ok(self.cf_x.unwrap_or(cf_u_i1_x_base.value()?))
|
Ok(self.cf_x.unwrap_or(cf_u_i1_x_base.value()?))
|
||||||
})?;
|
})?;
|
||||||
@@ -609,6 +628,7 @@ pub mod tests {
|
|||||||
fn test_committed_instance_hash() {
|
fn test_committed_instance_hash() {
|
||||||
let mut rng = ark_std::test_rng();
|
let mut rng = ark_std::test_rng();
|
||||||
let poseidon_config = poseidon_canonical_config::<Fr>();
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
|
let pp_hash = Fr::from(42u32); // only for test
|
||||||
|
|
||||||
let i = Fr::from(3_u32);
|
let i = Fr::from(3_u32);
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
@@ -622,11 +642,12 @@ pub mod tests {
|
|||||||
|
|
||||||
// compute the CommittedInstance hash natively
|
// compute the CommittedInstance hash natively
|
||||||
let h = ci
|
let h = ci
|
||||||
.hash(&poseidon_config, i, z_0.clone(), z_i.clone())
|
.hash(&poseidon_config, pp_hash, i, z_0.clone(), z_i.clone())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
|
|
||||||
|
let pp_hashVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(pp_hash)).unwrap();
|
||||||
let iVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(i)).unwrap();
|
let iVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(i)).unwrap();
|
||||||
let z_0Var = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_0.clone())).unwrap();
|
let z_0Var = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_0.clone())).unwrap();
|
||||||
let z_iVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_i.clone())).unwrap();
|
let z_iVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(z_i.clone())).unwrap();
|
||||||
@@ -636,7 +657,9 @@ pub mod tests {
|
|||||||
let crh_params = CRHParametersVar::<Fr>::new_constant(cs.clone(), poseidon_config).unwrap();
|
let crh_params = CRHParametersVar::<Fr>::new_constant(cs.clone(), poseidon_config).unwrap();
|
||||||
|
|
||||||
// compute the CommittedInstance hash in-circuit
|
// compute the CommittedInstance hash in-circuit
|
||||||
let (hVar, _) = ciVar.hash(&crh_params, iVar, z_0Var, z_iVar).unwrap();
|
let (hVar, _) = ciVar
|
||||||
|
.hash(&crh_params, pp_hashVar, iVar, z_0Var, z_iVar)
|
||||||
|
.unwrap();
|
||||||
assert!(cs.is_satisfied().unwrap());
|
assert!(cs.is_satisfied().unwrap());
|
||||||
|
|
||||||
// check that the natively computed and in-circuit computed hashes match
|
// check that the natively computed and in-circuit computed hashes match
|
||||||
@@ -663,9 +686,12 @@ pub mod tests {
|
|||||||
};
|
};
|
||||||
let cmT = Projective::rand(&mut rng);
|
let cmT = Projective::rand(&mut rng);
|
||||||
|
|
||||||
|
let pp_hash = Fr::from(42u32); // only for testing
|
||||||
|
|
||||||
// compute the challenge natively
|
// compute the challenge natively
|
||||||
let r_bits = ChallengeGadget::<Projective>::get_challenge_native(
|
let r_bits = ChallengeGadget::<Projective>::get_challenge_native(
|
||||||
&poseidon_config,
|
&poseidon_config,
|
||||||
|
pp_hash,
|
||||||
U_i.clone(),
|
U_i.clone(),
|
||||||
u_i.clone(),
|
u_i.clone(),
|
||||||
cmT,
|
cmT,
|
||||||
@@ -674,6 +700,7 @@ pub mod tests {
|
|||||||
let r = Fr::from_bigint(BigInteger::from_bits_le(&r_bits)).unwrap();
|
let r = Fr::from_bigint(BigInteger::from_bits_le(&r_bits)).unwrap();
|
||||||
|
|
||||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||||
|
let pp_hashVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(pp_hash)).unwrap();
|
||||||
let u_iVar =
|
let u_iVar =
|
||||||
CommittedInstanceVar::<Projective>::new_witness(cs.clone(), || Ok(u_i.clone()))
|
CommittedInstanceVar::<Projective>::new_witness(cs.clone(), || Ok(u_i.clone()))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
@@ -693,6 +720,7 @@ pub mod tests {
|
|||||||
let r_bitsVar = ChallengeGadget::<Projective>::get_challenge_gadget(
|
let r_bitsVar = ChallengeGadget::<Projective>::get_challenge_gadget(
|
||||||
cs.clone(),
|
cs.clone(),
|
||||||
&poseidon_config,
|
&poseidon_config,
|
||||||
|
pp_hashVar,
|
||||||
U_iVar_vec,
|
U_iVar_vec,
|
||||||
u_iVar,
|
u_iVar,
|
||||||
cmTVar,
|
cmTVar,
|
||||||
|
|||||||
@@ -90,7 +90,8 @@ 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>;
|
||||||
type VerifierParam = (S::VerifyingKey, CS1::VerifierParams);
|
/// VerifierParam = (pp_hash, snark::vk, commitment_scheme::vk)
|
||||||
|
type VerifierParam = (C1::ScalarField, S::VerifyingKey, CS1::VerifierParams);
|
||||||
type PublicInput = Vec<C1::ScalarField>;
|
type PublicInput = Vec<C1::ScalarField>;
|
||||||
type CommittedInstance = CommittedInstance<C1>;
|
type CommittedInstance = CommittedInstance<C1>;
|
||||||
|
|
||||||
@@ -115,9 +116,10 @@ where
|
|||||||
let nova_vp:
|
let nova_vp:
|
||||||
<Nova<C1, GC1, C2, GC2, FC, CS1, CS2> as FoldingScheme<C1, C2, FC>>::VerifierParam =
|
<Nova<C1, GC1, C2, GC2, FC, CS1, CS2> as FoldingScheme<C1, C2, FC>>::VerifierParam =
|
||||||
prep_param.1.clone().into();
|
prep_param.1.clone().into();
|
||||||
|
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 = (g16_vk, nova_vp.cs_vp);
|
let vp = (pp_hash, g16_vk, nova_vp.cs_vp);
|
||||||
Ok((pp, vp))
|
Ok((pp, vp))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +188,8 @@ where
|
|||||||
return Err(Error::NotEnoughSteps);
|
return Err(Error::NotEnoughSteps);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (snark_vk, cs_vk): (S::VerifyingKey, CS1::VerifierParams) = vp;
|
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);
|
||||||
@@ -196,7 +199,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> = vec![
|
let public_input: Vec<C1::ScalarField> = vec![
|
||||||
vec![i],
|
vec![pp_hash, i],
|
||||||
z_0,
|
z_0,
|
||||||
z_i,
|
z_i,
|
||||||
vec![U.u],
|
vec![U.u],
|
||||||
@@ -317,13 +320,12 @@ pub mod tests {
|
|||||||
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
||||||
use ark_groth16::Groth16;
|
use ark_groth16::Groth16;
|
||||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
||||||
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
|
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::commitment::kzg::{ProverKey as KZGProverKey, KZG};
|
use crate::commitment::kzg::KZG;
|
||||||
use crate::commitment::pedersen::Pedersen;
|
use crate::commitment::pedersen::Pedersen;
|
||||||
use crate::folding::nova::{get_cs_params_len, ProverParams};
|
use crate::folding::nova::PreprocessorParam;
|
||||||
use crate::frontend::tests::CubicFCircuit;
|
use crate::frontend::tests::CubicFCircuit;
|
||||||
use crate::transcript::poseidon::poseidon_canonical_config;
|
use crate::transcript::poseidon::poseidon_canonical_config;
|
||||||
|
|
||||||
@@ -357,59 +359,29 @@ pub mod tests {
|
|||||||
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 (cs_len, cf_cs_len) =
|
let prep_param = PreprocessorParam::new(poseidon_config, F_circuit);
|
||||||
get_cs_params_len::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>>(
|
let nova_params = N::preprocess(&mut rng, &prep_param).unwrap();
|
||||||
&poseidon_config,
|
|
||||||
F_circuit,
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let start = Instant::now();
|
|
||||||
let (kzg_pk, kzg_vk): (KZGProverKey<Projective>, KZGVerifierKey<Bn254>) =
|
|
||||||
KZG::<Bn254>::setup(&mut rng, cs_len).unwrap();
|
|
||||||
let (cf_pedersen_params, _) = Pedersen::<Projective2>::setup(&mut rng, cf_cs_len).unwrap();
|
|
||||||
println!("generated KZG params, {:?}", start.elapsed());
|
|
||||||
|
|
||||||
let prover_params =
|
|
||||||
ProverParams::<Projective, Projective2, KZG<Bn254>, Pedersen<Projective2>> {
|
|
||||||
poseidon_config: poseidon_config.clone(),
|
|
||||||
cs_pp: kzg_pk.clone(),
|
|
||||||
cf_cs_pp: cf_pedersen_params,
|
|
||||||
};
|
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
let mut nova = N::init(nova_params.clone(), F_circuit, z_0.clone()).unwrap();
|
||||||
println!("Nova initialized, {:?}", start.elapsed());
|
println!("Nova initialized, {:?}", start.elapsed());
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
nova.prove_step(&mut rng, vec![]).unwrap();
|
nova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
println!("prove_step, {:?}", start.elapsed());
|
println!("prove_step, {:?}", start.elapsed());
|
||||||
nova.prove_step(&mut rng, vec![]).unwrap(); // do a 2nd step
|
nova.prove_step(&mut rng, vec![]).unwrap(); // do a 2nd step
|
||||||
|
|
||||||
// generate Groth16 setup
|
|
||||||
let circuit = DeciderEthCircuit::<
|
|
||||||
Projective,
|
|
||||||
GVar,
|
|
||||||
Projective2,
|
|
||||||
GVar2,
|
|
||||||
KZG<Bn254>,
|
|
||||||
Pedersen<Projective2>,
|
|
||||||
>::from_nova::<CubicFCircuit<Fr>>(nova.clone())
|
|
||||||
.unwrap();
|
|
||||||
let mut rng = rand::rngs::OsRng;
|
let mut rng = rand::rngs::OsRng;
|
||||||
|
|
||||||
let start = Instant::now();
|
// prepare the Decider prover & verifier params
|
||||||
let (g16_pk, g16_vk) =
|
let (decider_pp, decider_vp) = D::preprocess(&mut rng, &nova_params, nova.clone()).unwrap();
|
||||||
Groth16::<Bn254>::circuit_specific_setup(circuit.clone(), &mut rng).unwrap();
|
|
||||||
println!("Groth16 setup, {:?}", start.elapsed());
|
|
||||||
|
|
||||||
// decider proof generation
|
// decider proof generation
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let decider_pp = (g16_pk, kzg_pk);
|
|
||||||
let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
|
let proof = D::prove(rng, decider_pp, nova.clone()).unwrap();
|
||||||
println!("Decider prove, {:?}", start.elapsed());
|
println!("Decider prove, {:?}", start.elapsed());
|
||||||
|
|
||||||
// decider proof verification
|
// decider proof verification
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let decider_vp = (g16_vk, kzg_vk);
|
|
||||||
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, nova.i, nova.z_0, nova.z_i, &nova.U_i, &nova.u_i, &proof,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ use ark_std::{log2, Zero};
|
|||||||
use core::{borrow::Borrow, marker::PhantomData};
|
use core::{borrow::Borrow, marker::PhantomData};
|
||||||
|
|
||||||
use super::{circuits::ChallengeGadget, nifs::NIFS};
|
use super::{circuits::ChallengeGadget, nifs::NIFS};
|
||||||
use crate::ccs::r1cs::R1CS;
|
use crate::arith::r1cs::R1CS;
|
||||||
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme};
|
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme};
|
||||||
use crate::folding::circuits::{
|
use crate::folding::circuits::{
|
||||||
nonnative::{
|
nonnative::{
|
||||||
@@ -223,6 +223,8 @@ where
|
|||||||
/// CycleFold PedersenParams over C2
|
/// CycleFold PedersenParams over C2
|
||||||
pub cf_pedersen_params: PedersenParams<C2>,
|
pub cf_pedersen_params: PedersenParams<C2>,
|
||||||
pub poseidon_config: PoseidonConfig<CF1<C1>>,
|
pub poseidon_config: PoseidonConfig<CF1<C1>>,
|
||||||
|
/// public params hash
|
||||||
|
pub pp_hash: Option<C1::ScalarField>,
|
||||||
pub i: Option<CF1<C1>>,
|
pub i: Option<CF1<C1>>,
|
||||||
/// initial state
|
/// initial state
|
||||||
pub z_0: Option<Vec<C1::ScalarField>>,
|
pub z_0: Option<Vec<C1::ScalarField>>,
|
||||||
@@ -273,6 +275,7 @@ where
|
|||||||
)?;
|
)?;
|
||||||
let r_bits = ChallengeGadget::<C1>::get_challenge_native(
|
let r_bits = ChallengeGadget::<C1>::get_challenge_native(
|
||||||
&nova.poseidon_config,
|
&nova.poseidon_config,
|
||||||
|
nova.pp_hash,
|
||||||
nova.U_i.clone(),
|
nova.U_i.clone(),
|
||||||
nova.u_i.clone(),
|
nova.u_i.clone(),
|
||||||
cmT,
|
cmT,
|
||||||
@@ -317,6 +320,7 @@ where
|
|||||||
cf_r1cs: nova.cf_r1cs,
|
cf_r1cs: nova.cf_r1cs,
|
||||||
cf_pedersen_params: nova.cf_cs_pp,
|
cf_pedersen_params: nova.cf_cs_pp,
|
||||||
poseidon_config: nova.poseidon_config,
|
poseidon_config: nova.poseidon_config,
|
||||||
|
pp_hash: Some(nova.pp_hash),
|
||||||
i: Some(nova.i),
|
i: Some(nova.i),
|
||||||
z_0: Some(nova.z_0),
|
z_0: Some(nova.z_0),
|
||||||
z_i: Some(nova.z_i),
|
z_i: Some(nova.z_i),
|
||||||
@@ -360,6 +364,9 @@ where
|
|||||||
Ok(self.r1cs.clone())
|
Ok(self.r1cs.clone())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
let pp_hash = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
|
||||||
|
Ok(self.pp_hash.unwrap_or_else(CF1::<C1>::zero))
|
||||||
|
})?;
|
||||||
let i =
|
let i =
|
||||||
FpVar::<CF1<C1>>::new_input(cs.clone(), || Ok(self.i.unwrap_or_else(CF1::<C1>::zero)))?;
|
FpVar::<CF1<C1>>::new_input(cs.clone(), || Ok(self.i.unwrap_or_else(CF1::<C1>::zero)))?;
|
||||||
let z_0 = Vec::<FpVar<CF1<C1>>>::new_input(cs.clone(), || {
|
let z_0 = Vec::<FpVar<CF1<C1>>>::new_input(cs.clone(), || {
|
||||||
@@ -421,9 +428,13 @@ where
|
|||||||
(u_i.u.is_one()?).enforce_equal(&Boolean::TRUE)?;
|
(u_i.u.is_one()?).enforce_equal(&Boolean::TRUE)?;
|
||||||
|
|
||||||
// 3.a u_i.x[0] == H(i, z_0, z_i, U_i)
|
// 3.a u_i.x[0] == H(i, z_0, z_i, U_i)
|
||||||
let (u_i_x, U_i_vec) =
|
let (u_i_x, U_i_vec) = U_i.clone().hash(
|
||||||
U_i.clone()
|
&crh_params,
|
||||||
.hash(&crh_params, i.clone(), z_0.clone(), z_i.clone())?;
|
pp_hash.clone(),
|
||||||
|
i.clone(),
|
||||||
|
z_0.clone(),
|
||||||
|
z_i.clone(),
|
||||||
|
)?;
|
||||||
(u_i.x[0]).enforce_equal(&u_i_x)?;
|
(u_i.x[0]).enforce_equal(&u_i_x)?;
|
||||||
|
|
||||||
#[cfg(feature = "light-test")]
|
#[cfg(feature = "light-test")]
|
||||||
@@ -454,7 +465,7 @@ where
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
// 3.b u_i.x[1] == H(cf_U_i)
|
// 3.b u_i.x[1] == H(cf_U_i)
|
||||||
let (cf_u_i_x, _) = cf_U_i.clone().hash(&crh_params)?;
|
let (cf_u_i_x, _) = cf_U_i.clone().hash(&crh_params, pp_hash.clone())?;
|
||||||
(u_i.x[1]).enforce_equal(&cf_u_i_x)?;
|
(u_i.x[1]).enforce_equal(&cf_u_i_x)?;
|
||||||
|
|
||||||
// 4. check Pedersen commitments of cf_U_i.{cmE, cmW}
|
// 4. check Pedersen commitments of cf_U_i.{cmE, cmW}
|
||||||
@@ -512,6 +523,7 @@ where
|
|||||||
let r_bits = ChallengeGadget::<C1>::get_challenge_gadget(
|
let r_bits = ChallengeGadget::<C1>::get_challenge_gadget(
|
||||||
cs.clone(),
|
cs.clone(),
|
||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
|
pp_hash,
|
||||||
U_i_vec,
|
U_i_vec,
|
||||||
u_i.clone(),
|
u_i.clone(),
|
||||||
cmT.clone(),
|
cmT.clone(),
|
||||||
@@ -611,10 +623,15 @@ pub mod tests {
|
|||||||
use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2};
|
use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z};
|
use crate::arith::{
|
||||||
use crate::ccs::r1cs::{extract_r1cs, extract_w_x};
|
r1cs::{
|
||||||
|
tests::{get_test_r1cs, get_test_z},
|
||||||
|
{extract_r1cs, extract_w_x},
|
||||||
|
},
|
||||||
|
Arith,
|
||||||
|
};
|
||||||
use crate::commitment::pedersen::Pedersen;
|
use crate::commitment::pedersen::Pedersen;
|
||||||
use crate::folding::nova::{get_cs_params_len, ProverParams, VerifierParams};
|
use crate::folding::nova::PreprocessorParam;
|
||||||
use crate::frontend::tests::{CubicFCircuit, CustomFCircuit, WrapperCircuit};
|
use crate::frontend::tests::{CubicFCircuit, CustomFCircuit, WrapperCircuit};
|
||||||
use crate::transcript::poseidon::poseidon_canonical_config;
|
use crate::transcript::poseidon::poseidon_canonical_config;
|
||||||
use crate::FoldingScheme;
|
use crate::FoldingScheme;
|
||||||
@@ -772,23 +789,6 @@ pub mod tests {
|
|||||||
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)];
|
||||||
|
|
||||||
// get the CS & CF_CS len
|
|
||||||
let (cs_len, cf_cs_len) =
|
|
||||||
get_cs_params_len::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>>(
|
|
||||||
&poseidon_config,
|
|
||||||
F_circuit,
|
|
||||||
)
|
|
||||||
.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();
|
|
||||||
|
|
||||||
let prover_params =
|
|
||||||
ProverParams::<Projective, Projective2, Pedersen<Projective>, Pedersen<Projective2>> {
|
|
||||||
poseidon_config: poseidon_config.clone(),
|
|
||||||
cs_pp: pedersen_params.clone(),
|
|
||||||
cf_cs_pp: cf_pedersen_params.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
type N = Nova<
|
type N = Nova<
|
||||||
Projective,
|
Projective,
|
||||||
GVar,
|
GVar,
|
||||||
@@ -799,22 +799,24 @@ pub mod tests {
|
|||||||
Pedersen<Projective2>,
|
Pedersen<Projective2>,
|
||||||
>;
|
>;
|
||||||
|
|
||||||
// generate a Nova instance and do a step of it
|
let prep_param = PreprocessorParam::<
|
||||||
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,
|
Projective,
|
||||||
Projective2,
|
Projective2,
|
||||||
|
CubicFCircuit<Fr>,
|
||||||
Pedersen<Projective>,
|
Pedersen<Projective>,
|
||||||
Pedersen<Projective2>,
|
Pedersen<Projective2>,
|
||||||
> {
|
>::new(poseidon_config, F_circuit);
|
||||||
poseidon_config: poseidon_config.clone(),
|
let (prover_params, verifier_params) = N::preprocess(&mut rng, &prep_param).unwrap();
|
||||||
r1cs: ivc_v.clone().r1cs,
|
|
||||||
cf_r1cs: ivc_v.clone().cf_r1cs,
|
// generate a Nova instance and do a step of it
|
||||||
cs_vp: pedersen_params,
|
let mut nova = N::init(
|
||||||
cf_cs_vp: cf_pedersen_params,
|
(prover_params, verifier_params.clone()),
|
||||||
};
|
F_circuit,
|
||||||
|
z_0.clone(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
nova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
|
let ivc_v = nova.clone();
|
||||||
let (running_instance, incoming_instance, cyclefold_instance) = ivc_v.instances();
|
let (running_instance, incoming_instance, cyclefold_instance) = ivc_v.instances();
|
||||||
N::verify(
|
N::verify(
|
||||||
verifier_params,
|
verifier_params,
|
||||||
|
|||||||
@@ -13,19 +13,18 @@ use ark_std::fmt::Debug;
|
|||||||
use ark_std::rand::RngCore;
|
use ark_std::rand::RngCore;
|
||||||
use ark_std::{One, Zero};
|
use ark_std::{One, Zero};
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use std::usize;
|
|
||||||
|
|
||||||
use crate::ccs::r1cs::{extract_r1cs, extract_w_x, R1CS};
|
use crate::arith::r1cs::{extract_r1cs, extract_w_x, R1CS};
|
||||||
use crate::commitment::CommitmentScheme;
|
use crate::commitment::CommitmentScheme;
|
||||||
use crate::folding::circuits::cyclefold::{fold_cyclefold_circuit, CycleFoldCircuit};
|
|
||||||
use crate::folding::circuits::{
|
use crate::folding::circuits::{
|
||||||
|
cyclefold::{fold_cyclefold_circuit, CycleFoldCircuit},
|
||||||
nonnative::{
|
nonnative::{
|
||||||
affine::nonnative_affine_to_field_elements, uint::nonnative_field_to_field_elements,
|
affine::nonnative_affine_to_field_elements, uint::nonnative_field_to_field_elements,
|
||||||
},
|
},
|
||||||
CF2,
|
CF2,
|
||||||
};
|
};
|
||||||
use crate::frontend::FCircuit;
|
use crate::frontend::FCircuit;
|
||||||
use crate::utils::{get_cm_coordinates, vec::is_zero_vec};
|
use crate::utils::{get_cm_coordinates, pp_hash, vec::is_zero_vec};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use crate::FoldingScheme;
|
use crate::FoldingScheme;
|
||||||
|
|
||||||
@@ -70,6 +69,7 @@ where
|
|||||||
pub fn hash(
|
pub fn hash(
|
||||||
&self,
|
&self,
|
||||||
poseidon_config: &PoseidonConfig<C::ScalarField>,
|
poseidon_config: &PoseidonConfig<C::ScalarField>,
|
||||||
|
pp_hash: C::ScalarField, // public params hash
|
||||||
i: C::ScalarField,
|
i: C::ScalarField,
|
||||||
z_0: Vec<C::ScalarField>,
|
z_0: Vec<C::ScalarField>,
|
||||||
z_i: Vec<C::ScalarField>,
|
z_i: Vec<C::ScalarField>,
|
||||||
@@ -80,7 +80,7 @@ where
|
|||||||
CRH::<C::ScalarField>::evaluate(
|
CRH::<C::ScalarField>::evaluate(
|
||||||
poseidon_config,
|
poseidon_config,
|
||||||
vec![
|
vec![
|
||||||
vec![i],
|
vec![pp_hash, i],
|
||||||
z_0,
|
z_0,
|
||||||
z_i,
|
z_i,
|
||||||
vec![self.u],
|
vec![self.u],
|
||||||
@@ -140,9 +140,13 @@ where
|
|||||||
pub fn hash_cyclefold(
|
pub fn hash_cyclefold(
|
||||||
&self,
|
&self,
|
||||||
poseidon_config: &PoseidonConfig<C::BaseField>,
|
poseidon_config: &PoseidonConfig<C::BaseField>,
|
||||||
|
pp_hash: C::BaseField, // public params hash
|
||||||
) -> Result<C::BaseField, Error> {
|
) -> Result<C::BaseField, Error> {
|
||||||
CRH::<C::BaseField>::evaluate(poseidon_config, self.to_field_elements().unwrap())
|
CRH::<C::BaseField>::evaluate(
|
||||||
.map_err(|e| Error::Other(e.to_string()))
|
poseidon_config,
|
||||||
|
[vec![pp_hash], self.to_field_elements().unwrap()].concat(),
|
||||||
|
)
|
||||||
|
.map_err(|e| Error::Other(e.to_string()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,6 +257,25 @@ where
|
|||||||
pub cf_cs_vp: CS2::VerifierParams,
|
pub cf_cs_vp: CS2::VerifierParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<C1, C2, CS1, CS2> VerifierParams<C1, C2, CS1, CS2>
|
||||||
|
where
|
||||||
|
C1: CurveGroup,
|
||||||
|
C2: CurveGroup,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
{
|
||||||
|
/// returns the hash of the public parameters of Nova
|
||||||
|
pub fn pp_hash(&self) -> Result<C1::ScalarField, Error> {
|
||||||
|
pp_hash::<C1, C2, CS1, CS2>(
|
||||||
|
&self.r1cs,
|
||||||
|
&self.cf_r1cs,
|
||||||
|
&self.cs_vp,
|
||||||
|
&self.cf_cs_vp,
|
||||||
|
&self.poseidon_config,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Implements Nova+CycleFold's IVC, described in [Nova](https://eprint.iacr.org/2021/370.pdf) and
|
/// Implements Nova+CycleFold's IVC, described in [Nova](https://eprint.iacr.org/2021/370.pdf) and
|
||||||
/// [CycleFold](https://eprint.iacr.org/2023/1192.pdf), following the FoldingScheme trait
|
/// [CycleFold](https://eprint.iacr.org/2023/1192.pdf), following the FoldingScheme trait
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
@@ -280,6 +303,8 @@ where
|
|||||||
pub cf_cs_pp: CS2::ProverParams,
|
pub cf_cs_pp: CS2::ProverParams,
|
||||||
/// F circuit, the circuit that is being folded
|
/// F circuit, the circuit that is being folded
|
||||||
pub F: FC,
|
pub F: FC,
|
||||||
|
/// public params hash
|
||||||
|
pub pp_hash: C1::ScalarField,
|
||||||
pub i: C1::ScalarField,
|
pub i: C1::ScalarField,
|
||||||
/// initial state
|
/// initial state
|
||||||
pub z_0: Vec<C1::ScalarField>,
|
pub z_0: Vec<C1::ScalarField>,
|
||||||
@@ -343,8 +368,8 @@ where
|
|||||||
cf_cs_pp = prep_param.clone().cf_cs_pp.unwrap();
|
cf_cs_pp = prep_param.clone().cf_cs_pp.unwrap();
|
||||||
cf_cs_vp = prep_param.clone().cf_cs_vp.unwrap();
|
cf_cs_vp = prep_param.clone().cf_cs_vp.unwrap();
|
||||||
} else {
|
} else {
|
||||||
(cs_pp, cs_vp) = CS1::setup(&mut rng, r1cs.A.n_rows).unwrap();
|
(cs_pp, cs_vp) = CS1::setup(&mut rng, r1cs.A.n_rows)?;
|
||||||
(cf_cs_pp, cf_cs_vp) = CS2::setup(&mut rng, cf_r1cs.A.n_rows).unwrap();
|
(cf_cs_pp, cf_cs_vp) = CS2::setup(&mut rng, cf_r1cs.A.n_rows)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let prover_params = ProverParams::<C1, C2, CS1, CS2> {
|
let prover_params = ProverParams::<C1, C2, CS1, CS2> {
|
||||||
@@ -356,14 +381,21 @@ where
|
|||||||
poseidon_config: prep_param.poseidon_config.clone(),
|
poseidon_config: prep_param.poseidon_config.clone(),
|
||||||
r1cs,
|
r1cs,
|
||||||
cf_r1cs,
|
cf_r1cs,
|
||||||
cs_vp: cs_vp.clone(),
|
cs_vp,
|
||||||
cf_cs_vp: cf_cs_vp.clone(),
|
cf_cs_vp,
|
||||||
};
|
};
|
||||||
Ok((prover_params.clone(), verifier_params))
|
|
||||||
|
Ok((prover_params, verifier_params))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes the Nova+CycleFold's IVC for the given parameters and initial state `z_0`.
|
/// Initializes the Nova+CycleFold's IVC for the given parameters and initial state `z_0`.
|
||||||
fn init(pp: &Self::ProverParam, F: FC, z_0: Vec<C1::ScalarField>) -> Result<Self, Error> {
|
fn init(
|
||||||
|
params: (Self::ProverParam, Self::VerifierParam),
|
||||||
|
F: FC,
|
||||||
|
z_0: Vec<C1::ScalarField>,
|
||||||
|
) -> Result<Self, Error> {
|
||||||
|
let (pp, vp) = params;
|
||||||
|
|
||||||
// prepare the circuit to obtain its R1CS
|
// prepare the circuit to obtain its R1CS
|
||||||
let cs = ConstraintSystem::<C1::ScalarField>::new_ref();
|
let cs = ConstraintSystem::<C1::ScalarField>::new_ref();
|
||||||
let cs2 = ConstraintSystem::<C1::BaseField>::new_ref();
|
let cs2 = ConstraintSystem::<C1::BaseField>::new_ref();
|
||||||
@@ -382,6 +414,9 @@ where
|
|||||||
let cs2 = cs2.into_inner().ok_or(Error::NoInnerConstraintSystem)?;
|
let cs2 = cs2.into_inner().ok_or(Error::NoInnerConstraintSystem)?;
|
||||||
let cf_r1cs = extract_r1cs::<C1::BaseField>(&cs2);
|
let cf_r1cs = extract_r1cs::<C1::BaseField>(&cs2);
|
||||||
|
|
||||||
|
// compute the public params hash
|
||||||
|
let pp_hash = vp.pp_hash()?;
|
||||||
|
|
||||||
// setup the dummy instances
|
// setup the dummy instances
|
||||||
let (w_dummy, u_dummy) = r1cs.dummy_instance();
|
let (w_dummy, u_dummy) = r1cs.dummy_instance();
|
||||||
let (cf_w_dummy, cf_u_dummy) = cf_r1cs.dummy_instance();
|
let (cf_w_dummy, cf_u_dummy) = cf_r1cs.dummy_instance();
|
||||||
@@ -398,6 +433,7 @@ where
|
|||||||
cs_pp: pp.cs_pp.clone(),
|
cs_pp: pp.cs_pp.clone(),
|
||||||
cf_cs_pp: pp.cf_cs_pp.clone(),
|
cf_cs_pp: pp.cf_cs_pp.clone(),
|
||||||
F,
|
F,
|
||||||
|
pp_hash,
|
||||||
i: C1::ScalarField::zero(),
|
i: C1::ScalarField::zero(),
|
||||||
z_0: z_0.clone(),
|
z_0: z_0.clone(),
|
||||||
z_i: z_0,
|
z_i: z_0,
|
||||||
@@ -453,6 +489,7 @@ where
|
|||||||
// r_bits is the r used to the RLC of the F' instances
|
// r_bits is the r used to the RLC of the F' instances
|
||||||
let r_bits = ChallengeGadget::<C1>::get_challenge_native(
|
let r_bits = ChallengeGadget::<C1>::get_challenge_native(
|
||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
|
self.pp_hash,
|
||||||
self.U_i.clone(),
|
self.U_i.clone(),
|
||||||
self.u_i.clone(),
|
self.u_i.clone(),
|
||||||
cmT,
|
cmT,
|
||||||
@@ -471,6 +508,7 @@ where
|
|||||||
// u_{i+1}.x[0] = H(i+1, z_0, z_{i+1}, U_{i+1})
|
// u_{i+1}.x[0] = H(i+1, z_0, z_{i+1}, U_{i+1})
|
||||||
let u_i1_x = U_i1.hash(
|
let u_i1_x = U_i1.hash(
|
||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
|
self.pp_hash,
|
||||||
self.i + C1::ScalarField::one(),
|
self.i + C1::ScalarField::one(),
|
||||||
self.z_0.clone(),
|
self.z_0.clone(),
|
||||||
z_i1.clone(),
|
z_i1.clone(),
|
||||||
@@ -479,11 +517,14 @@ where
|
|||||||
let cf_u_i1_x: C1::ScalarField;
|
let cf_u_i1_x: C1::ScalarField;
|
||||||
|
|
||||||
if self.i == C1::ScalarField::zero() {
|
if self.i == C1::ScalarField::zero() {
|
||||||
cf_u_i1_x = self.cf_U_i.hash_cyclefold(&self.poseidon_config)?;
|
cf_u_i1_x = self
|
||||||
|
.cf_U_i
|
||||||
|
.hash_cyclefold(&self.poseidon_config, self.pp_hash)?;
|
||||||
// base case
|
// base case
|
||||||
augmented_F_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
augmented_F_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
poseidon_config: self.poseidon_config.clone(),
|
poseidon_config: self.poseidon_config.clone(),
|
||||||
|
pp_hash: Some(self.pp_hash),
|
||||||
i: Some(C1::ScalarField::zero()), // = i=0
|
i: Some(C1::ScalarField::zero()), // = i=0
|
||||||
i_usize: Some(0),
|
i_usize: Some(0),
|
||||||
z_0: Some(self.z_0.clone()), // = z_i
|
z_0: Some(self.z_0.clone()), // = z_i
|
||||||
@@ -552,11 +593,12 @@ where
|
|||||||
let (_cfE_w_i, cfE_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) =
|
let (_cfE_w_i, cfE_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) =
|
||||||
self.fold_cyclefold_circuit(cfW_W_i1, cfW_U_i1.clone(), cfE_u_i_x, cfE_circuit)?;
|
self.fold_cyclefold_circuit(cfW_W_i1, cfW_U_i1.clone(), cfE_u_i_x, cfE_circuit)?;
|
||||||
|
|
||||||
cf_u_i1_x = cf_U_i1.hash_cyclefold(&self.poseidon_config)?;
|
cf_u_i1_x = cf_U_i1.hash_cyclefold(&self.poseidon_config, self.pp_hash)?;
|
||||||
|
|
||||||
augmented_F_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
augmented_F_circuit = AugmentedFCircuit::<C1, C2, GC2, FC> {
|
||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
poseidon_config: self.poseidon_config.clone(),
|
poseidon_config: self.poseidon_config.clone(),
|
||||||
|
pp_hash: Some(self.pp_hash),
|
||||||
i: Some(self.i),
|
i: Some(self.i),
|
||||||
i_usize: Some(i_usize),
|
i_usize: Some(i_usize),
|
||||||
z_0: Some(self.z_0.clone()),
|
z_0: Some(self.z_0.clone()),
|
||||||
@@ -670,14 +712,16 @@ where
|
|||||||
return Err(Error::IVCVerificationFail);
|
return Err(Error::IVCVerificationFail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let pp_hash = vp.pp_hash()?;
|
||||||
|
|
||||||
// check that u_i's output points to the running instance
|
// check that u_i's output points to the running instance
|
||||||
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
// u_i.X[0] == H(i, z_0, z_i, U_i)
|
||||||
let expected_u_i_x = U_i.hash(&vp.poseidon_config, num_steps, z_0, z_i.clone())?;
|
let expected_u_i_x = U_i.hash(&vp.poseidon_config, pp_hash, num_steps, z_0, z_i.clone())?;
|
||||||
if expected_u_i_x != u_i.x[0] {
|
if expected_u_i_x != u_i.x[0] {
|
||||||
return Err(Error::IVCVerificationFail);
|
return Err(Error::IVCVerificationFail);
|
||||||
}
|
}
|
||||||
// u_i.X[1] == H(cf_U_i)
|
// u_i.X[1] == H(cf_U_i)
|
||||||
let expected_cf_u_i_x = cf_U_i.hash_cyclefold(&vp.poseidon_config)?;
|
let expected_cf_u_i_x = cf_U_i.hash_cyclefold(&vp.poseidon_config, pp_hash)?;
|
||||||
if expected_cf_u_i_x != u_i.x[1] {
|
if expected_cf_u_i_x != u_i.x[1] {
|
||||||
return Err(Error::IVCVerificationFail);
|
return Err(Error::IVCVerificationFail);
|
||||||
}
|
}
|
||||||
@@ -767,6 +811,7 @@ where
|
|||||||
&self.poseidon_config,
|
&self.poseidon_config,
|
||||||
self.cf_r1cs.clone(),
|
self.cf_r1cs.clone(),
|
||||||
self.cf_cs_pp.clone(),
|
self.cf_cs_pp.clone(),
|
||||||
|
self.pp_hash,
|
||||||
cf_W_i,
|
cf_W_i,
|
||||||
cf_U_i,
|
cf_U_i,
|
||||||
cf_u_i_x,
|
cf_u_i_x,
|
||||||
@@ -884,10 +929,10 @@ pub mod tests {
|
|||||||
cf_cs_pp: None,
|
cf_cs_pp: None,
|
||||||
cf_cs_vp: None,
|
cf_cs_vp: None,
|
||||||
};
|
};
|
||||||
let (prover_params, verifier_params) = N::preprocess(&mut rng, &prep_param).unwrap();
|
let nova_params = N::preprocess(&mut rng, &prep_param).unwrap();
|
||||||
|
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
let mut nova = N::init(nova_params.clone(), F_circuit, z_0.clone()).unwrap();
|
||||||
|
|
||||||
let num_steps: usize = 3;
|
let num_steps: usize = 3;
|
||||||
for _ in 0..num_steps {
|
for _ in 0..num_steps {
|
||||||
@@ -897,7 +942,7 @@ pub mod tests {
|
|||||||
|
|
||||||
let (running_instance, incoming_instance, cyclefold_instance) = nova.instances();
|
let (running_instance, incoming_instance, cyclefold_instance) = nova.instances();
|
||||||
N::<CS1, CS2>::verify(
|
N::<CS1, CS2>::verify(
|
||||||
verifier_params,
|
nova_params.1, // Nova's verifier params
|
||||||
z_0,
|
z_0,
|
||||||
nova.z_i,
|
nova.z_i,
|
||||||
nova.i,
|
nova.i,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use ark_std::Zero;
|
|||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use super::{CommittedInstance, Witness};
|
use super::{CommittedInstance, Witness};
|
||||||
use crate::ccs::r1cs::R1CS;
|
use crate::arith::r1cs::R1CS;
|
||||||
use crate::commitment::CommitmentScheme;
|
use crate::commitment::CommitmentScheme;
|
||||||
use crate::transcript::Transcript;
|
use crate::transcript::Transcript;
|
||||||
use crate::utils::vec::{hadamard, mat_vec_mul, vec_add, vec_scalar_mul, vec_sub};
|
use crate::utils::vec::{hadamard, mat_vec_mul, vec_add, vec_scalar_mul, vec_sub};
|
||||||
@@ -205,7 +205,7 @@ pub mod tests {
|
|||||||
use ark_pallas::{Fr, Projective};
|
use ark_pallas::{Fr, Projective};
|
||||||
use ark_std::{ops::Mul, UniformRand};
|
use ark_std::{ops::Mul, UniformRand};
|
||||||
|
|
||||||
use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z};
|
use crate::arith::r1cs::tests::{get_test_r1cs, get_test_z};
|
||||||
use crate::commitment::pedersen::{Params as PedersenParams, Pedersen};
|
use crate::commitment::pedersen::{Params as PedersenParams, Pedersen};
|
||||||
use crate::folding::nova::circuits::ChallengeGadget;
|
use crate::folding::nova::circuits::ChallengeGadget;
|
||||||
use crate::folding::nova::traits::NovaR1CS;
|
use crate::folding::nova::traits::NovaR1CS;
|
||||||
@@ -259,8 +259,10 @@ pub mod tests {
|
|||||||
|
|
||||||
let poseidon_config = poseidon_canonical_config::<C::ScalarField>();
|
let poseidon_config = poseidon_canonical_config::<C::ScalarField>();
|
||||||
|
|
||||||
|
let pp_hash = C::ScalarField::from(42u32); // only for test
|
||||||
let r_bits = ChallengeGadget::<C>::get_challenge_native(
|
let r_bits = ChallengeGadget::<C>::get_challenge_native(
|
||||||
&poseidon_config,
|
&poseidon_config,
|
||||||
|
pp_hash,
|
||||||
ci1.clone(),
|
ci1.clone(),
|
||||||
ci2.clone(),
|
ci2.clone(),
|
||||||
cmT,
|
cmT,
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ use super::{circuits::AugmentedFCircuit, Nova, ProverParams};
|
|||||||
use super::{CommittedInstance, Witness};
|
use super::{CommittedInstance, Witness};
|
||||||
use crate::folding::circuits::{cyclefold::CycleFoldCircuit, CF2};
|
use crate::folding::circuits::{cyclefold::CycleFoldCircuit, CF2};
|
||||||
use crate::{
|
use crate::{
|
||||||
ccs::r1cs::extract_r1cs, commitment::CommitmentScheme, folding::circuits::CF1,
|
arith::r1cs::extract_r1cs, commitment::CommitmentScheme, folding::circuits::CF1,
|
||||||
frontend::FCircuit,
|
frontend::FCircuit,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -41,6 +41,7 @@ where
|
|||||||
mut writer: W,
|
mut writer: W,
|
||||||
compress: ark_serialize::Compress,
|
compress: ark_serialize::Compress,
|
||||||
) -> Result<(), ark_serialize::SerializationError> {
|
) -> Result<(), ark_serialize::SerializationError> {
|
||||||
|
self.pp_hash.serialize_with_mode(&mut writer, compress)?;
|
||||||
self.i.serialize_with_mode(&mut writer, compress)?;
|
self.i.serialize_with_mode(&mut writer, compress)?;
|
||||||
self.z_0.serialize_with_mode(&mut writer, compress)?;
|
self.z_0.serialize_with_mode(&mut writer, compress)?;
|
||||||
self.z_i.serialize_with_mode(&mut writer, compress)?;
|
self.z_i.serialize_with_mode(&mut writer, compress)?;
|
||||||
@@ -53,7 +54,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialized_size(&self, compress: ark_serialize::Compress) -> usize {
|
fn serialized_size(&self, compress: ark_serialize::Compress) -> usize {
|
||||||
self.i.serialized_size(compress)
|
self.pp_hash.serialized_size(compress)
|
||||||
|
+ self.i.serialized_size(compress)
|
||||||
+ self.z_0.serialized_size(compress)
|
+ self.z_0.serialized_size(compress)
|
||||||
+ self.z_i.serialized_size(compress)
|
+ self.z_i.serialized_size(compress)
|
||||||
+ self.w_i.serialized_size(compress)
|
+ self.w_i.serialized_size(compress)
|
||||||
@@ -115,6 +117,7 @@ where
|
|||||||
prover_params: ProverParams<C1, C2, CS1, CS2>,
|
prover_params: ProverParams<C1, C2, CS1, CS2>,
|
||||||
poseidon_config: PoseidonConfig<C1::ScalarField>,
|
poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||||
) -> Result<Self, ark_serialize::SerializationError> {
|
) -> Result<Self, ark_serialize::SerializationError> {
|
||||||
|
let pp_hash = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?;
|
||||||
let i = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?;
|
let i = C1::ScalarField::deserialize_with_mode(&mut reader, compress, validate)?;
|
||||||
let z_0 = Vec::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
|
let z_0 = Vec::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
|
||||||
let z_i = Vec::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
|
let z_i = Vec::<C1::ScalarField>::deserialize_with_mode(&mut reader, compress, validate)?;
|
||||||
@@ -151,8 +154,13 @@ where
|
|||||||
_gc1: PhantomData,
|
_gc1: PhantomData,
|
||||||
_c2: PhantomData,
|
_c2: PhantomData,
|
||||||
_gc2: PhantomData,
|
_gc2: PhantomData,
|
||||||
|
r1cs,
|
||||||
|
cf_r1cs,
|
||||||
|
poseidon_config,
|
||||||
cs_pp: prover_params.cs_pp,
|
cs_pp: prover_params.cs_pp,
|
||||||
cf_cs_pp: prover_params.cf_cs_pp,
|
cf_cs_pp: prover_params.cf_cs_pp,
|
||||||
|
F: f_circuit,
|
||||||
|
pp_hash,
|
||||||
i,
|
i,
|
||||||
z_0,
|
z_0,
|
||||||
z_i,
|
z_i,
|
||||||
@@ -162,10 +170,6 @@ where
|
|||||||
U_i,
|
U_i,
|
||||||
cf_W_i,
|
cf_W_i,
|
||||||
cf_U_i,
|
cf_U_i,
|
||||||
r1cs,
|
|
||||||
cf_r1cs,
|
|
||||||
poseidon_config,
|
|
||||||
F: f_circuit,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -174,17 +178,12 @@ where
|
|||||||
pub mod tests {
|
pub mod tests {
|
||||||
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
||||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
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 ark_serialize::{CanonicalSerialize, Compress, Validate};
|
||||||
use std::{fs, io::Write};
|
use std::{fs, io::Write};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
commitment::{
|
commitment::{kzg::KZG, pedersen::Pedersen},
|
||||||
kzg::{ProverKey as KZGProverKey, KZG},
|
folding::nova::{Nova, PreprocessorParam},
|
||||||
pedersen::Pedersen,
|
|
||||||
CommitmentScheme,
|
|
||||||
},
|
|
||||||
folding::nova::{get_cs_params_len, Nova, ProverParams},
|
|
||||||
frontend::{tests::CubicFCircuit, FCircuit},
|
frontend::{tests::CubicFCircuit, FCircuit},
|
||||||
transcript::poseidon::poseidon_canonical_config,
|
transcript::poseidon::poseidon_canonical_config,
|
||||||
FoldingScheme,
|
FoldingScheme,
|
||||||
@@ -195,15 +194,6 @@ pub mod tests {
|
|||||||
let mut rng = ark_std::test_rng();
|
let mut rng = ark_std::test_rng();
|
||||||
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 (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 (cf_pedersen_params, _) = Pedersen::<Projective2>::setup(&mut rng, cf_cs_len).unwrap();
|
|
||||||
|
|
||||||
// Initialize nova and make multiple `prove_step()`
|
// Initialize nova and make multiple `prove_step()`
|
||||||
type N = Nova<
|
type N = Nova<
|
||||||
@@ -215,15 +205,11 @@ pub mod tests {
|
|||||||
KZG<'static, Bn254>,
|
KZG<'static, Bn254>,
|
||||||
Pedersen<Projective2>,
|
Pedersen<Projective2>,
|
||||||
>;
|
>;
|
||||||
let prover_params =
|
let prep_param = PreprocessorParam::new(poseidon_config.clone(), F_circuit);
|
||||||
ProverParams::<Projective, Projective2, KZG<Bn254>, Pedersen<Projective2>> {
|
let nova_params = N::preprocess(&mut rng, &prep_param).unwrap();
|
||||||
poseidon_config: poseidon_config.clone(),
|
|
||||||
cs_pp: kzg_pk.clone(),
|
|
||||||
cf_cs_pp: cf_pedersen_params.clone(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
let mut nova = N::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
let mut nova = N::init(nova_params.clone(), F_circuit, z_0.clone()).unwrap();
|
||||||
|
|
||||||
let num_steps: usize = 3;
|
let num_steps: usize = 3;
|
||||||
for _ in 0..num_steps {
|
for _ in 0..num_steps {
|
||||||
@@ -257,7 +243,7 @@ pub mod tests {
|
|||||||
bytes.as_slice(),
|
bytes.as_slice(),
|
||||||
Compress::No,
|
Compress::No,
|
||||||
Validate::No,
|
Validate::No,
|
||||||
prover_params,
|
nova_params.0, // Nova's prover params
|
||||||
poseidon_config,
|
poseidon_config,
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use ark_ec::{CurveGroup, Group};
|
|||||||
use ark_std::{One, Zero};
|
use ark_std::{One, Zero};
|
||||||
|
|
||||||
use super::{CommittedInstance, Witness};
|
use super::{CommittedInstance, Witness};
|
||||||
use crate::ccs::r1cs::R1CS;
|
use crate::arith::{r1cs::R1CS, Arith};
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|
||||||
/// NovaR1CS extends R1CS methods with Nova specific methods
|
/// NovaR1CS extends R1CS methods with Nova specific methods
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use super::utils::{all_powers, betas_star, exponential_powers};
|
|||||||
use super::ProtoGalaxyError;
|
use super::ProtoGalaxyError;
|
||||||
use super::{CommittedInstance, Witness};
|
use super::{CommittedInstance, Witness};
|
||||||
|
|
||||||
use crate::ccs::r1cs::R1CS;
|
use crate::arith::r1cs::R1CS;
|
||||||
use crate::transcript::Transcript;
|
use crate::transcript::Transcript;
|
||||||
use crate::utils::vec::*;
|
use crate::utils::vec::*;
|
||||||
use crate::utils::virtual_polynomial::bit_decompose;
|
use crate::utils::virtual_polynomial::bit_decompose;
|
||||||
@@ -383,7 +383,7 @@ mod tests {
|
|||||||
use ark_pallas::{Fr, Projective};
|
use ark_pallas::{Fr, Projective};
|
||||||
use ark_std::UniformRand;
|
use ark_std::UniformRand;
|
||||||
|
|
||||||
use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z};
|
use crate::arith::r1cs::tests::{get_test_r1cs, get_test_z};
|
||||||
use crate::commitment::{pedersen::Pedersen, CommitmentScheme};
|
use crate::commitment::{pedersen::Pedersen, CommitmentScheme};
|
||||||
use crate::transcript::poseidon::{poseidon_canonical_config, PoseidonTranscript};
|
use crate::transcript::poseidon::{poseidon_canonical_config, PoseidonTranscript};
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use thiserror::Error;
|
|||||||
|
|
||||||
use crate::frontend::FCircuit;
|
use crate::frontend::FCircuit;
|
||||||
|
|
||||||
pub mod ccs;
|
pub mod arith;
|
||||||
pub mod commitment;
|
pub mod commitment;
|
||||||
pub mod constants;
|
pub mod constants;
|
||||||
pub mod folding;
|
pub mod folding;
|
||||||
@@ -122,7 +122,7 @@ where
|
|||||||
) -> Result<(Self::ProverParam, Self::VerifierParam), Error>;
|
) -> Result<(Self::ProverParam, Self::VerifierParam), Error>;
|
||||||
|
|
||||||
fn init(
|
fn init(
|
||||||
pp: &Self::ProverParam,
|
params: (Self::ProverParam, Self::VerifierParam),
|
||||||
step_circuit: FC,
|
step_circuit: FC,
|
||||||
z_0: Vec<C1::ScalarField>, // initial state
|
z_0: Vec<C1::ScalarField>, // initial state
|
||||||
) -> Result<Self, Error>;
|
) -> Result<Self, Error>;
|
||||||
|
|||||||
@@ -104,7 +104,7 @@ pub fn dense_vec_to_mle<F: PrimeField>(n_vars: usize, v: &[F]) -> SparseMultilin
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
ccs::tests::get_test_z,
|
arith::ccs::tests::get_test_z,
|
||||||
utils::multilinear_polynomial::fix_variables,
|
utils::multilinear_polynomial::fix_variables,
|
||||||
utils::multilinear_polynomial::tests::fix_last_variables,
|
utils::multilinear_polynomial::tests::fix_last_variables,
|
||||||
utils::{hypercube::BooleanHypercube, vec::tests::to_F_matrix},
|
utils::{hypercube::BooleanHypercube, vec::tests::to_F_matrix},
|
||||||
|
|||||||
@@ -1,6 +1,13 @@
|
|||||||
|
use ark_crypto_primitives::sponge::poseidon::PoseidonConfig;
|
||||||
use ark_ec::{AffineRepr, CurveGroup};
|
use ark_ec::{AffineRepr, CurveGroup};
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
|
use ark_serialize::CanonicalSerialize;
|
||||||
use ark_std::Zero;
|
use ark_std::Zero;
|
||||||
|
use sha3::{Digest, Sha3_256};
|
||||||
|
|
||||||
|
use crate::arith::Arith;
|
||||||
|
use crate::commitment::CommitmentScheme;
|
||||||
|
use crate::Error;
|
||||||
|
|
||||||
pub mod gadgets;
|
pub mod gadgets;
|
||||||
pub mod hypercube;
|
pub mod hypercube;
|
||||||
@@ -32,3 +39,64 @@ pub fn get_cm_coordinates<C: CurveGroup>(cm: &C) -> Vec<C::BaseField> {
|
|||||||
let (cm_x, cm_y) = cm.xy().unwrap_or(zero);
|
let (cm_x, cm_y) = cm.xy().unwrap_or(zero);
|
||||||
vec![*cm_x, *cm_y]
|
vec![*cm_x, *cm_y]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// returns the hash of the given public parameters of the Folding Scheme
|
||||||
|
pub fn pp_hash<C1, C2, CS1, CS2>(
|
||||||
|
arith: &impl Arith<C1::ScalarField>,
|
||||||
|
cf_arith: &impl Arith<C2::ScalarField>,
|
||||||
|
cs_vp: &CS1::VerifierParams,
|
||||||
|
cf_cs_vp: &CS2::VerifierParams,
|
||||||
|
poseidon_config: &PoseidonConfig<C1::ScalarField>,
|
||||||
|
) -> Result<C1::ScalarField, Error>
|
||||||
|
where
|
||||||
|
C1: CurveGroup,
|
||||||
|
C2: CurveGroup,
|
||||||
|
CS1: CommitmentScheme<C1>,
|
||||||
|
CS2: CommitmentScheme<C2>,
|
||||||
|
{
|
||||||
|
let mut hasher = Sha3_256::new();
|
||||||
|
|
||||||
|
// Fr & Fq modulus bit size
|
||||||
|
hasher.update(C1::ScalarField::MODULUS_BIT_SIZE.to_le_bytes());
|
||||||
|
hasher.update(C2::ScalarField::MODULUS_BIT_SIZE.to_le_bytes());
|
||||||
|
// AugmentedFCircuit Arith params
|
||||||
|
hasher.update(arith.params_to_bytes());
|
||||||
|
// CycleFold Circuit Arith params
|
||||||
|
hasher.update(cf_arith.params_to_bytes());
|
||||||
|
// cs_vp & cf_cs_vp (commitments setup)
|
||||||
|
let mut cs_vp_bytes = Vec::new();
|
||||||
|
cs_vp.serialize_uncompressed(&mut cs_vp_bytes)?;
|
||||||
|
hasher.update(cs_vp_bytes);
|
||||||
|
let mut cf_cs_vp_bytes = Vec::new();
|
||||||
|
cf_cs_vp.serialize_uncompressed(&mut cf_cs_vp_bytes)?;
|
||||||
|
hasher.update(cf_cs_vp_bytes);
|
||||||
|
// poseidon params
|
||||||
|
let mut poseidon_config_bytes = Vec::new();
|
||||||
|
poseidon_config
|
||||||
|
.full_rounds
|
||||||
|
.serialize_uncompressed(&mut poseidon_config_bytes)?;
|
||||||
|
poseidon_config
|
||||||
|
.partial_rounds
|
||||||
|
.serialize_uncompressed(&mut poseidon_config_bytes)?;
|
||||||
|
poseidon_config
|
||||||
|
.alpha
|
||||||
|
.serialize_uncompressed(&mut poseidon_config_bytes)?;
|
||||||
|
poseidon_config
|
||||||
|
.ark
|
||||||
|
.serialize_uncompressed(&mut poseidon_config_bytes)?;
|
||||||
|
poseidon_config
|
||||||
|
.mds
|
||||||
|
.serialize_uncompressed(&mut poseidon_config_bytes)?;
|
||||||
|
poseidon_config
|
||||||
|
.rate
|
||||||
|
.serialize_uncompressed(&mut poseidon_config_bytes)?;
|
||||||
|
poseidon_config
|
||||||
|
.capacity
|
||||||
|
.serialize_uncompressed(&mut poseidon_config_bytes)?;
|
||||||
|
hasher.update(poseidon_config_bytes);
|
||||||
|
|
||||||
|
let public_params_hash = hasher.finalize();
|
||||||
|
Ok(C1::ScalarField::from_le_bytes_mod_order(
|
||||||
|
&public_params_hash,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::utils::encoding::{G1Repr, G2Repr};
|
|||||||
use crate::utils::HeaderInclusion;
|
use crate::utils::HeaderInclusion;
|
||||||
use crate::{ProtocolVerifierKey, GPL3_SDPX_IDENTIFIER};
|
use crate::{ProtocolVerifierKey, GPL3_SDPX_IDENTIFIER};
|
||||||
use ark_bn254::Bn254;
|
use ark_bn254::Bn254;
|
||||||
use ark_groth16::VerifyingKey;
|
use ark_groth16::VerifyingKey as ArkVerifyingKey;
|
||||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
|
||||||
@@ -48,10 +48,10 @@ impl From<Groth16VerifierKey> for Groth16Verifier {
|
|||||||
// Ideally this would be linked to the `Decider` trait in FoldingSchemes.
|
// Ideally this would be linked to the `Decider` trait in FoldingSchemes.
|
||||||
// For now, this is the easiest as NovaCycleFold isn't clear target from where we can get all it's needed arguments.
|
// For now, this is the easiest as NovaCycleFold isn't clear target from where we can get all it's needed arguments.
|
||||||
#[derive(CanonicalDeserialize, CanonicalSerialize, Clone, PartialEq, Debug)]
|
#[derive(CanonicalDeserialize, CanonicalSerialize, Clone, PartialEq, Debug)]
|
||||||
pub struct Groth16VerifierKey(pub(crate) VerifyingKey<Bn254>);
|
pub struct Groth16VerifierKey(pub(crate) ArkVerifyingKey<Bn254>);
|
||||||
|
|
||||||
impl From<VerifyingKey<Bn254>> for Groth16VerifierKey {
|
impl From<ArkVerifyingKey<Bn254>> for Groth16VerifierKey {
|
||||||
fn from(value: VerifyingKey<Bn254>) -> Self {
|
fn from(value: ArkVerifyingKey<Bn254>) -> Self {
|
||||||
Self(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,7 +95,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn groth16_vk_serde_roundtrip() {
|
fn groth16_vk_serde_roundtrip() {
|
||||||
let (_, _, _, vk, _) = setup(DEFAULT_SETUP_LEN);
|
let (_, _, _, _, vk, _) = setup(DEFAULT_SETUP_LEN);
|
||||||
|
|
||||||
let g16_vk = Groth16VerifierKey::from(vk);
|
let g16_vk = Groth16VerifierKey::from(vk);
|
||||||
let mut bytes = vec![];
|
let mut bytes = vec![];
|
||||||
@@ -109,7 +109,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn test_groth16_verifier_accepts_and_rejects_proofs() {
|
fn test_groth16_verifier_accepts_and_rejects_proofs() {
|
||||||
let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
|
let mut rng = ark_std::rand::rngs::StdRng::seed_from_u64(test_rng().next_u64());
|
||||||
let (_, _, g16_pk, g16_vk, circuit) = setup(DEFAULT_SETUP_LEN);
|
let (_, _, _, g16_pk, g16_vk, circuit) = setup(DEFAULT_SETUP_LEN);
|
||||||
let g16_vk = Groth16VerifierKey::from(g16_vk);
|
let g16_vk = Groth16VerifierKey::from(g16_vk);
|
||||||
|
|
||||||
let proof = Groth16::<Bn254>::prove(&g16_pk, circuit, &mut rng).unwrap();
|
let proof = Groth16::<Bn254>::prove(&g16_pk, circuit, &mut rng).unwrap();
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn kzg_vk_serde_roundtrip() {
|
fn kzg_vk_serde_roundtrip() {
|
||||||
let (pk, vk, _, _, _) = setup(DEFAULT_SETUP_LEN);
|
let (_, pk, vk, _, _, _) = setup(DEFAULT_SETUP_LEN);
|
||||||
|
|
||||||
let kzg_vk = KZG10VerifierKey::from((vk, pk.powers_of_g[0..3].to_vec()));
|
let kzg_vk = KZG10VerifierKey::from((vk, pk.powers_of_g[0..3].to_vec()));
|
||||||
let mut bytes = vec![];
|
let mut bytes = vec![];
|
||||||
@@ -115,7 +115,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn kzg_verifier_compiles() {
|
fn kzg_verifier_compiles() {
|
||||||
let (kzg_pk, kzg_vk, _, _, _) = setup(DEFAULT_SETUP_LEN);
|
let (_, kzg_pk, kzg_vk, _, _, _) = setup(DEFAULT_SETUP_LEN);
|
||||||
let kzg_vk = KZG10VerifierKey::from((kzg_vk.clone(), kzg_pk.powers_of_g[0..3].to_vec()));
|
let kzg_vk = KZG10VerifierKey::from((kzg_vk.clone(), kzg_pk.powers_of_g[0..3].to_vec()));
|
||||||
|
|
||||||
let res = HeaderInclusion::<KZG10Verifier>::builder()
|
let res = HeaderInclusion::<KZG10Verifier>::builder()
|
||||||
@@ -136,7 +136,7 @@ mod tests {
|
|||||||
let transcript_p = &mut PoseidonTranscript::<G1>::new(&poseidon_config);
|
let transcript_p = &mut PoseidonTranscript::<G1>::new(&poseidon_config);
|
||||||
let transcript_v = &mut PoseidonTranscript::<G1>::new(&poseidon_config);
|
let transcript_v = &mut PoseidonTranscript::<G1>::new(&poseidon_config);
|
||||||
|
|
||||||
let (kzg_pk, kzg_vk, _, _, _) = setup(DEFAULT_SETUP_LEN);
|
let (_, kzg_pk, kzg_vk, _, _, _) = setup(DEFAULT_SETUP_LEN);
|
||||||
let kzg_vk = KZG10VerifierKey::from((kzg_vk.clone(), kzg_pk.powers_of_g[0..3].to_vec()));
|
let kzg_vk = KZG10VerifierKey::from((kzg_vk.clone(), kzg_pk.powers_of_g[0..3].to_vec()));
|
||||||
|
|
||||||
let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(&mut rng))
|
let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(&mut rng))
|
||||||
|
|||||||
@@ -97,6 +97,7 @@ pub mod tests {
|
|||||||
pub fn setup<'a>(
|
pub fn setup<'a>(
|
||||||
n: usize,
|
n: usize,
|
||||||
) -> (
|
) -> (
|
||||||
|
Fr, // public params hash
|
||||||
KZGProverKey<'a, G1>,
|
KZGProverKey<'a, G1>,
|
||||||
KZGVerifierKey<Bn254>,
|
KZGVerifierKey<Bn254>,
|
||||||
ark_groth16::ProvingKey<Bn254>,
|
ark_groth16::ProvingKey<Bn254>,
|
||||||
@@ -115,6 +116,7 @@ pub mod tests {
|
|||||||
|
|
||||||
let (kzg_pk, kzg_vk): (KZGProverKey<G1>, KZGVerifierKey<Bn254>) =
|
let (kzg_pk, kzg_vk): (KZGProverKey<G1>, KZGVerifierKey<Bn254>) =
|
||||||
KZG::<Bn254>::setup(&mut rng, n).unwrap();
|
KZG::<Bn254>::setup(&mut rng, n).unwrap();
|
||||||
(kzg_pk, kzg_vk, g16_pk, g16_vk, circuit)
|
let pp_hash = Fr::from(42u32); // only for test
|
||||||
|
(pp_hash, kzg_pk, kzg_vk, g16_pk, g16_vk, circuit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#![allow(non_snake_case)]
|
#![allow(non_snake_case)]
|
||||||
#![allow(non_camel_case_types)]
|
#![allow(non_camel_case_types)]
|
||||||
|
#![allow(clippy::upper_case_acronyms)]
|
||||||
|
|
||||||
use ark_bn254::{Bn254, Fq, G1Affine};
|
use ark_bn254::{Bn254, Fq, Fr, G1Affine};
|
||||||
use ark_groth16::VerifyingKey;
|
use ark_groth16::VerifyingKey as ArkG16VerifierKey;
|
||||||
use ark_poly_commit::kzg10::VerifierKey;
|
use ark_poly_commit::kzg10::VerifierKey as ArkKZG10VerifierKey;
|
||||||
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
use ark_serialize::{CanonicalDeserialize, CanonicalSerialize};
|
||||||
use askama::Template;
|
use askama::Template;
|
||||||
|
|
||||||
@@ -27,6 +28,7 @@ pub fn get_decider_template_for_cyclefold_decider(
|
|||||||
#[derive(Template, Default)]
|
#[derive(Template, Default)]
|
||||||
#[template(path = "nova_cyclefold_decider.askama.sol", ext = "sol")]
|
#[template(path = "nova_cyclefold_decider.askama.sol", ext = "sol")]
|
||||||
pub struct NovaCycleFoldDecider {
|
pub struct NovaCycleFoldDecider {
|
||||||
|
pp_hash: Fr, // public params hash
|
||||||
groth16_verifier: Groth16Verifier,
|
groth16_verifier: Groth16Verifier,
|
||||||
kzg10_verifier: KZG10Verifier,
|
kzg10_verifier: KZG10Verifier,
|
||||||
// z_len denotes the FCircuit state (z_i) length
|
// z_len denotes the FCircuit state (z_i) length
|
||||||
@@ -42,6 +44,7 @@ impl From<NovaCycleFoldVerifierKey> for NovaCycleFoldDecider {
|
|||||||
let public_inputs_len = groth16_verifier.gamma_abc_len;
|
let public_inputs_len = groth16_verifier.gamma_abc_len;
|
||||||
let bits_per_limb = NonNativeUintVar::<Fq>::bits_per_limb();
|
let bits_per_limb = NonNativeUintVar::<Fq>::bits_per_limb();
|
||||||
Self {
|
Self {
|
||||||
|
pp_hash: value.pp_hash,
|
||||||
groth16_verifier,
|
groth16_verifier,
|
||||||
kzg10_verifier: KZG10Verifier::from(value.kzg_vk),
|
kzg10_verifier: KZG10Verifier::from(value.kzg_vk),
|
||||||
z_len: value.z_len,
|
z_len: value.z_len,
|
||||||
@@ -54,6 +57,7 @@ impl From<NovaCycleFoldVerifierKey> for NovaCycleFoldDecider {
|
|||||||
|
|
||||||
#[derive(CanonicalDeserialize, CanonicalSerialize, PartialEq, Debug, Clone)]
|
#[derive(CanonicalDeserialize, CanonicalSerialize, PartialEq, Debug, Clone)]
|
||||||
pub struct NovaCycleFoldVerifierKey {
|
pub struct NovaCycleFoldVerifierKey {
|
||||||
|
pp_hash: Fr,
|
||||||
g16_vk: Groth16VerifierKey,
|
g16_vk: Groth16VerifierKey,
|
||||||
kzg_vk: KZG10VerifierKey,
|
kzg_vk: KZG10VerifierKey,
|
||||||
z_len: usize,
|
z_len: usize,
|
||||||
@@ -73,25 +77,37 @@ impl ProtocolVerifierKey for NovaCycleFoldVerifierKey {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<(Groth16VerifierKey, KZG10VerifierKey, usize)> for NovaCycleFoldVerifierKey {
|
impl From<(Fr, Groth16VerifierKey, KZG10VerifierKey, usize)> for NovaCycleFoldVerifierKey {
|
||||||
fn from(value: (Groth16VerifierKey, KZG10VerifierKey, usize)) -> Self {
|
fn from(value: (Fr, Groth16VerifierKey, KZG10VerifierKey, usize)) -> Self {
|
||||||
Self {
|
Self {
|
||||||
g16_vk: value.0,
|
pp_hash: value.0,
|
||||||
kzg_vk: value.1,
|
g16_vk: value.1,
|
||||||
z_len: value.2,
|
kzg_vk: value.2,
|
||||||
|
z_len: value.3,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// implements From assuming that the 'batchCheck' method from the KZG10 template will not be used
|
// implements From assuming that the 'batchCheck' method from the KZG10 template will not be used
|
||||||
// in the NovaCycleFoldDecider verifier contract
|
// in the NovaCycleFoldDecider verifier contract
|
||||||
impl From<((VerifyingKey<Bn254>, VerifierKey<Bn254>), usize)> for NovaCycleFoldVerifierKey {
|
impl
|
||||||
fn from(value: ((VerifyingKey<Bn254>, VerifierKey<Bn254>), usize)) -> Self {
|
From<(
|
||||||
|
(Fr, ArkG16VerifierKey<Bn254>, ArkKZG10VerifierKey<Bn254>),
|
||||||
|
usize,
|
||||||
|
)> for NovaCycleFoldVerifierKey
|
||||||
|
{
|
||||||
|
fn from(
|
||||||
|
value: (
|
||||||
|
(Fr, ArkG16VerifierKey<Bn254>, ArkKZG10VerifierKey<Bn254>),
|
||||||
|
usize,
|
||||||
|
),
|
||||||
|
) -> Self {
|
||||||
let decider_vp = value.0;
|
let decider_vp = value.0;
|
||||||
let g16_vk = Groth16VerifierKey::from(decider_vp.0);
|
let g16_vk = Groth16VerifierKey::from(decider_vp.1);
|
||||||
// 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.1, Vec::new()));
|
let kzg_vk = KZG10VerifierKey::from((decider_vp.2, Vec::new()));
|
||||||
Self {
|
Self {
|
||||||
|
pp_hash: decider_vp.0,
|
||||||
g16_vk,
|
g16_vk,
|
||||||
kzg_vk,
|
kzg_vk,
|
||||||
z_len: value.1,
|
z_len: value.1,
|
||||||
@@ -101,12 +117,14 @@ impl From<((VerifyingKey<Bn254>, VerifierKey<Bn254>), usize)> for NovaCycleFoldV
|
|||||||
|
|
||||||
impl NovaCycleFoldVerifierKey {
|
impl NovaCycleFoldVerifierKey {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
vkey_g16: VerifyingKey<Bn254>,
|
pp_hash: Fr,
|
||||||
vkey_kzg: VerifierKey<Bn254>,
|
vkey_g16: ArkG16VerifierKey<Bn254>,
|
||||||
|
vkey_kzg: ArkKZG10VerifierKey<Bn254>,
|
||||||
crs_points: Vec<G1Affine>,
|
crs_points: Vec<G1Affine>,
|
||||||
z_len: usize,
|
z_len: usize,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
pp_hash,
|
||||||
g16_vk: Groth16VerifierKey::from(vkey_g16),
|
g16_vk: Groth16VerifierKey::from(vkey_g16),
|
||||||
kzg_vk: KZG10VerifierKey::from((vkey_kzg, crs_points)),
|
kzg_vk: KZG10VerifierKey::from((vkey_kzg, crs_points)),
|
||||||
z_len,
|
z_len,
|
||||||
@@ -117,12 +135,9 @@ impl NovaCycleFoldVerifierKey {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1};
|
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1};
|
||||||
use ark_crypto_primitives::snark::SNARK;
|
|
||||||
use ark_ff::PrimeField;
|
use ark_ff::PrimeField;
|
||||||
use ark_groth16::VerifyingKey as G16VerifierKey;
|
use ark_groth16::Groth16;
|
||||||
use ark_groth16::{Groth16, ProvingKey};
|
|
||||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2};
|
use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2};
|
||||||
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
|
|
||||||
use ark_r1cs_std::alloc::AllocVar;
|
use ark_r1cs_std::alloc::AllocVar;
|
||||||
use ark_r1cs_std::fields::fp::FpVar;
|
use ark_r1cs_std::fields::fp::FpVar;
|
||||||
use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
|
use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError};
|
||||||
@@ -132,15 +147,10 @@ mod tests {
|
|||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use folding_schemes::{
|
use folding_schemes::{
|
||||||
commitment::{
|
commitment::{kzg::KZG, pedersen::Pedersen},
|
||||||
kzg::{ProverKey as KZGProverKey, KZG},
|
|
||||||
pedersen::Pedersen,
|
|
||||||
CommitmentScheme,
|
|
||||||
},
|
|
||||||
folding::nova::{
|
folding::nova::{
|
||||||
decider_eth::{prepare_calldata, Decider as DeciderEth},
|
decider_eth::{prepare_calldata, Decider as DeciderEth},
|
||||||
decider_eth_circuit::DeciderEthCircuit,
|
Nova, PreprocessorParam,
|
||||||
get_cs_params_len, Nova, ProverParams,
|
|
||||||
},
|
},
|
||||||
frontend::FCircuit,
|
frontend::FCircuit,
|
||||||
transcript::poseidon::poseidon_canonical_config,
|
transcript::poseidon::poseidon_canonical_config,
|
||||||
@@ -156,6 +166,24 @@ mod tests {
|
|||||||
NovaCycleFoldVerifierKey, ProtocolVerifierKey,
|
NovaCycleFoldVerifierKey, ProtocolVerifierKey,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type NOVA<FC> = Nova<G1, GVar, G2, GVar2, FC, KZG<'static, Bn254>, Pedersen<G2>>;
|
||||||
|
type DECIDER<FC> = DeciderEth<
|
||||||
|
G1,
|
||||||
|
GVar,
|
||||||
|
G2,
|
||||||
|
GVar2,
|
||||||
|
FC,
|
||||||
|
KZG<'static, Bn254>,
|
||||||
|
Pedersen<G2>,
|
||||||
|
Groth16<Bn254>,
|
||||||
|
NOVA<FC>,
|
||||||
|
>;
|
||||||
|
|
||||||
|
type FS_PP<FC> = <NOVA<FC> as FoldingScheme<G1, G2, FC>>::ProverParam;
|
||||||
|
type FS_VP<FC> = <NOVA<FC> as FoldingScheme<G1, G2, FC>>::VerifierParam;
|
||||||
|
type DECIDER_PP<FC> = <DECIDER<FC> as Decider<G1, G2, FC, NOVA<FC>>>::ProverParam;
|
||||||
|
type DECIDER_VP<FC> = <DECIDER<FC> as Decider<G1, G2, FC, NOVA<FC>>>::VerifierParam;
|
||||||
|
|
||||||
/// Test circuit to be folded
|
/// Test circuit to be folded
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct CubicFCircuit<F: PrimeField> {
|
pub struct CubicFCircuit<F: PrimeField> {
|
||||||
@@ -256,10 +284,10 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nova_cyclefold_vk_serde_roundtrip() {
|
fn nova_cyclefold_vk_serde_roundtrip() {
|
||||||
let (_, kzg_vk, _, g16_vk, _) = setup(DEFAULT_SETUP_LEN);
|
let (pp_hash, _, kzg_vk, _, g16_vk, _) = setup(DEFAULT_SETUP_LEN);
|
||||||
|
|
||||||
let mut bytes = vec![];
|
let mut bytes = vec![];
|
||||||
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from(((g16_vk, kzg_vk), 1));
|
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from(((pp_hash, g16_vk, kzg_vk), 1));
|
||||||
|
|
||||||
nova_cyclefold_vk
|
nova_cyclefold_vk
|
||||||
.serialize_protocol_verifier_key(&mut bytes)
|
.serialize_protocol_verifier_key(&mut bytes)
|
||||||
@@ -272,8 +300,8 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nova_cyclefold_decider_template_renders() {
|
fn nova_cyclefold_decider_template_renders() {
|
||||||
let (_, 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(((g16_vk, kzg_vk), 1));
|
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from(((pp_hash, g16_vk, kzg_vk), 1));
|
||||||
|
|
||||||
let decider_solidity_code = HeaderInclusion::<NovaCycleFoldDecider>::builder()
|
let decider_solidity_code = HeaderInclusion::<NovaCycleFoldDecider>::builder()
|
||||||
.template(nova_cyclefold_vk)
|
.template(nova_cyclefold_vk)
|
||||||
@@ -282,59 +310,29 @@ mod tests {
|
|||||||
save_solidity("NovaDecider.sol", &decider_solidity_code.render().unwrap());
|
save_solidity("NovaDecider.sol", &decider_solidity_code.render().unwrap());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(clippy::type_complexity)]
|
|
||||||
fn init_test_prover_params<FC: FCircuit<Fr, Params = ()>>() -> (
|
|
||||||
ProverParams<G1, G2, KZG<'static, Bn254>, Pedersen<G2>>,
|
|
||||||
KZGVerifierKey<Bn254>,
|
|
||||||
) {
|
|
||||||
let mut rng = ark_std::test_rng();
|
|
||||||
let poseidon_config = poseidon_canonical_config::<Fr>();
|
|
||||||
let f_circuit = FC::new(()).unwrap();
|
|
||||||
let (cs_len, cf_cs_len) =
|
|
||||||
get_cs_params_len::<G1, GVar, G2, GVar2, FC>(&poseidon_config, f_circuit).unwrap();
|
|
||||||
let (kzg_pk, kzg_vk): (KZGProverKey<G1>, KZGVerifierKey<Bn254>) =
|
|
||||||
KZG::<Bn254>::setup(&mut rng, cs_len).unwrap();
|
|
||||||
let (cf_pedersen_params, _) = Pedersen::<G2>::setup(&mut rng, cf_cs_len).unwrap();
|
|
||||||
let fs_prover_params = ProverParams::<G1, G2, KZG<Bn254>, Pedersen<G2>> {
|
|
||||||
poseidon_config: poseidon_config.clone(),
|
|
||||||
cs_pp: kzg_pk.clone(),
|
|
||||||
cf_cs_pp: cf_pedersen_params,
|
|
||||||
};
|
|
||||||
(fs_prover_params, kzg_vk)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Initializes Nova parameters and DeciderEth parameters. Only for test purposes.
|
/// Initializes Nova parameters and DeciderEth parameters. Only for test purposes.
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn init_params<FC: FCircuit<Fr, Params = ()>>() -> (
|
fn init_params<FC: FCircuit<Fr, Params = ()>>(
|
||||||
ProverParams<G1, G2, KZG<'static, Bn254>, Pedersen<G2>>,
|
) -> ((FS_PP<FC>, FS_VP<FC>), (DECIDER_PP<FC>, DECIDER_VP<FC>)) {
|
||||||
KZGVerifierKey<Bn254>,
|
|
||||||
ProvingKey<Bn254>,
|
|
||||||
G16VerifierKey<Bn254>,
|
|
||||||
) {
|
|
||||||
let mut rng = rand::rngs::OsRng;
|
let mut rng = rand::rngs::OsRng;
|
||||||
let start = Instant::now();
|
let poseidon_config = poseidon_canonical_config::<Fr>();
|
||||||
let (fs_prover_params, kzg_vk) = init_test_prover_params::<FC>();
|
|
||||||
println!("generated Nova folding params: {:?}", start.elapsed());
|
|
||||||
let f_circuit = FC::new(()).unwrap();
|
let f_circuit = FC::new(()).unwrap();
|
||||||
|
let prep_param = PreprocessorParam::<G1, G2, FC, KZG<'static, Bn254>, Pedersen<G2>>::new(
|
||||||
pub type NOVA_FCircuit<FC> =
|
poseidon_config,
|
||||||
Nova<G1, GVar, G2, GVar2, FC, KZG<'static, Bn254>, Pedersen<G2>>;
|
f_circuit.clone(),
|
||||||
let z_0 = vec![Fr::zero(); f_circuit.state_len()];
|
|
||||||
let nova = NOVA_FCircuit::init(&fs_prover_params, f_circuit, z_0.clone()).unwrap();
|
|
||||||
|
|
||||||
let decider_circuit =
|
|
||||||
DeciderEthCircuit::<G1, GVar, G2, GVar2, KZG<Bn254>, Pedersen<G2>>::from_nova::<FC>(
|
|
||||||
nova.clone(),
|
|
||||||
)
|
|
||||||
.unwrap();
|
|
||||||
let start = Instant::now();
|
|
||||||
let (g16_pk, g16_vk) =
|
|
||||||
Groth16::<Bn254>::circuit_specific_setup(decider_circuit.clone(), &mut rng).unwrap();
|
|
||||||
println!(
|
|
||||||
"generated G16 (Decider circuit) params: {:?}",
|
|
||||||
start.elapsed()
|
|
||||||
);
|
);
|
||||||
(fs_prover_params, kzg_vk, g16_pk, g16_vk)
|
let nova_params = NOVA::preprocess(&mut rng, &prep_param).unwrap();
|
||||||
|
let nova = NOVA::init(
|
||||||
|
nova_params.clone(),
|
||||||
|
f_circuit.clone(),
|
||||||
|
vec![Fr::zero(); f_circuit.state_len()].clone(),
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let decider_params =
|
||||||
|
DECIDER::preprocess(&mut rng, &nova_params.clone(), nova.clone()).unwrap();
|
||||||
|
|
||||||
|
(nova_params, decider_params)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This function allows to define which FCircuit to use for the test, and how many prove_step
|
/// This function allows to define which FCircuit to use for the test, and how many prove_step
|
||||||
@@ -346,52 +344,31 @@ mod tests {
|
|||||||
/// - modifies the z_0 and checks that it does not pass the EVM check
|
/// - modifies the z_0 and checks that it does not pass the EVM check
|
||||||
#[allow(clippy::type_complexity)]
|
#[allow(clippy::type_complexity)]
|
||||||
fn nova_cyclefold_solidity_verifier_opt<FC: FCircuit<Fr, Params = ()>>(
|
fn nova_cyclefold_solidity_verifier_opt<FC: FCircuit<Fr, Params = ()>>(
|
||||||
params: (
|
fs_params: (FS_PP<FC>, FS_VP<FC>),
|
||||||
ProverParams<G1, G2, KZG<'static, Bn254>, Pedersen<G2>>,
|
decider_params: (DECIDER_PP<FC>, DECIDER_VP<FC>),
|
||||||
KZGVerifierKey<Bn254>,
|
|
||||||
ProvingKey<Bn254>,
|
|
||||||
G16VerifierKey<Bn254>,
|
|
||||||
),
|
|
||||||
z_0: Vec<Fr>,
|
z_0: Vec<Fr>,
|
||||||
n_steps: usize,
|
n_steps: usize,
|
||||||
) {
|
) {
|
||||||
let (fs_prover_params, kzg_vk, g16_pk, g16_vk) = params.clone();
|
let (decider_pp, decider_vp) = decider_params;
|
||||||
|
|
||||||
pub type NOVA_FCircuit<FC> =
|
|
||||||
Nova<G1, GVar, G2, GVar2, FC, KZG<'static, Bn254>, Pedersen<G2>>;
|
|
||||||
pub type DECIDERETH_FCircuit<FC> = DeciderEth<
|
|
||||||
G1,
|
|
||||||
GVar,
|
|
||||||
G2,
|
|
||||||
GVar2,
|
|
||||||
FC,
|
|
||||||
KZG<'static, Bn254>,
|
|
||||||
Pedersen<G2>,
|
|
||||||
Groth16<Bn254>,
|
|
||||||
NOVA_FCircuit<FC>,
|
|
||||||
>;
|
|
||||||
let f_circuit = FC::new(()).unwrap();
|
let f_circuit = FC::new(()).unwrap();
|
||||||
|
|
||||||
let nova_cyclefold_vk = NovaCycleFoldVerifierKey::from((
|
let nova_cyclefold_vk =
|
||||||
(g16_vk.clone(), kzg_vk.clone()),
|
NovaCycleFoldVerifierKey::from((decider_vp.clone(), f_circuit.state_len()));
|
||||||
f_circuit.state_len(),
|
|
||||||
));
|
|
||||||
|
|
||||||
let mut rng = rand::rngs::OsRng;
|
let mut rng = rand::rngs::OsRng;
|
||||||
|
|
||||||
let mut nova = NOVA_FCircuit::init(&fs_prover_params, f_circuit, z_0).unwrap();
|
let mut nova = NOVA::<FC>::init(fs_params, f_circuit, z_0).unwrap();
|
||||||
for _ in 0..n_steps {
|
for _ in 0..n_steps {
|
||||||
nova.prove_step(&mut rng, vec![]).unwrap();
|
nova.prove_step(&mut rng, vec![]).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
let start = Instant::now();
|
let start = Instant::now();
|
||||||
let proof =
|
let proof = DECIDER::<FC>::prove(rng, decider_pp, nova.clone()).unwrap();
|
||||||
DECIDERETH_FCircuit::prove(rng, (g16_pk, fs_prover_params.cs_pp.clone()), nova.clone())
|
|
||||||
.unwrap();
|
|
||||||
println!("generated Decider proof: {:?}", start.elapsed());
|
println!("generated Decider proof: {:?}", start.elapsed());
|
||||||
|
|
||||||
let verified = DECIDERETH_FCircuit::<FC>::verify(
|
let verified = DECIDER::<FC>::verify(
|
||||||
(g16_vk, kzg_vk),
|
decider_vp,
|
||||||
nova.i,
|
nova.i,
|
||||||
nova.z_0.clone(),
|
nova.z_0.clone(),
|
||||||
nova.z_i.clone(),
|
nova.z_i.clone(),
|
||||||
@@ -448,12 +425,22 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nova_cyclefold_solidity_verifier() {
|
fn nova_cyclefold_solidity_verifier() {
|
||||||
let params = init_params::<CubicFCircuit<Fr>>();
|
let (nova_params, decider_params) = init_params::<CubicFCircuit<Fr>>();
|
||||||
let z_0 = vec![Fr::from(3_u32)];
|
let z_0 = vec![Fr::from(3_u32)];
|
||||||
nova_cyclefold_solidity_verifier_opt::<CubicFCircuit<Fr>>(params.clone(), z_0.clone(), 2);
|
nova_cyclefold_solidity_verifier_opt::<CubicFCircuit<Fr>>(
|
||||||
nova_cyclefold_solidity_verifier_opt::<CubicFCircuit<Fr>>(params.clone(), z_0.clone(), 3);
|
nova_params.clone(),
|
||||||
|
decider_params.clone(),
|
||||||
|
z_0.clone(),
|
||||||
|
2,
|
||||||
|
);
|
||||||
|
nova_cyclefold_solidity_verifier_opt::<CubicFCircuit<Fr>>(
|
||||||
|
nova_params,
|
||||||
|
decider_params,
|
||||||
|
z_0,
|
||||||
|
3,
|
||||||
|
);
|
||||||
|
|
||||||
let params = init_params::<MultiInputsFCircuit<Fr>>();
|
let (nova_params, decider_params) = init_params::<MultiInputsFCircuit<Fr>>();
|
||||||
let z_0 = vec![
|
let z_0 = vec![
|
||||||
Fr::from(1_u32),
|
Fr::from(1_u32),
|
||||||
Fr::from(1_u32),
|
Fr::from(1_u32),
|
||||||
@@ -462,12 +449,14 @@ mod tests {
|
|||||||
Fr::from(1_u32),
|
Fr::from(1_u32),
|
||||||
];
|
];
|
||||||
nova_cyclefold_solidity_verifier_opt::<MultiInputsFCircuit<Fr>>(
|
nova_cyclefold_solidity_verifier_opt::<MultiInputsFCircuit<Fr>>(
|
||||||
params.clone(),
|
nova_params.clone(),
|
||||||
|
decider_params.clone(),
|
||||||
z_0.clone(),
|
z_0.clone(),
|
||||||
2,
|
2,
|
||||||
);
|
);
|
||||||
nova_cyclefold_solidity_verifier_opt::<MultiInputsFCircuit<Fr>>(
|
nova_cyclefold_solidity_verifier_opt::<MultiInputsFCircuit<Fr>>(
|
||||||
params.clone(),
|
nova_params,
|
||||||
|
decider_params,
|
||||||
z_0.clone(),
|
z_0.clone(),
|
||||||
3,
|
3,
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -78,10 +78,11 @@ contract NovaDecider is Groth16Verifier, KZG10Verifier {
|
|||||||
// from gamma_abc_len, we subtract 1.
|
// from gamma_abc_len, we subtract 1.
|
||||||
uint256[{{ public_inputs_len - 1 }}] memory public_inputs;
|
uint256[{{ public_inputs_len - 1 }}] memory public_inputs;
|
||||||
|
|
||||||
public_inputs[0] = i_z0_zi[0];
|
public_inputs[0] = {{pp_hash}};
|
||||||
|
public_inputs[1] = i_z0_zi[0];
|
||||||
|
|
||||||
for (uint i = 0; i < {{ z_len * 2 }}; i++) {
|
for (uint i = 0; i < {{ z_len * 2 }}; i++) {
|
||||||
public_inputs[1 + i] = i_z0_zi[1 + i];
|
public_inputs[2 + i] = i_z0_zi[1 + i];
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -91,9 +92,9 @@ contract NovaDecider is Groth16Verifier, KZG10Verifier {
|
|||||||
uint256 x0 = rlc(U_i_x_u_i_cmW[0], U_i_u_u_i_u_r[2], u_i_x_cmT[0]);
|
uint256 x0 = rlc(U_i_x_u_i_cmW[0], U_i_u_u_i_u_r[2], u_i_x_cmT[0]);
|
||||||
uint256 x1 = rlc(U_i_x_u_i_cmW[1], U_i_u_u_i_u_r[2], u_i_x_cmT[1]);
|
uint256 x1 = rlc(U_i_x_u_i_cmW[1], U_i_u_u_i_u_r[2], u_i_x_cmT[1]);
|
||||||
|
|
||||||
public_inputs[{{ z_len * 2 + 1 }}] = u;
|
public_inputs[{{ z_len * 2 + 2 }}] = u;
|
||||||
public_inputs[{{ z_len * 2 + 2 }}] = x0;
|
public_inputs[{{ z_len * 2 + 3 }}] = x0;
|
||||||
public_inputs[{{ z_len * 2 + 3 }}] = x1;
|
public_inputs[{{ z_len * 2 + 4 }}] = x1;
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -106,8 +107,8 @@ contract NovaDecider is Groth16Verifier, KZG10Verifier {
|
|||||||
uint256[{{num_limbs}}] memory cmE_y_limbs = LimbsDecomposition.decompose(cmE[1]);
|
uint256[{{num_limbs}}] memory cmE_y_limbs = LimbsDecomposition.decompose(cmE[1]);
|
||||||
|
|
||||||
for (uint8 k = 0; k < {{num_limbs}}; k++) {
|
for (uint8 k = 0; k < {{num_limbs}}; k++) {
|
||||||
public_inputs[{{ z_len * 2 + 4 }} + k] = cmE_x_limbs[k];
|
public_inputs[{{ z_len * 2 + 5 }} + k] = cmE_x_limbs[k];
|
||||||
public_inputs[{{ z_len * 2 + 4 + num_limbs }} + k] = cmE_y_limbs[k];
|
public_inputs[{{ z_len * 2 + 5 + num_limbs }} + k] = cmE_y_limbs[k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -124,8 +125,8 @@ contract NovaDecider is Groth16Verifier, KZG10Verifier {
|
|||||||
uint256[{{num_limbs}}] memory cmW_y_limbs = LimbsDecomposition.decompose(cmW[1]);
|
uint256[{{num_limbs}}] memory cmW_y_limbs = LimbsDecomposition.decompose(cmW[1]);
|
||||||
|
|
||||||
for (uint8 k = 0; k < {{num_limbs}}; k++) {
|
for (uint8 k = 0; k < {{num_limbs}}; k++) {
|
||||||
public_inputs[{{ z_len * 2 + 4 + num_limbs * 2 }} + k] = cmW_x_limbs[k];
|
public_inputs[{{ z_len * 2 + 5 + num_limbs * 2 }} + k] = cmW_x_limbs[k];
|
||||||
public_inputs[{{ z_len * 2 + 4 + num_limbs * 3 }} + k] = cmW_y_limbs[k];
|
public_inputs[{{ z_len * 2 + 5 + num_limbs * 3 }} + k] = cmW_y_limbs[k];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,10 +135,10 @@ contract NovaDecider is Groth16Verifier, KZG10Verifier {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// add challenges
|
// add challenges
|
||||||
public_inputs[{{ z_len * 2 + 4 + num_limbs * 4 }}] = challenge_W_challenge_E_kzg_evals[0];
|
public_inputs[{{ z_len * 2 + 5 + num_limbs * 4 }}] = challenge_W_challenge_E_kzg_evals[0];
|
||||||
public_inputs[{{ z_len * 2 + 4 + num_limbs * 4 + 1 }}] = challenge_W_challenge_E_kzg_evals[1];
|
public_inputs[{{ z_len * 2 + 5 + num_limbs * 4 + 1 }}] = challenge_W_challenge_E_kzg_evals[1];
|
||||||
public_inputs[{{ z_len * 2 + 4 + num_limbs * 4 + 2 }}] = challenge_W_challenge_E_kzg_evals[2];
|
public_inputs[{{ z_len * 2 + 5 + num_limbs * 4 + 2 }}] = challenge_W_challenge_E_kzg_evals[2];
|
||||||
public_inputs[{{ z_len * 2 + 4 + num_limbs * 4 + 3 }}] = challenge_W_challenge_E_kzg_evals[3];
|
public_inputs[{{ z_len * 2 + 5 + num_limbs * 4 + 3 }}] = challenge_W_challenge_E_kzg_evals[3];
|
||||||
|
|
||||||
uint256[{{num_limbs}}] memory cmT_x_limbs;
|
uint256[{{num_limbs}}] memory cmT_x_limbs;
|
||||||
uint256[{{num_limbs}}] memory cmT_y_limbs;
|
uint256[{{num_limbs}}] memory cmT_y_limbs;
|
||||||
@@ -146,8 +147,8 @@ contract NovaDecider is Groth16Verifier, KZG10Verifier {
|
|||||||
cmT_y_limbs = LimbsDecomposition.decompose(u_i_x_cmT[3]);
|
cmT_y_limbs = LimbsDecomposition.decompose(u_i_x_cmT[3]);
|
||||||
|
|
||||||
for (uint8 k = 0; k < {{num_limbs}}; k++) {
|
for (uint8 k = 0; k < {{num_limbs}}; k++) {
|
||||||
public_inputs[{{ z_len * 2 + 4 + num_limbs * 4 }} + 4 + k] = cmT_x_limbs[k];
|
public_inputs[{{ z_len * 2 + 5 + num_limbs * 4 }} + 4 + k] = cmT_x_limbs[k];
|
||||||
public_inputs[{{ z_len * 2 + 4 + num_limbs * 5}} + 4 + k] = cmT_y_limbs[k];
|
public_inputs[{{ z_len * 2 + 5 + num_limbs * 5}} + 4 + k] = cmT_y_limbs[k];
|
||||||
}
|
}
|
||||||
|
|
||||||
// last element of the groth16 proof's public inputs is `r`
|
// last element of the groth16 proof's public inputs is `r`
|
||||||
|
|||||||
Reference in New Issue
Block a user