Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes a bug in the tests #156

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 10 additions & 7 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::{R1CSInstance, RelaxedR1CSInstance},
r1cs::RelaxedR1CSInstance,
traits::{
circuit::StepCircuit, commitment::CommitmentTrait, Group, ROCircuitTrait, ROConstantsCircuit,
},
Expand All @@ -34,9 +34,9 @@ use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NovaAugmentedCircuitParams {
limb_width: usize,
n_limbs: usize,
is_primary_circuit: bool, // A boolean indicating if this is the primary circuit
pub limb_width: usize,
pub n_limbs: usize,
pub is_primary_circuit: bool, // A boolean indicating if this is the primary circuit
}

impl NovaAugmentedCircuitParams {
Expand All @@ -57,7 +57,7 @@ pub struct NovaAugmentedCircuitInputs<G: Group> {
z0: Vec<G::Base>,
zi: Option<Vec<G::Base>>,
U: Option<RelaxedR1CSInstance<G>>,
u: Option<R1CSInstance<G>>,
u: Option<RelaxedR1CSInstance<G>>,
T: Option<Commitment<G>>,
}

Expand All @@ -70,7 +70,7 @@ impl<G: Group> NovaAugmentedCircuitInputs<G> {
z0: Vec<G::Base>,
zi: Option<Vec<G::Base>>,
U: Option<RelaxedR1CSInstance<G>>,
u: Option<R1CSInstance<G>>,
u: Option<RelaxedR1CSInstance<G>>,
T: Option<Commitment<G>>,
) -> Self {
Self {
Expand Down Expand Up @@ -376,6 +376,7 @@ mod tests {
type G2 = pasta_curves::vesta::Point;

use crate::constants::{BN_LIMB_WIDTH, BN_N_LIMBS};
use crate::r1cs::RelaxedR1CSWitness;
use crate::{
bellperson::r1cs::{NovaShape, NovaWitness},
provider::poseidon::PoseidonConstantsCircuit,
Expand Down Expand Up @@ -437,8 +438,10 @@ mod tests {
);
let _ = circuit1.synthesize(&mut cs1);
let (inst1, witness1) = cs1.r1cs_instance_and_witness(&shape1, &ck1).unwrap();
let inst1 = RelaxedR1CSInstance::from_r1cs_instance(&ck1, &shape1, &inst1);
let witness1 = RelaxedR1CSWitness::from_r1cs_witness(&shape1, &witness1);
// Make sure that this is satisfiable
assert!(shape1.is_sat(&ck1, &inst1, &witness1).is_ok());
assert!(shape1.is_sat_relaxed(&ck1, &inst1, &witness1).is_ok());

// Execute the base case for the secondary
let zero2 = <<G1 as Group>::Base as Field>::zero();
Expand Down
3 changes: 3 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,4 +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,
}
101 changes: 99 additions & 2 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::{R1CSInstance, RelaxedR1CSInstance},
r1cs::RelaxedR1CSInstance,
traits::{commitment::CommitmentTrait, Group, ROCircuitTrait, ROConstantsCircuit},
};
use bellperson::{
Expand All @@ -33,7 +33,7 @@ impl<G: Group> AllocatedR1CSInstance<G> {
/// Takes the r1cs instance and creates a new allocated r1cs instance
pub fn alloc<CS: ConstraintSystem<<G as Group>::Base>>(
mut cs: CS,
u: Option<R1CSInstance<G>>,
u: Option<RelaxedR1CSInstance<G>>,
) -> Result<Self, SynthesisError> {
// Check that the incoming instance has exactly 2 io
let W = AllocatedPoint::alloc(
Expand Down Expand Up @@ -338,6 +338,103 @@ 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,
})
}

/// If the condition is true then returns this otherwise it returns the other
pub fn conditionally_select<CS: ConstraintSystem<<G as Group>::Base>>(
&self,
Expand Down
70 changes: 49 additions & 21 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ mod bellperson;
mod circuit;
mod constants;
mod nifs;
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;
Expand All @@ -38,7 +40,7 @@ use errors::NovaError;
use ff::Field;
use gadgets::utils::scalar_as_base;
use nifs::NIFS;
use r1cs::{R1CSInstance, R1CSShape, R1CSWitness, RelaxedR1CSInstance, RelaxedR1CSWitness};
use r1cs::{R1CSShape, RelaxedR1CSInstance, RelaxedR1CSWitness};
use serde::{Deserialize, Serialize};
use traits::{
circuit::StepCircuit,
Expand Down Expand Up @@ -166,12 +168,12 @@ where
{
r_W_primary: RelaxedR1CSWitness<G1>,
r_U_primary: RelaxedR1CSInstance<G1>,
l_w_primary: R1CSWitness<G1>,
l_u_primary: R1CSInstance<G1>,
l_w_primary: RelaxedR1CSWitness<G1>,
l_u_primary: RelaxedR1CSInstance<G1>,
r_W_secondary: RelaxedR1CSWitness<G2>,
r_U_secondary: RelaxedR1CSInstance<G2>,
l_w_secondary: R1CSWitness<G2>,
l_u_secondary: R1CSInstance<G2>,
l_w_secondary: RelaxedR1CSWitness<G2>,
l_u_secondary: RelaxedR1CSInstance<G2>,
i: usize,
zi_primary: Vec<G1::Scalar>,
zi_secondary: Vec<G2::Scalar>,
Expand Down Expand Up @@ -225,6 +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 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 All @@ -248,19 +257,19 @@ where
.map_err(|_e| NovaError::UnSat)?;

// IVC proof for the primary circuit
let l_w_primary = w_primary;
let l_u_primary = u_primary;
let r_W_primary =
RelaxedR1CSWitness::from_r1cs_witness(&pp.r1cs_shape_primary, &l_w_primary);
let r_U_primary = RelaxedR1CSInstance::from_r1cs_instance(
&pp.ck_primary,
&pp.r1cs_shape_primary,
&l_u_primary,
);
let l_w_primary = w_primary.clone();
let l_u_primary = u_primary.clone();
let r_W_primary = w_primary;
let r_U_primary = u_primary;

// IVC proof of the secondary circuit
let l_w_secondary = w_secondary;
let l_u_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,6 +333,14 @@ 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);

// fold the primary circuit's instance
let (nifs_primary, (r_U_primary, r_W_primary)) = NIFS::prove(
&pp.ck_primary,
Expand Down Expand Up @@ -358,6 +375,14 @@ 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,
);

// update the running instances and witnesses
let zi_primary = c_primary.output(&r_snark.zi_primary);
let zi_secondary = c_secondary.output(&r_snark.zi_secondary);
Expand Down Expand Up @@ -462,8 +487,11 @@ where
)
},
|| {
pp.r1cs_shape_primary
.is_sat(&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 All @@ -477,7 +505,7 @@ where
)
},
|| {
pp.r1cs_shape_secondary.is_sat(
pp.r1cs_shape_secondary.is_sat_relaxed(
&pp.ck_secondary,
&self.l_u_secondary,
&self.l_w_secondary,
Expand Down Expand Up @@ -552,12 +580,12 @@ where
S2: RelaxedR1CSSNARKTrait<G2>,
{
r_U_primary: RelaxedR1CSInstance<G1>,
l_u_primary: R1CSInstance<G1>,
l_u_primary: RelaxedR1CSInstance<G1>,
nifs_primary: NIFS<G1>,
f_W_snark_primary: S1,

r_U_secondary: RelaxedR1CSInstance<G2>,
l_u_secondary: R1CSInstance<G2>,
l_u_secondary: RelaxedR1CSInstance<G2>,
nifs_secondary: NIFS<G2>,
f_W_snark_secondary: S2,

Expand Down
Loading