Skip to content

Commit bb0dd4f

Browse files
committed
Add CycleFoldCommittedInstanceVar::new_incoming_from_components to simplify the construction of incoming CF instances
1 parent d779889 commit bb0dd4f

File tree

4 files changed

+110
-157
lines changed

4 files changed

+110
-157
lines changed

folding-schemes/src/folding/circuits/cyclefold.rs

Lines changed: 45 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,12 @@ use ark_r1cs_std::{
1515
use ark_relations::r1cs::{
1616
ConstraintSynthesizer, ConstraintSystem, ConstraintSystemRef, Namespace, SynthesisError,
1717
};
18-
use ark_std::fmt::Debug;
19-
use ark_std::rand::RngCore;
20-
use ark_std::Zero;
21-
use core::{borrow::Borrow, marker::PhantomData};
18+
use ark_std::{borrow::Borrow, fmt::Debug, marker::PhantomData, rand::RngCore, One, Zero};
2219

23-
use super::{nonnative::uint::NonNativeUintVar, CF1, CF2};
20+
use super::{
21+
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
22+
CF1, CF2,
23+
};
2424
use crate::arith::r1cs::{extract_w_x, R1CS};
2525
use crate::commitment::CommitmentScheme;
2626
use crate::constants::NOVA_N_BITS_RO;
@@ -46,6 +46,7 @@ where
4646
pub cmW: GC,
4747
pub x: Vec<NonNativeUintVar<CF2<C>>>,
4848
}
49+
4950
impl<C, GC> AllocVar<CycleFoldCommittedInstance<C>, CF2<C>> for CycleFoldCommittedInstanceVar<C, GC>
5051
where
5152
C: CurveGroup,
@@ -127,6 +128,45 @@ where
127128
}
128129
}
129130

131+
impl<C2, GC2> CycleFoldCommittedInstanceVar<C2, GC2>
132+
where
133+
C2: CurveGroup,
134+
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
135+
C2::BaseField: PrimeField,
136+
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
137+
{
138+
/// Creates a new `CycleFoldCommittedInstanceVar` from the given components.
139+
pub fn new_incoming_from_components<C1: CurveGroup<ScalarField = C2::BaseField>>(
140+
cmW: GC2,
141+
r_bits: &[Boolean<CF2<C2>>],
142+
points: Vec<NonNativeAffineVar<C1>>,
143+
) -> Result<Self, SynthesisError> {
144+
// Construct the public inputs `x` from `r_bits` and `points`.
145+
// Note that the underlying field can only safely store
146+
// `CF1::<C2>::MODULUS_BIT_SIZE - 1` bits, but `r_bits` may be longer
147+
// than that.
148+
// Thus, we need to chunk `r_bits` into pieces and convert each piece
149+
// to a `NonNativeUintVar`.
150+
let x = r_bits
151+
.chunks(CF1::<C2>::MODULUS_BIT_SIZE as usize - 1)
152+
.map(|bits| {
153+
let mut bits = bits.to_vec();
154+
bits.resize(CF1::<C2>::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
155+
NonNativeUintVar::from(&bits)
156+
})
157+
.chain(points.into_iter().flat_map(|p| [p.x, p.y]))
158+
.collect::<Vec<_>>();
159+
Ok(Self {
160+
// `cmE` is always zero for incoming instances
161+
cmE: GC2::zero(),
162+
// `u` is always one for incoming instances
163+
u: NonNativeUintVar::new_constant(ConstraintSystemRef::None, CF1::<C2>::one())?,
164+
cmW,
165+
x,
166+
})
167+
}
168+
}
169+
130170
impl<C: CurveGroup> CycleFoldCommittedInstance<C>
131171
where
132172
<C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField + Absorb,

folding-schemes/src/folding/hypernova/circuits.rs

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ use crate::folding::{
3535
CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
3636
CycleFoldConfig, NIFSFullGadget,
3737
},
38-
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
38+
nonnative::affine::NonNativeAffineVar,
3939
sum_check::{IOPProofVar, SumCheckVerifierGadget, VPAuxInfoVar},
4040
utils::EqEvalGadget,
4141
CF1, CF2,
@@ -812,41 +812,22 @@ where
812812
let x = FpVar::new_input(cs.clone(), || Ok(self.x.unwrap_or(u_i1_x_base.value()?)))?;
813813
x.enforce_equal(&is_basecase.select(&u_i1_x_base, &u_i1_x)?)?;
814814

815-
// convert rho_bits of the rho_vec to a `NonNativeFieldVar`
816-
let mut rho_bits_resized = rho_bits.clone();
817-
rho_bits_resized.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
818-
let rho_nonnat = NonNativeUintVar::from(&rho_bits_resized);
819-
820815
// CycleFold part
821-
// C.1. Compute cf1_u_i.x and cf2_u_i.x
822-
let cf_x: Vec<NonNativeUintVar<CF2<C2>>> = [
823-
vec![rho_nonnat],
816+
// C.1. Compute `cf_u_i.x`
817+
// C.2. Construct `cf_u_i`
818+
let cf_u_i = CycleFoldCommittedInstanceVar::new_incoming_from_components(
819+
// `cf_u_i.cmW` is provided by the prover as witness.
820+
GC2::new_witness(cs.clone(), || Ok(self.cf_u_i_cmW.unwrap_or(C2::zero())))?,
821+
// The computation of `cf_u_i.x` requires the randomness `rho_bits`
822+
// and the commitments `C` in LCCCS and CCCS instances.
823+
&rho_bits,
824824
all_Us
825-
.iter()
826-
.flat_map(|U| vec![U.C.x.clone(), U.C.y.clone()])
825+
.into_iter()
826+
.map(|U| U.C)
827+
.chain(all_us.into_iter().map(|u| u.C))
828+
.chain(vec![U_i1.C])
827829
.collect(),
828-
all_us
829-
.iter()
830-
.flat_map(|u| vec![u.C.x.clone(), u.C.y.clone()])
831-
.collect(),
832-
vec![U_i1.C.x, U_i1.C.y],
833-
]
834-
.concat();
835-
836-
// ensure that cf_u has as public inputs the C from main instances U_i, u_i, U_i+1
837-
// coordinates of the commitments.
838-
// C.2. Construct `cf_u_i`
839-
let cf_u_i = CycleFoldCommittedInstanceVar::<C2, GC2> {
840-
// cf1_u_i.cmE = 0. Notice that we enforce cmE to be equal to 0 since it is allocated
841-
// as 0.
842-
cmE: GC2::zero(),
843-
// cf1_u_i.u = 1
844-
u: NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::one())?,
845-
// cf_u_i.cmW is provided by the prover as witness
846-
cmW: GC2::new_witness(cs.clone(), || Ok(self.cf_u_i_cmW.unwrap_or(C2::zero())))?,
847-
// cf_u_i.x is computed in step 1
848-
x: cf_x,
849-
};
830+
)?;
850831

851832
// C.3. nifs.verify (fold_committed_instance), obtains cf_U_{i+1} by folding cf_u_i & cf_U_i.
852833
// compute cf_r = H(cf_u_i, cf_U_i, cf_cmT)

folding-schemes/src/folding/nova/circuits.rs

Lines changed: 19 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use ark_r1cs_std::{
1717
R1CSVar, ToConstraintFieldGadget,
1818
};
1919
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError};
20-
use ark_std::{fmt::Debug, One, Zero};
20+
use ark_std::{fmt::Debug, Zero};
2121
use core::{borrow::Borrow, marker::PhantomData};
2222

2323
use super::{CommittedInstance, NovaCycleFoldConfig};
@@ -27,7 +27,7 @@ use crate::folding::circuits::{
2727
CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
2828
CycleFoldConfig, NIFSFullGadget,
2929
},
30-
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
30+
nonnative::affine::NonNativeAffineVar,
3131
CF1, CF2,
3232
};
3333
use crate::frontend::FCircuit;
@@ -405,12 +405,6 @@ where
405405
cmT.clone(),
406406
)?;
407407
let r = Boolean::le_bits_to_fp_var(&r_bits)?;
408-
// Also convert r_bits to a `NonNativeFieldVar`
409-
let r_nonnat = {
410-
let mut bits = r_bits;
411-
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
412-
NonNativeUintVar::from(&bits)
413-
};
414408

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

443437
// CycleFold part
444438
// C.1. Compute cf1_u_i.x and cf2_u_i.x
445-
let cfW_x = vec![
446-
r_nonnat.clone(),
447-
U_i.cmW.x,
448-
U_i.cmW.y,
449-
u_i.cmW.x,
450-
u_i.cmW.y,
451-
U_i1.cmW.x,
452-
U_i1.cmW.y,
453-
];
454-
let cfE_x = vec![
455-
r_nonnat, U_i.cmE.x, U_i.cmE.y, cmT.x, cmT.y, U_i1.cmE.x, U_i1.cmE.y,
456-
];
457-
458-
// ensure that cf1_u & cf2_u have as public inputs the cmW & cmE from main instances U_i,
459-
// u_i, U_i+1 coordinates of the commitments
460439
// C.2. Construct `cf1_u_i` and `cf2_u_i`
461-
let cf1_u_i = CycleFoldCommittedInstanceVar {
462-
// cf1_u_i.cmE = 0
463-
cmE: GC2::zero(),
464-
// cf1_u_i.u = 1
465-
u: NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::one())?,
466-
// cf1_u_i.cmW is provided by the prover as witness
467-
cmW: GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW.unwrap_or(C2::zero())))?,
468-
// cf1_u_i.x is computed in step 1
469-
x: cfW_x,
470-
};
471-
let cf2_u_i = CycleFoldCommittedInstanceVar {
472-
// cf2_u_i.cmE = 0
473-
cmE: GC2::zero(),
474-
// cf2_u_i.u = 1
475-
u: NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::one())?,
476-
// cf2_u_i.cmW is provided by the prover as witness
477-
cmW: GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW.unwrap_or(C2::zero())))?,
478-
// cf2_u_i.x is computed in step 1
479-
x: cfE_x,
480-
};
440+
let cf1_u_i = CycleFoldCommittedInstanceVar::new_incoming_from_components(
441+
// `cf1_u_i.cmW` is provided by the prover as witness.
442+
GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW.unwrap_or(C2::zero())))?,
443+
// The computation of `cf1_u_i.x` requires the randomness `r_bits`
444+
// and the commitments `cmW` in CommittedInstances.
445+
&r_bits,
446+
vec![U_i.cmW, u_i.cmW, U_i1.cmW],
447+
)?;
448+
let cf2_u_i = CycleFoldCommittedInstanceVar::new_incoming_from_components(
449+
// `cf2_u_i.cmW` is provided by the prover as witness.
450+
GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW.unwrap_or(C2::zero())))?,
451+
// The computation of `cf2_u_i.x` requires the randomness `r_bits`,
452+
// the commitments `cmE` in CommittedInstances, and the cross term
453+
// commitment `cmT`.
454+
&r_bits,
455+
vec![U_i.cmE, cmT, U_i1.cmE],
456+
)?;
481457

482458
// C.3. nifs.verify, obtains cf1_U_{i+1} by folding cf1_u_i & cf_U_i, and then cf_U_{i+1}
483459
// by folding cf2_u_i & cf1_U_{i+1}.

folding-schemes/src/folding/protogalaxy/circuits.rs

Lines changed: 32 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,14 @@ use ark_ff::PrimeField;
88
use ark_poly::{univariate::DensePolynomial, EvaluationDomain, GeneralEvaluationDomain};
99
use ark_r1cs_std::{
1010
alloc::AllocVar,
11-
boolean::Boolean,
1211
eq::EqGadget,
1312
fields::{fp::FpVar, FieldVar},
1413
groups::{CurveVar, GroupOpsBounds},
1514
poly::polynomial::univariate::dense::DensePolynomialVar,
1615
R1CSVar, ToBitsGadget, ToConstraintFieldGadget,
1716
};
1817
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError};
19-
use ark_std::{fmt::Debug, marker::PhantomData, One, Zero};
18+
use ark_std::{fmt::Debug, marker::PhantomData, Zero};
2019

2120
use super::{
2221
folding::lagrange_polys,
@@ -29,7 +28,7 @@ use crate::{
2928
CycleFoldChallengeGadget, CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar,
3029
CycleFoldConfig, NIFSFullGadget,
3130
},
32-
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
31+
nonnative::affine::NonNativeAffineVar,
3332
CF1, CF2,
3433
},
3534
frontend::FCircuit,
@@ -165,7 +164,7 @@ impl AugmentationGadget {
165164
Ok((U, L_X_evals))
166165
}
167166

168-
pub fn prepare_and_fold_cyclefold<
167+
pub fn fold_cyclefold<
169168
C1: CurveGroup<BaseField = C2::ScalarField, ScalarField = C2::BaseField>,
170169
C2: CurveGroup,
171170
GC2: CurveVar<C2, CF2<C2>> + ToConstraintFieldGadget<CF2<C2>>,
@@ -174,32 +173,19 @@ impl AugmentationGadget {
174173
transcript: &mut PoseidonSpongeVar<CF1<C1>>,
175174
pp_hash: FpVar<CF1<C1>>,
176175
mut cf_U: CycleFoldCommittedInstanceVar<C2, GC2>,
177-
cf_u_cmWs: Vec<GC2>,
178-
cf_u_xs: Vec<Vec<NonNativeUintVar<CF1<C1>>>>,
176+
cf_us: Vec<CycleFoldCommittedInstanceVar<C2, GC2>>,
179177
cf_cmTs: Vec<GC2>,
180178
) -> Result<CycleFoldCommittedInstanceVar<C2, GC2>, SynthesisError>
181179
where
182180
C2::BaseField: PrimeField + Absorb,
183181
for<'a> &'a GC2: GroupOpsBounds<'a, C2, GC2>,
184182
{
185-
assert_eq!(cf_u_cmWs.len(), cf_u_xs.len());
186-
assert_eq!(cf_u_xs.len(), cf_cmTs.len());
183+
assert_eq!(cf_us.len(), cf_cmTs.len());
187184

188185
// Fold the incoming CycleFold instances into the running CycleFold
189186
// instance in a iterative way, since `NIFSFullGadget` only supports
190187
// folding one incoming instance at a time.
191-
for ((cmW, x), cmT) in cf_u_cmWs.into_iter().zip(cf_u_xs).zip(cf_cmTs) {
192-
// Prepare the incoming CycleFold instance `cf_u` for the current
193-
// iteration.
194-
// For each CycleFold instance `cf_u`, we have `cf_u.cmE = 0`, and
195-
// `cf_u.u = 1`.
196-
let cf_u = CycleFoldCommittedInstanceVar {
197-
cmE: GC2::zero(),
198-
u: NonNativeUintVar::new_constant(ConstraintSystemRef::None, C1::BaseField::one())?,
199-
cmW,
200-
x,
201-
};
202-
188+
for (cf_u, cmT) in cf_us.into_iter().zip(cf_cmTs) {
203189
let cf_r_bits = CycleFoldChallengeGadget::get_challenge_gadget(
204190
transcript,
205191
pp_hash.clone(),
@@ -401,63 +387,33 @@ where
401387

402388
// CycleFold part
403389
// C.1. Compute cf1_u_i.x and cf2_u_i.x
404-
let mut r0_bits = r[0].to_bits_le()?;
405-
let mut r1_bits = r[1].to_bits_le()?;
406-
r0_bits.resize(C1::ScalarField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
407-
r1_bits.resize(C1::ScalarField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
408-
let cf1_x = [
409-
r0_bits
410-
.chunks(C1::BaseField::MODULUS_BIT_SIZE as usize - 1)
411-
.map(|bits| {
412-
let mut bits = bits.to_vec();
413-
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
414-
NonNativeUintVar::from(&bits)
415-
})
416-
.collect::<Vec<_>>(),
417-
vec![
418-
NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::zero())?,
419-
NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::zero())?,
420-
U_i.phi.x.clone(),
421-
U_i.phi.y.clone(),
422-
phi_stars[0].x.clone(),
423-
phi_stars[0].y.clone(),
424-
],
425-
]
426-
.concat();
427-
let cf2_x = [
428-
r1_bits
429-
.chunks(C1::BaseField::MODULUS_BIT_SIZE as usize - 1)
430-
.map(|bits| {
431-
let mut bits = bits.to_vec();
432-
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
433-
NonNativeUintVar::from(&bits)
434-
})
435-
.collect::<Vec<_>>(),
436-
vec![
437-
phi_stars[0].x.clone(),
438-
phi_stars[0].y.clone(),
439-
u_i_phi.x.clone(),
440-
u_i_phi.y.clone(),
441-
U_i1.phi.x.clone(),
442-
U_i1.phi.y.clone(),
443-
],
444-
]
445-
.concat();
446-
447-
// C.2. Prepare incoming CycleFold instances
448-
// C.3. Fold incoming CycleFold instances into the running instance
449-
let cf_U_i1 =
450-
AugmentationGadget::prepare_and_fold_cyclefold::<C1, C2, GC2, PoseidonSponge<CF1<C1>>>(
451-
&mut transcript,
452-
pp_hash.clone(),
453-
cf_U_i,
454-
vec![
455-
GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW))?,
456-
GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW))?,
457-
],
458-
vec![cf1_x, cf2_x],
459-
vec![cf1_cmT, cf2_cmT],
390+
// C.2. Construct `cf1_u_i` and `cf2_u_i`
391+
let cf1_u: CycleFoldCommittedInstanceVar<C2, GC2> =
392+
CycleFoldCommittedInstanceVar::new_incoming_from_components(
393+
// `cf1_u_i.cmW` is provided by the prover as witness.
394+
GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW))?,
395+
// The computation of `cf1_u_i.x` requires the randomness `r[0]`, the
396+
// commitments `phi` in CommittedInstances, and `phi_stars[0]`.
397+
&r[0].to_bits_le()?,
398+
vec![NonNativeAffineVar::zero(), U_i.phi, phi_stars[0].clone()],
460399
)?;
400+
let cf2_u = CycleFoldCommittedInstanceVar::new_incoming_from_components(
401+
// `cf2_u_i.cmW` is provided by the prover as witness.
402+
GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW))?,
403+
// The computation of `cf2_u_i.x` requires the randomness `r[1]`, the
404+
// commitments `phi` in CommittedInstances, and `phi_stars[0]`.
405+
&r[1].to_bits_le()?,
406+
vec![phi_stars[0].clone(), u_i_phi, U_i1.phi],
407+
)?;
408+
409+
// C.3. Fold incoming CycleFold instances into the running instance
410+
let cf_U_i1 = AugmentationGadget::fold_cyclefold::<C1, C2, GC2, PoseidonSponge<CF1<C1>>>(
411+
&mut transcript,
412+
pp_hash.clone(),
413+
cf_U_i,
414+
vec![cf1_u, cf2_u],
415+
vec![cf1_cmT, cf2_cmT],
416+
)?;
461417

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

0 commit comments

Comments
 (0)