mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-11 16:31:32 +01:00
Compute Decider's CM challenges in Groth16 circuit, link G16 & KZG proofs in Onchain Decider, refactor CommitmentScheme trait (#79)
* Compute Decider's CM challenges in Groth16 circuit, link G16 & KZG proofs in Onchain Decider, refactor CommitmentScheme trait - Refactor commitment package - Refactor `Commitment` trait and the kzg, ipa, pedersen impls - Add methods to prove & verify given challenges (not computing them in-method) - Add KZG challenges computation in decider_eth_circuit - Add cmE & cmW KZG proving & verification in DeciderEth - Link Decider's Groth16 proof & KZG proofs data - Fix point to bytes arkworks inconsistency - Patch ark_curves to use a cherry-picked version with bn254::constraints & grumpkin for v0.4.0 (once arkworks v0.5.0 is released this will no longer be needed) * DeciderEthCircuit: Add check eval=p(c) for E & W The check is temporary disabled due https://github.com/privacy-scaling-explorations/folding-schemes/issues/80, but the public inputs and logic are there, to be able to continue the other parts development while issue #80 is solved.
This commit is contained in:
@@ -11,7 +11,7 @@ use super::utils::compute_sum_Mz;
|
||||
use crate::ccs::CCS;
|
||||
use crate::commitment::{
|
||||
pedersen::{Params as PedersenParams, Pedersen},
|
||||
CommitmentProver,
|
||||
CommitmentScheme,
|
||||
};
|
||||
use crate::utils::hypercube::BooleanHypercube;
|
||||
use crate::utils::mle::matrix_to_mle;
|
||||
@@ -44,7 +44,7 @@ impl<C: CurveGroup> CCS<C> {
|
||||
) -> Result<(CCCS<C>, Witness<C::ScalarField>), Error> {
|
||||
let w: Vec<C::ScalarField> = z[(1 + self.l)..].to_vec();
|
||||
let r_w = C::ScalarField::rand(rng);
|
||||
let C = Pedersen::<C>::commit(pedersen_params, &w, &r_w)?;
|
||||
let C = Pedersen::<C, true>::commit(pedersen_params, &w, &r_w)?;
|
||||
|
||||
Ok((
|
||||
CCCS::<C> {
|
||||
@@ -112,7 +112,7 @@ impl<C: CurveGroup> CCCS<C> {
|
||||
) -> Result<(), Error> {
|
||||
// check that C is the commitment of w. Notice that this is not verifying a Pedersen
|
||||
// opening, but checking that the commitment comes from committing to the witness.
|
||||
if self.C != Pedersen::<C>::commit(pedersen_params, &w.w, &w.r_w)? {
|
||||
if self.C != Pedersen::<C, true>::commit(pedersen_params, &w.w, &w.r_w)? {
|
||||
return Err(Error::NotSatisfied);
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ mod tests {
|
||||
tests::{get_test_ccs, get_test_z},
|
||||
CCS,
|
||||
},
|
||||
commitment::pedersen::Pedersen,
|
||||
commitment::{pedersen::Pedersen, CommitmentScheme},
|
||||
folding::hypernova::utils::{
|
||||
compute_c_from_sigmas_and_thetas, compute_sigmas_and_thetas, sum_ci_mul_prod_thetaj,
|
||||
sum_muls_gamma_pows_eq_sigma,
|
||||
@@ -180,7 +180,8 @@ mod tests {
|
||||
let r_x_prime: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();
|
||||
|
||||
// Initialize a multifolding object
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
|
||||
let sigmas_thetas =
|
||||
compute_sigmas_and_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime);
|
||||
@@ -224,7 +225,8 @@ mod tests {
|
||||
let r_x_prime: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();
|
||||
|
||||
// Initialize a multifolding object
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
|
||||
let sigmas_thetas =
|
||||
compute_sigmas_and_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime);
|
||||
@@ -267,7 +269,8 @@ mod tests {
|
||||
let r_x_prime: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();
|
||||
|
||||
// Initialize a multifolding object
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
|
||||
let sigmas_thetas =
|
||||
compute_sigmas_and_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime);
|
||||
|
||||
@@ -10,7 +10,7 @@ use super::utils::{compute_all_sum_Mz_evals, compute_sum_Mz};
|
||||
use crate::ccs::CCS;
|
||||
use crate::commitment::{
|
||||
pedersen::{Params as PedersenParams, Pedersen},
|
||||
CommitmentProver,
|
||||
CommitmentScheme,
|
||||
};
|
||||
use crate::utils::mle::{matrix_to_mle, vec_to_mle};
|
||||
use crate::utils::virtual_polynomial::VirtualPolynomial;
|
||||
@@ -46,7 +46,7 @@ impl<C: CurveGroup> CCS<C> {
|
||||
) -> Result<(LCCCS<C>, Witness<C::ScalarField>), Error> {
|
||||
let w: Vec<C::ScalarField> = z[(1 + self.l)..].to_vec();
|
||||
let r_w = C::ScalarField::rand(rng);
|
||||
let C = Pedersen::<C>::commit(pedersen_params, &w, &r_w)?;
|
||||
let C = Pedersen::<C, true>::commit(pedersen_params, &w, &r_w)?;
|
||||
|
||||
let r_x: Vec<C::ScalarField> = (0..self.s).map(|_| C::ScalarField::rand(rng)).collect();
|
||||
let v = self.compute_v_j(z, &r_x);
|
||||
@@ -97,7 +97,7 @@ impl<C: CurveGroup> LCCCS<C> {
|
||||
) -> Result<(), Error> {
|
||||
// check that C is the commitment of w. Notice that this is not verifying a Pedersen
|
||||
// opening, but checking that the Commitment comes from committing to the witness.
|
||||
if self.C != Pedersen::<C>::commit(pedersen_params, &w.w, &w.r_w)? {
|
||||
if self.C != Pedersen::<C, true>::commit(pedersen_params, &w.w, &w.r_w)? {
|
||||
return Err(Error::NotSatisfied);
|
||||
}
|
||||
|
||||
@@ -131,7 +131,8 @@ pub mod tests {
|
||||
let z = get_test_z(3);
|
||||
ccs.check_relation(&z.clone()).unwrap();
|
||||
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
let (lcccs, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z).unwrap();
|
||||
// with our test vector coming from R1CS, v should have length 3
|
||||
assert_eq!(lcccs.v.len(), 3);
|
||||
@@ -161,7 +162,8 @@ pub mod tests {
|
||||
bad_z[3] = Fr::zero();
|
||||
assert!(ccs.check_relation(&bad_z.clone()).is_err());
|
||||
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
// Compute v_j with the right z
|
||||
let (lcccs, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z).unwrap();
|
||||
// with our test vector coming from R1CS, v should have length 3
|
||||
|
||||
@@ -378,7 +378,7 @@ pub mod tests {
|
||||
use ark_std::test_rng;
|
||||
use ark_std::UniformRand;
|
||||
|
||||
use crate::commitment::pedersen::Pedersen;
|
||||
use crate::commitment::{pedersen::Pedersen, CommitmentScheme};
|
||||
use ark_pallas::{Fr, Projective};
|
||||
|
||||
#[test]
|
||||
@@ -395,7 +395,8 @@ pub mod tests {
|
||||
let sigmas_thetas =
|
||||
compute_sigmas_and_thetas(&ccs, &[z1.clone()], &[z2.clone()], &r_x_prime);
|
||||
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
|
||||
let (lcccs, w1) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
|
||||
let (cccs, w2) = ccs.to_cccs(&mut rng, &pedersen_params, &z2).unwrap();
|
||||
@@ -430,7 +431,8 @@ pub mod tests {
|
||||
|
||||
// Create a basic CCS circuit
|
||||
let ccs = get_test_ccs::<Projective>();
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
|
||||
// Generate a satisfying witness
|
||||
let z_1 = get_test_z(3);
|
||||
@@ -489,7 +491,8 @@ pub mod tests {
|
||||
|
||||
let ccs = get_test_ccs::<Projective>();
|
||||
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
|
||||
// LCCCS witness
|
||||
let z_1 = get_test_z(2);
|
||||
@@ -557,7 +560,8 @@ pub mod tests {
|
||||
|
||||
// Create a basic CCS circuit
|
||||
let ccs = get_test_ccs::<Projective>();
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
|
||||
let mu = 10;
|
||||
let nu = 15;
|
||||
@@ -639,7 +643,8 @@ pub mod tests {
|
||||
|
||||
// Create a basic CCS circuit
|
||||
let ccs = get_test_ccs::<Projective>();
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
|
||||
let poseidon_config = poseidon_test_config::<Fr>();
|
||||
// Prover's transcript
|
||||
|
||||
@@ -199,7 +199,7 @@ pub mod tests {
|
||||
use ark_std::Zero;
|
||||
|
||||
use crate::ccs::tests::{get_test_ccs, get_test_z};
|
||||
use crate::commitment::pedersen::Pedersen;
|
||||
use crate::commitment::{pedersen::Pedersen, CommitmentScheme};
|
||||
use crate::utils::multilinear_polynomial::tests::fix_last_variables;
|
||||
use crate::utils::virtual_polynomial::eq_eval;
|
||||
|
||||
@@ -290,7 +290,8 @@ pub mod tests {
|
||||
let r_x_prime: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();
|
||||
|
||||
// Initialize a multifolding object
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
|
||||
|
||||
let sigmas_thetas =
|
||||
@@ -333,7 +334,8 @@ pub mod tests {
|
||||
let beta: Vec<Fr> = (0..ccs.s).map(|_| Fr::rand(&mut rng)).collect();
|
||||
|
||||
// Initialize a multifolding object
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, ccs.n - ccs.l - 1);
|
||||
let (pedersen_params, _) =
|
||||
Pedersen::<Projective>::setup(&mut rng, ccs.n - ccs.l - 1).unwrap();
|
||||
let (lcccs_instance, _) = ccs.to_lcccs(&mut rng, &pedersen_params, &z1).unwrap();
|
||||
|
||||
let mut sum_v_j_gamma = Fr::zero();
|
||||
|
||||
@@ -509,8 +509,8 @@ where
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use ark_bn254::{Fr, G1Projective as Projective};
|
||||
use ark_ff::BigInteger;
|
||||
use ark_pallas::{Fr, Projective};
|
||||
use ark_r1cs_std::{alloc::AllocVar, R1CSVar};
|
||||
use ark_relations::r1cs::ConstraintSystem;
|
||||
use ark_std::UniformRand;
|
||||
|
||||
@@ -175,7 +175,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// ChallengeGadget computes the RO challenge used for the CycleFold instances NIFS, it contains a
|
||||
/// CycleFoldChallengeGadget computes the RO challenge used for the CycleFold instances NIFS, it contains a
|
||||
/// rust-native and a in-circuit compatible versions.
|
||||
pub struct CycleFoldChallengeGadget<C: CurveGroup, GC: CurveVar<C, CF2<C>>> {
|
||||
_c: PhantomData<C>, // Nova's Curve2, the one used for the CycleFold circuit
|
||||
@@ -252,19 +252,15 @@ where
|
||||
.collect::<Vec<UInt8<CF2<C>>>>();
|
||||
|
||||
let input: Vec<UInt8<CF2<C>>> = [
|
||||
U_i.cmE.to_bytes()?,
|
||||
pointvar_to_bytes(U_i.cmE)?,
|
||||
U_i.u.to_bytes()?,
|
||||
U_i.cmW.to_bytes()?,
|
||||
pointvar_to_bytes(U_i.cmW)?,
|
||||
U_i_x_bytes,
|
||||
u_i.cmE.to_bytes()?,
|
||||
pointvar_to_bytes(u_i.cmE)?,
|
||||
u_i.u.to_bytes()?,
|
||||
u_i.cmW.to_bytes()?,
|
||||
pointvar_to_bytes(u_i.cmW)?,
|
||||
u_i_x_bytes,
|
||||
cmT.to_bytes()?,
|
||||
// TODO instead of bytes, use field elements, but needs x,y coordinates from
|
||||
// u_i.{cmE,cmW}, U_i.{cmE,cmW}, cmT. Depends exposing x,y coordinates of GC. Issue to
|
||||
// keep track of this:
|
||||
// https://github.com/privacy-scaling-explorations/folding-schemes/issues/44
|
||||
pointvar_to_bytes(cmT)?,
|
||||
]
|
||||
.concat();
|
||||
sponge.absorb(&input)?;
|
||||
@@ -273,17 +269,26 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// returns the bytes being compatible with the ark_r1cs_std `.to_bytes` approach
|
||||
/// returns the bytes being compatible with the pointvar_to_bytes method.
|
||||
/// These methods are temporary once arkworks has the fix to prevent different to_bytes behaviour
|
||||
/// across different curves. Eg, in pasta and bn254: pasta returns 65 bytes both native and gadget,
|
||||
/// whereas bn254 returns 64 bytes native and 65 in gadget, also the penultimate byte is different
|
||||
/// natively than in gadget.
|
||||
fn point_to_bytes<C: CurveGroup>(p: C) -> Result<Vec<u8>, Error> {
|
||||
let l = p.uncompressed_size();
|
||||
let mut b = Vec::new();
|
||||
p.serialize_uncompressed(&mut b)?;
|
||||
b[l - 1] = 0;
|
||||
if p.is_zero() {
|
||||
b[l / 2] = 1;
|
||||
b[l - 1] = 1;
|
||||
}
|
||||
Ok(b)
|
||||
Ok(b[..63].to_vec())
|
||||
}
|
||||
fn pointvar_to_bytes<C: CurveGroup, GC: CurveVar<C, CF2<C>>>(
|
||||
p: GC,
|
||||
) -> Result<Vec<UInt8<CF2<C>>>, SynthesisError> {
|
||||
let b = p.to_bytes()?;
|
||||
Ok(b[..63].to_vec())
|
||||
}
|
||||
|
||||
/// CycleFoldCircuit contains the constraints that check the correct fold of the committed
|
||||
@@ -350,8 +355,8 @@ where
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use ark_bn254::{constraints::GVar, Fq, Fr, G1Projective as Projective};
|
||||
use ark_ff::BigInteger;
|
||||
use ark_pallas::{constraints::GVar, Fq, Fr, Projective};
|
||||
use ark_r1cs_std::{alloc::AllocVar, R1CSVar};
|
||||
use ark_relations::r1cs::ConstraintSystem;
|
||||
use ark_std::UniformRand;
|
||||
@@ -468,6 +473,21 @@ pub mod tests {
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_point_bytes() {
|
||||
let mut rng = ark_std::test_rng();
|
||||
|
||||
let p = Projective::rand(&mut rng);
|
||||
let p_bytes = point_to_bytes(p).unwrap();
|
||||
|
||||
let cs = ConstraintSystem::<Fq>::new_ref();
|
||||
let pVar = GVar::new_witness(cs.clone(), || Ok(p)).unwrap();
|
||||
assert_eq!(pVar.value().unwrap(), p);
|
||||
|
||||
let p_bytesVar = &pointvar_to_bytes(pVar).unwrap();
|
||||
assert_eq!(p_bytesVar.value().unwrap(), p_bytes);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cyclefold_challenge_gadget() {
|
||||
let mut rng = ark_std::test_rng();
|
||||
|
||||
@@ -1,47 +1,76 @@
|
||||
/// This file implements the onchain (Ethereum's EVM) decider.
|
||||
use ark_crypto_primitives::sponge::Absorb;
|
||||
use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb};
|
||||
use ark_ec::{CurveGroup, Group};
|
||||
use ark_ff::PrimeField;
|
||||
use ark_ff::{BigInteger, PrimeField};
|
||||
use ark_r1cs_std::fields::nonnative::params::OptimizationType;
|
||||
use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar};
|
||||
use ark_snark::SNARK;
|
||||
use ark_std::rand::CryptoRng;
|
||||
use ark_std::rand::RngCore;
|
||||
use ark_std::rand::{CryptoRng, RngCore};
|
||||
use ark_std::Zero;
|
||||
use core::marker::PhantomData;
|
||||
|
||||
pub use super::decider_eth_circuit::DeciderEthCircuit;
|
||||
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentProver};
|
||||
pub use super::decider_eth_circuit::{DeciderEthCircuit, KZGChallengesGadget};
|
||||
use super::{
|
||||
circuits::{ChallengeGadget, CF2},
|
||||
nifs::NIFS,
|
||||
CommittedInstance, Nova, Witness,
|
||||
};
|
||||
use crate::commitment::{
|
||||
kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme,
|
||||
};
|
||||
use crate::folding::circuits::nonnative::point_to_nonnative_limbs_custom_opt;
|
||||
use crate::folding::nova::{circuits::CF2, CommittedInstance, Nova};
|
||||
use crate::frontend::FCircuit;
|
||||
use crate::Error;
|
||||
use crate::{Decider as DeciderTrait, FoldingScheme};
|
||||
use ark_r1cs_std::fields::nonnative::params::OptimizationType;
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||
pub struct Proof<C1, CS1, S>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
CS1: CommitmentScheme<C1, ProverChallenge = C1::ScalarField, Challenge = C1::ScalarField>,
|
||||
S: SNARK<C1::ScalarField>,
|
||||
{
|
||||
snark_proof: S::Proof,
|
||||
kzg_proofs: [CS1::Proof; 2],
|
||||
// cmT and r are values for the last fold, U_{i+1}=NIFS.V(r, U_i, u_i, cmT), and they are
|
||||
// checked in-circuit
|
||||
cmT: C1,
|
||||
r: C1::ScalarField,
|
||||
// the KZG challenges are provided by the prover, but in-circuit they are checked to match
|
||||
// the in-circuit computed computed ones.
|
||||
kzg_challenges: [C1::ScalarField; 2],
|
||||
}
|
||||
|
||||
/// Onchain Decider, for ethereum use cases
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Decider<C1, GC1, C2, GC2, FC, CP1, CP2, S, FS> {
|
||||
pub struct Decider<C1, GC1, C2, GC2, FC, CS1, CS2, S, FS> {
|
||||
_c1: PhantomData<C1>,
|
||||
_gc1: PhantomData<GC1>,
|
||||
_c2: PhantomData<C2>,
|
||||
_gc2: PhantomData<GC2>,
|
||||
_fc: PhantomData<FC>,
|
||||
_cp1: PhantomData<CP1>,
|
||||
_cp2: PhantomData<CP2>,
|
||||
_cs1: PhantomData<CS1>,
|
||||
_cs2: PhantomData<CS2>,
|
||||
_s: PhantomData<S>,
|
||||
_fs: PhantomData<FS>,
|
||||
}
|
||||
|
||||
impl<C1, GC1, C2, GC2, FC, CP1, CP2, S, FS> DeciderTrait<C1, C2, FC, FS>
|
||||
for Decider<C1, GC1, C2, GC2, FC, CP1, CP2, S, FS>
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2, S, FS> DeciderTrait<C1, C2, FC, FS>
|
||||
for Decider<C1, GC1, C2, GC2, FC, CS1, CS2, S, FS>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>>,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CP1: CommitmentProver<C1>,
|
||||
// enforce that the CP2 is Pedersen commitment, since we're at Ethereum's EVM decider
|
||||
CP2: CommitmentProver<C2, Params = PedersenParams<C2>>,
|
||||
CS1: CommitmentScheme<
|
||||
C1,
|
||||
ProverChallenge = C1::ScalarField,
|
||||
Challenge = C1::ScalarField,
|
||||
Proof = KZGProof<C1>,
|
||||
>, // KZG commitment, where challenge is C1::Fr elem
|
||||
// enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider
|
||||
CS2: CommitmentScheme<C2, ProverParams = PedersenParams<C2>>,
|
||||
S: SNARK<C1::ScalarField>,
|
||||
FS: FoldingScheme<C1, C2, FC>,
|
||||
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||
@@ -51,84 +80,192 @@ where
|
||||
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
|
||||
for<'b> &'b GC2: GroupOpsBounds<'b, C2, GC2>,
|
||||
// constrain FS into Nova, since this is a Decider specifically for Nova
|
||||
Nova<C1, GC1, C2, GC2, FC, CP1, CP2>: From<FS>,
|
||||
Nova<C1, GC1, C2, GC2, FC, CS1, CS2>: From<FS>,
|
||||
{
|
||||
type ProverParam = S::ProvingKey;
|
||||
type Proof = S::Proof;
|
||||
type VerifierParam = S::VerifyingKey;
|
||||
type ProverParam = (
|
||||
PoseidonConfig<C1::ScalarField>,
|
||||
S::ProvingKey,
|
||||
CS1::ProverParams,
|
||||
);
|
||||
type Proof = Proof<C1, CS1, S>;
|
||||
type VerifierParam = (S::VerifyingKey, CS1::VerifierParams);
|
||||
type PublicInput = Vec<C1::ScalarField>;
|
||||
type CommittedInstanceWithWitness = ();
|
||||
type CommittedInstance = CommittedInstance<C1>;
|
||||
|
||||
fn prove(
|
||||
pp: &Self::ProverParam,
|
||||
pp: Self::ProverParam,
|
||||
mut rng: impl RngCore + CryptoRng,
|
||||
folding_scheme: FS,
|
||||
) -> Result<Self::Proof, Error> {
|
||||
let circuit =
|
||||
DeciderEthCircuit::<C1, GC1, C2, GC2, CP1, CP2>::from_nova::<FC>(folding_scheme.into());
|
||||
let (poseidon_config, snark_pk, cs_pk): (
|
||||
PoseidonConfig<C1::ScalarField>,
|
||||
S::ProvingKey,
|
||||
CS1::ProverParams,
|
||||
) = pp;
|
||||
|
||||
S::prove(pp, circuit.clone(), &mut rng).map_err(|e| Error::Other(e.to_string()))
|
||||
let circuit = DeciderEthCircuit::<C1, GC1, C2, GC2, CS1, CS2>::from_nova::<FC>(
|
||||
folding_scheme.into(),
|
||||
)?;
|
||||
|
||||
let snark_proof = S::prove(&snark_pk, circuit.clone(), &mut rng)
|
||||
.map_err(|e| Error::Other(e.to_string()))?;
|
||||
|
||||
let U_i = circuit
|
||||
.U_i
|
||||
.clone()
|
||||
.ok_or(Error::MissingValue("U_i".to_string()))?;
|
||||
let W_i = circuit
|
||||
.W_i
|
||||
.clone()
|
||||
.ok_or(Error::MissingValue("W_i".to_string()))?;
|
||||
let u_i = circuit
|
||||
.u_i
|
||||
.clone()
|
||||
.ok_or(Error::MissingValue("u_i".to_string()))?;
|
||||
let w_i = circuit
|
||||
.w_i
|
||||
.clone()
|
||||
.ok_or(Error::MissingValue("w_i".to_string()))?;
|
||||
|
||||
// compute NIFS.P((U_d, W_d), (u_d, w_d)) = (U_{d+1}, W_{d+1}, cmT)
|
||||
let (T, cmT) = NIFS::<C1, CS1>::compute_cmT(&cs_pk, &circuit.r1cs, &w_i, &u_i, &W_i, &U_i)?;
|
||||
let r_bits = ChallengeGadget::<C1>::get_challenge_native(
|
||||
&poseidon_config,
|
||||
U_i.clone(),
|
||||
u_i.clone(),
|
||||
cmT,
|
||||
)?;
|
||||
let r_Fr = C1::ScalarField::from_bigint(BigInteger::from_bits_le(&r_bits))
|
||||
.ok_or(Error::OutOfBounds)?;
|
||||
let (W_i1, _): (Witness<C1>, CommittedInstance<C1>) =
|
||||
NIFS::<C1, CS1>::fold_instances(r_Fr, &W_i, &U_i, &w_i, &u_i, &T, cmT)?;
|
||||
|
||||
// get the challenges that have been already computed when preparing the circuit inputs in
|
||||
// the above `from_nova` call
|
||||
let challenge_W = circuit
|
||||
.kzg_c_W
|
||||
.ok_or(Error::MissingValue("kzg_c_W".to_string()))?;
|
||||
let challenge_E = circuit
|
||||
.kzg_c_E
|
||||
.ok_or(Error::MissingValue("kzg_c_E".to_string()))?;
|
||||
|
||||
// generate KZG proofs
|
||||
let U_cmW_proof = CS1::prove_with_challenge(
|
||||
&cs_pk,
|
||||
challenge_W,
|
||||
&W_i1.W,
|
||||
&C1::ScalarField::zero(),
|
||||
None,
|
||||
)?;
|
||||
let U_cmE_proof = CS1::prove_with_challenge(
|
||||
&cs_pk,
|
||||
challenge_E,
|
||||
&W_i1.E,
|
||||
&C1::ScalarField::zero(),
|
||||
None,
|
||||
)?;
|
||||
|
||||
Ok(Self::Proof {
|
||||
snark_proof,
|
||||
kzg_proofs: [U_cmW_proof, U_cmE_proof],
|
||||
cmT,
|
||||
r: r_Fr,
|
||||
kzg_challenges: [challenge_W, challenge_E],
|
||||
})
|
||||
}
|
||||
|
||||
fn verify(
|
||||
vp: &Self::VerifierParam,
|
||||
vp: Self::VerifierParam,
|
||||
i: C1::ScalarField,
|
||||
z_0: Vec<C1::ScalarField>,
|
||||
z_i: Vec<C1::ScalarField>,
|
||||
running_instance: &Self::CommittedInstance,
|
||||
incoming_instance: &Self::CommittedInstance,
|
||||
proof: Self::Proof,
|
||||
) -> Result<bool, Error> {
|
||||
let (cmE_x, cmE_y) = point_to_nonnative_limbs_custom_opt::<C1>(
|
||||
running_instance.cmE,
|
||||
OptimizationType::Constraints,
|
||||
)?;
|
||||
let (cmW_x, cmW_y) = point_to_nonnative_limbs_custom_opt::<C1>(
|
||||
running_instance.cmW,
|
||||
OptimizationType::Constraints,
|
||||
)?;
|
||||
let (snark_vk, cs_vk): (S::VerifyingKey, CS1::VerifierParams) = vp;
|
||||
|
||||
// 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 (cmE_x, cmE_y) =
|
||||
point_to_nonnative_limbs_custom_opt::<C1>(U.cmE, OptimizationType::Constraints)?;
|
||||
let (cmW_x, cmW_y) =
|
||||
point_to_nonnative_limbs_custom_opt::<C1>(U.cmW, OptimizationType::Constraints)?;
|
||||
let (cmT_x, cmT_y) =
|
||||
point_to_nonnative_limbs_custom_opt::<C1>(proof.cmT, OptimizationType::Constraints)?;
|
||||
|
||||
let public_input: Vec<C1::ScalarField> = vec![
|
||||
vec![i],
|
||||
z_0,
|
||||
z_i,
|
||||
vec![running_instance.u],
|
||||
running_instance.x.clone(),
|
||||
vec![U.u],
|
||||
U.x.clone(),
|
||||
cmE_x,
|
||||
cmE_y,
|
||||
cmW_x,
|
||||
cmW_y,
|
||||
proof.kzg_challenges.to_vec(),
|
||||
vec![
|
||||
proof.kzg_proofs[0].eval, // eval_W
|
||||
proof.kzg_proofs[1].eval, // eval_E
|
||||
],
|
||||
cmT_x,
|
||||
cmT_y,
|
||||
vec![proof.r],
|
||||
]
|
||||
.concat();
|
||||
S::verify(vp, &public_input, &proof).map_err(|e| Error::Other(e.to_string()))
|
||||
|
||||
let snark_v = S::verify(&snark_vk, &public_input, &proof.snark_proof)
|
||||
.map_err(|e| Error::Other(e.to_string()))?;
|
||||
if !snark_v {
|
||||
return Err(Error::SNARKVerificationFail);
|
||||
}
|
||||
|
||||
// we're at the Ethereum EVM case, so the CS1 is KZG commitments
|
||||
CS1::verify_with_challenge(
|
||||
&cs_vk,
|
||||
proof.kzg_challenges[0],
|
||||
&U.cmW,
|
||||
&proof.kzg_proofs[0],
|
||||
)?;
|
||||
CS1::verify_with_challenge(
|
||||
&cs_vk,
|
||||
proof.kzg_challenges[1],
|
||||
&U.cmE,
|
||||
&proof.kzg_proofs[1],
|
||||
)?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
||||
use ark_groth16::Groth16;
|
||||
use ark_mnt4_298::{constraints::G1Var as GVar, Fr, G1Projective as Projective, MNT4_298};
|
||||
use ark_mnt6_298::{constraints::G1Var as GVar2, G1Projective 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 crate::commitment::kzg::{ProverKey as KZGProverKey, KZG};
|
||||
use crate::commitment::pedersen::Pedersen;
|
||||
use crate::folding::nova::{get_pedersen_params_len, ProverParams};
|
||||
use crate::folding::nova::{get_cs_params_len, ProverParams};
|
||||
use crate::frontend::tests::CubicFCircuit;
|
||||
use crate::transcript::poseidon::poseidon_test_config;
|
||||
|
||||
// Note: since we're testing a big circuit, this test takes a bit more of computation and time,
|
||||
// do not run in the normal CI.
|
||||
// To run the test use `--ignored` flag, eg. `cargo test -- --ignored`
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_decider() {
|
||||
// use Nova as FoldingScheme
|
||||
type NOVA = Nova<
|
||||
Projective,
|
||||
GVar,
|
||||
Projective2,
|
||||
GVar2,
|
||||
CubicFCircuit<Fr>,
|
||||
Pedersen<Projective>,
|
||||
KZG<'static, Bn254>,
|
||||
Pedersen<Projective2>,
|
||||
>;
|
||||
type DECIDER = Decider<
|
||||
@@ -137,10 +274,10 @@ pub mod tests {
|
||||
Projective2,
|
||||
GVar2,
|
||||
CubicFCircuit<Fr>,
|
||||
Pedersen<Projective>,
|
||||
KZG<'static, Bn254>,
|
||||
Pedersen<Projective2>,
|
||||
Groth16<MNT4_298>, // here we define the Snark to use in the decider
|
||||
NOVA, // here we define the FoldingScheme to use
|
||||
Groth16<Bn254>, // here we define the Snark to use in the decider
|
||||
NOVA, // here we define the FoldingScheme to use
|
||||
>;
|
||||
|
||||
let mut rng = ark_std::test_rng();
|
||||
@@ -149,31 +286,32 @@ pub mod tests {
|
||||
let F_circuit = CubicFCircuit::<Fr>::new(());
|
||||
let z_0 = vec![Fr::from(3_u32)];
|
||||
|
||||
let (cm_len, cf_cm_len) =
|
||||
get_pedersen_params_len::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>>(
|
||||
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>::new_params(&mut rng, cm_len);
|
||||
let cf_pedersen_params = Pedersen::<Projective2>::new_params(&mut rng, cf_cm_len);
|
||||
|
||||
let start = Instant::now();
|
||||
let prover_params =
|
||||
ProverParams::<Projective, Projective2, Pedersen<Projective>, Pedersen<Projective2>> {
|
||||
poseidon_config: poseidon_config.clone(),
|
||||
cm_params: pedersen_params,
|
||||
cf_cm_params: cf_pedersen_params,
|
||||
};
|
||||
println!("generating pedersen params, {:?}", start.elapsed());
|
||||
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_params: kzg_pk.clone(),
|
||||
cf_cs_params: cf_pedersen_params,
|
||||
};
|
||||
|
||||
// use Nova as FoldingScheme
|
||||
let start = Instant::now();
|
||||
let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
||||
println!("Nova initialized, {:?}", start.elapsed());
|
||||
let start = Instant::now();
|
||||
nova.prove_step().unwrap();
|
||||
println!("prove_step, {:?}", start.elapsed());
|
||||
nova.prove_step().unwrap(); // do a 2nd step
|
||||
|
||||
// generate Groth16 setup
|
||||
let circuit = DeciderEthCircuit::<
|
||||
@@ -181,23 +319,31 @@ pub mod tests {
|
||||
GVar,
|
||||
Projective2,
|
||||
GVar2,
|
||||
Pedersen<Projective>,
|
||||
KZG<Bn254>,
|
||||
Pedersen<Projective2>,
|
||||
>::from_nova::<CubicFCircuit<Fr>>(nova.clone());
|
||||
>::from_nova::<CubicFCircuit<Fr>>(nova.clone())
|
||||
.unwrap();
|
||||
let mut rng = rand::rngs::OsRng;
|
||||
|
||||
let start = Instant::now();
|
||||
let (pk, vk) =
|
||||
Groth16::<MNT4_298>::circuit_specific_setup(circuit.clone(), &mut rng).unwrap();
|
||||
let (g16_pk, g16_vk) =
|
||||
Groth16::<Bn254>::circuit_specific_setup(circuit.clone(), &mut rng).unwrap();
|
||||
println!("Groth16 setup, {:?}", start.elapsed());
|
||||
|
||||
// decider proof generation
|
||||
let start = Instant::now();
|
||||
let proof = DECIDER::prove(&pk, rng, nova.clone()).unwrap();
|
||||
println!("Decider Groth16 prove, {:?}", start.elapsed());
|
||||
let decider_pp = (poseidon_config.clone(), g16_pk, kzg_pk);
|
||||
let proof = DECIDER::prove(decider_pp, rng, nova.clone()).unwrap();
|
||||
println!("Decider prove, {:?}", start.elapsed());
|
||||
|
||||
// decider proof verification
|
||||
let verified = DECIDER::verify(&vk, nova.i, nova.z_0, nova.z_i, &nova.U_i, proof).unwrap();
|
||||
let start = Instant::now();
|
||||
let decider_vp = (g16_vk, kzg_vk);
|
||||
let verified = DECIDER::verify(
|
||||
decider_vp, nova.i, nova.z_0, nova.z_i, &nova.U_i, &nova.u_i, proof,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(verified);
|
||||
println!("Decider verify, {:?}", start.elapsed());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,29 +3,40 @@
|
||||
use ark_crypto_primitives::crh::poseidon::constraints::CRHParametersVar;
|
||||
use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb};
|
||||
use ark_ec::{CurveGroup, Group};
|
||||
use ark_ff::PrimeField;
|
||||
use ark_ff::{BigInteger, PrimeField};
|
||||
use ark_poly::Polynomial;
|
||||
use ark_r1cs_std::{
|
||||
alloc::{AllocVar, AllocationMode},
|
||||
boolean::Boolean,
|
||||
eq::EqGadget,
|
||||
fields::{fp::FpVar, nonnative::NonNativeFieldVar, FieldVar},
|
||||
groups::GroupOpsBounds,
|
||||
poly::{domain::Radix2DomainVar, evaluations::univariate::EvaluationsVar},
|
||||
prelude::CurveVar,
|
||||
ToConstraintFieldGadget,
|
||||
};
|
||||
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError};
|
||||
use ark_std::{One, Zero};
|
||||
use ark_std::{log2, One, Zero};
|
||||
use core::{borrow::Borrow, marker::PhantomData};
|
||||
|
||||
use super::{circuits::ChallengeGadget, nifs::NIFS};
|
||||
use crate::ccs::r1cs::R1CS;
|
||||
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentProver};
|
||||
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme};
|
||||
use crate::folding::circuits::nonnative::{point_to_nonnative_limbs, NonNativeAffineVar};
|
||||
use crate::folding::nova::{
|
||||
circuits::{CommittedInstanceVar, CF1, CF2},
|
||||
CommittedInstance, Nova, Witness,
|
||||
};
|
||||
use crate::frontend::FCircuit;
|
||||
use crate::utils::gadgets::{
|
||||
hadamard, mat_vec_mul_sparse, vec_add, vec_scalar_mul, SparseMatrixVar,
|
||||
use crate::transcript::{
|
||||
poseidon::{PoseidonTranscript, PoseidonTranscriptVar},
|
||||
Transcript, TranscriptVar,
|
||||
};
|
||||
use crate::utils::{
|
||||
gadgets::{hadamard, mat_vec_mul_sparse, vec_add, vec_scalar_mul, SparseMatrixVar},
|
||||
vec::poly_from_vec,
|
||||
};
|
||||
use crate::Error;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RelaxedR1CSGadget<F: PrimeField, CF: PrimeField, FV: FieldVar<F, CF>> {
|
||||
@@ -178,21 +189,21 @@ where
|
||||
/// Circuit that implements the in-circuit checks needed for the onchain (Ethereum's EVM)
|
||||
/// verification.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct DeciderEthCircuit<C1, GC1, C2, GC2, CP1, CP2>
|
||||
pub struct DeciderEthCircuit<C1, GC1, C2, GC2, CS1, CS2>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>>,
|
||||
C2: CurveGroup,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
CP1: CommitmentProver<C1>,
|
||||
CP2: CommitmentProver<C2>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
{
|
||||
_c1: PhantomData<C1>,
|
||||
_gc1: PhantomData<GC1>,
|
||||
_c2: PhantomData<C2>,
|
||||
_gc2: PhantomData<GC2>,
|
||||
_cp1: PhantomData<CP1>,
|
||||
_cp2: PhantomData<CP2>,
|
||||
_cs1: PhantomData<CS1>,
|
||||
_cs2: PhantomData<CS2>,
|
||||
|
||||
/// E vector's length of the Nova instance witness
|
||||
pub E_len: usize,
|
||||
@@ -215,36 +226,89 @@ where
|
||||
pub w_i: Option<Witness<C1>>,
|
||||
pub U_i: Option<CommittedInstance<C1>>,
|
||||
pub W_i: Option<Witness<C1>>,
|
||||
pub U_i1: Option<CommittedInstance<C1>>,
|
||||
pub W_i1: Option<Witness<C1>>,
|
||||
pub cmT: Option<C1>,
|
||||
pub r: Option<C1::ScalarField>,
|
||||
/// CycleFold running instance
|
||||
pub cf_U_i: Option<CommittedInstance<C2>>,
|
||||
pub cf_W_i: Option<Witness<C2>>,
|
||||
|
||||
/// KZG challenges
|
||||
pub kzg_c_W: Option<C1::ScalarField>,
|
||||
pub kzg_c_E: Option<C1::ScalarField>,
|
||||
pub eval_W: Option<C1::ScalarField>,
|
||||
pub eval_E: Option<C1::ScalarField>,
|
||||
}
|
||||
impl<C1, GC1, C2, GC2, CP1, CP2> DeciderEthCircuit<C1, GC1, C2, GC2, CP1, CP2>
|
||||
impl<C1, GC1, C2, GC2, CS1, CS2> DeciderEthCircuit<C1, GC1, C2, GC2, CS1, CS2>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>>,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
CP1: CommitmentProver<C1>,
|
||||
// enforce that the CP2 is Pedersen commitment, since we're at Ethereum's EVM decider
|
||||
CP2: CommitmentProver<C2, Params = PedersenParams<C2>>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
// enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider
|
||||
CS2: CommitmentScheme<C2, ProverParams = PedersenParams<C2>>,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||
{
|
||||
pub fn from_nova<FC: FCircuit<C1::ScalarField>>(
|
||||
nova: Nova<C1, GC1, C2, GC2, FC, CP1, CP2>,
|
||||
) -> Self {
|
||||
Self {
|
||||
nova: Nova<C1, GC1, C2, GC2, FC, CS1, CS2>,
|
||||
) -> Result<Self, Error> {
|
||||
// compute the U_{i+1}, W_{i+1}
|
||||
let (T, cmT) = NIFS::<C1, CS1>::compute_cmT(
|
||||
&nova.cs_params,
|
||||
&nova.r1cs.clone(),
|
||||
&nova.w_i.clone(),
|
||||
&nova.u_i.clone(),
|
||||
&nova.W_i.clone(),
|
||||
&nova.U_i.clone(),
|
||||
)?;
|
||||
let r_bits = ChallengeGadget::<C1>::get_challenge_native(
|
||||
&nova.poseidon_config,
|
||||
nova.U_i.clone(),
|
||||
nova.u_i.clone(),
|
||||
cmT,
|
||||
)?;
|
||||
let r_Fr = C1::ScalarField::from_bigint(BigInteger::from_bits_le(&r_bits))
|
||||
.ok_or(Error::OutOfBounds)?;
|
||||
let (W_i1, U_i1) = NIFS::<C1, CS1>::fold_instances(
|
||||
r_Fr, &nova.W_i, &nova.U_i, &nova.w_i, &nova.u_i, &T, cmT,
|
||||
)?;
|
||||
|
||||
// compute the KZG challenges used as inputs in the circuit
|
||||
let (kzg_challenge_W, kzg_challenge_E) =
|
||||
KZGChallengesGadget::<C1>::get_challenges_native(&nova.poseidon_config, U_i1.clone())?;
|
||||
|
||||
// get KZG evals
|
||||
let mut W = W_i1.W.clone();
|
||||
W.extend(
|
||||
std::iter::repeat(C1::ScalarField::zero())
|
||||
.take(W_i1.W.len().next_power_of_two() - W_i1.W.len()),
|
||||
);
|
||||
let mut E = W_i1.E.clone();
|
||||
E.extend(
|
||||
std::iter::repeat(C1::ScalarField::zero())
|
||||
.take(W_i1.E.len().next_power_of_two() - W_i1.E.len()),
|
||||
);
|
||||
let p_W = poly_from_vec(W.to_vec())?;
|
||||
let eval_W = p_W.evaluate(&kzg_challenge_W);
|
||||
let p_E = poly_from_vec(E.to_vec())?;
|
||||
let eval_E = p_E.evaluate(&kzg_challenge_E);
|
||||
|
||||
Ok(Self {
|
||||
_c1: PhantomData,
|
||||
_gc1: PhantomData,
|
||||
_c2: PhantomData,
|
||||
_gc2: PhantomData,
|
||||
_cp1: PhantomData,
|
||||
_cp2: PhantomData,
|
||||
_cs1: PhantomData,
|
||||
_cs2: PhantomData,
|
||||
|
||||
E_len: nova.W_i.E.len(),
|
||||
cf_E_len: nova.cf_W_i.E.len(),
|
||||
r1cs: nova.r1cs,
|
||||
cf_r1cs: nova.cf_r1cs,
|
||||
cf_pedersen_params: nova.cf_cm_params,
|
||||
cf_pedersen_params: nova.cf_cs_params,
|
||||
poseidon_config: nova.poseidon_config,
|
||||
i: Some(nova.i),
|
||||
z_0: Some(nova.z_0),
|
||||
@@ -253,21 +317,29 @@ where
|
||||
w_i: Some(nova.w_i),
|
||||
U_i: Some(nova.U_i),
|
||||
W_i: Some(nova.W_i),
|
||||
U_i1: Some(U_i1),
|
||||
W_i1: Some(W_i1),
|
||||
cmT: Some(cmT),
|
||||
r: Some(r_Fr),
|
||||
cf_U_i: Some(nova.cf_U_i),
|
||||
cf_W_i: Some(nova.cf_W_i),
|
||||
}
|
||||
kzg_c_W: Some(kzg_challenge_W),
|
||||
kzg_c_E: Some(kzg_challenge_E),
|
||||
eval_W: Some(eval_W),
|
||||
eval_E: Some(eval_E),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<C1, GC1, C2, GC2, CP1, CP2> ConstraintSynthesizer<CF1<C1>>
|
||||
for DeciderEthCircuit<C1, GC1, C2, GC2, CP1, CP2>
|
||||
impl<C1, GC1, C2, GC2, CS1, CS2> ConstraintSynthesizer<CF1<C1>>
|
||||
for DeciderEthCircuit<C1, GC1, C2, GC2, CS1, CS2>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>>,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
CP1: CommitmentProver<C1>,
|
||||
CP2: CommitmentProver<C2>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||
<C2 as CurveGroup>::BaseField: PrimeField,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
@@ -299,14 +371,29 @@ where
|
||||
let u_i = CommittedInstanceVar::<C1>::new_witness(cs.clone(), || {
|
||||
Ok(self.u_i.unwrap_or(u_dummy_native.clone()))
|
||||
})?;
|
||||
let w_i = WitnessVar::<C1>::new_witness(cs.clone(), || {
|
||||
Ok(self.w_i.unwrap_or(w_dummy_native.clone()))
|
||||
})?;
|
||||
let U_i = CommittedInstanceVar::<C1>::new_input(cs.clone(), || {
|
||||
let U_i = CommittedInstanceVar::<C1>::new_witness(cs.clone(), || {
|
||||
Ok(self.U_i.unwrap_or(u_dummy_native.clone()))
|
||||
})?;
|
||||
let W_i = WitnessVar::<C1>::new_witness(cs.clone(), || {
|
||||
Ok(self.W_i.unwrap_or(w_dummy_native.clone()))
|
||||
// here (U_i1, W_i1) = NIFS.P( (U_i,W_i), (u_i,w_i))
|
||||
let U_i1 = CommittedInstanceVar::<C1>::new_input(cs.clone(), || {
|
||||
Ok(self.U_i1.unwrap_or(u_dummy_native.clone()))
|
||||
})?;
|
||||
let W_i1 = WitnessVar::<C1>::new_witness(cs.clone(), || {
|
||||
Ok(self.W_i1.unwrap_or(w_dummy_native.clone()))
|
||||
})?;
|
||||
|
||||
// allocate the inputs for the check 6
|
||||
let kzg_c_W = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
|
||||
Ok(self.kzg_c_W.unwrap_or_else(CF1::<C1>::zero))
|
||||
})?;
|
||||
let kzg_c_E = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
|
||||
Ok(self.kzg_c_E.unwrap_or_else(CF1::<C1>::zero))
|
||||
})?;
|
||||
let _eval_W = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
|
||||
Ok(self.eval_W.unwrap_or_else(CF1::<C1>::zero))
|
||||
})?;
|
||||
let _eval_E = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
|
||||
Ok(self.eval_E.unwrap_or_else(CF1::<C1>::zero))
|
||||
})?;
|
||||
|
||||
let crh_params = CRHParametersVar::<C1::ScalarField>::new_constant(
|
||||
@@ -314,31 +401,17 @@ where
|
||||
self.poseidon_config.clone(),
|
||||
)?;
|
||||
|
||||
// 1. check RelaxedR1CS of u_i
|
||||
let z_u: Vec<FpVar<CF1<C1>>> = [
|
||||
vec![FpVar::<CF1<C1>>::one()],
|
||||
u_i.x.to_vec(),
|
||||
w_i.W.to_vec(),
|
||||
]
|
||||
.concat();
|
||||
RelaxedR1CSGadget::<C1::ScalarField, CF1<C1>, FpVar<CF1<C1>>>::check(
|
||||
r1cs.clone(),
|
||||
w_i.E,
|
||||
u_i.u.clone(),
|
||||
z_u,
|
||||
)?;
|
||||
|
||||
// 2. check RelaxedR1CS of U_i
|
||||
let z_U: Vec<FpVar<CF1<C1>>> =
|
||||
[vec![U_i.u.clone()], U_i.x.to_vec(), W_i.W.to_vec()].concat();
|
||||
// 1. check RelaxedR1CS of U_{i+1}
|
||||
let z_U1: Vec<FpVar<CF1<C1>>> =
|
||||
[vec![U_i1.u.clone()], U_i1.x.to_vec(), W_i1.W.to_vec()].concat();
|
||||
RelaxedR1CSGadget::<C1::ScalarField, CF1<C1>, FpVar<CF1<C1>>>::check(
|
||||
r1cs,
|
||||
W_i.E,
|
||||
U_i.u.clone(),
|
||||
z_U,
|
||||
W_i1.E.clone(),
|
||||
U_i1.u.clone(),
|
||||
z_U1,
|
||||
)?;
|
||||
|
||||
// 3. u_i.cmE==cm(0), u_i.u==1
|
||||
// 2. u_i.cmE==cm(0), u_i.u==1
|
||||
// Here zero_x & zero_y are the x & y coordinates of the zero point affine representation.
|
||||
let zero_x = NonNativeFieldVar::<C1::BaseField, C1::ScalarField>::new_constant(
|
||||
cs.clone(),
|
||||
@@ -348,19 +421,19 @@ where
|
||||
cs.clone(),
|
||||
C1::BaseField::one(),
|
||||
)?;
|
||||
(u_i.cmE.x.is_eq(&zero_x)?).enforce_equal(&Boolean::TRUE)?;
|
||||
(u_i.cmE.y.is_eq(&zero_y)?).enforce_equal(&Boolean::TRUE)?;
|
||||
u_i.cmE.x.enforce_equal(&zero_x)?;
|
||||
u_i.cmE.y.enforce_equal(&zero_y)?;
|
||||
(u_i.u.is_one()?).enforce_equal(&Boolean::TRUE)?;
|
||||
|
||||
// 4. u_i.x == H(i, z_0, z_i, U_i)
|
||||
let (u_i_x, _) = U_i
|
||||
.clone()
|
||||
.hash(&crh_params, i.clone(), z_0.clone(), z_i.clone())?;
|
||||
// 3. u_i.x == H(i, z_0, z_i, U_i)
|
||||
let (u_i_x, U_i_vec) =
|
||||
U_i.clone()
|
||||
.hash(&crh_params, i.clone(), z_0.clone(), z_i.clone())?;
|
||||
(u_i.x[0]).enforce_equal(&u_i_x)?;
|
||||
|
||||
// The following two checks (and their respective allocations) are disabled for normal
|
||||
// tests since they take ~24.5M constraints and would take several minutes (and RAM) to run
|
||||
// the test
|
||||
// tests since they take several millions of constraints and would take several minutes
|
||||
// (and RAM) to run the test.
|
||||
#[cfg(not(test))]
|
||||
{
|
||||
// imports here instead of at the top of the file, so we avoid having multiple
|
||||
@@ -381,7 +454,7 @@ where
|
||||
Ok(self.cf_W_i.unwrap_or(w_dummy_native.clone()))
|
||||
})?;
|
||||
|
||||
// 5. check Pedersen commitments of cf_U_i.{cmE, cmW}
|
||||
// 4. check Pedersen commitments of cf_U_i.{cmE, cmW}
|
||||
let H = GC2::new_constant(cs.clone(), self.cf_pedersen_params.h)?;
|
||||
let G = Vec::<GC2>::new_constant(cs.clone(), self.cf_pedersen_params.generators)?;
|
||||
let cf_W_i_E_bits: Result<Vec<Vec<Boolean<CF1<C1>>>>, SynthesisError> =
|
||||
@@ -406,7 +479,7 @@ where
|
||||
NonNativeFieldVar<C1::BaseField, CF1<C1>>,
|
||||
>::new_witness(cs.clone(), || Ok(self.cf_r1cs.clone()))?;
|
||||
|
||||
// 6. check RelaxedR1CS of cf_U_i
|
||||
// 5. check RelaxedR1CS of cf_U_i
|
||||
let cf_z_U: Vec<NonNativeFieldVar<C2::ScalarField, CF1<C1>>> =
|
||||
[vec![cf_U_i.u.clone()], cf_U_i.x.to_vec(), cf_W_i.W.to_vec()].concat();
|
||||
RelaxedR1CSGadget::<
|
||||
@@ -416,10 +489,122 @@ where
|
||||
>::check(cf_r1cs, cf_W_i.E, cf_U_i.u.clone(), cf_z_U)?;
|
||||
}
|
||||
|
||||
// 6. check KZG challenges
|
||||
let (incircuit_c_W, incircuit_c_E) = KZGChallengesGadget::<C1>::get_challenges_gadget(
|
||||
cs.clone(),
|
||||
&self.poseidon_config,
|
||||
U_i1.clone(),
|
||||
)?;
|
||||
incircuit_c_W.enforce_equal(&kzg_c_W)?;
|
||||
incircuit_c_E.enforce_equal(&kzg_c_E)?;
|
||||
|
||||
// Check 7 is temporary disabled due
|
||||
// https://github.com/privacy-scaling-explorations/folding-schemes/issues/80
|
||||
//
|
||||
// 7. check eval_W==p_W(c_W) and eval_E==p_E(c_E)
|
||||
// let incircuit_eval_W = evaluate_gadget::<CF1<C1>>(W_i1.W, incircuit_c_W)?;
|
||||
// let incircuit_eval_E = evaluate_gadget::<CF1<C1>>(W_i1.E, incircuit_c_E)?;
|
||||
// incircuit_eval_W.enforce_equal(&eval_W)?;
|
||||
// incircuit_eval_E.enforce_equal(&eval_E)?;
|
||||
|
||||
// 8. compute the NIFS.V challenge and check that matches the one from the public input (so we
|
||||
// avoid the verifier computing it)
|
||||
let cmT =
|
||||
NonNativeAffineVar::new_input(cs.clone(), || Ok(self.cmT.unwrap_or_else(C1::zero)))?;
|
||||
let r_bits = ChallengeGadget::<C1>::get_challenge_gadget(
|
||||
cs.clone(),
|
||||
&self.poseidon_config,
|
||||
U_i_vec,
|
||||
u_i.clone(),
|
||||
cmT.clone(),
|
||||
)?;
|
||||
let r_Fr = Boolean::le_bits_to_fp_var(&r_bits)?;
|
||||
// check that the in-circuit computed r is equal to the inputted r
|
||||
let r =
|
||||
FpVar::<CF1<C1>>::new_input(cs.clone(), || Ok(self.r.unwrap_or_else(CF1::<C1>::zero)))?;
|
||||
r_Fr.enforce_equal(&r)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Interpolates the polynomial from the given vector, and then returns it's evaluation at the
|
||||
/// given point.
|
||||
#[allow(unused)] // unused while check 7 is disabled
|
||||
fn evaluate_gadget<F: PrimeField>(
|
||||
v: Vec<FpVar<F>>,
|
||||
point: FpVar<F>,
|
||||
) -> Result<FpVar<F>, SynthesisError> {
|
||||
if !v.len().is_power_of_two() {
|
||||
return Err(SynthesisError::Unsatisfiable);
|
||||
}
|
||||
let n = v.len() as u64;
|
||||
let gen = F::get_root_of_unity(n).unwrap();
|
||||
let domain = Radix2DomainVar::new(gen, log2(v.len()) as u64, FpVar::one()).unwrap();
|
||||
|
||||
let evaluations_var = EvaluationsVar::from_vec_and_domain(v, domain, true);
|
||||
evaluations_var.interpolate_and_evaluate(&point)
|
||||
}
|
||||
|
||||
/// Gadget that computes the KZG challenges, also offers the rust native implementation compatible
|
||||
/// with the gadget.
|
||||
pub struct KZGChallengesGadget<C: CurveGroup> {
|
||||
_c: PhantomData<C>,
|
||||
}
|
||||
impl<C> KZGChallengesGadget<C>
|
||||
where
|
||||
C: CurveGroup,
|
||||
C::ScalarField: PrimeField,
|
||||
<C as CurveGroup>::BaseField: PrimeField,
|
||||
C::ScalarField: Absorb,
|
||||
{
|
||||
pub fn get_challenges_native(
|
||||
poseidon_config: &PoseidonConfig<C::ScalarField>,
|
||||
U_i: CommittedInstance<C>,
|
||||
) -> Result<(C::ScalarField, C::ScalarField), Error> {
|
||||
let (cmE_x_limbs, cmE_y_limbs): (Vec<C::ScalarField>, Vec<C::ScalarField>) =
|
||||
point_to_nonnative_limbs::<C>(U_i.cmE)?;
|
||||
let (cmW_x_limbs, cmW_y_limbs): (Vec<C::ScalarField>, Vec<C::ScalarField>) =
|
||||
point_to_nonnative_limbs::<C>(U_i.cmW)?;
|
||||
|
||||
let transcript = &mut PoseidonTranscript::<C>::new(poseidon_config);
|
||||
// compute the KZG challenges, which are computed in-circuit and checked that it matches
|
||||
// the inputted one
|
||||
transcript.absorb_vec(&cmW_x_limbs);
|
||||
transcript.absorb_vec(&cmW_y_limbs);
|
||||
let challenge_W = transcript.get_challenge();
|
||||
transcript.absorb_vec(&cmE_x_limbs);
|
||||
transcript.absorb_vec(&cmE_y_limbs);
|
||||
let challenge_E = transcript.get_challenge();
|
||||
|
||||
Ok((challenge_W, challenge_E))
|
||||
}
|
||||
// compatible with the native get_challenges_native
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub fn get_challenges_gadget(
|
||||
cs: ConstraintSystemRef<C::ScalarField>,
|
||||
poseidon_config: &PoseidonConfig<C::ScalarField>,
|
||||
U_i: CommittedInstanceVar<C>,
|
||||
) -> Result<(FpVar<C::ScalarField>, FpVar<C::ScalarField>), SynthesisError> {
|
||||
let mut transcript =
|
||||
PoseidonTranscriptVar::<CF1<C>>::new(cs.clone(), &poseidon_config.clone());
|
||||
|
||||
let cmW_x_limbs = U_i.cmW.x.to_constraint_field()?;
|
||||
let cmW_y_limbs = U_i.cmW.y.to_constraint_field()?;
|
||||
transcript.absorb_vec(&cmW_x_limbs)?;
|
||||
transcript.absorb_vec(&cmW_y_limbs)?;
|
||||
let challenge_W = transcript.get_challenge()?;
|
||||
|
||||
let cmE_x_limbs = U_i.cmE.x.to_constraint_field()?;
|
||||
let cmE_y_limbs = U_i.cmE.y.to_constraint_field()?;
|
||||
transcript.absorb_vec(&cmE_x_limbs)?;
|
||||
transcript.absorb_vec(&cmE_y_limbs)?;
|
||||
let challenge_E = transcript.get_challenge()?;
|
||||
|
||||
Ok((challenge_W, challenge_E))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
@@ -439,10 +624,11 @@ pub mod tests {
|
||||
fields::{fp::FpVar, nonnative::NonNativeFieldVar},
|
||||
};
|
||||
use ark_relations::r1cs::ConstraintSystem;
|
||||
use ark_std::UniformRand;
|
||||
use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2};
|
||||
|
||||
use crate::commitment::pedersen::Pedersen;
|
||||
use crate::folding::nova::{get_pedersen_params_len, ProverParams, VerifierParams};
|
||||
use crate::folding::nova::{get_cs_params_len, ProverParams, VerifierParams};
|
||||
use crate::frontend::tests::{CubicFCircuit, CustomFCircuit, WrapperCircuit};
|
||||
use crate::transcript::poseidon::poseidon_test_config;
|
||||
use crate::FoldingScheme;
|
||||
@@ -610,21 +796,21 @@ pub mod tests {
|
||||
let F_circuit = CubicFCircuit::<Fr>::new(());
|
||||
let z_0 = vec![Fr::from(3_u32)];
|
||||
|
||||
// get the CM & CF_CM len
|
||||
let (cm_len, cf_cm_len) =
|
||||
get_pedersen_params_len::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>>(
|
||||
// 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>::new_params(&mut rng, cm_len);
|
||||
let cf_pedersen_params = Pedersen::<Projective2>::new_params(&mut rng, cf_cm_len);
|
||||
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(),
|
||||
cm_params: pedersen_params,
|
||||
cf_cm_params: cf_pedersen_params,
|
||||
cs_params: pedersen_params,
|
||||
cf_cs_params: cf_pedersen_params,
|
||||
};
|
||||
|
||||
type NOVA = Nova<
|
||||
@@ -666,12 +852,82 @@ pub mod tests {
|
||||
GVar2,
|
||||
Pedersen<Projective>,
|
||||
Pedersen<Projective2>,
|
||||
>::from_nova(nova);
|
||||
>::from_nova(nova)
|
||||
.unwrap();
|
||||
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
|
||||
// generate the constraints and check that are satisfied by the inputs
|
||||
decider_circuit.generate_constraints(cs.clone()).unwrap();
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
dbg!(cs.num_constraints());
|
||||
}
|
||||
|
||||
// checks that the gadget and native implementations of the challenge computation match
|
||||
#[test]
|
||||
fn test_kzg_challenge_gadget() {
|
||||
let mut rng = ark_std::test_rng();
|
||||
let poseidon_config = poseidon_test_config::<Fr>();
|
||||
|
||||
let U_i = CommittedInstance::<Projective> {
|
||||
cmE: Projective::rand(&mut rng),
|
||||
u: Fr::rand(&mut rng),
|
||||
cmW: Projective::rand(&mut rng),
|
||||
x: vec![Fr::rand(&mut rng); 1],
|
||||
};
|
||||
|
||||
// compute the challenge natively
|
||||
let (challenge_W, challenge_E) =
|
||||
KZGChallengesGadget::<Projective>::get_challenges_native(&poseidon_config, U_i.clone())
|
||||
.unwrap();
|
||||
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
let U_iVar =
|
||||
CommittedInstanceVar::<Projective>::new_witness(cs.clone(), || Ok(U_i.clone()))
|
||||
.unwrap();
|
||||
|
||||
let (challenge_W_Var, challenge_E_Var) =
|
||||
KZGChallengesGadget::<Projective>::get_challenges_gadget(
|
||||
cs.clone(),
|
||||
&poseidon_config,
|
||||
U_iVar,
|
||||
)
|
||||
.unwrap();
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
|
||||
// check that the natively computed and in-circuit computed hashes match
|
||||
use ark_r1cs_std::R1CSVar;
|
||||
assert_eq!(challenge_W_Var.value().unwrap(), challenge_W);
|
||||
assert_eq!(challenge_E_Var.value().unwrap(), challenge_E);
|
||||
}
|
||||
|
||||
// The test test_polynomial_interpolation is temporary disabled due
|
||||
// https://github.com/privacy-scaling-explorations/folding-schemes/issues/80
|
||||
// for n<=11 it will work, but for n>11 it will fail with stack overflow.
|
||||
#[ignore]
|
||||
#[test]
|
||||
fn test_polynomial_interpolation() {
|
||||
let mut rng = ark_std::test_rng();
|
||||
let n = 12;
|
||||
let l = 1 << n;
|
||||
|
||||
let v: Vec<Fr> = std::iter::repeat_with(|| Fr::rand(&mut rng))
|
||||
.take(l)
|
||||
.collect();
|
||||
let challenge = Fr::rand(&mut rng);
|
||||
|
||||
use ark_poly::Polynomial;
|
||||
let polynomial = poly_from_vec(v.to_vec()).unwrap();
|
||||
let eval = polynomial.evaluate(&challenge);
|
||||
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
let vVar = Vec::<FpVar<Fr>>::new_witness(cs.clone(), || Ok(v)).unwrap();
|
||||
let challengeVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(challenge)).unwrap();
|
||||
|
||||
let evalVar = evaluate_gadget::<Fr>(vVar, challengeVar).unwrap();
|
||||
|
||||
use ark_r1cs_std::R1CSVar;
|
||||
assert_eq!(evalVar.value().unwrap(), eval);
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use core::marker::PhantomData;
|
||||
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
|
||||
|
||||
use crate::ccs::r1cs::{extract_r1cs, extract_w_x, R1CS};
|
||||
use crate::commitment::CommitmentProver;
|
||||
use crate::commitment::CommitmentScheme;
|
||||
use crate::folding::circuits::nonnative::point_to_nonnative_limbs;
|
||||
use crate::frontend::FCircuit;
|
||||
use crate::utils::vec::is_zero_vec;
|
||||
@@ -115,16 +115,16 @@ where
|
||||
rW: C::ScalarField::zero(),
|
||||
}
|
||||
}
|
||||
pub fn commit<CP: CommitmentProver<C>>(
|
||||
pub fn commit<CS: CommitmentScheme<C>>(
|
||||
&self,
|
||||
params: &CP::Params,
|
||||
params: &CS::ProverParams,
|
||||
x: Vec<C::ScalarField>,
|
||||
) -> Result<CommittedInstance<C>, Error> {
|
||||
let mut cmE = C::zero();
|
||||
if !is_zero_vec::<C::ScalarField>(&self.E) {
|
||||
cmE = CP::commit(params, &self.E, &self.rE)?;
|
||||
cmE = CS::commit(params, &self.E, &self.rE)?;
|
||||
}
|
||||
let cmW = CP::commit(params, &self.W, &self.rW)?;
|
||||
let cmW = CS::commit(params, &self.W, &self.rW)?;
|
||||
Ok(CommittedInstance {
|
||||
cmE,
|
||||
u: C::ScalarField::one(),
|
||||
@@ -135,16 +135,16 @@ where
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ProverParams<C1, C2, CP1, CP2>
|
||||
pub struct ProverParams<C1, C2, CS1, CS2>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
C2: CurveGroup,
|
||||
CP1: CommitmentProver<C1>,
|
||||
CP2: CommitmentProver<C2>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
{
|
||||
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||
pub cm_params: CP1::Params,
|
||||
pub cf_cm_params: CP2::Params,
|
||||
pub cs_params: CS1::ProverParams,
|
||||
pub cf_cs_params: CS2::ProverParams,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -157,15 +157,15 @@ pub struct VerifierParams<C1: CurveGroup, C2: CurveGroup> {
|
||||
/// 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
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Nova<C1, GC1, C2, GC2, FC, CP1, CP2>
|
||||
pub struct Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>>,
|
||||
C2: CurveGroup,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CP1: CommitmentProver<C1>,
|
||||
CP2: CommitmentProver<C2>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
{
|
||||
_gc1: PhantomData<GC1>,
|
||||
_c2: PhantomData<C2>,
|
||||
@@ -175,10 +175,10 @@ where
|
||||
/// R1CS of the CycleFold circuit
|
||||
pub cf_r1cs: R1CS<C2::ScalarField>,
|
||||
pub poseidon_config: PoseidonConfig<C1::ScalarField>,
|
||||
/// CommitmentProver::Params over C1
|
||||
pub cm_params: CP1::Params,
|
||||
/// CycleFold CommitmentProver::Params, over C2
|
||||
pub cf_cm_params: CP2::Params,
|
||||
/// CommitmentScheme::ProverParams over C1
|
||||
pub cs_params: CS1::ProverParams,
|
||||
/// CycleFold CommitmentScheme::ProverParams, over C2
|
||||
pub cf_cs_params: CS2::ProverParams,
|
||||
/// F circuit, the circuit that is being folded
|
||||
pub F: FC,
|
||||
pub i: C1::ScalarField,
|
||||
@@ -197,16 +197,16 @@ where
|
||||
pub cf_U_i: CommittedInstance<C2>,
|
||||
}
|
||||
|
||||
impl<C1, GC1, C2, GC2, FC, CP1, CP2> FoldingScheme<C1, C2, FC>
|
||||
for Nova<C1, GC1, C2, GC2, FC, CP1, CP2>
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2> FoldingScheme<C1, C2, FC>
|
||||
for Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>>,
|
||||
C2: CurveGroup,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CP1: CommitmentProver<C1>,
|
||||
CP2: CommitmentProver<C2>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||
<C2 as CurveGroup>::BaseField: PrimeField,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
@@ -216,7 +216,7 @@ where
|
||||
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
|
||||
{
|
||||
type PreprocessorParam = (Self::ProverParam, FC);
|
||||
type ProverParam = ProverParams<C1, C2, CP1, CP2>;
|
||||
type ProverParam = ProverParams<C1, C2, CS1, CS2>;
|
||||
type VerifierParam = VerifierParams<C1, C2>;
|
||||
type CommittedInstanceWithWitness = (CommittedInstance<C1>, Witness<C1>);
|
||||
type CFCommittedInstanceWithWitness = (CommittedInstance<C2>, Witness<C2>);
|
||||
@@ -270,8 +270,8 @@ where
|
||||
r1cs,
|
||||
cf_r1cs,
|
||||
poseidon_config: pp.poseidon_config.clone(),
|
||||
cm_params: pp.cm_params.clone(),
|
||||
cf_cm_params: pp.cf_cm_params.clone(),
|
||||
cs_params: pp.cs_params.clone(),
|
||||
cf_cs_params: pp.cf_cs_params.clone(),
|
||||
F,
|
||||
i: C1::ScalarField::zero(),
|
||||
z_0: z_0.clone(),
|
||||
@@ -315,7 +315,7 @@ where
|
||||
.ok_or(Error::OutOfBounds)?;
|
||||
|
||||
// fold Nova instances
|
||||
let (W_i1, U_i1): (Witness<C1>, CommittedInstance<C1>) = NIFS::<C1, CP1>::fold_instances(
|
||||
let (W_i1, U_i1): (Witness<C1>, CommittedInstance<C1>) = NIFS::<C1, CS1>::fold_instances(
|
||||
r_Fr, &self.W_i, &self.U_i, &self.w_i, &self.u_i, &T, cmT,
|
||||
)?;
|
||||
|
||||
@@ -355,7 +355,7 @@ where
|
||||
};
|
||||
|
||||
#[cfg(test)]
|
||||
NIFS::<C1, CP1>::verify_folded_instance(r_Fr, &self.U_i, &self.u_i, &U_i1, &cmT)?;
|
||||
NIFS::<C1, CS1>::verify_folded_instance(r_Fr, &self.U_i, &self.u_i, &U_i1, &cmT)?;
|
||||
} else {
|
||||
// CycleFold part:
|
||||
// get the vector used as public inputs 'x' in the CycleFold circuit
|
||||
@@ -444,6 +444,9 @@ where
|
||||
|
||||
augmented_F_circuit.generate_constraints(cs.clone())?;
|
||||
|
||||
#[cfg(test)]
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
|
||||
let cs = cs.into_inner().ok_or(Error::NoInnerConstraintSystem)?;
|
||||
let (w_i1, x_i1) = extract_w_x::<C1::ScalarField>(&cs);
|
||||
if x_i1[0] != u_i1_x {
|
||||
@@ -459,7 +462,7 @@ where
|
||||
self.i += C1::ScalarField::one();
|
||||
self.z_i = z_i1.clone();
|
||||
self.w_i = Witness::<C1>::new(w_i1, self.r1cs.A.n_rows);
|
||||
self.u_i = self.w_i.commit::<CP1>(&self.cm_params, vec![u_i1_x])?;
|
||||
self.u_i = self.w_i.commit::<CS1>(&self.cs_params, vec![u_i1_x])?;
|
||||
self.W_i = W_i1.clone();
|
||||
self.U_i = U_i1.clone();
|
||||
|
||||
@@ -533,15 +536,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C1, GC1, C2, GC2, FC, CP1, CP2> Nova<C1, GC1, C2, GC2, FC, CP1, CP2>
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2> Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>>,
|
||||
C2: CurveGroup,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CP1: CommitmentProver<C1>,
|
||||
CP2: CommitmentProver<C2>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
<C2 as CurveGroup>::BaseField: PrimeField,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
<C2 as Group>::ScalarField: Absorb,
|
||||
@@ -549,8 +552,8 @@ where
|
||||
{
|
||||
// computes T and cmT for the AugmentedFCircuit
|
||||
fn compute_cmT(&self) -> Result<(Vec<C1::ScalarField>, C1), Error> {
|
||||
NIFS::<C1, CP1>::compute_cmT(
|
||||
&self.cm_params,
|
||||
NIFS::<C1, CS1>::compute_cmT(
|
||||
&self.cs_params,
|
||||
&self.r1cs,
|
||||
&self.w_i,
|
||||
&self.u_i,
|
||||
@@ -566,8 +569,8 @@ where
|
||||
cf_W_i: &Witness<C2>,
|
||||
cf_U_i: &CommittedInstance<C2>,
|
||||
) -> Result<(Vec<C2::ScalarField>, C2), Error> {
|
||||
NIFS::<C2, CP2>::compute_cyclefold_cmT(
|
||||
&self.cf_cm_params,
|
||||
NIFS::<C2, CS2>::compute_cyclefold_cmT(
|
||||
&self.cf_cs_params,
|
||||
&self.cf_r1cs,
|
||||
cf_w_i,
|
||||
cf_u_i,
|
||||
@@ -577,15 +580,15 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C1, GC1, C2, GC2, FC, CP1, CP2> Nova<C1, GC1, C2, GC2, FC, CP1, CP2>
|
||||
impl<C1, GC1, C2, GC2, FC, CS1, CS2> Nova<C1, GC1, C2, GC2, FC, CS1, CS2>
|
||||
where
|
||||
C1: CurveGroup,
|
||||
GC1: CurveVar<C1, CF2<C1>>,
|
||||
C2: CurveGroup,
|
||||
GC2: CurveVar<C2, CF2<C2>>,
|
||||
FC: FCircuit<C1::ScalarField>,
|
||||
CP1: CommitmentProver<C1>,
|
||||
CP2: CommitmentProver<C2>,
|
||||
CS1: CommitmentScheme<C1>,
|
||||
CS2: CommitmentScheme<C2>,
|
||||
<C1 as CurveGroup>::BaseField: PrimeField,
|
||||
<C2 as CurveGroup>::BaseField: PrimeField,
|
||||
<C1 as Group>::ScalarField: Absorb,
|
||||
@@ -630,7 +633,7 @@ where
|
||||
// fold cyclefold instances
|
||||
let cf_w_i = Witness::<C2>::new(cf_w_i.clone(), self.cf_r1cs.A.n_rows);
|
||||
let cf_u_i: CommittedInstance<C2> =
|
||||
cf_w_i.commit::<CP2>(&self.cf_cm_params, cf_x_i.clone())?;
|
||||
cf_w_i.commit::<CS2>(&self.cf_cs_params, cf_x_i.clone())?;
|
||||
|
||||
// compute T* and cmT* for CycleFoldCircuit
|
||||
let (cf_T, cf_cmT) = self.compute_cf_cmT(&cf_w_i, &cf_u_i, &cf_W_i, &cf_U_i)?;
|
||||
@@ -644,7 +647,7 @@ where
|
||||
let cf_r_Fq = C1::BaseField::from_bigint(BigInteger::from_bits_le(&cf_r_bits))
|
||||
.ok_or(Error::OutOfBounds)?;
|
||||
|
||||
let (cf_W_i1, cf_U_i1) = NIFS::<C2, CP2>::fold_instances(
|
||||
let (cf_W_i1, cf_U_i1) = NIFS::<C2, CS2>::fold_instances(
|
||||
cf_r_Fq, &cf_W_i, &cf_U_i, &cf_w_i, &cf_u_i, &cf_T, cf_cmT,
|
||||
)?;
|
||||
Ok((cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, cf_r_Fq))
|
||||
@@ -693,7 +696,7 @@ where
|
||||
|
||||
/// helper method to get the pedersen params length for both the AugmentedFCircuit and the
|
||||
/// CycleFold circuit
|
||||
pub fn get_pedersen_params_len<C1, GC1, C2, GC2, FC>(
|
||||
pub fn get_cs_params_len<C1, GC1, C2, GC2, FC>(
|
||||
poseidon_config: &PoseidonConfig<C1::ScalarField>,
|
||||
F_circuit: FC,
|
||||
) -> Result<(usize, usize), Error>
|
||||
@@ -715,6 +718,7 @@ where
|
||||
Ok((r1cs.A.n_rows, cf_r1cs.A.n_rows))
|
||||
}
|
||||
|
||||
/// returns the coordinates of a commitment point
|
||||
pub(crate) fn get_cm_coordinates<C: CurveGroup>(cm: &C) -> Vec<C::BaseField> {
|
||||
let zero = (&C::BaseField::zero(), &C::BaseField::one());
|
||||
let cm = cm.into_affine();
|
||||
@@ -725,8 +729,10 @@ pub(crate) fn get_cm_coordinates<C: CurveGroup>(cm: &C) -> Vec<C::BaseField> {
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use ark_pallas::{constraints::GVar, Fr, Projective};
|
||||
use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2};
|
||||
use crate::commitment::kzg::{ProverKey as KZGProverKey, KZG};
|
||||
use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective};
|
||||
use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2};
|
||||
use ark_poly_commit::kzg10::VerifierKey as KZGVerifierKey;
|
||||
|
||||
use crate::commitment::pedersen::Pedersen;
|
||||
use crate::frontend::tests::CubicFCircuit;
|
||||
@@ -736,38 +742,56 @@ pub mod tests {
|
||||
/// AugmentedFCircuit
|
||||
#[test]
|
||||
fn test_ivc() {
|
||||
type NOVA = Nova<
|
||||
Projective,
|
||||
GVar,
|
||||
Projective2,
|
||||
GVar2,
|
||||
CubicFCircuit<Fr>,
|
||||
Pedersen<Projective>,
|
||||
Pedersen<Projective2>,
|
||||
>;
|
||||
|
||||
let mut rng = ark_std::test_rng();
|
||||
let poseidon_config = poseidon_test_config::<Fr>();
|
||||
|
||||
let F_circuit = CubicFCircuit::<Fr>::new(());
|
||||
let z_0 = vec![Fr::from(3_u32)];
|
||||
|
||||
let (cm_len, cf_cm_len) =
|
||||
get_pedersen_params_len::<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>>(
|
||||
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>::new_params(&mut rng, cm_len);
|
||||
let cf_pedersen_params = Pedersen::<Projective2>::new_params(&mut rng, cf_cm_len);
|
||||
let (kzg_pk, _): (KZGProverKey<Projective>, KZGVerifierKey<Bn254>) =
|
||||
KZG::<Bn254>::setup(&mut rng, cs_len).unwrap();
|
||||
let (pedersen_params, _) = Pedersen::<Projective>::setup(&mut rng, cs_len).unwrap();
|
||||
let (cf_pedersen_params, _) = Pedersen::<Projective2>::setup(&mut rng, cf_cs_len).unwrap();
|
||||
|
||||
let prover_params =
|
||||
ProverParams::<Projective, Projective2, Pedersen<Projective>, Pedersen<Projective2>> {
|
||||
poseidon_config: poseidon_config.clone(),
|
||||
cm_params: pedersen_params,
|
||||
cf_cm_params: cf_pedersen_params,
|
||||
};
|
||||
// run the test using Pedersen commitments on both sides of the curve cycle
|
||||
test_ivc_opt::<Pedersen<Projective>, Pedersen<Projective2>>(
|
||||
poseidon_config.clone(),
|
||||
pedersen_params,
|
||||
cf_pedersen_params.clone(),
|
||||
F_circuit,
|
||||
);
|
||||
// run the test using KZG for the commitments on the main curve, and Pedersen for the
|
||||
// commitments on the secondary curve
|
||||
test_ivc_opt::<KZG<Bn254>, Pedersen<Projective2>>(
|
||||
poseidon_config,
|
||||
kzg_pk,
|
||||
cf_pedersen_params,
|
||||
F_circuit,
|
||||
);
|
||||
}
|
||||
|
||||
// test_ivc allowing to choose the CommitmentSchemes
|
||||
fn test_ivc_opt<CS1: CommitmentScheme<Projective>, CS2: CommitmentScheme<Projective2>>(
|
||||
poseidon_config: PoseidonConfig<Fr>,
|
||||
cs_params: CS1::ProverParams,
|
||||
cf_cs_params: CS2::ProverParams,
|
||||
F_circuit: CubicFCircuit<Fr>,
|
||||
) {
|
||||
type NOVA<CS1, CS2> =
|
||||
Nova<Projective, GVar, Projective2, GVar2, CubicFCircuit<Fr>, CS1, CS2>;
|
||||
|
||||
let prover_params = ProverParams::<Projective, Projective2, CS1, CS2> {
|
||||
poseidon_config: poseidon_config.clone(),
|
||||
cs_params,
|
||||
cf_cs_params,
|
||||
};
|
||||
|
||||
let z_0 = vec![Fr::from(3_u32)];
|
||||
let mut nova = NOVA::init(&prover_params, F_circuit, z_0.clone()).unwrap();
|
||||
|
||||
let num_steps: usize = 3;
|
||||
@@ -782,7 +806,7 @@ pub mod tests {
|
||||
cf_r1cs: nova.clone().cf_r1cs,
|
||||
};
|
||||
let (running_instance, incoming_instance, cyclefold_instance) = nova.instances();
|
||||
NOVA::verify(
|
||||
NOVA::<CS1, CS2>::verify(
|
||||
verifier_params,
|
||||
z_0,
|
||||
nova.z_i,
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
use ark_crypto_primitives::sponge::Absorb;
|
||||
use ark_ec::{CurveGroup, Group};
|
||||
use ark_std::One;
|
||||
use ark_std::Zero;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use super::{CommittedInstance, Witness};
|
||||
use crate::ccs::r1cs::R1CS;
|
||||
use crate::commitment::CommitmentProver;
|
||||
use crate::commitment::CommitmentScheme;
|
||||
use crate::transcript::Transcript;
|
||||
use crate::utils::vec::*;
|
||||
use crate::Error;
|
||||
|
||||
/// Implements the Non-Interactive Folding Scheme described in section 4 of
|
||||
/// [Nova](https://eprint.iacr.org/2021/370.pdf)
|
||||
pub struct NIFS<C: CurveGroup, CP: CommitmentProver<C>> {
|
||||
pub struct NIFS<C: CurveGroup, CS: CommitmentScheme<C>> {
|
||||
_c: PhantomData<C>,
|
||||
_cp: PhantomData<CP>,
|
||||
_cp: PhantomData<CS>,
|
||||
}
|
||||
|
||||
impl<C: CurveGroup, CP: CommitmentProver<C>> NIFS<C, CP>
|
||||
impl<C: CurveGroup, CS: CommitmentScheme<C>> NIFS<C, CS>
|
||||
where
|
||||
<C as Group>::ScalarField: Absorb,
|
||||
{
|
||||
@@ -90,7 +90,7 @@ where
|
||||
|
||||
/// compute_cmT is part of the NIFS.P logic
|
||||
pub fn compute_cmT(
|
||||
cm_prover_params: &CP::Params,
|
||||
cs_prover_params: &CS::ProverParams,
|
||||
r1cs: &R1CS<C::ScalarField>,
|
||||
w1: &Witness<C>,
|
||||
ci1: &CommittedInstance<C>,
|
||||
@@ -102,12 +102,12 @@ where
|
||||
|
||||
// compute cross terms
|
||||
let T = Self::compute_T(r1cs, ci1.u, ci2.u, &z1, &z2)?;
|
||||
// use r_T=1 since we don't need hiding property for cm(T)
|
||||
let cmT = CP::commit(cm_prover_params, &T, &C::ScalarField::one())?;
|
||||
// use r_T=0 since we don't need hiding property for cm(T)
|
||||
let cmT = CS::commit(cs_prover_params, &T, &C::ScalarField::zero())?;
|
||||
Ok((T, cmT))
|
||||
}
|
||||
pub fn compute_cyclefold_cmT(
|
||||
cm_prover_params: &CP::Params,
|
||||
cs_prover_params: &CS::ProverParams,
|
||||
r1cs: &R1CS<C::ScalarField>, // R1CS over C2.Fr=C1.Fq (here C=C2)
|
||||
w1: &Witness<C>,
|
||||
ci1: &CommittedInstance<C>,
|
||||
@@ -122,8 +122,8 @@ where
|
||||
|
||||
// compute cross terms
|
||||
let T = Self::compute_T(r1cs, ci1.u, ci2.u, &z1, &z2)?;
|
||||
// use r_T=1 since we don't need hiding property for cm(T)
|
||||
let cmT = CP::commit(cm_prover_params, &T, &C::ScalarField::one())?;
|
||||
// use r_T=0 since we don't need hiding property for cm(T)
|
||||
let cmT = CS::commit(cs_prover_params, &T, &C::ScalarField::zero())?;
|
||||
Ok((T, cmT))
|
||||
}
|
||||
|
||||
@@ -140,11 +140,11 @@ where
|
||||
cmT: C,
|
||||
) -> Result<(Witness<C>, CommittedInstance<C>), Error> {
|
||||
// fold witness
|
||||
// use r_T=1 since we don't need hiding property for cm(T)
|
||||
let w3 = NIFS::<C, CP>::fold_witness(r, w1, w2, T, C::ScalarField::one())?;
|
||||
// use r_T=0 since we don't need hiding property for cm(T)
|
||||
let w3 = NIFS::<C, CS>::fold_witness(r, w1, w2, T, C::ScalarField::zero())?;
|
||||
|
||||
// fold committed instances
|
||||
let ci3 = NIFS::<C, CP>::fold_committed_instance(r, ci1, ci2, &cmT);
|
||||
let ci3 = NIFS::<C, CS>::fold_committed_instance(r, ci1, ci2, &cmT);
|
||||
|
||||
Ok((w3, ci3))
|
||||
}
|
||||
@@ -158,7 +158,7 @@ where
|
||||
ci2: &CommittedInstance<C>,
|
||||
cmT: &C,
|
||||
) -> CommittedInstance<C> {
|
||||
NIFS::<C, CP>::fold_committed_instance(r, ci1, ci2, cmT)
|
||||
NIFS::<C, CS>::fold_committed_instance(r, ci1, ci2, cmT)
|
||||
}
|
||||
|
||||
/// Verify committed folded instance (ci) relations. Notice that this method does not open the
|
||||
@@ -184,15 +184,15 @@ where
|
||||
|
||||
pub fn prove_commitments(
|
||||
tr: &mut impl Transcript<C>,
|
||||
cm_prover_params: &CP::Params,
|
||||
cs_prover_params: &CS::ProverParams,
|
||||
w: &Witness<C>,
|
||||
ci: &CommittedInstance<C>,
|
||||
T: Vec<C::ScalarField>,
|
||||
cmT: &C,
|
||||
) -> Result<[CP::Proof; 3], Error> {
|
||||
let cmE_proof = CP::prove(cm_prover_params, tr, &ci.cmE, &w.E, &w.rE, None)?;
|
||||
let cmW_proof = CP::prove(cm_prover_params, tr, &ci.cmW, &w.W, &w.rW, None)?;
|
||||
let cmT_proof = CP::prove(cm_prover_params, tr, cmT, &T, &C::ScalarField::one(), None)?; // cm(T) is committed with rT=1
|
||||
) -> Result<[CS::Proof; 3], Error> {
|
||||
let cmE_proof = CS::prove(cs_prover_params, tr, &ci.cmE, &w.E, &w.rE, None)?;
|
||||
let cmW_proof = CS::prove(cs_prover_params, tr, &ci.cmW, &w.W, &w.rW, None)?;
|
||||
let cmT_proof = CS::prove(cs_prover_params, tr, cmT, &T, &C::ScalarField::zero(), None)?; // cm(T) is committed with rT=0
|
||||
Ok([cmE_proof, cmW_proof, cmT_proof])
|
||||
}
|
||||
}
|
||||
@@ -213,67 +213,64 @@ pub mod tests {
|
||||
use crate::utils::vec::vec_scalar_mul;
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fn prepare_simple_fold_inputs() -> (
|
||||
PedersenParams<Projective>,
|
||||
PoseidonConfig<Fr>,
|
||||
R1CS<Fr>,
|
||||
Witness<Projective>, // w1
|
||||
CommittedInstance<Projective>, // ci1
|
||||
Witness<Projective>, // w2
|
||||
CommittedInstance<Projective>, // ci2
|
||||
Witness<Projective>, // w3
|
||||
CommittedInstance<Projective>, // ci3
|
||||
Vec<Fr>, // T
|
||||
Projective, // cmT
|
||||
Vec<bool>, // r_bits
|
||||
Fr, // r_Fr
|
||||
) {
|
||||
pub(crate) fn prepare_simple_fold_inputs<C>() -> (
|
||||
PedersenParams<C>,
|
||||
PoseidonConfig<C::ScalarField>,
|
||||
R1CS<C::ScalarField>,
|
||||
Witness<C>, // w1
|
||||
CommittedInstance<C>, // ci1
|
||||
Witness<C>, // w2
|
||||
CommittedInstance<C>, // ci2
|
||||
Witness<C>, // w3
|
||||
CommittedInstance<C>, // ci3
|
||||
Vec<C::ScalarField>, // T
|
||||
C, // cmT
|
||||
Vec<bool>, // r_bits
|
||||
C::ScalarField, // r_Fr
|
||||
)
|
||||
where
|
||||
C: CurveGroup,
|
||||
<C as CurveGroup>::BaseField: PrimeField,
|
||||
C::ScalarField: Absorb,
|
||||
{
|
||||
let r1cs = get_test_r1cs();
|
||||
let z1 = get_test_z(3);
|
||||
let z2 = get_test_z(4);
|
||||
let (w1, x1) = r1cs.split_z(&z1);
|
||||
let (w2, x2) = r1cs.split_z(&z2);
|
||||
|
||||
let w1 = Witness::<Projective>::new(w1.clone(), r1cs.A.n_rows);
|
||||
let w2 = Witness::<Projective>::new(w2.clone(), r1cs.A.n_rows);
|
||||
let w1 = Witness::<C>::new(w1.clone(), r1cs.A.n_rows);
|
||||
let w2 = Witness::<C>::new(w2.clone(), r1cs.A.n_rows);
|
||||
|
||||
let mut rng = ark_std::test_rng();
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, r1cs.A.n_cols);
|
||||
let (pedersen_params, _) = Pedersen::<C>::setup(&mut rng, r1cs.A.n_cols).unwrap();
|
||||
|
||||
// compute committed instances
|
||||
let ci1 = w1
|
||||
.commit::<Pedersen<Projective>>(&pedersen_params, x1.clone())
|
||||
.commit::<Pedersen<C>>(&pedersen_params, x1.clone())
|
||||
.unwrap();
|
||||
let ci2 = w2
|
||||
.commit::<Pedersen<Projective>>(&pedersen_params, x2.clone())
|
||||
.commit::<Pedersen<C>>(&pedersen_params, x2.clone())
|
||||
.unwrap();
|
||||
|
||||
// NIFS.P
|
||||
let (T, cmT) = NIFS::<Projective, Pedersen<Projective>>::compute_cmT(
|
||||
&pedersen_params,
|
||||
&r1cs,
|
||||
&w1,
|
||||
&ci1,
|
||||
&w2,
|
||||
&ci2,
|
||||
)
|
||||
.unwrap();
|
||||
let (T, cmT) =
|
||||
NIFS::<C, Pedersen<C>>::compute_cmT(&pedersen_params, &r1cs, &w1, &ci1, &w2, &ci2)
|
||||
.unwrap();
|
||||
|
||||
let poseidon_config = poseidon_test_config::<Fr>();
|
||||
let poseidon_config = poseidon_test_config::<C::ScalarField>();
|
||||
|
||||
let r_bits = ChallengeGadget::<Projective>::get_challenge_native(
|
||||
let r_bits = ChallengeGadget::<C>::get_challenge_native(
|
||||
&poseidon_config,
|
||||
ci1.clone(),
|
||||
ci2.clone(),
|
||||
cmT,
|
||||
)
|
||||
.unwrap();
|
||||
let r_Fr = Fr::from_bigint(BigInteger::from_bits_le(&r_bits)).unwrap();
|
||||
let r_Fr = C::ScalarField::from_bigint(BigInteger::from_bits_le(&r_bits)).unwrap();
|
||||
|
||||
let (w3, ci3) = NIFS::<Projective, Pedersen<Projective>>::fold_instances(
|
||||
r_Fr, &w1, &ci1, &w2, &ci2, &T, cmT,
|
||||
)
|
||||
.unwrap();
|
||||
let (w3, ci3) =
|
||||
NIFS::<C, Pedersen<C>>::fold_instances(r_Fr, &w1, &ci1, &w2, &ci2, &T, cmT).unwrap();
|
||||
|
||||
(
|
||||
pedersen_params,
|
||||
@@ -300,7 +297,7 @@ pub mod tests {
|
||||
let (w1, x1) = r1cs.split_z(&z1);
|
||||
|
||||
let mut rng = ark_std::test_rng();
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, r1cs.A.n_cols);
|
||||
let (pedersen_params, _) = Pedersen::<Projective>::setup(&mut rng, r1cs.A.n_cols).unwrap();
|
||||
|
||||
// dummy instance, witness and public inputs zeroes
|
||||
let w_dummy = Witness::<Projective>::new(vec![Fr::zero(); w1.len()], r1cs.A.n_rows);
|
||||
@@ -386,22 +383,22 @@ pub mod tests {
|
||||
Pedersen::<Projective>::verify(
|
||||
&pedersen_params,
|
||||
&mut transcript_v,
|
||||
ci3.cmE,
|
||||
cm_proofs[0].clone(),
|
||||
&ci3.cmE,
|
||||
&cm_proofs[0].clone(),
|
||||
)
|
||||
.unwrap();
|
||||
Pedersen::<Projective>::verify(
|
||||
&pedersen_params,
|
||||
&mut transcript_v,
|
||||
ci3.cmW,
|
||||
cm_proofs[1].clone(),
|
||||
&ci3.cmW,
|
||||
&cm_proofs[1].clone(),
|
||||
)
|
||||
.unwrap();
|
||||
Pedersen::<Projective>::verify(
|
||||
&pedersen_params,
|
||||
&mut transcript_v,
|
||||
cmT,
|
||||
cm_proofs[2].clone(),
|
||||
&cmT,
|
||||
&cm_proofs[2].clone(),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
@@ -413,7 +410,7 @@ pub mod tests {
|
||||
let (w, x) = r1cs.split_z(&z);
|
||||
|
||||
let mut rng = ark_std::test_rng();
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, r1cs.A.n_cols);
|
||||
let (pedersen_params, _) = Pedersen::<Projective>::setup(&mut rng, r1cs.A.n_cols).unwrap();
|
||||
|
||||
// prepare the running instance
|
||||
let mut running_instance_w = Witness::<Projective>::new(w.clone(), r1cs.A.n_rows);
|
||||
|
||||
@@ -384,7 +384,7 @@ mod tests {
|
||||
use ark_std::UniformRand;
|
||||
|
||||
use crate::ccs::r1cs::tests::{get_test_r1cs, get_test_z};
|
||||
use crate::commitment::{pedersen::Pedersen, CommitmentProver};
|
||||
use crate::commitment::{pedersen::Pedersen, CommitmentScheme};
|
||||
use crate::transcript::poseidon::{poseidon_test_config, PoseidonTranscript};
|
||||
|
||||
pub(crate) fn check_instance<C: CurveGroup>(
|
||||
@@ -452,7 +452,7 @@ mod tests {
|
||||
Vec<CommittedInstance<Projective>>,
|
||||
) {
|
||||
let mut rng = ark_std::test_rng();
|
||||
let pedersen_params = Pedersen::<Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
|
||||
let (pedersen_params, _) = Pedersen::<Projective>::setup(&mut rng, 100).unwrap(); // 100 is wip, will get it from actual vec
|
||||
|
||||
let z = get_test_z::<Fr>(3);
|
||||
let mut zs: Vec<Vec<Fr>> = Vec::new();
|
||||
@@ -471,8 +471,8 @@ mod tests {
|
||||
w: z.clone(),
|
||||
r_w: Fr::rand(&mut rng),
|
||||
};
|
||||
let phi =
|
||||
Pedersen::<Projective>::commit(&pedersen_params, &witness.w, &witness.r_w).unwrap();
|
||||
let phi = Pedersen::<Projective, true>::commit(&pedersen_params, &witness.w, &witness.r_w)
|
||||
.unwrap();
|
||||
let instance = CommittedInstance::<Projective> {
|
||||
phi,
|
||||
betas: betas.clone(),
|
||||
@@ -487,9 +487,12 @@ mod tests {
|
||||
w: zs[i].clone(),
|
||||
r_w: Fr::rand(&mut rng),
|
||||
};
|
||||
let phi_i =
|
||||
Pedersen::<Projective>::commit(&pedersen_params, &witness_i.w, &witness_i.r_w)
|
||||
.unwrap();
|
||||
let phi_i = Pedersen::<Projective, true>::commit(
|
||||
&pedersen_params,
|
||||
&witness_i.w,
|
||||
&witness_i.r_w,
|
||||
)
|
||||
.unwrap();
|
||||
let instance_i = CommittedInstance::<Projective> {
|
||||
phi: phi_i,
|
||||
betas: betas.clone(),
|
||||
|
||||
Reference in New Issue
Block a user