arnaucube
arnaucube/sonobePublic Self-hosted repository
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
winderica winderica@gmail.com
Thu, 03 Oct 2024 22:32:16 +0800
commit

ed1488978cd4170e830c063b152248c71b832da2

parent

a07e17e9db782f9090603b54e15bb5f905b023a4

M folding-schemes/src/folding/hypernova/decider_eth_circuit.rs → folding-schemes/src/folding/hypernova/decider_eth_circuit.rs

@@ -26,7 +26,6 @@ circuits::{CCCSVar, LCCCSVar, NIMFSGadget, ProofVar as NIMFSProofVar},

nimfs::{NIMFSProof, NIMFS}, HyperNova, Witness, CCCS, LCCCS, }; -use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme}; use crate::folding::circuits::{ cyclefold::{CycleFoldCommittedInstance, CycleFoldWitness}, CF1, CF2,

@@ -41,6 +40,10 @@ use crate::Error;

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.

@@ -322,7 +325,7 @@ // allocate the inputs for the check 6

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)) })?;

@@ -423,14 +426,6 @@ // circuit, in the smart contract, but here we're computing it in-circuit, and we reuse the

// `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).

@@ -461,6 +456,10 @@ // in-circuit, and we defer it to outside the circuit.

computed_U_i1.u.enforce_equal(&U_i1.u)?; 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.
M folding-schemes/src/folding/nova/decider_circuits.rs → 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 @@ })?;

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)) })?;

@@ -296,15 +298,11 @@ KZGChallengesGadget::<C1>::get_challenges_gadget(&mut transcript, U_i1.clone())?;

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)

@@ -451,7 +449,7 @@ })?;

// 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 @@ let cs_c_E = FpVar::<CF1<C2>>::new_input(cs.clone(), || {

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)) })?;

@@ -479,14 +477,11 @@ KZGChallengesGadget::<C2>::get_challenges_gadget(&mut transcript, cf_U_i.clone())?;

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(()) }
M folding-schemes/src/folding/nova/decider_eth_circuit.rs → folding-schemes/src/folding/nova/decider_eth_circuit.rs

@@ -383,10 +383,10 @@ let kzg_c_E = FpVar::<CF1<C1>>::new_input(cs.clone(), || {

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)) })?;

@@ -498,15 +498,11 @@ KZGChallengesGadget::<C1>::get_challenges_gadget(&mut transcript, U_i1.clone())?;

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)

@@ -523,13 +519,11 @@

/// 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();

@@ -884,10 +878,6 @@ assert_eq!(challenge_W_Var.value().unwrap(), challenge_W);

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();