Skip to content

Commit

Permalink
Port paranova.
Browse files Browse the repository at this point in the history
  • Loading branch information
porcuquine committed Oct 28, 2023
1 parent 170818e commit af289aa
Show file tree
Hide file tree
Showing 12 changed files with 1,789 additions and 66 deletions.
18 changes: 11 additions & 7 deletions src/circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,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 @@ -31,9 +31,9 @@ use serde::{Deserialize, Serialize};

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

impl NovaAugmentedCircuitParams {
Expand All @@ -54,7 +54,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 @@ -66,7 +66,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 @@ -372,6 +372,7 @@ mod tests {
bellpepper::r1cs::{NovaShape, NovaWitness},
gadgets::utils::scalar_as_base,
provider::poseidon::PoseidonConstantsCircuit,
r1cs::RelaxedR1CSWitness,
traits::circuit::TrivialCircuit,
};

Expand Down Expand Up @@ -421,8 +422,11 @@ mod tests {
NovaAugmentedCircuit::new(primary_params, Some(inputs1), &tc1, ro_consts1);
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,6 +50,9 @@ pub enum NovaError {
/// returned when the multiset check fails
#[error("InvalidMultisetProof")]
InvalidMultisetProof,
/// 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 product proof check fails
#[error("InvalidProductProof")]
InvalidProductProof,
Expand Down
105 changes: 103 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 bellpepper::gadgets::{boolean::Boolean, num::AllocatedNum, Assignment};
Expand All @@ -31,7 +31,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 @@ -315,6 +315,107 @@ 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 + 10);
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);
ro.absorb(&T.y);
ro.absorb(&T.is_infinity);
let r_bits = ro.squeeze(cs.namespace(|| "r bits"), NUM_CHALLENGE_BITS)?;
let r = le_bits_to_num(cs.namespace(|| "r"), &r_bits)?;

// W_fold = self.W + r * u.W
let rW = u.W.scalar_mul(cs.namespace(|| "r * u.W"), &r_bits)?;
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)?;
let r_e_2 = u.E.scalar_mul(cs.namespace(|| "r * E_2"), &r_bits)?;
// 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(|| "rT + 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_u_r = AllocatedNum::alloc(cs.namespace(|| "u_u times r"), || {
Ok(*self.u.get_value().get()? * r.get_value().get()?)
})?;
let u_fold = AllocatedNum::alloc(cs.namespace(|| "u_fold"), || {
Ok(*self.u.get_value().get()? + u_u_r.get_value().get()?)
})?;
cs.enforce(
|| "Check u_fold",
|lc| lc,
|lc| lc,
|lc| lc + u_fold.get_variable() - self.u.get_variable() - u_u_r.get_variable(),
);

// Fold the IO:
// Analyze r into limbs
let r_bn = BigNat::from_num(
cs.namespace(|| "allocate r_bn"),
&Num::from(r),
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(&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(&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
Loading

0 comments on commit af289aa

Please sign in to comment.