From ed1488978cd4170e830c063b152248c71b832da2 Mon Sep 17 00:00:00 2001 From: winderica Date: Thu, 3 Oct 2024 22:32:16 +0800 Subject: [PATCH] Resolve the stack overflow issue when evaluating polynomials in-circuit (#166) * Resolve the stack overflow issue when evaluating polynomials in-circuit * Format * Add the missing line of comment --- .../folding/hypernova/decider_eth_circuit.rs | 19 +++++----- .../src/folding/nova/decider_circuits.rs | 37 ++++++++----------- .../src/folding/nova/decider_eth_circuit.rs | 28 +++++--------- 3 files changed, 34 insertions(+), 50 deletions(-) diff --git a/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs b/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs index 6bff8ba..1fdad88 100644 --- a/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs @@ -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, @@ -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)] @@ -322,7 +325,7 @@ where let kzg_challenge = FpVar::>::new_input(cs.clone(), || { Ok(self.kzg_challenge.unwrap_or_else(CF1::::zero)) })?; - let _eval_W = FpVar::>::new_input(cs.clone(), || { + let eval_W = FpVar::>::new_input(cs.clone(), || { Ok(self.eval_W.unwrap_or_else(CF1::::zero)) })?; @@ -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::>(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). @@ -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::>(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)?; diff --git a/folding-schemes/src/folding/nova/decider_circuits.rs b/folding-schemes/src/folding/nova/decider_circuits.rs index 6e84fc0..0db2106 100644 --- a/folding-schemes/src/folding/nova/decider_circuits.rs +++ b/folding-schemes/src/folding/nova/decider_circuits.rs @@ -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, @@ -239,10 +241,10 @@ where let cs_c_E = FpVar::>::new_input(cs.clone(), || { Ok(self.cs_c_E.unwrap_or_else(CF1::::zero)) })?; - let _eval_W = FpVar::>::new_input(cs.clone(), || { + let eval_W = FpVar::>::new_input(cs.clone(), || { Ok(self.eval_W.unwrap_or_else(CF1::::zero)) })?; - let _eval_E = FpVar::>::new_input(cs.clone(), || { + let eval_E = FpVar::>::new_input(cs.clone(), || { Ok(self.eval_E.unwrap_or_else(CF1::::zero)) })?; @@ -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::>(W_i1.W, incircuit_c_W)?; - // let incircuit_eval_E = evaluate_gadget::>(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::>(W_i1.W, incircuit_c_W)?; + let incircuit_eval_E = evaluate_gadget::>(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) @@ -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 = @@ -466,10 +464,10 @@ where Ok(self.cs_c_E.unwrap_or_else(CF1::::zero)) })?; // allocate the inputs for the check 7.2 - let _eval_W = FpVar::>::new_input(cs.clone(), || { + let eval_W = FpVar::>::new_input(cs.clone(), || { Ok(self.eval_W.unwrap_or_else(CF1::::zero)) })?; - let _eval_E = FpVar::>::new_input(cs.clone(), || { + let eval_E = FpVar::>::new_input(cs.clone(), || { Ok(self.eval_E.unwrap_or_else(CF1::::zero)) })?; @@ -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::>(W_i1.W, incircuit_c_W)?; - // let incircuit_eval_E = evaluate_gadget::>(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::>(cf_W_i.W, incircuit_c_W)?; + let incircuit_eval_E = evaluate_gadget::>(cf_W_i.E, incircuit_c_E)?; + incircuit_eval_W.enforce_equal(&eval_W)?; + incircuit_eval_E.enforce_equal(&eval_E)?; Ok(()) } diff --git a/folding-schemes/src/folding/nova/decider_eth_circuit.rs b/folding-schemes/src/folding/nova/decider_eth_circuit.rs index 18abfe8..37a5a67 100644 --- a/folding-schemes/src/folding/nova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/nova/decider_eth_circuit.rs @@ -383,10 +383,10 @@ where Ok(self.kzg_c_E.unwrap_or_else(CF1::::zero)) })?; // allocate the inputs for the check 5.2 - let _eval_W = FpVar::>::new_input(cs.clone(), || { + let eval_W = FpVar::>::new_input(cs.clone(), || { Ok(self.eval_W.unwrap_or_else(CF1::::zero)) })?; - let _eval_E = FpVar::>::new_input(cs.clone(), || { + let eval_E = FpVar::>::new_input(cs.clone(), || { Ok(self.eval_E.unwrap_or_else(CF1::::zero)) })?; @@ -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::>(W_i1.W, incircuit_c_W)?; - // let incircuit_eval_E = evaluate_gadget::>(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::>(W_i1.W, incircuit_c_W)?; + let incircuit_eval_E = evaluate_gadget::>(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) @@ -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( - v: Vec>, +pub fn evaluate_gadget( + mut v: Vec>, point: FpVar, ) -> Result, 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(); @@ -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();