Skip to content

Commit

Permalink
Merge pull request #4 from privacy-scaling-explorations/violet/featue…
Browse files Browse the repository at this point in the history
…/r1cs_folding_generalization

Finish the prover merge code
  • Loading branch information
chiro-hiro authored Mar 29, 2023
2 parents 82ffef9 + 398caa9 commit 0fa40d7
Show file tree
Hide file tree
Showing 8 changed files with 905 additions and 805 deletions.
4 changes: 2 additions & 2 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
alloc_num_equals, alloc_scalar_as_base, alloc_zero, conditionally_select_vec, le_bits_to_num,
},
},
r1cs::{RelaxedR1CSInstance},
r1cs::RelaxedR1CSInstance,
traits::{
circuit::StepCircuit, commitment::CommitmentTrait, Group, ROCircuitTrait, ROConstantsCircuit,
},
Expand Down Expand Up @@ -377,7 +377,7 @@ mod tests {

use crate::constants::{BN_LIMB_WIDTH, BN_N_LIMBS};
use crate::r1cs::RelaxedR1CSWitness;
use crate::{
use crate::{
bellperson::r1cs::{NovaShape, NovaWitness},
provider::poseidon::PoseidonConstantsCircuit,
traits::{circuit::TrivialTestCircuit, ROConstantsTrait},
Expand Down
6 changes: 3 additions & 3 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub enum NovaError {
/// returned when the product proof check fails
#[error("InvalidProductProof")]
InvalidProductProof,
/// returned when the tree node is attempting to merge with a node which has a greater than 1 gap in steps
#[error("InvalidNodeMerge")]
InvalidNodeMerge,
/// returned when the tree node is attempting to merge with a node which has a greater than 1 gap in steps
#[error("InvalidNodeMerge")]
InvalidNodeMerge,
}
192 changes: 97 additions & 95 deletions src/gadgets/r1cs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use crate::{
conditionally_select_bignat, le_bits_to_num,
},
},
r1cs::{RelaxedR1CSInstance},
r1cs::RelaxedR1CSInstance,
traits::{commitment::CommitmentTrait, Group, ROCircuitTrait, ROConstantsCircuit},
};
use bellperson::{
Expand Down Expand Up @@ -338,100 +338,102 @@ impl<G: Group> AllocatedRelaxedR1CSInstance<G> {
})
}

/// Folds self with a relaxed r1cs instance and returns the result
#[allow(clippy::too_many_arguments)]
#[allow(unused)]
pub fn fold_with_relaxed_r1cs<CS: ConstraintSystem<<G as Group>::Base>>(
&self,
mut cs: CS,
params: AllocatedNum<G::Base>, // hash of R1CSShape of F'
u: AllocatedRelaxedR1CSInstance<G>,
T: AllocatedPoint<G>,
ro_consts: ROConstantsCircuit<G>,
limb_width: usize,
n_limbs: usize,
) -> Result<AllocatedRelaxedR1CSInstance<G>, SynthesisError> {
// Compute r:
let mut ro = G::ROCircuit::new(ro_consts, NUM_FE_FOR_RO);
ro.absorb(params);
self.absorb_in_ro(cs.namespace(|| "absorb running instance"), &mut ro)?;
u.absorb_in_ro(cs.namespace(|| "absorb running instance u"), &mut ro)?;
ro.absorb(T.x.clone());
ro.absorb(T.y.clone());
ro.absorb(T.is_infinity.clone());
let r_bits = ro.squeeze(cs.namespace(|| "r bits"), NUM_CHALLENGE_BITS)?;
let r = le_bits_to_num(cs.namespace(|| "r"), r_bits.clone())?;

// W_fold = self.W + r * u.W
let rW = u.W.scalar_mul(cs.namespace(|| "r * u.W"), r_bits.clone())?;
let W_fold = self.W.add(cs.namespace(|| "self.W + r * u.W"), &rW)?;

// E_fold = self.E + r * T + r * r * U.E
let rT = T.scalar_mul(cs.namespace(|| "r * T"), r_bits.clone())?;
let r_e_2 = u.E.scalar_mul(cs.namespace(|| "r * E_2"), r_bits.clone())?;
// Todo - there has to be a better way than 2 scalar mul
let r_squared_e_2 = r_e_2.scalar_mul(cs.namespace(|| "r * r * E_2"), r_bits)?;
let rT_plus_r_squared_E_2 = rT.add(cs.namespace(|| "r * r * E_2"), &r_squared_e_2)?;
let E_fold = self.E.add(cs.namespace(|| "self.E + r * T"), &rT_plus_r_squared_E_2)?;

// u_fold = u_r + r
let u_fold = AllocatedNum::alloc(cs.namespace(|| "u_fold"), || {
Ok(*self.u.get_value().get()? + r.get_value().get()?)
})?;
cs.enforce(
|| "Check u_fold",
|lc| lc,
|lc| lc,
|lc| lc + u_fold.get_variable() - self.u.get_variable() - r.get_variable(),
);

// Fold the IO:
// Analyze r into limbs
let r_bn = BigNat::from_num(
cs.namespace(|| "allocate r_bn"),
Num::from(r.clone()),
limb_width,
n_limbs,
)?;

// Allocate the order of the non-native field as a constant
let m_bn = alloc_bignat_constant(
cs.namespace(|| "alloc m"),
&G::get_curve_params().2,
limb_width,
n_limbs,
)?;

// Analyze X0 to bignat, NOTE - we copied this code from above but here changed it because the u.X0 is already BigNat
// for u of the type relaxed R1CS
let X0_bn = u.X0.clone();

// Fold self.X[0] + r * X[0]
let (_, r_0) = X0_bn.mult_mod(cs.namespace(|| "r*X[0]"), &r_bn, &m_bn)?;
// add X_r[0]
let r_new_0 = self.X0.add::<CS>(&r_0)?;
// Now reduce
let X0_fold = r_new_0.red_mod(cs.namespace(|| "reduce folded X[0]"), &m_bn)?;

// Analyze X1 to bignat, NOTE - we copied this code from above but here changed it because the u.X0 is already BigNat
// for u of the type relaxed R1CS
let X1_bn = u.X1.clone();

// Fold self.X[1] + r * X[1]
let (_, r_1) = X1_bn.mult_mod(cs.namespace(|| "r*X[1]"), &r_bn, &m_bn)?;
// add X_r[1]
let r_new_1 = self.X1.add::<CS>(&r_1)?;
// Now reduce
let X1_fold = r_new_1.red_mod(cs.namespace(|| "reduce folded X[1]"), &m_bn)?;

Ok(Self {
W: W_fold,
E: E_fold,
u: u_fold,
X0: X0_fold,
X1: X1_fold,
})
}
/// Folds self with a relaxed r1cs instance and returns the result
#[allow(clippy::too_many_arguments)]
#[allow(unused)]
pub fn fold_with_relaxed_r1cs<CS: ConstraintSystem<<G as Group>::Base>>(
&self,
mut cs: CS,
params: AllocatedNum<G::Base>, // hash of R1CSShape of F'
u: AllocatedRelaxedR1CSInstance<G>,
T: AllocatedPoint<G>,
ro_consts: ROConstantsCircuit<G>,
limb_width: usize,
n_limbs: usize,
) -> Result<AllocatedRelaxedR1CSInstance<G>, SynthesisError> {
// Compute r:
let mut ro = G::ROCircuit::new(ro_consts, NUM_FE_FOR_RO);
ro.absorb(params);
self.absorb_in_ro(cs.namespace(|| "absorb running instance"), &mut ro)?;
u.absorb_in_ro(cs.namespace(|| "absorb running instance u"), &mut ro)?;
ro.absorb(T.x.clone());
ro.absorb(T.y.clone());
ro.absorb(T.is_infinity.clone());
let r_bits = ro.squeeze(cs.namespace(|| "r bits"), NUM_CHALLENGE_BITS)?;
let r = le_bits_to_num(cs.namespace(|| "r"), r_bits.clone())?;

// W_fold = self.W + r * u.W
let rW = u.W.scalar_mul(cs.namespace(|| "r * u.W"), r_bits.clone())?;
let W_fold = self.W.add(cs.namespace(|| "self.W + r * u.W"), &rW)?;

// E_fold = self.E + r * T + r * r * U.E
let rT = T.scalar_mul(cs.namespace(|| "r * T"), r_bits.clone())?;
let r_e_2 = u.E.scalar_mul(cs.namespace(|| "r * E_2"), r_bits.clone())?;
// Todo - there has to be a better way than 2 scalar mul
let r_squared_e_2 = r_e_2.scalar_mul(cs.namespace(|| "r * r * E_2"), r_bits)?;
let rT_plus_r_squared_E_2 = rT.add(cs.namespace(|| "r * r * E_2"), &r_squared_e_2)?;
let E_fold = self
.E
.add(cs.namespace(|| "self.E + r * T"), &rT_plus_r_squared_E_2)?;

// u_fold = u_r + r
let u_fold = AllocatedNum::alloc(cs.namespace(|| "u_fold"), || {
Ok(*self.u.get_value().get()? + r.get_value().get()?)
})?;
cs.enforce(
|| "Check u_fold",
|lc| lc,
|lc| lc,
|lc| lc + u_fold.get_variable() - self.u.get_variable() - r.get_variable(),
);

// Fold the IO:
// Analyze r into limbs
let r_bn = BigNat::from_num(
cs.namespace(|| "allocate r_bn"),
Num::from(r.clone()),
limb_width,
n_limbs,
)?;

// Allocate the order of the non-native field as a constant
let m_bn = alloc_bignat_constant(
cs.namespace(|| "alloc m"),
&G::get_curve_params().2,
limb_width,
n_limbs,
)?;

// Analyze X0 to bignat, NOTE - we copied this code from above but here changed it because the u.X0 is already BigNat
// for u of the type relaxed R1CS
let X0_bn = u.X0.clone();

// Fold self.X[0] + r * X[0]
let (_, r_0) = X0_bn.mult_mod(cs.namespace(|| "r*X[0]"), &r_bn, &m_bn)?;
// add X_r[0]
let r_new_0 = self.X0.add::<CS>(&r_0)?;
// Now reduce
let X0_fold = r_new_0.red_mod(cs.namespace(|| "reduce folded X[0]"), &m_bn)?;

// Analyze X1 to bignat, NOTE - we copied this code from above but here changed it because the u.X0 is already BigNat
// for u of the type relaxed R1CS
let X1_bn = u.X1.clone();

// Fold self.X[1] + r * X[1]
let (_, r_1) = X1_bn.mult_mod(cs.namespace(|| "r*X[1]"), &r_bn, &m_bn)?;
// add X_r[1]
let r_new_1 = self.X1.add::<CS>(&r_1)?;
// Now reduce
let X1_fold = r_new_1.red_mod(cs.namespace(|| "reduce folded X[1]"), &m_bn)?;

Ok(Self {
W: W_fold,
E: E_fold,
u: u_fold,
X0: X0_fold,
X1: X1_fold,
})
}

/// If the condition is true then returns this otherwise it returns the other
pub fn conditionally_select<CS: ConstraintSystem<<G as Group>::Base>>(
Expand Down
46 changes: 34 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ mod bellperson;
mod circuit;
mod constants;
mod nifs;
mod r1cs;
mod parallel_circuit;
mod r1cs;

// public modules
pub mod errors;
pub mod gadgets;
pub mod parallel_prover;
pub mod provider;
pub mod spartan;
pub mod traits;
pub mod parallel_prover;

use crate::bellperson::{
r1cs::{NovaShape, NovaWitness},
Expand Down Expand Up @@ -227,9 +227,13 @@ where
.r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.ck_primary)
.map_err(|_e| NovaError::UnSat)?;

let u_primary = RelaxedR1CSInstance::from_r1cs_instance(&pp.ck_primary, &pp.r1cs_shape_primary, &u_primary);
let u_primary = RelaxedR1CSInstance::from_r1cs_instance(
&pp.ck_primary,
&pp.r1cs_shape_primary,
&u_primary,
);
let w_primary = RelaxedR1CSWitness::from_r1cs_witness(&pp.r1cs_shape_primary, &w_primary);

// base case for the secondary
let mut cs_secondary: SatisfyingAssignment<G2> = SatisfyingAssignment::new();
let inputs_secondary: NovaAugmentedCircuitInputs<G1> = NovaAugmentedCircuitInputs::new(
Expand Down Expand Up @@ -259,8 +263,13 @@ where
let r_U_primary = u_primary;

// IVC proof of the secondary circuit
let l_w_secondary = RelaxedR1CSWitness::<G2>::from_r1cs_witness(&pp.r1cs_shape_secondary, &w_secondary);
let l_u_secondary = RelaxedR1CSInstance::<G2>::from_r1cs_instance( &pp.ck_secondary,&pp.r1cs_shape_secondary,&u_secondary);
let l_w_secondary =
RelaxedR1CSWitness::<G2>::from_r1cs_witness(&pp.r1cs_shape_secondary, &w_secondary);
let l_u_secondary = RelaxedR1CSInstance::<G2>::from_r1cs_instance(
&pp.ck_secondary,
&pp.r1cs_shape_secondary,
&u_secondary,
);
let r_W_secondary = RelaxedR1CSWitness::<G2>::default(&pp.r1cs_shape_secondary);
let r_U_secondary =
RelaxedR1CSInstance::<G2>::default(&pp.ck_secondary, &pp.r1cs_shape_secondary);
Expand Down Expand Up @@ -324,8 +333,13 @@ where
.r1cs_instance_and_witness(&pp.r1cs_shape_primary, &pp.ck_primary)
.map_err(|_e| NovaError::UnSat)?;

let l_u_primary = RelaxedR1CSInstance::from_r1cs_instance(&pp.ck_primary, &pp.r1cs_shape_primary, &l_u_primary);
let l_w_primary = RelaxedR1CSWitness::from_r1cs_witness(&pp.r1cs_shape_primary, &l_w_primary);
let l_u_primary = RelaxedR1CSInstance::from_r1cs_instance(
&pp.ck_primary,
&pp.r1cs_shape_primary,
&l_u_primary,
);
let l_w_primary =
RelaxedR1CSWitness::from_r1cs_witness(&pp.r1cs_shape_primary, &l_w_primary);

// fold the primary circuit's instance
let (nifs_primary, (r_U_primary, r_W_primary)) = NIFS::prove(
Expand Down Expand Up @@ -361,8 +375,13 @@ where
.r1cs_instance_and_witness(&pp.r1cs_shape_secondary, &pp.ck_secondary)
.map_err(|_e| NovaError::UnSat)?;

let l_w_secondary = RelaxedR1CSWitness::<G2>::from_r1cs_witness(&pp.r1cs_shape_secondary, &l_w_secondary);
let l_u_secondary = RelaxedR1CSInstance::<G2>::from_r1cs_instance( &pp.ck_secondary,&pp.r1cs_shape_secondary,&l_u_secondary);
let l_w_secondary =
RelaxedR1CSWitness::<G2>::from_r1cs_witness(&pp.r1cs_shape_secondary, &l_w_secondary);
let l_u_secondary = RelaxedR1CSInstance::<G2>::from_r1cs_instance(
&pp.ck_secondary,
&pp.r1cs_shape_secondary,
&l_u_secondary,
);

// update the running instances and witnesses
let zi_primary = c_primary.output(&r_snark.zi_primary);
Expand Down Expand Up @@ -468,8 +487,11 @@ where
)
},
|| {
pp.r1cs_shape_primary
.is_sat_relaxed(&pp.ck_primary, &self.l_u_primary, &self.l_w_primary)
pp.r1cs_shape_primary.is_sat_relaxed(
&pp.ck_primary,
&self.l_u_primary,
&self.l_w_primary,
)
},
)
},
Expand Down
2 changes: 1 addition & 1 deletion src/nifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ impl<G: Group> NIFS<G> {
mod tests {
use super::*;
use crate::{
r1cs::{R1CS, R1CSInstance, R1CSWitness},
r1cs::{R1CSInstance, R1CSWitness, R1CS},
traits::{Group, ROConstantsTrait},
};
use ::bellperson::{gadgets::num::AllocatedNum, ConstraintSystem, SynthesisError};
Expand Down
Loading

0 comments on commit 0fa40d7

Please sign in to comment.