Skip to content

Commit

Permalink
Resolve the stack overflow issue when evaluating polynomials in-circu…
Browse files Browse the repository at this point in the history
…it (#166)

* Resolve the stack overflow issue when evaluating polynomials in-circuit

* Format

* Add the missing line of comment
  • Loading branch information
winderica authored Oct 3, 2024
1 parent a07e17e commit ed14889
Show file tree
Hide file tree
Showing 3 changed files with 34 additions and 50 deletions.
19 changes: 9 additions & 10 deletions folding-schemes/src/folding/hypernova/decider_eth_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ use super::{
nimfs::{NIMFSProof, NIMFS},
HyperNova, Witness, CCCS, LCCCS,
};
use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme};
use crate::folding::circuits::{
cyclefold::{CycleFoldCommittedInstance, CycleFoldWitness},
CF1, CF2,
Expand All @@ -42,6 +41,10 @@ use crate::{
arith::{ccs::CCS, r1cs::R1CS},
folding::traits::{CommittedInstanceVarOps, Dummy, WitnessVarOps},
};
use crate::{
commitment::{pedersen::Params as PedersenParams, CommitmentScheme},
folding::nova::decider_eth_circuit::evaluate_gadget,
};

/// In-circuit representation of the Witness associated to the CommittedInstance.
#[derive(Debug, Clone)]
Expand Down Expand Up @@ -322,7 +325,7 @@ where
let kzg_challenge = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
Ok(self.kzg_challenge.unwrap_or_else(CF1::<C1>::zero))
})?;
let _eval_W = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
let eval_W = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
Ok(self.eval_W.unwrap_or_else(CF1::<C1>::zero))
})?;

Expand Down Expand Up @@ -423,14 +426,6 @@ where
// `rho_bits` computed along the way of computing `computed_U_i1` for the later `rho_powers`
// check (6.b).

// Check 7 is temporary disabled due
// https://github.com/privacy-scaling-explorations/sonobe/issues/80
log::warn!("[WARNING]: issue #80 (https://github.com/privacy-scaling-explorations/sonobe/issues/80) is not resolved yet.");
//
// 7. check eval_W==p_W(c_W)
// let incircuit_eval_W = evaluate_gadget::<CF1<C1>>(W_i1.W, incircuit_c_W)?;
// incircuit_eval_W.enforce_equal(&eval_W)?;

// 8.a verify the NIMFS.V of the final fold, and check that the obtained rho_powers from the
// transcript match the one from the public input (so we avoid the onchain logic of the
// verifier computing it).
Expand Down Expand Up @@ -462,6 +457,10 @@ where
computed_U_i1.r_x.enforce_equal(&U_i1.r_x)?;
computed_U_i1.v.enforce_equal(&U_i1.v)?;

// 7. check eval_W==p_W(c_W)
let incircuit_eval_W = evaluate_gadget::<CF1<C1>>(W_i1.w, incircuit_challenge)?;
incircuit_eval_W.enforce_equal(&eval_W)?;

// 8.b check that the in-circuit computed r is equal to the inputted r.

let rho = Boolean::le_bits_to_fp_var(&rho_bits)?;
Expand Down
37 changes: 16 additions & 21 deletions folding-schemes/src/folding/nova/decider_circuits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ use core::marker::PhantomData;

use super::{
circuits::{ChallengeGadget, CommittedInstanceVar},
decider_eth_circuit::{KZGChallengesGadget, R1CSVar, RelaxedR1CSGadget, WitnessVar},
decider_eth_circuit::{
evaluate_gadget, KZGChallengesGadget, R1CSVar, RelaxedR1CSGadget, WitnessVar,
},
nifs::NIFS,
traits::NIFSTrait,
CommittedInstance, Nova, Witness,
Expand Down Expand Up @@ -239,10 +241,10 @@ where
let cs_c_E = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
Ok(self.cs_c_E.unwrap_or_else(CF1::<C1>::zero))
})?;
let _eval_W = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
let eval_W = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
Ok(self.eval_W.unwrap_or_else(CF1::<C1>::zero))
})?;
let _eval_E = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
let eval_E = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
Ok(self.eval_E.unwrap_or_else(CF1::<C1>::zero))
})?;

Expand Down Expand Up @@ -296,15 +298,11 @@ where
incircuit_c_W.enforce_equal(&cs_c_W)?;
incircuit_c_E.enforce_equal(&cs_c_E)?;

// Check 5.2 is temporary disabled due
// https://github.com/privacy-scaling-explorations/sonobe/issues/80
log::warn!("[WARNING]: issue #80 (https://github.com/privacy-scaling-explorations/sonobe/issues/80) is not resolved yet.");
//
// 5.2. check eval_W==p_W(c_W) and eval_E==p_E(c_E)
// let incircuit_eval_W = evaluate_gadget::<CF1<C1>>(W_i1.W, incircuit_c_W)?;
// let incircuit_eval_E = evaluate_gadget::<CF1<C1>>(W_i1.E, incircuit_c_E)?;
// incircuit_eval_W.enforce_equal(&eval_W)?;
// incircuit_eval_E.enforce_equal(&eval_E)?;
let incircuit_eval_W = evaluate_gadget::<CF1<C1>>(W_i1.W, incircuit_c_W)?;
let incircuit_eval_E = evaluate_gadget::<CF1<C1>>(W_i1.E, incircuit_c_E)?;
incircuit_eval_W.enforce_equal(&eval_W)?;
incircuit_eval_E.enforce_equal(&eval_E)?;

// 1.1.b check that the NIFS.V challenge matches the one from the public input (so we avoid
// the verifier computing it)
Expand Down Expand Up @@ -451,7 +449,7 @@ where

// 6. check RelaxedR1CS of cf_U_i
let cf_z_U = [vec![cf_U_i.u.clone()], cf_U_i.x.to_vec(), cf_W_i.W.to_vec()].concat();
RelaxedR1CSGadget::check_native(cf_r1cs, cf_W_i.E, cf_U_i.u.clone(), cf_z_U)?;
RelaxedR1CSGadget::check_native(cf_r1cs, cf_W_i.E.clone(), cf_U_i.u.clone(), cf_z_U)?;

// `transcript` is for challenge generation.
let mut transcript =
Expand All @@ -466,10 +464,10 @@ where
Ok(self.cs_c_E.unwrap_or_else(CF1::<C2>::zero))
})?;
// allocate the inputs for the check 7.2
let _eval_W = FpVar::<CF1<C2>>::new_input(cs.clone(), || {
let eval_W = FpVar::<CF1<C2>>::new_input(cs.clone(), || {
Ok(self.eval_W.unwrap_or_else(CF1::<C2>::zero))
})?;
let _eval_E = FpVar::<CF1<C2>>::new_input(cs.clone(), || {
let eval_E = FpVar::<CF1<C2>>::new_input(cs.clone(), || {
Ok(self.eval_E.unwrap_or_else(CF1::<C2>::zero))
})?;

Expand All @@ -479,14 +477,11 @@ where
incircuit_c_W.enforce_equal(&cs_c_W)?;
incircuit_c_E.enforce_equal(&cs_c_E)?;

// Check 7.2 is temporary disabled due
// https://github.com/privacy-scaling-explorations/sonobe/issues/80
log::warn!("[WARNING]: issue #80 (https://github.com/privacy-scaling-explorations/sonobe/issues/80) is not resolved yet.");
// 7.2. check eval_W==p_W(c_W) and eval_E==p_E(c_E)
// let incircuit_eval_W = evaluate_gadget::<CF1<C1>>(W_i1.W, incircuit_c_W)?;
// let incircuit_eval_E = evaluate_gadget::<CF1<C1>>(W_i1.E, incircuit_c_E)?;
// incircuit_eval_W.enforce_equal(&eval_W)?;
// incircuit_eval_E.enforce_equal(&eval_E)?;
let incircuit_eval_W = evaluate_gadget::<CF1<C2>>(cf_W_i.W, incircuit_c_W)?;
let incircuit_eval_E = evaluate_gadget::<CF1<C2>>(cf_W_i.E, incircuit_c_E)?;
incircuit_eval_W.enforce_equal(&eval_W)?;
incircuit_eval_E.enforce_equal(&eval_E)?;

Ok(())
}
Expand Down
28 changes: 9 additions & 19 deletions folding-schemes/src/folding/nova/decider_eth_circuit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,10 +383,10 @@ where
Ok(self.kzg_c_E.unwrap_or_else(CF1::<C1>::zero))
})?;
// allocate the inputs for the check 5.2
let _eval_W = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
let eval_W = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
Ok(self.eval_W.unwrap_or_else(CF1::<C1>::zero))
})?;
let _eval_E = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
let eval_E = FpVar::<CF1<C1>>::new_input(cs.clone(), || {
Ok(self.eval_E.unwrap_or_else(CF1::<C1>::zero))
})?;

Expand Down Expand Up @@ -498,15 +498,11 @@ where
incircuit_c_W.enforce_equal(&kzg_c_W)?;
incircuit_c_E.enforce_equal(&kzg_c_E)?;

// Check 5.2 is temporary disabled due
// https://github.com/privacy-scaling-explorations/sonobe/issues/80
log::warn!("[WARNING]: issue #80 (https://github.com/privacy-scaling-explorations/sonobe/issues/80) is not resolved yet.");
//
// 5.2. check eval_W==p_W(c_W) and eval_E==p_E(c_E)
// let incircuit_eval_W = evaluate_gadget::<CF1<C1>>(W_i1.W, incircuit_c_W)?;
// let incircuit_eval_E = evaluate_gadget::<CF1<C1>>(W_i1.E, incircuit_c_E)?;
// incircuit_eval_W.enforce_equal(&eval_W)?;
// incircuit_eval_E.enforce_equal(&eval_E)?;
let incircuit_eval_W = evaluate_gadget::<CF1<C1>>(W_i1.W, incircuit_c_W)?;
let incircuit_eval_E = evaluate_gadget::<CF1<C1>>(W_i1.E, incircuit_c_E)?;
incircuit_eval_W.enforce_equal(&eval_W)?;
incircuit_eval_E.enforce_equal(&eval_E)?;

// 1.1.b check that the NIFS.V challenge matches the one from the public input (so we avoid
// the verifier computing it)
Expand All @@ -523,13 +519,11 @@ where
/// Interpolates the polynomial from the given vector, and then returns it's evaluation at the
/// given point.
#[allow(unused)] // unused while check 7 is disabled
fn evaluate_gadget<F: PrimeField>(
v: Vec<FpVar<F>>,
pub fn evaluate_gadget<F: PrimeField>(
mut v: Vec<FpVar<F>>,
point: FpVar<F>,
) -> Result<FpVar<F>, SynthesisError> {
if !v.len().is_power_of_two() {
return Err(SynthesisError::Unsatisfiable);
}
v.resize(v.len().next_power_of_two(), FpVar::zero());
let n = v.len() as u64;
let gen = F::get_root_of_unity(n).unwrap();
let domain = Radix2DomainVar::new(gen, log2(v.len()) as u64, FpVar::one()).unwrap();
Expand Down Expand Up @@ -884,10 +878,6 @@ pub mod tests {
assert_eq!(challenge_E_Var.value().unwrap(), challenge_E);
}

// The test test_polynomial_interpolation is temporary disabled due
// https://github.com/privacy-scaling-explorations/sonobe/issues/80
// for n<=11 it will work, but for n>11 it will fail with stack overflow.
#[ignore]
#[test]
fn test_polynomial_interpolation() {
let mut rng = ark_std::test_rng();
Expand Down

0 comments on commit ed14889

Please sign in to comment.