mirror of
https://github.com/arnaucube/sonobe.git
synced 2026-01-28 14:56:40 +01:00
Refactor Arith trait (#162)
* `Dummy` trait * More generic design for `Arith` * Distinguish between incoming and running instances in ProtoGalaxy * Format * Fix unit test * Fix incorrect arguments supplied to `CycleFoldWitness::dummy` * `RUNNING` and `INCOMING` constants * Better name and docs for `eval_core` * More docs for `Arith` methods and implementations * Fix missing imports
This commit is contained in:
@@ -31,7 +31,10 @@ use crate::folding::circuits::{
|
||||
};
|
||||
use crate::frontend::FCircuit;
|
||||
use crate::transcript::{AbsorbNonNativeGadget, Transcript, TranscriptVar};
|
||||
use crate::{constants::NOVA_N_BITS_RO, folding::traits::CommittedInstanceVarOps};
|
||||
use crate::{
|
||||
constants::NOVA_N_BITS_RO,
|
||||
folding::traits::{CommittedInstanceVarOps, Dummy},
|
||||
};
|
||||
|
||||
/// CommittedInstanceVar contains the u, x, cmE and cmW values which are folded on the main Nova
|
||||
/// constraints field (E1::Fr, where E1 is the main curve). The peculiarity is that cmE and cmW are
|
||||
|
||||
@@ -40,7 +40,7 @@ use crate::folding::circuits::{
|
||||
CF1, CF2,
|
||||
};
|
||||
use crate::folding::nova::NovaCycleFoldConfig;
|
||||
use crate::folding::traits::CommittedInstanceVarOps;
|
||||
use crate::folding::traits::{CommittedInstanceVarOps, Dummy};
|
||||
use crate::frontend::FCircuit;
|
||||
use crate::utils::vec::poly_from_vec;
|
||||
use crate::Error;
|
||||
@@ -214,11 +214,8 @@ where
|
||||
Ok(self.z_i.unwrap_or(vec![CF1::<C1>::zero()]))
|
||||
})?;
|
||||
|
||||
let u_dummy_native = CommittedInstance::<C1>::dummy(2);
|
||||
let w_dummy_native = Witness::<C1>::dummy(
|
||||
self.r1cs.A.n_cols - 3, /* (3=2+1, since u_i.x.len=2) */
|
||||
self.E_len,
|
||||
);
|
||||
let u_dummy_native = CommittedInstance::<C1>::dummy(&self.r1cs);
|
||||
let w_dummy_native = Witness::<C1>::dummy(&self.r1cs);
|
||||
|
||||
let u_i = CommittedInstanceVar::<C1>::new_witness(cs.clone(), || {
|
||||
Ok(self.u_i.unwrap_or(u_dummy_native.clone()))
|
||||
@@ -436,9 +433,8 @@ where
|
||||
Ok(self.pp_hash.unwrap_or_else(CF1::<C2>::zero))
|
||||
})?;
|
||||
|
||||
let cf_u_dummy_native = CommittedInstance::<C2>::dummy(NovaCycleFoldConfig::<C1>::IO_LEN);
|
||||
let w_dummy_native =
|
||||
Witness::<C2>::dummy(self.cf_r1cs.A.n_cols - 1 - self.cf_r1cs.l, self.cf_E_len);
|
||||
let cf_u_dummy_native = CommittedInstance::<C2>::dummy(&self.cf_r1cs);
|
||||
let w_dummy_native = Witness::<C2>::dummy(&self.cf_r1cs);
|
||||
let cf_U_i = CommittedInstanceVar::<C2>::new_input(cs.clone(), || {
|
||||
Ok(self.cf_U_i.unwrap_or_else(|| cf_u_dummy_native.clone()))
|
||||
})?;
|
||||
|
||||
@@ -29,6 +29,7 @@ use super::{
|
||||
nifs::NIFS,
|
||||
CommittedInstance, Nova, Witness,
|
||||
};
|
||||
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme};
|
||||
use crate::folding::circuits::{
|
||||
cyclefold::{CycleFoldCommittedInstance, CycleFoldWitness},
|
||||
nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar},
|
||||
@@ -41,10 +42,9 @@ use crate::utils::{
|
||||
vec::poly_from_vec,
|
||||
};
|
||||
use crate::Error;
|
||||
use crate::{arith::r1cs::R1CS, folding::traits::WitnessVarOps};
|
||||
use crate::{
|
||||
commitment::{pedersen::Params as PedersenParams, CommitmentScheme},
|
||||
folding::traits::CommittedInstanceVarOps,
|
||||
arith::r1cs::R1CS,
|
||||
folding::traits::{CommittedInstanceVarOps, Dummy, WitnessVarOps},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -356,11 +356,8 @@ where
|
||||
Ok(self.z_i.unwrap_or(vec![CF1::<C1>::zero()]))
|
||||
})?;
|
||||
|
||||
let u_dummy_native = CommittedInstance::<C1>::dummy(2);
|
||||
let w_dummy_native = Witness::<C1>::dummy(
|
||||
self.r1cs.A.n_cols - 3, /* (3=2+1, since u_i.x.len=2) */
|
||||
self.E_len,
|
||||
);
|
||||
let u_dummy_native = CommittedInstance::<C1>::dummy(&self.r1cs);
|
||||
let w_dummy_native = Witness::<C1>::dummy(&self.r1cs);
|
||||
|
||||
let u_i = CommittedInstanceVar::<C1>::new_witness(cs.clone(), || {
|
||||
Ok(self.u_i.unwrap_or(u_dummy_native.clone()))
|
||||
@@ -437,10 +434,7 @@ where
|
||||
|
||||
let cf_u_dummy_native =
|
||||
CycleFoldCommittedInstance::<C2>::dummy(NovaCycleFoldConfig::<C1>::IO_LEN);
|
||||
let w_dummy_native = CycleFoldWitness::<C2>::dummy(
|
||||
self.cf_r1cs.A.n_cols - 1 - self.cf_r1cs.l,
|
||||
self.cf_E_len,
|
||||
);
|
||||
let w_dummy_native = CycleFoldWitness::<C2>::dummy(&self.cf_r1cs);
|
||||
let cf_U_i = CycleFoldCommittedInstanceVar::<C2, GC2>::new_witness(cs.clone(), || {
|
||||
Ok(self.cf_U_i.unwrap_or_else(|| cf_u_dummy_native.clone()))
|
||||
})?;
|
||||
@@ -608,7 +602,6 @@ pub mod tests {
|
||||
r1cs::{
|
||||
extract_r1cs, extract_w_x,
|
||||
tests::{get_test_r1cs, get_test_z},
|
||||
RelaxedR1CS,
|
||||
},
|
||||
Arith,
|
||||
};
|
||||
@@ -618,20 +611,18 @@ pub mod tests {
|
||||
use crate::transcript::poseidon::poseidon_canonical_config;
|
||||
use crate::FoldingScheme;
|
||||
|
||||
fn prepare_instances<C: CurveGroup, CS: CommitmentScheme<C>, R: Rng>(
|
||||
// Convert `z` to a witness-instance pair for the relaxed R1CS
|
||||
fn prepare_relaxed_witness_instance<C: CurveGroup, CS: CommitmentScheme<C>, R: Rng>(
|
||||
mut rng: R,
|
||||
r1cs: &R1CS<C::ScalarField>,
|
||||
z: &[C::ScalarField],
|
||||
) -> (Witness<C>, CommittedInstance<C>)
|
||||
where
|
||||
C::ScalarField: Absorb,
|
||||
{
|
||||
) -> (Witness<C>, CommittedInstance<C>) {
|
||||
let (w, x) = r1cs.split_z(z);
|
||||
|
||||
let (cs_pp, _) = CS::setup(&mut rng, max(w.len(), r1cs.A.n_rows)).unwrap();
|
||||
|
||||
let mut w = Witness::new::<false>(w, r1cs.A.n_rows, &mut rng);
|
||||
w.E = r1cs.eval_relation(z).unwrap();
|
||||
w.E = r1cs.eval_at_z(z).unwrap();
|
||||
let mut u = w.commit::<CS, false>(&cs_pp, x).unwrap();
|
||||
u.u = z[0];
|
||||
|
||||
@@ -643,9 +634,10 @@ pub mod tests {
|
||||
let rng = &mut thread_rng();
|
||||
|
||||
let r1cs: R1CS<Fr> = get_test_r1cs();
|
||||
|
||||
let mut z = get_test_z(3);
|
||||
z[0] = Fr::rand(rng);
|
||||
let (w, u) = prepare_instances::<_, Pedersen<Projective>, _>(rng, &r1cs, &z);
|
||||
z[0] = Fr::rand(rng); // Randomize `z[0]` (i.e. `u.u`) to test the relaxed R1CS
|
||||
let (w, u) = prepare_relaxed_witness_instance::<_, Pedersen<Projective>, _>(rng, &r1cs, &z);
|
||||
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
|
||||
@@ -673,12 +665,11 @@ pub mod tests {
|
||||
|
||||
let r1cs = extract_r1cs::<Fr>(&cs);
|
||||
let (w, x) = extract_w_x::<Fr>(&cs);
|
||||
let mut z = [vec![Fr::one()], x, w].concat();
|
||||
r1cs.check_relation(&z).unwrap();
|
||||
r1cs.check_relation(&w, &x).unwrap();
|
||||
|
||||
z[0] = Fr::rand(rng);
|
||||
let (w, u) = prepare_instances::<_, Pedersen<Projective>, _>(rng, &r1cs, &z);
|
||||
r1cs.check_relaxed_relation(&w, &u).unwrap();
|
||||
let z = [vec![Fr::rand(rng)], x, w].concat();
|
||||
let (w, u) = prepare_relaxed_witness_instance::<_, Pedersen<Projective>, _>(rng, &r1cs, &z);
|
||||
r1cs.check_relation(&w, &u).unwrap();
|
||||
|
||||
// set new CS for the circuit that checks the RelaxedR1CS of our original circuit
|
||||
let cs = ConstraintSystem::<Fr>::new_ref();
|
||||
@@ -767,9 +758,10 @@ pub mod tests {
|
||||
let cs = cs.into_inner().unwrap();
|
||||
let r1cs = extract_r1cs::<Fq>(&cs);
|
||||
let (w, x) = extract_w_x::<Fq>(&cs);
|
||||
let z = [vec![Fq::rand(rng)], x, w].concat();
|
||||
|
||||
let (w, u) = prepare_instances::<_, Pedersen<Projective2>, _>(rng, &r1cs, &z);
|
||||
let z = [vec![Fq::rand(rng)], x, w].concat();
|
||||
let (w, u) =
|
||||
prepare_relaxed_witness_instance::<_, Pedersen<Projective2>, _>(rng, &r1cs, &z);
|
||||
|
||||
// natively
|
||||
let cs = ConstraintSystem::<Fq>::new_ref();
|
||||
|
||||
@@ -19,18 +19,21 @@ use crate::folding::circuits::cyclefold::{
|
||||
fold_cyclefold_circuit, CycleFoldCircuit, CycleFoldCommittedInstance, CycleFoldConfig,
|
||||
CycleFoldWitness,
|
||||
};
|
||||
use crate::folding::circuits::CF2;
|
||||
use crate::folding::{
|
||||
circuits::{CF1, CF2},
|
||||
traits::Dummy,
|
||||
};
|
||||
use crate::frontend::FCircuit;
|
||||
use crate::transcript::{poseidon::poseidon_canonical_config, AbsorbNonNative, Transcript};
|
||||
use crate::utils::vec::is_zero_vec;
|
||||
use crate::Error;
|
||||
use crate::FoldingScheme;
|
||||
use crate::{arith::r1cs::RelaxedR1CS, commitment::CommitmentScheme};
|
||||
use crate::{
|
||||
arith::r1cs::{extract_r1cs, extract_w_x, R1CS},
|
||||
constants::NOVA_N_BITS_RO,
|
||||
utils::{get_cm_coordinates, pp_hash},
|
||||
};
|
||||
use crate::{arith::Arith, commitment::CommitmentScheme};
|
||||
|
||||
use circuits::{AugmentedFCircuit, ChallengeGadget, CommittedInstanceVar};
|
||||
use nifs::NIFS;
|
||||
@@ -76,17 +79,23 @@ pub struct CommittedInstance<C: CurveGroup> {
|
||||
pub x: Vec<C::ScalarField>,
|
||||
}
|
||||
|
||||
impl<C: CurveGroup> CommittedInstance<C> {
|
||||
pub fn dummy(io_len: usize) -> Self {
|
||||
impl<C: CurveGroup> Dummy<usize> for CommittedInstance<C> {
|
||||
fn dummy(io_len: usize) -> Self {
|
||||
Self {
|
||||
cmE: C::zero(),
|
||||
u: C::ScalarField::zero(),
|
||||
u: CF1::<C>::zero(),
|
||||
cmW: C::zero(),
|
||||
x: vec![C::ScalarField::zero(); io_len],
|
||||
x: vec![CF1::<C>::zero(); io_len],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: CurveGroup> Dummy<&R1CS<CF1<C>>> for CommittedInstance<C> {
|
||||
fn dummy(r1cs: &R1CS<CF1<C>>) -> Self {
|
||||
Self::dummy(r1cs.l)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: CurveGroup> Absorb for CommittedInstance<C>
|
||||
where
|
||||
C::ScalarField: Absorb,
|
||||
@@ -149,18 +158,6 @@ impl<C: CurveGroup> Witness<C> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn dummy(w_len: usize, e_len: usize) -> Self {
|
||||
let (rW, rE) = (C::ScalarField::zero(), C::ScalarField::zero());
|
||||
let w = vec![C::ScalarField::zero(); w_len];
|
||||
|
||||
Self {
|
||||
E: vec![C::ScalarField::zero(); e_len],
|
||||
rE,
|
||||
W: w,
|
||||
rW,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn commit<CS: CommitmentScheme<C, HC>, const HC: bool>(
|
||||
&self,
|
||||
params: &CS::ProverParams,
|
||||
@@ -180,6 +177,17 @@ impl<C: CurveGroup> Witness<C> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: CurveGroup> Dummy<&R1CS<CF1<C>>> for Witness<C> {
|
||||
fn dummy(r1cs: &R1CS<CF1<C>>) -> Self {
|
||||
Self {
|
||||
E: vec![C::ScalarField::zero(); r1cs.A.n_rows],
|
||||
rE: C::ScalarField::zero(),
|
||||
W: vec![C::ScalarField::zero(); r1cs.A.n_cols - 1 - r1cs.l],
|
||||
rW: C::ScalarField::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C: CurveGroup> WitnessOps<C::ScalarField> for Witness<C> {
|
||||
type Var = WitnessVar<C>;
|
||||
|
||||
@@ -562,9 +570,9 @@ where
|
||||
let pp_hash = vp.pp_hash()?;
|
||||
|
||||
// setup the dummy instances
|
||||
let (W_dummy, U_dummy) = r1cs.dummy_running_instance();
|
||||
let (w_dummy, u_dummy) = r1cs.dummy_incoming_instance();
|
||||
let (cf_W_dummy, cf_U_dummy) = cf_r1cs.dummy_running_instance();
|
||||
let (W_dummy, U_dummy) = r1cs.dummy_witness_instance();
|
||||
let (w_dummy, u_dummy) = r1cs.dummy_witness_instance();
|
||||
let (cf_W_dummy, cf_U_dummy) = cf_r1cs.dummy_witness_instance();
|
||||
|
||||
// W_dummy=W_0 is a 'dummy witness', all zeroes, but with the size corresponding to the
|
||||
// R1CS that we're working with.
|
||||
@@ -815,10 +823,11 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
{
|
||||
self.cf_r1cs.check_tight_relation(&_cfW_w_i, &cfW_u_i)?;
|
||||
self.cf_r1cs.check_tight_relation(&_cfE_w_i, &cfE_u_i)?;
|
||||
self.cf_r1cs
|
||||
.check_relaxed_relation(&self.cf_W_i, &self.cf_U_i)?;
|
||||
cfW_u_i.check_incoming()?;
|
||||
cfE_u_i.check_incoming()?;
|
||||
self.cf_r1cs.check_relation(&_cfW_w_i, &cfW_u_i)?;
|
||||
self.cf_r1cs.check_relation(&_cfE_w_i, &cfE_u_i)?;
|
||||
self.cf_r1cs.check_relation(&self.cf_W_i, &self.cf_U_i)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -850,8 +859,9 @@ where
|
||||
|
||||
#[cfg(test)]
|
||||
{
|
||||
self.r1cs.check_tight_relation(&self.w_i, &self.u_i)?;
|
||||
self.r1cs.check_relaxed_relation(&self.W_i, &self.U_i)?;
|
||||
self.u_i.check_incoming()?;
|
||||
self.r1cs.check_relation(&self.w_i, &self.u_i)?;
|
||||
self.r1cs.check_relation(&self.W_i, &self.U_i)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -917,13 +927,15 @@ where
|
||||
return Err(Error::IVCVerificationFail);
|
||||
}
|
||||
|
||||
// check R1CS satisfiability, which also enforces u_i.cmE==0, u_i.u==1
|
||||
vp.r1cs.check_tight_relation(&w_i, &u_i)?;
|
||||
// check R1CS satisfiability, which is equivalent to checking if `u_i`
|
||||
// is an incoming instance and if `w_i` and `u_i` satisfy RelaxedR1CS
|
||||
u_i.check_incoming()?;
|
||||
vp.r1cs.check_relation(&w_i, &u_i)?;
|
||||
// check RelaxedR1CS satisfiability
|
||||
vp.r1cs.check_relaxed_relation(&W_i, &U_i)?;
|
||||
vp.r1cs.check_relation(&W_i, &U_i)?;
|
||||
|
||||
// check CycleFold RelaxedR1CS satisfiability
|
||||
vp.cf_r1cs.check_relaxed_relation(&cf_W_i, &cf_U_i)?;
|
||||
vp.cf_r1cs.check_relation(&cf_W_i, &cf_U_i)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -210,13 +210,16 @@ pub mod tests {
|
||||
use ark_pallas::{Fr, Projective};
|
||||
use ark_std::{ops::Mul, test_rng, UniformRand};
|
||||
|
||||
use crate::arith::r1cs::{
|
||||
tests::{get_test_r1cs, get_test_z},
|
||||
RelaxedR1CS,
|
||||
};
|
||||
use crate::commitment::pedersen::{Params as PedersenParams, Pedersen};
|
||||
use crate::folding::nova::circuits::ChallengeGadget;
|
||||
use crate::transcript::poseidon::poseidon_canonical_config;
|
||||
use crate::{
|
||||
arith::{
|
||||
r1cs::tests::{get_test_r1cs, get_test_z},
|
||||
Arith,
|
||||
},
|
||||
folding::traits::Dummy,
|
||||
};
|
||||
|
||||
#[allow(clippy::type_complexity)]
|
||||
pub(crate) fn prepare_simple_fold_inputs<C>() -> (
|
||||
@@ -302,13 +305,13 @@ pub mod tests {
|
||||
fn test_nifs_fold_dummy() {
|
||||
let r1cs = get_test_r1cs::<Fr>();
|
||||
let z1 = get_test_z(3);
|
||||
let (w1, x1) = r1cs.split_z(&z1);
|
||||
let (_, x1) = r1cs.split_z(&z1);
|
||||
|
||||
let mut rng = ark_std::test_rng();
|
||||
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>::dummy(w1.len(), r1cs.A.n_rows);
|
||||
let w_dummy = Witness::<Projective>::dummy(&r1cs);
|
||||
let mut u_dummy = w_dummy
|
||||
.commit::<Pedersen<Projective>, false>(&pedersen_params, vec![Fr::zero(); x1.len()])
|
||||
.unwrap();
|
||||
@@ -318,8 +321,8 @@ pub mod tests {
|
||||
let u_i = u_dummy.clone();
|
||||
let W_i = w_dummy.clone();
|
||||
let U_i = u_dummy.clone();
|
||||
r1cs.check_relaxed_relation(&w_i, &u_i).unwrap();
|
||||
r1cs.check_relaxed_relation(&W_i, &U_i).unwrap();
|
||||
r1cs.check_relation(&w_i, &u_i).unwrap();
|
||||
r1cs.check_relation(&W_i, &U_i).unwrap();
|
||||
|
||||
let r_Fr = Fr::from(3_u32);
|
||||
|
||||
@@ -336,7 +339,7 @@ pub mod tests {
|
||||
r_Fr, &w_i, &u_i, &W_i, &U_i, &T, cmT,
|
||||
)
|
||||
.unwrap();
|
||||
r1cs.check_relaxed_relation(&W_i1, &U_i1).unwrap();
|
||||
r1cs.check_relation(&W_i1, &U_i1).unwrap();
|
||||
}
|
||||
|
||||
// fold 2 instances into one
|
||||
@@ -350,9 +353,9 @@ pub mod tests {
|
||||
assert_eq!(ci3_v, ci3);
|
||||
|
||||
// check that relations hold for the 2 inputted instances and the folded one
|
||||
r1cs.check_relaxed_relation(&w1, &ci1).unwrap();
|
||||
r1cs.check_relaxed_relation(&w2, &ci2).unwrap();
|
||||
r1cs.check_relaxed_relation(&w3, &ci3).unwrap();
|
||||
r1cs.check_relation(&w1, &ci1).unwrap();
|
||||
r1cs.check_relation(&w2, &ci2).unwrap();
|
||||
r1cs.check_relation(&w3, &ci3).unwrap();
|
||||
|
||||
// check that folded commitments from folded instance (ci) are equal to folding the
|
||||
// use folded rE, rW to commit w3
|
||||
@@ -427,7 +430,7 @@ pub mod tests {
|
||||
.commit::<Pedersen<Projective>, false>(&pedersen_params, x)
|
||||
.unwrap();
|
||||
|
||||
r1cs.check_relaxed_relation(&running_instance_w, &running_committed_instance)
|
||||
r1cs.check_relation(&running_instance_w, &running_committed_instance)
|
||||
.unwrap();
|
||||
|
||||
let num_iters = 10;
|
||||
@@ -440,7 +443,7 @@ pub mod tests {
|
||||
let incoming_committed_instance = incoming_instance_w
|
||||
.commit::<Pedersen<Projective>, false>(&pedersen_params, x)
|
||||
.unwrap();
|
||||
r1cs.check_relaxed_relation(&incoming_instance_w, &incoming_committed_instance)
|
||||
r1cs.check_relation(&incoming_instance_w, &incoming_committed_instance)
|
||||
.unwrap();
|
||||
|
||||
let r = Fr::rand(&mut rng); // folding challenge would come from the RO
|
||||
@@ -474,7 +477,7 @@ pub mod tests {
|
||||
&cmT,
|
||||
);
|
||||
|
||||
r1cs.check_relaxed_relation(&folded_w, &folded_committed_instance)
|
||||
r1cs.check_relation(&folded_w, &folded_committed_instance)
|
||||
.unwrap();
|
||||
|
||||
// set running_instance for next loop iteration
|
||||
|
||||
@@ -1,50 +1,66 @@
|
||||
use ark_ec::CurveGroup;
|
||||
use ark_std::{rand::RngCore, One, UniformRand};
|
||||
use ark_std::{rand::RngCore, UniformRand};
|
||||
|
||||
use super::{CommittedInstance, Witness};
|
||||
use crate::arith::r1cs::{RelaxedR1CS, R1CS};
|
||||
use crate::arith::ArithSampler;
|
||||
use crate::arith::{r1cs::R1CS, Arith};
|
||||
use crate::commitment::CommitmentScheme;
|
||||
use crate::folding::circuits::CF1;
|
||||
use crate::Error;
|
||||
|
||||
impl<C: CurveGroup> RelaxedR1CS<C, Witness<C>, CommittedInstance<C>> for R1CS<C::ScalarField> {
|
||||
fn dummy_running_instance(&self) -> (Witness<C>, CommittedInstance<C>) {
|
||||
let w_len = self.A.n_cols - 1 - self.l;
|
||||
let w_dummy = Witness::<C>::dummy(w_len, self.A.n_rows);
|
||||
let u_dummy = CommittedInstance::<C>::dummy(self.l);
|
||||
(w_dummy, u_dummy)
|
||||
/// Implements `Arith` for R1CS, where the witness is of type [`Witness`], and
|
||||
/// the committed instance is of type [`CommittedInstance`].
|
||||
///
|
||||
/// Due to the error terms `Witness.E` and `CommittedInstance.u`, R1CS here is
|
||||
/// considered as a relaxed R1CS.
|
||||
///
|
||||
/// One may wonder why we do not provide distinct structs for R1CS and relaxed
|
||||
/// R1CS.
|
||||
/// This is because both plain R1CS and relaxed R1CS have the same structure:
|
||||
/// they are both represented by three matrices.
|
||||
/// What makes them different is the error terms, which are not part of the R1CS
|
||||
/// struct, but are part of the witness and committed instance.
|
||||
///
|
||||
/// As a follow-up, one may further ask why not providing a trait for relaxed
|
||||
/// R1CS and implement it for the `R1CS` struct, where the relaxed R1CS trait
|
||||
/// has methods for relaxed satisfiability check, while the `Arith` trait that
|
||||
/// `R1CS` implements has methods for plain satisfiability check.
|
||||
/// However, it would be more ideal if we have a single method that can smartly
|
||||
/// choose the type of satisfiability check, which would make the code more
|
||||
/// generic and easier to maintain.
|
||||
///
|
||||
/// This is achieved thanks to the new design of the [`Arith`] trait, where we
|
||||
/// can implement the trait for the same constraint system with different types
|
||||
/// of witnesses and committed instances.
|
||||
/// For R1CS, whether it is relaxed or not is now determined by the types of `W`
|
||||
/// and `U`: the satisfiability check is relaxed if `W` and `U` are defined by
|
||||
/// folding schemes, and plain if they are vectors of field elements.
|
||||
impl<C: CurveGroup> Arith<Witness<C>, CommittedInstance<C>> for R1CS<CF1<C>> {
|
||||
type Evaluation = Vec<CF1<C>>;
|
||||
|
||||
fn eval_relation(
|
||||
&self,
|
||||
w: &Witness<C>,
|
||||
u: &CommittedInstance<C>,
|
||||
) -> Result<Self::Evaluation, Error> {
|
||||
self.eval_at_z(&[&[u.u][..], &u.x, &w.W].concat())
|
||||
}
|
||||
|
||||
fn dummy_incoming_instance(&self) -> (Witness<C>, CommittedInstance<C>) {
|
||||
self.dummy_running_instance()
|
||||
}
|
||||
|
||||
fn is_relaxed(_w: &Witness<C>, u: &CommittedInstance<C>) -> bool {
|
||||
u.cmE != C::zero() || u.u != C::ScalarField::one()
|
||||
}
|
||||
|
||||
fn extract_z(w: &Witness<C>, u: &CommittedInstance<C>) -> Vec<C::ScalarField> {
|
||||
[&[u.u][..], &u.x, &w.W].concat()
|
||||
}
|
||||
|
||||
fn check_error_terms(
|
||||
fn check_evaluation(
|
||||
w: &Witness<C>,
|
||||
_u: &CommittedInstance<C>,
|
||||
e: Vec<C::ScalarField>,
|
||||
e: Self::Evaluation,
|
||||
) -> Result<(), Error> {
|
||||
if w.E == e {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::NotSatisfied)
|
||||
}
|
||||
(w.E == e).then_some(()).ok_or(Error::NotSatisfied)
|
||||
}
|
||||
}
|
||||
|
||||
fn sample<CS>(
|
||||
impl<C: CurveGroup> ArithSampler<C, Witness<C>, CommittedInstance<C>> for R1CS<CF1<C>> {
|
||||
fn sample_witness_instance<CS: CommitmentScheme<C, true>>(
|
||||
&self,
|
||||
params: &CS::ProverParams,
|
||||
mut rng: impl RngCore,
|
||||
) -> Result<(Witness<C>, CommittedInstance<C>), Error>
|
||||
where
|
||||
CS: crate::commitment::CommitmentScheme<C, true>,
|
||||
{
|
||||
) -> Result<(Witness<C>, CommittedInstance<C>), Error> {
|
||||
// Implements sampling a (committed) RelaxedR1CS
|
||||
// See construction 5 in https://eprint.iacr.org/2023/573.pdf
|
||||
let u = C::ScalarField::rand(&mut rng);
|
||||
@@ -61,16 +77,7 @@ impl<C: CurveGroup> RelaxedR1CS<C, Witness<C>, CommittedInstance<C>> for R1CS<C:
|
||||
z.extend(&x);
|
||||
z.extend(&W);
|
||||
|
||||
let E = <Self as RelaxedR1CS<C, Witness<C>, CommittedInstance<C>>>::compute_E(
|
||||
&self.A, &self.B, &self.C, &z, &u,
|
||||
)?;
|
||||
|
||||
debug_assert!(
|
||||
z.len() == self.A.n_cols,
|
||||
"Length of z is {}, while A has {} columns.",
|
||||
z.len(),
|
||||
self.A.n_cols
|
||||
);
|
||||
let E = self.eval_at_z(&z)?;
|
||||
|
||||
let witness = Witness { E, rE, W, rW };
|
||||
let mut cm_witness = witness.commit::<CS, true>(params, x)?;
|
||||
@@ -79,7 +86,7 @@ impl<C: CurveGroup> RelaxedR1CS<C, Witness<C>, CommittedInstance<C>> for R1CS<C:
|
||||
cm_witness.u = u;
|
||||
|
||||
debug_assert!(
|
||||
self.check_relaxed_relation(&witness, &cm_witness).is_ok(),
|
||||
self.check_relation(&witness, &cm_witness).is_ok(),
|
||||
"Sampled a non satisfiable relaxed R1CS, sampled u: {}, computed E: {:?}",
|
||||
u,
|
||||
witness.E
|
||||
|
||||
@@ -35,7 +35,7 @@ use ark_ff::{BigInteger, PrimeField};
|
||||
use ark_std::{One, Zero};
|
||||
|
||||
use crate::{
|
||||
arith::r1cs::{RelaxedR1CS, R1CS},
|
||||
arith::{r1cs::R1CS, Arith, ArithSampler},
|
||||
folding::traits::CommittedInstanceOps,
|
||||
RngCore,
|
||||
};
|
||||
@@ -142,7 +142,9 @@ where
|
||||
let pi = FoldingProof { cmT };
|
||||
|
||||
// 2. Sample a satisfying relaxed R1CS instance-witness pair (W_r, U_r)
|
||||
let (W_r, U_r) = nova.r1cs.sample::<CS1>(&nova.cs_pp, &mut rng)?;
|
||||
let (W_r, U_r) = nova
|
||||
.r1cs
|
||||
.sample_witness_instance::<CS1>(&nova.cs_pp, &mut rng)?;
|
||||
|
||||
// 3. Fold the instance-witness pair (U_f, W_f) with (U_r, W_r)
|
||||
// a. Compute T
|
||||
@@ -279,10 +281,10 @@ where
|
||||
);
|
||||
|
||||
// 5. Check that W^{\prime}_i is a satisfying witness
|
||||
r1cs.check_relaxed_relation(&proof.W_i_prime, &U_i_prime)?;
|
||||
r1cs.check_relation(&proof.W_i_prime, &U_i_prime)?;
|
||||
|
||||
// 6. Check that the cyclefold instance-witness pair satisfies the cyclefold relaxed r1cs
|
||||
cf_r1cs.check_relaxed_relation(&proof.cf_W_i, &proof.cf_U_i)?;
|
||||
cf_r1cs.check_relation(&proof.cf_W_i, &proof.cf_U_i)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -370,7 +372,7 @@ pub mod tests {
|
||||
);
|
||||
let (_, sampled_committed_instance) = nova
|
||||
.r1cs
|
||||
.sample::<Pedersen<Projective, true>>(&nova.cs_pp, rng)
|
||||
.sample_witness_instance::<Pedersen<Projective, true>>(&nova.cs_pp, rng)
|
||||
.unwrap();
|
||||
|
||||
// proof verification fails with incorrect running instance
|
||||
@@ -407,7 +409,7 @@ pub mod tests {
|
||||
);
|
||||
let (sampled_committed_witness, _) = nova
|
||||
.r1cs
|
||||
.sample::<Pedersen<Projective, true>>(&nova.cs_pp, rng)
|
||||
.sample_witness_instance::<Pedersen<Projective, true>>(&nova.cs_pp, rng)
|
||||
.unwrap();
|
||||
|
||||
// proof generation fails with incorrect running witness
|
||||
|
||||
Reference in New Issue
Block a user