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

Port paranova. #86

Draft
wants to merge 1 commit into
base: dev
Choose a base branch
from
Draft
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
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
Loading