mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-28 14:56:40 +01:00
Reduce the number of constraints in DeciderEthCircuit (#88)
* Add a dedicated variant of `mat_vec_mul_sparse` for `NonNativeFieldVar` * Switch to a customized in-circuit nonnative implementation for efficiency * Comments and tests for `NonNativeUintVar` * Make `CycleFoldCircuit` a bit smaller * Faster trusted setup and proof generation by avoiding some nested LCs * Check the remaining limbs in a more safe way * Format * Disable the non-native checks in tests again * Clarify the group operation in `enforce_equal_unaligned` * Explain the rationale behind non-native mat-vec multiplication * Explain the difference with some other impls of `enforce_equal_unaligned` * Format
This commit is contained in:
@@ -14,13 +14,13 @@ use ark_r1cs_std::{
|
||||
alloc::{AllocVar, AllocationMode},
|
||||
boolean::Boolean,
|
||||
eq::EqGadget,
|
||||
fields::{fp::FpVar, nonnative::NonNativeFieldVar, FieldVar},
|
||||
fields::{fp::FpVar, FieldVar},
|
||||
groups::GroupOpsBounds,
|
||||
prelude::CurveVar,
|
||||
R1CSVar, ToConstraintFieldGadget,
|
||||
};
|
||||
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError};
|
||||
use ark_std::{fmt::Debug, Zero};
|
||||
use ark_std::{fmt::Debug, One, Zero};
|
||||
use core::{borrow::Borrow, marker::PhantomData};
|
||||
|
||||
use super::{
|
||||
@@ -29,9 +29,12 @@ use super::{
|
||||
},
|
||||
CommittedInstance,
|
||||
};
|
||||
use crate::folding::circuits::nonnative::{nonnative_affine_to_field_elements, NonNativeAffineVar};
|
||||
use crate::constants::N_BITS_RO;
|
||||
use crate::folding::circuits::nonnative::{
|
||||
affine::{nonnative_affine_to_field_elements, NonNativeAffineVar},
|
||||
uint::NonNativeUintVar,
|
||||
};
|
||||
use crate::frontend::FCircuit;
|
||||
use crate::{constants::N_BITS_RO, folding::circuits::nonnative::nonnative_field_var_from_le_bits};
|
||||
|
||||
/// CF1 represents the ConstraintField used for the main Nova circuit which is over E1::Fr, where
|
||||
/// E1 is the main curve where we do the folding.
|
||||
@@ -402,7 +405,11 @@ where
|
||||
)?;
|
||||
let r = Boolean::le_bits_to_fp_var(&r_bits)?;
|
||||
// Also convert r_bits to a `NonNativeFieldVar`
|
||||
let r_nonnat = nonnative_field_var_from_le_bits(cs.clone(), &r_bits)?;
|
||||
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`
|
||||
@@ -452,7 +459,7 @@ where
|
||||
// cf1_u_i.cmE = 0
|
||||
cmE: GC2::zero(),
|
||||
// cf1_u_i.u = 1
|
||||
u: NonNativeFieldVar::one(),
|
||||
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
|
||||
@@ -462,7 +469,7 @@ where
|
||||
// cf2_u_i.cmE = 0
|
||||
cmE: GC2::zero(),
|
||||
// cf2_u_i.u = 1
|
||||
u: NonNativeFieldVar::one(),
|
||||
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
|
||||
@@ -482,7 +489,11 @@ where
|
||||
cf1_cmT.clone(),
|
||||
)?;
|
||||
// Convert cf1_r_bits to a `NonNativeFieldVar`
|
||||
let cf1_r_nonnat = nonnative_field_var_from_le_bits(cs.clone(), &cf1_r_bits)?;
|
||||
let cf1_r_nonnat = {
|
||||
let mut bits = cf1_r_bits.clone();
|
||||
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
|
||||
NonNativeUintVar::from(&bits)
|
||||
};
|
||||
// Fold cf1_u_i & cf_U_i into cf1_U_{i+1}
|
||||
let cf1_U_i1 = NIFSFullGadget::<C2, GC2>::fold_committed_instance(
|
||||
cf1_r_bits,
|
||||
@@ -500,7 +511,11 @@ where
|
||||
cf2_u_i.clone(),
|
||||
cf2_cmT.clone(),
|
||||
)?;
|
||||
let cf2_r_nonnat = nonnative_field_var_from_le_bits(cs.clone(), &cf2_r_bits)?;
|
||||
let cf2_r_nonnat = {
|
||||
let mut bits = cf2_r_bits.clone();
|
||||
bits.resize(C1::BaseField::MODULUS_BIT_SIZE as usize, Boolean::FALSE);
|
||||
NonNativeUintVar::from(&bits)
|
||||
};
|
||||
let cf_U_i1 = NIFSFullGadget::<C2, GC2>::fold_committed_instance(
|
||||
cf2_r_bits,
|
||||
cf2_r_nonnat,
|
||||
|
||||
@@ -16,7 +16,7 @@ use ark_r1cs_std::{
|
||||
alloc::{AllocVar, AllocationMode},
|
||||
boolean::Boolean,
|
||||
eq::EqGadget,
|
||||
fields::{fp::FpVar, nonnative::NonNativeFieldVar, FieldVar},
|
||||
fields::{fp::FpVar, FieldVar},
|
||||
groups::GroupOpsBounds,
|
||||
prelude::CurveVar,
|
||||
ToConstraintFieldGadget,
|
||||
@@ -29,7 +29,7 @@ use core::{borrow::Borrow, marker::PhantomData};
|
||||
use super::circuits::CF2;
|
||||
use super::CommittedInstance;
|
||||
use crate::constants::N_BITS_RO;
|
||||
use crate::folding::circuits::nonnative::nonnative_field_var_to_constraint_field;
|
||||
use crate::folding::circuits::nonnative::uint::NonNativeUintVar;
|
||||
use crate::Error;
|
||||
|
||||
// public inputs length for the CycleFoldCircuit: |[r, p1.x,y, p2.x,y, p3.x,y]|
|
||||
@@ -43,9 +43,9 @@ where
|
||||
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
|
||||
{
|
||||
pub cmE: GC,
|
||||
pub u: NonNativeFieldVar<C::ScalarField, CF2<C>>,
|
||||
pub u: NonNativeUintVar<CF2<C>>,
|
||||
pub cmW: GC,
|
||||
pub x: Vec<NonNativeFieldVar<C::ScalarField, CF2<C>>>,
|
||||
pub x: Vec<NonNativeUintVar<CF2<C>>>,
|
||||
}
|
||||
impl<C, GC> AllocVar<CommittedInstance<C>, CF2<C>> for CycleFoldCommittedInstanceVar<C, GC>
|
||||
where
|
||||
@@ -64,16 +64,8 @@ where
|
||||
|
||||
let cmE = GC::new_variable(cs.clone(), || Ok(val.borrow().cmE), mode)?;
|
||||
let cmW = GC::new_variable(cs.clone(), || Ok(val.borrow().cmW), mode)?;
|
||||
let u = NonNativeFieldVar::<C::ScalarField, CF2<C>>::new_variable(
|
||||
cs.clone(),
|
||||
|| Ok(val.borrow().u),
|
||||
mode,
|
||||
)?;
|
||||
let x = Vec::<NonNativeFieldVar<C::ScalarField, CF2<C>>>::new_variable(
|
||||
cs.clone(),
|
||||
|| Ok(val.borrow().x.clone()),
|
||||
mode,
|
||||
)?;
|
||||
let u = NonNativeUintVar::new_variable(cs.clone(), || Ok(val.borrow().u), mode)?;
|
||||
let x = Vec::new_variable(cs.clone(), || Ok(val.borrow().x.clone()), mode)?;
|
||||
|
||||
Ok(Self { cmE, u, cmW, x })
|
||||
})
|
||||
@@ -99,10 +91,10 @@ where
|
||||
let is_inf = cmE_is_inf.double()? + cmW_is_inf;
|
||||
|
||||
Ok([
|
||||
nonnative_field_var_to_constraint_field(&self.u)?,
|
||||
self.u.to_constraint_field()?,
|
||||
self.x
|
||||
.iter()
|
||||
.map(nonnative_field_var_to_constraint_field)
|
||||
.map(|i| i.to_constraint_field())
|
||||
.collect::<Result<Vec<_>, _>>()?
|
||||
.concat(),
|
||||
cmE_elems,
|
||||
@@ -193,7 +185,7 @@ where
|
||||
pub fn fold_committed_instance(
|
||||
// assumes that r_bits is equal to r_nonnat just that in a different format
|
||||
r_bits: Vec<Boolean<CF2<C>>>,
|
||||
r_nonnat: NonNativeFieldVar<C::ScalarField, CF2<C>>,
|
||||
r_nonnat: NonNativeUintVar<CF2<C>>,
|
||||
cmT: GC,
|
||||
ci1: CycleFoldCommittedInstanceVar<C, GC>,
|
||||
// ci2 is assumed to be always with cmE=0, u=1 (checks done previous to this method)
|
||||
@@ -202,20 +194,23 @@ where
|
||||
Ok(CycleFoldCommittedInstanceVar {
|
||||
cmE: cmT.scalar_mul_le(r_bits.iter())? + ci1.cmE,
|
||||
cmW: ci1.cmW + ci2.cmW.scalar_mul_le(r_bits.iter())?,
|
||||
u: ci1.u + r_nonnat.clone(),
|
||||
u: ci1.u.add_no_align(&r_nonnat).modulo::<C::ScalarField>()?,
|
||||
x: ci1
|
||||
.x
|
||||
.iter()
|
||||
.zip(ci2.x)
|
||||
.map(|(a, b)| a + &r_nonnat * &b)
|
||||
.collect::<Vec<_>>(),
|
||||
.map(|(a, b)| {
|
||||
a.add_no_align(&r_nonnat.mul_no_align(&b)?)
|
||||
.modulo::<C::ScalarField>()
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn verify(
|
||||
// assumes that r_bits is equal to r_nonnat just that in a different format
|
||||
r_bits: Vec<Boolean<CF2<C>>>,
|
||||
r_nonnat: NonNativeFieldVar<C::ScalarField, CF2<C>>,
|
||||
r_nonnat: NonNativeUintVar<CF2<C>>,
|
||||
cmT: GC,
|
||||
ci1: CycleFoldCommittedInstanceVar<C, GC>,
|
||||
// ci2 is assumed to be always with cmE=0, u=1 (checks done previous to this method)
|
||||
@@ -225,9 +220,11 @@ where
|
||||
let ci = Self::fold_committed_instance(r_bits, r_nonnat, cmT, ci1, ci2)?;
|
||||
|
||||
ci.cmE.enforce_equal(&ci3.cmE)?;
|
||||
ci.u.enforce_equal(&ci3.u)?;
|
||||
ci.u.enforce_equal_unaligned(&ci3.u)?;
|
||||
ci.cmW.enforce_equal(&ci3.cmW)?;
|
||||
ci.x.enforce_equal(&ci3.x)?;
|
||||
for (x, y) in ci.x.iter().zip(ci3.x.iter()) {
|
||||
x.enforce_equal_unaligned(y)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -316,7 +313,6 @@ pub struct CycleFoldCircuit<C: CurveGroup, GC: CurveVar<C, CF2<C>>> {
|
||||
pub r_bits: Option<Vec<bool>>,
|
||||
pub p1: Option<C>,
|
||||
pub p2: Option<C>,
|
||||
pub p3: Option<C>,
|
||||
pub x: Option<Vec<CF2<C>>>, // public inputs (cf_u_{i+1}.x)
|
||||
}
|
||||
impl<C: CurveGroup, GC: CurveVar<C, CF2<C>>> CycleFoldCircuit<C, GC> {
|
||||
@@ -326,7 +322,6 @@ impl<C: CurveGroup, GC: CurveVar<C, CF2<C>>> CycleFoldCircuit<C, GC> {
|
||||
r_bits: None,
|
||||
p1: None,
|
||||
p2: None,
|
||||
p3: None,
|
||||
x: None,
|
||||
}
|
||||
}
|
||||
@@ -344,7 +339,11 @@ where
|
||||
})?;
|
||||
let p1 = GC::new_witness(cs.clone(), || Ok(self.p1.unwrap_or(C::zero())))?;
|
||||
let p2 = GC::new_witness(cs.clone(), || Ok(self.p2.unwrap_or(C::zero())))?;
|
||||
let p3 = GC::new_witness(cs.clone(), || Ok(self.p3.unwrap_or(C::zero())))?;
|
||||
// Fold the original Nova instances natively in CycleFold
|
||||
// For the cmW we're computing: U_i1.cmW = U_i.cmW + r * u_i.cmW
|
||||
// For the cmE we're computing: U_i1.cmE = U_i.cmE + r * cmT + r^2 * u_i.cmE, where u_i.cmE
|
||||
// is assumed to be 0, so, U_i1.cmE = U_i.cmE + r * cmT
|
||||
let p3 = &p1 + p2.scalar_mul_le(r_bits.iter())?;
|
||||
|
||||
let x = Vec::<FpVar<CF2<C>>>::new_input(cs.clone(), || {
|
||||
Ok(self.x.unwrap_or(vec![CF2::<C>::zero(); CF_IO_LEN]))
|
||||
@@ -356,19 +355,13 @@ where
|
||||
let r: FpVar<CF2<C>> = Boolean::le_bits_to_fp_var(&r_bits)?;
|
||||
let points_coords: Vec<FpVar<CF2<C>>> = [
|
||||
vec![r],
|
||||
p1.clone().to_constraint_field()?[..2].to_vec(),
|
||||
p2.clone().to_constraint_field()?[..2].to_vec(),
|
||||
p3.clone().to_constraint_field()?[..2].to_vec(),
|
||||
p1.to_constraint_field()?[..2].to_vec(),
|
||||
p2.to_constraint_field()?[..2].to_vec(),
|
||||
p3.to_constraint_field()?[..2].to_vec(),
|
||||
]
|
||||
.concat();
|
||||
points_coords.enforce_equal(&x)?;
|
||||
|
||||
// Fold the original Nova instances natively in CycleFold
|
||||
// For the cmW we're checking: U_i1.cmW == U_i.cmW + r * u_i.cmW
|
||||
// For the cmE we're checking: U_i1.cmE == U_i.cmE + r * cmT + r^2 * u_i.cmE, where u_i.cmE
|
||||
// is assumed to be 0, so, U_i1.cmE == U_i.cmE + r * cmT
|
||||
p3.enforce_equal(&(p1 + p2.scalar_mul_le(r_bits.iter())?))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -429,7 +422,6 @@ pub mod tests {
|
||||
r_bits: Some(r_bits.clone()),
|
||||
p1: Some(ci1.clone().cmW),
|
||||
p2: Some(ci2.clone().cmW),
|
||||
p3: Some(ci3.clone().cmW),
|
||||
x: Some(cfW_u_i_x.clone()),
|
||||
};
|
||||
cfW_circuit.generate_constraints(cs.clone()).unwrap();
|
||||
@@ -449,7 +441,6 @@ pub mod tests {
|
||||
r_bits: Some(r_bits.clone()),
|
||||
p1: Some(ci1.clone().cmE),
|
||||
p2: Some(cmT),
|
||||
p3: Some(ci3.clone().cmE),
|
||||
x: Some(cfE_u_i_x.clone()),
|
||||
};
|
||||
cfE_circuit.generate_constraints(cs.clone()).unwrap();
|
||||
@@ -462,8 +453,7 @@ pub mod tests {
|
||||
|
||||
let cs = ConstraintSystem::<Fq>::new_ref();
|
||||
|
||||
let r_nonnatVar =
|
||||
NonNativeFieldVar::<Fr, Fq>::new_witness(cs.clone(), || Ok(r_Fr)).unwrap();
|
||||
let r_nonnatVar = NonNativeUintVar::<Fq>::new_witness(cs.clone(), || Ok(r_Fr)).unwrap();
|
||||
let r_bitsVar = Vec::<Boolean<Fq>>::new_witness(cs.clone(), || Ok(r_bits)).unwrap();
|
||||
|
||||
let ci1Var =
|
||||
|
||||
@@ -13,7 +13,7 @@ use super::{circuits::CF2, nifs::NIFS, CommittedInstance, Nova};
|
||||
use crate::commitment::{
|
||||
kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme,
|
||||
};
|
||||
use crate::folding::circuits::nonnative::NonNativeAffineVar;
|
||||
use crate::folding::circuits::nonnative::affine::NonNativeAffineVar;
|
||||
use crate::frontend::FCircuit;
|
||||
use crate::Error;
|
||||
use crate::{Decider as DeciderTrait, FoldingScheme};
|
||||
|
||||
@@ -9,7 +9,7 @@ use ark_r1cs_std::{
|
||||
alloc::{AllocVar, AllocationMode},
|
||||
boolean::Boolean,
|
||||
eq::EqGadget,
|
||||
fields::{fp::FpVar, nonnative::NonNativeFieldVar, FieldVar},
|
||||
fields::{fp::FpVar, FieldVar},
|
||||
groups::GroupOpsBounds,
|
||||
poly::{domain::Radix2DomainVar, evaluations::univariate::EvaluationsVar},
|
||||
prelude::CurveVar,
|
||||
@@ -22,7 +22,10 @@ use core::{borrow::Borrow, marker::PhantomData};
|
||||
use super::{circuits::ChallengeGadget, nifs::NIFS};
|
||||
use crate::ccs::r1cs::R1CS;
|
||||
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme};
|
||||
use crate::folding::circuits::nonnative::{nonnative_affine_to_field_elements, NonNativeAffineVar};
|
||||
use crate::folding::circuits::nonnative::{
|
||||
affine::{nonnative_affine_to_field_elements, NonNativeAffineVar},
|
||||
uint::NonNativeUintVar,
|
||||
};
|
||||
use crate::folding::nova::{
|
||||
circuits::{CommittedInstanceVar, CF1, CF2},
|
||||
CommittedInstance, Nova, Witness,
|
||||
@@ -33,40 +36,54 @@ use crate::transcript::{
|
||||
Transcript, TranscriptVar,
|
||||
};
|
||||
use crate::utils::{
|
||||
gadgets::{hadamard, mat_vec_mul_sparse, vec_add, vec_scalar_mul, SparseMatrixVar},
|
||||
gadgets::{MatrixGadget, SparseMatrixVar, VectorGadget},
|
||||
vec::poly_from_vec,
|
||||
};
|
||||
use crate::Error;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RelaxedR1CSGadget<F: PrimeField, CF: PrimeField, FV: FieldVar<F, CF>> {
|
||||
_f: PhantomData<F>,
|
||||
_cf: PhantomData<CF>,
|
||||
_fv: PhantomData<FV>,
|
||||
}
|
||||
impl<F: PrimeField, CF: PrimeField, FV: FieldVar<F, CF>> RelaxedR1CSGadget<F, CF, FV> {
|
||||
/// performs the RelaxedR1CS check (Az∘Bz==uCz+E)
|
||||
pub fn check(
|
||||
r1cs: R1CSVar<F, CF, FV>,
|
||||
E: Vec<FV>,
|
||||
u: FV,
|
||||
z: Vec<FV>,
|
||||
pub struct RelaxedR1CSGadget {}
|
||||
impl RelaxedR1CSGadget {
|
||||
/// performs the RelaxedR1CS check for native variables (Az∘Bz==uCz+E)
|
||||
pub fn check_native<F: PrimeField>(
|
||||
r1cs: R1CSVar<F, F, FpVar<F>>,
|
||||
E: Vec<FpVar<F>>,
|
||||
u: FpVar<F>,
|
||||
z: Vec<FpVar<F>>,
|
||||
) -> Result<(), SynthesisError> {
|
||||
let Az = mat_vec_mul_sparse(r1cs.A, z.clone());
|
||||
let Bz = mat_vec_mul_sparse(r1cs.B, z.clone());
|
||||
let Cz = mat_vec_mul_sparse(r1cs.C, z.clone());
|
||||
let uCz = vec_scalar_mul(&Cz, &u);
|
||||
let uCzE = vec_add(&uCz, &E)?;
|
||||
let AzBz = hadamard(&Az, &Bz)?;
|
||||
for i in 0..AzBz.len() {
|
||||
AzBz[i].enforce_equal(&uCzE[i].clone())?;
|
||||
}
|
||||
let Az = r1cs.A.mul_vector(&z)?;
|
||||
let Bz = r1cs.B.mul_vector(&z)?;
|
||||
let Cz = r1cs.C.mul_vector(&z)?;
|
||||
let uCzE = Cz.mul_scalar(&u)?.add(&E)?;
|
||||
let AzBz = Az.hadamard(&Bz)?;
|
||||
AzBz.enforce_equal(&uCzE)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// performs the RelaxedR1CS check for non-native variables (Az∘Bz==uCz+E)
|
||||
pub fn check_nonnative<F: PrimeField, CF: PrimeField>(
|
||||
r1cs: R1CSVar<F, CF, NonNativeUintVar<CF>>,
|
||||
E: Vec<NonNativeUintVar<CF>>,
|
||||
u: NonNativeUintVar<CF>,
|
||||
z: Vec<NonNativeUintVar<CF>>,
|
||||
) -> Result<(), SynthesisError> {
|
||||
// First we do addition and multiplication without mod F's order
|
||||
let Az = r1cs.A.mul_vector(&z)?;
|
||||
let Bz = r1cs.B.mul_vector(&z)?;
|
||||
let Cz = r1cs.C.mul_vector(&z)?;
|
||||
let uCzE = Cz.mul_scalar(&u)?.add(&E)?;
|
||||
let AzBz = Az.hadamard(&Bz)?;
|
||||
|
||||
// Then we compare the results by checking if they are congruent
|
||||
// modulo the field order
|
||||
AzBz.into_iter()
|
||||
.zip(uCzE)
|
||||
.try_for_each(|(a, b)| a.enforce_congruent::<F>(&b))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct R1CSVar<F: PrimeField, CF: PrimeField, FV: FieldVar<F, CF>> {
|
||||
pub struct R1CSVar<F: PrimeField, CF: PrimeField, FV: AllocVar<F, CF>> {
|
||||
_f: PhantomData<F>,
|
||||
_cf: PhantomData<CF>,
|
||||
_fv: PhantomData<FV>,
|
||||
@@ -79,7 +96,7 @@ impl<F, CF, FV> AllocVar<R1CS<F>, CF> for R1CSVar<F, CF, FV>
|
||||
where
|
||||
F: PrimeField,
|
||||
CF: PrimeField,
|
||||
FV: FieldVar<F, CF>,
|
||||
FV: AllocVar<F, CF>,
|
||||
{
|
||||
fn new_variable<T: Borrow<R1CS<F>>>(
|
||||
cs: impl Into<Namespace<CF>>,
|
||||
@@ -146,10 +163,10 @@ where
|
||||
/// non-native representation, since it is used to represent the CycleFold witness.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CycleFoldWitnessVar<C: CurveGroup> {
|
||||
pub E: Vec<NonNativeFieldVar<C::ScalarField, CF2<C>>>,
|
||||
pub rE: NonNativeFieldVar<C::ScalarField, CF2<C>>,
|
||||
pub W: Vec<NonNativeFieldVar<C::ScalarField, CF2<C>>>,
|
||||
pub rW: NonNativeFieldVar<C::ScalarField, CF2<C>>,
|
||||
pub E: Vec<NonNativeUintVar<CF2<C>>>,
|
||||
pub rE: NonNativeUintVar<CF2<C>>,
|
||||
pub W: Vec<NonNativeUintVar<CF2<C>>>,
|
||||
pub rW: NonNativeUintVar<CF2<C>>,
|
||||
}
|
||||
|
||||
impl<C> AllocVar<Witness<C>, CF2<C>> for CycleFoldWitnessVar<C>
|
||||
@@ -165,21 +182,11 @@ where
|
||||
f().and_then(|val| {
|
||||
let cs = cs.into();
|
||||
|
||||
let E: Vec<NonNativeFieldVar<C::ScalarField, CF2<C>>> =
|
||||
Vec::new_variable(cs.clone(), || Ok(val.borrow().E.clone()), mode)?;
|
||||
let rE = NonNativeFieldVar::<C::ScalarField, CF2<C>>::new_variable(
|
||||
cs.clone(),
|
||||
|| Ok(val.borrow().rE),
|
||||
mode,
|
||||
)?;
|
||||
let E = Vec::new_variable(cs.clone(), || Ok(val.borrow().E.clone()), mode)?;
|
||||
let rE = NonNativeUintVar::new_variable(cs.clone(), || Ok(val.borrow().rE), mode)?;
|
||||
|
||||
let W: Vec<NonNativeFieldVar<C::ScalarField, CF2<C>>> =
|
||||
Vec::new_variable(cs.clone(), || Ok(val.borrow().W.clone()), mode)?;
|
||||
let rW = NonNativeFieldVar::<C::ScalarField, CF2<C>>::new_variable(
|
||||
cs.clone(),
|
||||
|| Ok(val.borrow().rW),
|
||||
mode,
|
||||
)?;
|
||||
let W = Vec::new_variable(cs.clone(), || Ok(val.borrow().W.clone()), mode)?;
|
||||
let rW = NonNativeUintVar::new_variable(cs.clone(), || Ok(val.borrow().rW), mode)?;
|
||||
|
||||
Ok(Self { E, rE, W, rW })
|
||||
})
|
||||
@@ -404,18 +411,13 @@ where
|
||||
// 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_i1.E.clone(),
|
||||
U_i1.u.clone(),
|
||||
z_U1,
|
||||
)?;
|
||||
RelaxedR1CSGadget::check_native(r1cs, W_i1.E.clone(), U_i1.u.clone(), z_U1)?;
|
||||
|
||||
// 2. u_i.cmE==cm(0), u_i.u==1
|
||||
// Here zero is the x & y coordinates of the zero point affine representation.
|
||||
let zero = NonNativeFieldVar::<C1::BaseField, C1::ScalarField>::zero();
|
||||
u_i.cmE.x.enforce_equal(&zero)?;
|
||||
u_i.cmE.y.enforce_equal(&zero)?;
|
||||
let zero = NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::zero())?;
|
||||
u_i.cmE.x.enforce_equal_unaligned(&zero)?;
|
||||
u_i.cmE.y.enforce_equal_unaligned(&zero)?;
|
||||
(u_i.u.is_one()?).enforce_equal(&Boolean::TRUE)?;
|
||||
|
||||
// 3.a u_i.x[0] == H(i, z_0, z_i, U_i)
|
||||
@@ -470,20 +472,15 @@ where
|
||||
PedersenGadget::<C2, GC2>::commit(H, G, cf_W_i_W_bits?, cf_W_i.rW.to_bits_le()?)?;
|
||||
cf_U_i.cmW.enforce_equal(&computed_cmW)?;
|
||||
|
||||
let cf_r1cs = R1CSVar::<
|
||||
C1::BaseField,
|
||||
CF1<C1>,
|
||||
NonNativeFieldVar<C1::BaseField, CF1<C1>>,
|
||||
>::new_witness(cs.clone(), || Ok(self.cf_r1cs.clone()))?;
|
||||
let cf_r1cs =
|
||||
R1CSVar::<C1::BaseField, CF1<C1>, NonNativeUintVar<CF1<C1>>>::new_witness(
|
||||
cs.clone(),
|
||||
|| Ok(self.cf_r1cs.clone()),
|
||||
)?;
|
||||
|
||||
// 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::<
|
||||
C2::ScalarField,
|
||||
CF1<C1>,
|
||||
NonNativeFieldVar<C2::ScalarField, CF1<C1>>,
|
||||
>::check(cf_r1cs, cf_W_i.E, cf_U_i.u.clone(), cf_z_U)?;
|
||||
let cf_z_U = [vec![cf_U_i.u.clone()], cf_U_i.x.to_vec(), cf_W_i.W.to_vec()].concat();
|
||||
RelaxedR1CSGadget::check_nonnative(cf_r1cs, cf_W_i.E, cf_U_i.u.clone(), cf_z_U)?;
|
||||
}
|
||||
|
||||
// 6. check KZG challenges
|
||||
@@ -632,7 +629,7 @@ pub mod tests {
|
||||
let uVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(rel_r1cs.u)).unwrap();
|
||||
let r1csVar = R1CSVar::<Fr, Fr, FpVar<Fr>>::new_witness(cs.clone(), || Ok(r1cs)).unwrap();
|
||||
|
||||
RelaxedR1CSGadget::<Fr, Fr, FpVar<Fr>>::check(r1csVar, EVar, uVar, zVar).unwrap();
|
||||
RelaxedR1CSGadget::check_native(r1csVar, EVar, uVar, zVar).unwrap();
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
}
|
||||
|
||||
@@ -663,7 +660,7 @@ pub mod tests {
|
||||
let uVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(relaxed_r1cs.u)).unwrap();
|
||||
let r1csVar = R1CSVar::<Fr, Fr, FpVar<Fr>>::new_witness(cs.clone(), || Ok(r1cs)).unwrap();
|
||||
|
||||
RelaxedR1CSGadget::<Fr, Fr, FpVar<Fr>>::check(r1csVar, EVar, uVar, zVar).unwrap();
|
||||
RelaxedR1CSGadget::check_native(r1csVar, EVar, uVar, zVar).unwrap();
|
||||
assert!(cs.is_satisfied().unwrap());
|
||||
}
|
||||
|
||||
@@ -752,20 +749,16 @@ pub mod tests {
|
||||
let uVar = FpVar::<Fq>::new_witness(cs.clone(), || Ok(relaxed_r1cs.u)).unwrap();
|
||||
let r1csVar =
|
||||
R1CSVar::<Fq, Fq, FpVar<Fq>>::new_witness(cs.clone(), || Ok(r1cs.clone())).unwrap();
|
||||
RelaxedR1CSGadget::<Fq, Fq, FpVar<Fq>>::check(r1csVar, EVar, uVar, zVar).unwrap();
|
||||
RelaxedR1CSGadget::check_native(r1csVar, EVar, uVar, zVar).unwrap();
|
||||
|
||||
// non-natively
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
let zVar = Vec::<NonNativeFieldVar<Fq, Fr>>::new_witness(cs.clone(), || Ok(z)).unwrap();
|
||||
let EVar = Vec::<NonNativeFieldVar<Fq, Fr>>::new_witness(cs.clone(), || Ok(relaxed_r1cs.E))
|
||||
.unwrap();
|
||||
let uVar =
|
||||
NonNativeFieldVar::<Fq, Fr>::new_witness(cs.clone(), || Ok(relaxed_r1cs.u)).unwrap();
|
||||
let zVar = Vec::new_witness(cs.clone(), || Ok(z)).unwrap();
|
||||
let EVar = Vec::new_witness(cs.clone(), || Ok(relaxed_r1cs.E)).unwrap();
|
||||
let uVar = NonNativeUintVar::<Fr>::new_witness(cs.clone(), || Ok(relaxed_r1cs.u)).unwrap();
|
||||
let r1csVar =
|
||||
R1CSVar::<Fq, Fr, NonNativeFieldVar<Fq, Fr>>::new_witness(cs.clone(), || Ok(r1cs))
|
||||
.unwrap();
|
||||
RelaxedR1CSGadget::<Fq, Fr, NonNativeFieldVar<Fq, Fr>>::check(r1csVar, EVar, uVar, zVar)
|
||||
.unwrap();
|
||||
R1CSVar::<Fq, Fr, NonNativeUintVar<Fr>>::new_witness(cs.clone(), || Ok(r1cs)).unwrap();
|
||||
RelaxedR1CSGadget::check_nonnative(r1csVar, EVar, uVar, zVar).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -16,7 +16,7 @@ use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem};
|
||||
use crate::ccs::r1cs::{extract_r1cs, extract_w_x, R1CS};
|
||||
use crate::commitment::CommitmentScheme;
|
||||
use crate::folding::circuits::nonnative::{
|
||||
nonnative_affine_to_field_elements, nonnative_field_to_field_elements,
|
||||
affine::nonnative_affine_to_field_elements, uint::nonnative_field_to_field_elements,
|
||||
};
|
||||
use crate::frontend::FCircuit;
|
||||
use crate::utils::vec::is_zero_vec;
|
||||
@@ -434,7 +434,6 @@ where
|
||||
r_bits: Some(r_bits.clone()),
|
||||
p1: Some(self.U_i.clone().cmW),
|
||||
p2: Some(self.u_i.clone().cmW),
|
||||
p3: Some(U_i1.clone().cmW),
|
||||
x: Some(cfW_u_i_x.clone()),
|
||||
};
|
||||
let cfE_circuit = CycleFoldCircuit::<C1, GC1> {
|
||||
@@ -442,7 +441,6 @@ where
|
||||
r_bits: Some(r_bits.clone()),
|
||||
p1: Some(self.U_i.clone().cmE),
|
||||
p2: Some(cmT),
|
||||
p3: Some(U_i1.clone().cmE),
|
||||
x: Some(cfE_u_i_x.clone()),
|
||||
};
|
||||
|
||||
@@ -482,8 +480,8 @@ where
|
||||
cf_x: Some(cf_u_i1_x),
|
||||
};
|
||||
|
||||
self.cf_W_i = cf_W_i1.clone();
|
||||
self.cf_U_i = cf_U_i1.clone();
|
||||
self.cf_W_i = cf_W_i1;
|
||||
self.cf_U_i = cf_U_i1;
|
||||
|
||||
#[cfg(test)]
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user