Skip to content

Commit

Permalink
Add CycleFoldCommittedInstanceVar::new_incoming_from_components to …
Browse files Browse the repository at this point in the history
…simplify the construction of incoming CF instances
  • Loading branch information
winderica committed Sep 11, 2024
1 parent d779889 commit bb0dd4f
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 157 deletions.
50 changes: 45 additions & 5 deletions folding-schemes/src/folding/circuits/cyclefold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ use ark_r1cs_std::{
use ark_relations::r1cs::{
ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, Namespace, SynthesisError,
};
use ark_std::fmt::Debug;
use ark_std::rand::RngCore;
use ark_std::Zero;
use core::{borrow::Borrow, marker::PhantomData};
use ark_std::{borrow::Borrow, fmt::Debug, marker::PhantomData, rand::RngCore, One, Zero};

use super::{nonnative::uint::NonNativeUintVar, CF1, CF2};
use super::{
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
CF1, CF2,
};
use crate::arith::r1cs::{extract_w_x, R1CS};
use crate::commitment::CommitmentScheme;
use crate::constants::NOVA_N_BITS_RO;
Expand All @@ -46,6 +46,7 @@ where
pub cmW: GC,
pub x: Vec<NonNativeUintVar<CF2<C>>>,
}

impl<C, GC> AllocVar<CycleFoldCommittedInstance<C>, CF2<C>> for CycleFoldCommittedInstanceVar<C, GC>
where
C: CurveGroup,
Expand Down Expand Up @@ -127,6 +128,45 @@ where
}
}

impl<C2, GC2> CycleFoldCommittedInstanceVar<C2, GC2>
where
C2: CurveGroup,
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
C2::BaseField: PrimeField,
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
{
/// Creates a new `CycleFoldCommittedInstanceVar` from the given components.
pub fn new_incoming_from_components<C1: CurveGroup<ScalarField = C2::BaseField>>(
cmW: GC2,
r_bits: &[Boolean<CF2<C2>>],
points: Vec<NonNativeAffineVar<C1>>,
) -> Result<Self, SynthesisError> {
// Construct the public inputs `x` from `r_bits` and `points`.
// Note that the underlying field can only safely store
// `CF1::<C2>::MODULUS_BIT_SIZE - 1` bits, but `r_bits` may be longer
// than that.
// Thus, we need to chunk `r_bits` into pieces and convert each piece
// to a `NonNativeUintVar`.
let x = r_bits
.chunks(CF1::<C2>::MODULUS_BIT_SIZE as usize - 1)
.map(|bits| {
let mut bits = bits.to_vec();
bits.resize(CF1::<C2>::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
NonNativeUintVar::from(&bits)
})
.chain(points.into_iter().flat_map(|p| [p.x, p.y]))
.collect::<Vec<_>>();
Ok(Self {
// `cmE` is always zero for incoming instances
cmE: GC2::zero(),
// `u` is always one for incoming instances
u: NonNativeUintVar::new_constant(ConstraintSystemRef::None, CF1::<C2>::one())?,
cmW,
x,
})
}
}

impl<C: CurveGroup> CycleFoldCommittedInstance<C>
where
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField + Absorb,
Expand Down
47 changes: 14 additions & 33 deletions folding-schemes/src/folding/hypernova/circuits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ use crate::folding::{
CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
CycleFoldConfig, NIFSFullGadget,
},
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
nonnative::affine::NonNativeAffineVar,
sum_check::{IOPProofVar, SumCheckVerifierGadget, VPAuxInfoVar},
utils::EqEvalGadget,
CF1, CF2,
Expand Down Expand Up @@ -812,41 +812,22 @@ where
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?;
x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?;

// convert rho_bits of the rho_vec to a `NonNativeFieldVar`
let mut rho_bits_resized = rho_bits.clone();
rho_bits_resized.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
let rho_nonnat = NonNativeUintVar::from(&rho_bits_resized);

// CycleFold part
// C.1. Compute cf1_u_i.x and cf2_u_i.x
let cf_x: Vec<NonNativeUintVar<CF2<C2>>> = [
vec![rho_nonnat],
// C.1. Compute `cf_u_i.x`
// C.2. Construct `cf_u_i`
let cf_u_i = CycleFoldCommittedInstanceVar::new_incoming_from_components(
// `cf_u_i.cmW` is provided by the prover as witness.
GC2::new_witness(cs.clone(), || Ok(self.cf_u_i_cmW.unwrap_or(C2::zero())))?,
// The computation of `cf_u_i.x` requires the randomness `rho_bits`
// and the commitments `C` in LCCCS and CCCS instances.
&rho_bits,
all_Us
.iter()
.flat_map(|U| vec![U.C.x.clone(), U.C.y.clone()])
.into_iter()
.map(|U| U.C)
.chain(all_us.into_iter().map(|u| u.C))
.chain(vec![U_i1.C])
.collect(),
all_us
.iter()
.flat_map(|u| vec![u.C.x.clone(), u.C.y.clone()])
.collect(),
vec![U_i1.C.x, U_i1.C.y],
]
.concat();

// ensure that cf_u has as public inputs the C from main instances U_i, u_i, U_i+1
// coordinates of the commitments.
// C.2. Construct `cf_u_i`
let cf_u_i = CycleFoldCommittedInstanceVar::<C2, GC2> {
// cf1_u_i.cmE = 0. Notice that we enforce cmE to be equal to 0 since it is allocated
// as 0.
cmE: GC2::zero(),
// cf1_u_i.u = 1
u: NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::one())?,
// cf_u_i.cmW is provided by the prover as witness
cmW: GC2::new_witness(cs.clone(), || Ok(self.cf_u_i_cmW.unwrap_or(C2::zero())))?,
// cf_u_i.x is computed in step 1
x: cf_x,
};
)?;

// C.3. nifs.verify (fold_committed_instance), obtains cf_U_{i+1} by folding cf_u_i & cf_U_i.
// compute cf_r = H(cf_u_i, cf_U_i, cf_cmT)
Expand Down
62 changes: 19 additions & 43 deletions folding-schemes/src/folding/nova/circuits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use ark_r1cs_std::{
R1CSVar, ToConstraintFieldGadget,
};
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError};
use ark_std::{fmt::Debug, One, Zero};
use ark_std::{fmt::Debug, Zero};
use core::{borrow::Borrow, marker::PhantomData};

use super::{CommittedInstance, NovaCycleFoldConfig};
Expand All @@ -27,7 +27,7 @@ use crate::folding::circuits::{
CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
CycleFoldConfig, NIFSFullGadget,
},
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
nonnative::affine::NonNativeAffineVar,
CF1, CF2,
};
use crate::frontend::FCircuit;
Expand Down Expand Up @@ -405,12 +405,6 @@ where
cmT.clone(),
)?;
let r = Boolean::le_bits_to_fp_var(&r_bits)?;
// Also convert r_bits to a `NonNativeFieldVar`
let r_nonnat = {
let mut bits = r_bits;
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
NonNativeUintVar::from(&bits)
};

// Notice that NIFSGadget::fold_committed_instance does not fold cmE & cmW.
// We set `U_i1.cmE` and `U_i1.cmW` to unconstrained witnesses `U_i1_cmE` and `U_i1_cmW`
Expand Down Expand Up @@ -442,42 +436,24 @@ where

// CycleFold part
// C.1. Compute cf1_u_i.x and cf2_u_i.x
let cfW_x = vec![
r_nonnat.clone(),
U_i.cmW.x,
U_i.cmW.y,
u_i.cmW.x,
u_i.cmW.y,
U_i1.cmW.x,
U_i1.cmW.y,
];
let cfE_x = vec![
r_nonnat, U_i.cmE.x, U_i.cmE.y, cmT.x, cmT.y, U_i1.cmE.x, U_i1.cmE.y,
];

// ensure that cf1_u & cf2_u have as public inputs the cmW & cmE from main instances U_i,
// u_i, U_i+1 coordinates of the commitments
// C.2. Construct `cf1_u_i` and `cf2_u_i`
let cf1_u_i = CycleFoldCommittedInstanceVar {
// cf1_u_i.cmE = 0
cmE: GC2::zero(),
// cf1_u_i.u = 1
u: NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::one())?,
// cf1_u_i.cmW is provided by the prover as witness
cmW: GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW.unwrap_or(C2::zero())))?,
// cf1_u_i.x is computed in step 1
x: cfW_x,
};
let cf2_u_i = CycleFoldCommittedInstanceVar {
// cf2_u_i.cmE = 0
cmE: GC2::zero(),
// cf2_u_i.u = 1
u: NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::one())?,
// cf2_u_i.cmW is provided by the prover as witness
cmW: GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW.unwrap_or(C2::zero())))?,
// cf2_u_i.x is computed in step 1
x: cfE_x,
};
let cf1_u_i = CycleFoldCommittedInstanceVar::new_incoming_from_components(
// `cf1_u_i.cmW` is provided by the prover as witness.
GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW.unwrap_or(C2::zero())))?,
// The computation of `cf1_u_i.x` requires the randomness `r_bits`
// and the commitments `cmW` in CommittedInstances.
&r_bits,
vec![U_i.cmW, u_i.cmW, U_i1.cmW],
)?;
let cf2_u_i = CycleFoldCommittedInstanceVar::new_incoming_from_components(
// `cf2_u_i.cmW` is provided by the prover as witness.
GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW.unwrap_or(C2::zero())))?,
// The computation of `cf2_u_i.x` requires the randomness `r_bits`,
// the commitments `cmE` in CommittedInstances, and the cross term
// commitment `cmT`.
&r_bits,
vec![U_i.cmE, cmT, U_i1.cmE],
)?;

// C.3. nifs.verify, obtains cf1_U_{i+1} by folding cf1_u_i & cf_U_i, and then cf_U_{i+1}
// by folding cf2_u_i & cf1_U_{i+1}.
Expand Down
108 changes: 32 additions & 76 deletions folding-schemes/src/folding/protogalaxy/circuits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,14 @@ use ark_ff::PrimeField;
use ark_poly::{univariate::DensePolynomial, EvaluationDomain, GeneralEvaluationDomain};
use ark_r1cs_std::{
alloc::AllocVar,
boolean::Boolean,
eq::EqGadget,
fields::{fp::FpVar, FieldVar},
groups::{CurveVar, GroupOpsBounds},
poly::polynomial::univariate::dense::DensePolynomialVar,
R1CSVar, ToBitsGadget, ToConstraintFieldGadget,
};
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError};
use ark_std::{fmt::Debug, marker::PhantomData, One, Zero};
use ark_std::{fmt::Debug, marker::PhantomData, Zero};

use super::{
folding::lagrange_polys,
Expand All @@ -29,7 +28,7 @@ use crate::{
CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
CycleFoldConfig, NIFSFullGadget,
},
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
nonnative::affine::NonNativeAffineVar,
CF1, CF2,
},
frontend::FCircuit,
Expand Down Expand Up @@ -165,7 +164,7 @@ impl AugmentationGadget {
Ok((U, L_X_evals))
}

pub fn prepare_and_fold_cyclefold<
pub fn fold_cyclefold<
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
C2: CurveGroup,
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
Expand All @@ -174,32 +173,19 @@ impl AugmentationGadget {
transcript: &mut PoseidonSpongeVar<CF1<C1>>,
pp_hash: FpVar<CF1<C1>>,
mut cf_U: CycleFoldCommittedInstanceVar<C2, GC2>,
cf_u_cmWs: Vec<GC2>,
cf_u_xs: Vec<Vec<NonNativeUintVar<CF1<C1>>>>,
cf_us: Vec<CycleFoldCommittedInstanceVar<C2, GC2>>,
cf_cmTs: Vec<GC2>,
) -> Result<CycleFoldCommittedInstanceVar<C2, GC2>, SynthesisError>
where
C2::BaseField: PrimeField + Absorb,
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
{
assert_eq!(cf_u_cmWs.len(), cf_u_xs.len());
assert_eq!(cf_u_xs.len(), cf_cmTs.len());
assert_eq!(cf_us.len(), cf_cmTs.len());

// Fold the incoming CycleFold instances into the running CycleFold
// instance in a iterative way, since `NIFSFullGadget` only supports
// folding one incoming instance at a time.
for ((cmW, x), cmT) in cf_u_cmWs.into_iter().zip(cf_u_xs).zip(cf_cmTs) {
// Prepare the incoming CycleFold instance `cf_u` for the current
// iteration.
// For each CycleFold instance `cf_u`, we have `cf_u.cmE = 0`, and
// `cf_u.u = 1`.
let cf_u = CycleFoldCommittedInstanceVar {
cmE: GC2::zero(),
u: NonNativeUintVar::new_constant(ConstraintSystemRef::None, C1::BaseField::one())?,
cmW,
x,
};

for (cf_u, cmT) in cf_us.into_iter().zip(cf_cmTs) {
let cf_r_bits = CycleFoldChallengeGadget::get_challenge_gadget(
transcript,
pp_hash.clone(),
Expand Down Expand Up @@ -401,63 +387,33 @@ where

// CycleFold part
// C.1. Compute cf1_u_i.x and cf2_u_i.x
let mut r0_bits = r[0].to_bits_le()?;
let mut r1_bits = r[1].to_bits_le()?;
r0_bits.resize(C1::ScalarField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
r1_bits.resize(C1::ScalarField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
let cf1_x = [
r0_bits
.chunks(C1::BaseField::MODULUS_BIT_SIZE as usize - 1)
.map(|bits| {
let mut bits = bits.to_vec();
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
NonNativeUintVar::from(&bits)
})
.collect::<Vec<_>>(),
vec![
NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::zero())?,
NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::zero())?,
U_i.phi.x.clone(),
U_i.phi.y.clone(),
phi_stars[0].x.clone(),
phi_stars[0].y.clone(),
],
]
.concat();
let cf2_x = [
r1_bits
.chunks(C1::BaseField::MODULUS_BIT_SIZE as usize - 1)
.map(|bits| {
let mut bits = bits.to_vec();
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
NonNativeUintVar::from(&bits)
})
.collect::<Vec<_>>(),
vec![
phi_stars[0].x.clone(),
phi_stars[0].y.clone(),
u_i_phi.x.clone(),
u_i_phi.y.clone(),
U_i1.phi.x.clone(),
U_i1.phi.y.clone(),
],
]
.concat();

// C.2. Prepare incoming CycleFold instances
// C.3. Fold incoming CycleFold instances into the running instance
let cf_U_i1 =
AugmentationGadget::prepare_and_fold_cyclefold::<C1, C2, GC2, PoseidonSponge<CF1<C1>>>(
&mut transcript,
pp_hash.clone(),
cf_U_i,
vec![
GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW))?,
GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW))?,
],
vec![cf1_x, cf2_x],
vec![cf1_cmT, cf2_cmT],
// C.2. Construct `cf1_u_i` and `cf2_u_i`
let cf1_u: CycleFoldCommittedInstanceVar<C2, GC2> =
CycleFoldCommittedInstanceVar::new_incoming_from_components(
// `cf1_u_i.cmW` is provided by the prover as witness.
GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW))?,
// The computation of `cf1_u_i.x` requires the randomness `r[0]`, the
// commitments `phi` in CommittedInstances, and `phi_stars[0]`.
&r[0].to_bits_le()?,
vec![NonNativeAffineVar::zero(), U_i.phi, phi_stars[0].clone()],
)?;
let cf2_u = CycleFoldCommittedInstanceVar::new_incoming_from_components(
// `cf2_u_i.cmW` is provided by the prover as witness.
GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW))?,
// The computation of `cf2_u_i.x` requires the randomness `r[1]`, the
// commitments `phi` in CommittedInstances, and `phi_stars[0]`.
&r[1].to_bits_le()?,
vec![phi_stars[0].clone(), u_i_phi, U_i1.phi],
)?;

// C.3. Fold incoming CycleFold instances into the running instance
let cf_U_i1 = AugmentationGadget::fold_cyclefold::<C1, C2, GC2, PoseidonSponge<CF1<C1>>>(
&mut transcript,
pp_hash.clone(),
cf_U_i,
vec![cf1_u, cf2_u],
vec![cf1_cmT, cf2_cmT],
)?;

// Back to Primary Part
// P.4.b compute and check the second output of F'
Expand Down

0 comments on commit bb0dd4f

Please sign in to comment.