From 1ef933a70707fe08865c88ca71269e87fa887855 Mon Sep 17 00:00:00 2001 From: winderica Date: Thu, 26 Dec 2024 17:00:51 +0800 Subject: [PATCH 1/2] Refactor and simplify the design of traits (#189) * Simplify trait bounds by introducing `Sonobe{Field, Curve}` * `ToEth` trait * Simplify `Inputize` by separating `InputizeNonNative` from it * Refactor * Make CycleFold related interfaces cleaner * Fmt and fix clippy * Remove the `Sonobe` prefix from `Field` and `Curve` traits --- benches/common.rs | 14 +- benches/hypernova.rs | 12 +- benches/nova.rs | 12 +- benches/protogalaxy.rs | 12 +- examples/circom_full_flow.rs | 9 +- examples/external_inputs.rs | 6 +- examples/full_flow.rs | 20 +- examples/multi_inputs.rs | 6 +- examples/noir_full_flow.rs | 19 +- examples/noname_full_flow.rs | 17 +- examples/sha256.rs | 6 +- folding-schemes/src/arith/mod.rs | 5 +- folding-schemes/src/arith/r1cs/circuits.rs | 10 +- folding-schemes/src/commitment/ipa.rs | 89 ++--- folding-schemes/src/commitment/kzg.rs | 19 +- folding-schemes/src/commitment/mod.rs | 17 +- folding-schemes/src/commitment/pedersen.rs | 35 +- .../src/folding/circuits/cyclefold.rs | 367 ++++++------------ .../src/folding/circuits/decider/mod.rs | 16 +- .../src/folding/circuits/decider/off_chain.rs | 35 +- .../src/folding/circuits/decider/on_chain.rs | 40 +- .../src/folding/circuits/nonnative/affine.rs | 139 ++++--- .../src/folding/circuits/nonnative/uint.rs | 122 +++--- folding-schemes/src/folding/hypernova/cccs.rs | 46 +-- .../src/folding/hypernova/circuits.rs | 252 +++++------- .../src/folding/hypernova/decider_eth.rs | 54 +-- .../folding/hypernova/decider_eth_circuit.rs | 39 +- .../src/folding/hypernova/lcccs.rs | 50 +-- folding-schemes/src/folding/hypernova/mod.rs | 198 ++++------ .../src/folding/hypernova/nimfs.rs | 17 +- .../src/folding/hypernova/utils.rs | 10 +- folding-schemes/src/folding/mod.rs | 26 +- folding-schemes/src/folding/nova/circuits.rs | 79 ++-- folding-schemes/src/folding/nova/decider.rs | 70 +--- .../src/folding/nova/decider_circuits.rs | 50 +-- .../src/folding/nova/decider_eth.rs | 127 ++---- .../src/folding/nova/decider_eth_circuit.rs | 47 +-- folding-schemes/src/folding/nova/mod.rs | 288 +++++--------- folding-schemes/src/folding/nova/nifs/mod.rs | 7 +- folding-schemes/src/folding/nova/nifs/mova.rs | 39 +- folding-schemes/src/folding/nova/nifs/nova.rs | 27 +- .../src/folding/nova/nifs/nova_circuits.rs | 40 +- folding-schemes/src/folding/nova/nifs/ova.rs | 48 +-- .../src/folding/nova/nifs/ova_circuits.rs | 36 +- .../src/folding/nova/nifs/pointvsline.rs | 15 +- folding-schemes/src/folding/nova/traits.rs | 9 +- folding-schemes/src/folding/nova/zk.rs | 158 +++----- .../src/folding/protogalaxy/circuits.rs | 73 ++-- .../src/folding/protogalaxy/decider_eth.rs | 65 +--- .../protogalaxy/decider_eth_circuit.rs | 35 +- .../src/folding/protogalaxy/folding.rs | 15 +- .../src/folding/protogalaxy/mod.rs | 195 ++++------ .../src/folding/protogalaxy/traits.rs | 25 +- folding-schemes/src/folding/traits.rs | 48 ++- folding-schemes/src/frontend/utils.rs | 8 +- folding-schemes/src/lib.rs | 83 +++- folding-schemes/src/transcript/mod.rs | 32 +- folding-schemes/src/transcript/poseidon.rs | 4 +- .../src/utils/espresso/sum_check/mod.rs | 5 +- folding-schemes/src/utils/eth.rs | 58 +++ folding-schemes/src/utils/gadgets.rs | 7 +- folding-schemes/src/utils/mod.rs | 11 +- .../src/verifiers/nova_cyclefold.rs | 19 +- 63 files changed, 1342 insertions(+), 2100 deletions(-) create mode 100644 folding-schemes/src/utils/eth.rs diff --git a/benches/common.rs b/benches/common.rs index 2f0b57cc..6c632b4b 100644 --- a/benches/common.rs +++ b/benches/common.rs @@ -1,26 +1,20 @@ -use ark_ec::CurveGroup; -use ark_ff::PrimeField; use criterion::*; use folding_schemes::{ frontend::{utils::CustomFCircuit, FCircuit}, - Error, FoldingScheme, + Curve, Error, FoldingScheme, }; pub(crate) fn bench_ivc_opt< - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, FS: FoldingScheme>, >( c: &mut Criterion, name: String, n: usize, prep_param: FS::PreprocessorParam, -) -> Result<(), Error> -where - C1: CurveGroup, - C2::BaseField: PrimeField, -{ +) -> Result<(), Error> { let fcircuit_size = 1 << n; // 2^n let f_circuit = CustomFCircuit::::new(fcircuit_size)?; diff --git a/benches/hypernova.rs b/benches/hypernova.rs index 103822cd..d3f4421c 100644 --- a/benches/hypernova.rs +++ b/benches/hypernova.rs @@ -1,10 +1,10 @@ use criterion::*; use pprof::criterion::{Output, PProfProfiler}; -use ark_bn254::{constraints::GVar as bn_GVar, Fr as bn_Fr, G1Projective as bn_G}; -use ark_grumpkin::{constraints::GVar as grumpkin_GVar, Projective as grumpkin_G}; -use ark_pallas::{constraints::GVar as pallas_GVar, Fr as pallas_Fr, Projective as pallas_G}; -use ark_vesta::{constraints::GVar as vesta_GVar, Projective as vesta_G}; +use ark_bn254::{Fr as bn_Fr, G1Projective as bn_G}; +use ark_grumpkin::Projective as grumpkin_G; +use ark_pallas::{Fr as pallas_Fr, Projective as pallas_G}; +use ark_vesta::Projective as vesta_G; use folding_schemes::{ commitment::pedersen::Pedersen, @@ -30,9 +30,7 @@ fn bench_hypernova_ivc(c: &mut Criterion) { vesta_G, HyperNova< pallas_G, - pallas_GVar, vesta_G, - vesta_GVar, CustomFCircuit, Pedersen, Pedersen, @@ -60,9 +58,7 @@ fn bench_hypernova_ivc(c: &mut Criterion) { grumpkin_G, HyperNova< bn_G, - bn_GVar, grumpkin_G, - grumpkin_GVar, CustomFCircuit, Pedersen, Pedersen, diff --git a/benches/nova.rs b/benches/nova.rs index 469e2358..eed5419e 100644 --- a/benches/nova.rs +++ b/benches/nova.rs @@ -1,10 +1,10 @@ use criterion::*; use pprof::criterion::{Output, PProfProfiler}; -use ark_bn254::{constraints::GVar as bn_GVar, Fr as bn_Fr, G1Projective as bn_G}; -use ark_grumpkin::{constraints::GVar as grumpkin_GVar, Projective as grumpkin_G}; -use ark_pallas::{constraints::GVar as pallas_GVar, Fr as pallas_Fr, Projective as pallas_G}; -use ark_vesta::{constraints::GVar as vesta_GVar, Projective as vesta_G}; +use ark_bn254::{Fr as bn_Fr, G1Projective as bn_G}; +use ark_grumpkin::Projective as grumpkin_G; +use ark_pallas::{Fr as pallas_Fr, Projective as pallas_G}; +use ark_vesta::Projective as vesta_G; use folding_schemes::{ commitment::pedersen::Pedersen, @@ -30,9 +30,7 @@ fn bench_nova_ivc(c: &mut Criterion) { vesta_G, Nova< pallas_G, - pallas_GVar, vesta_G, - vesta_GVar, CustomFCircuit, Pedersen, Pedersen, @@ -53,9 +51,7 @@ fn bench_nova_ivc(c: &mut Criterion) { grumpkin_G, Nova< bn_G, - bn_GVar, grumpkin_G, - grumpkin_GVar, CustomFCircuit, Pedersen, Pedersen, diff --git a/benches/protogalaxy.rs b/benches/protogalaxy.rs index cbe72fac..ace36c35 100644 --- a/benches/protogalaxy.rs +++ b/benches/protogalaxy.rs @@ -1,10 +1,10 @@ use criterion::*; use pprof::criterion::{Output, PProfProfiler}; -use ark_bn254::{constraints::GVar as bn_GVar, Fr as bn_Fr, G1Projective as bn_G}; -use ark_grumpkin::{constraints::GVar as grumpkin_GVar, Projective as grumpkin_G}; -use ark_pallas::{constraints::GVar as pallas_GVar, Fr as pallas_Fr, Projective as pallas_G}; -use ark_vesta::{constraints::GVar as vesta_GVar, Projective as vesta_G}; +use ark_bn254::{Fr as bn_Fr, G1Projective as bn_G}; +use ark_grumpkin::Projective as grumpkin_G; +use ark_pallas::{Fr as pallas_Fr, Projective as pallas_G}; +use ark_vesta::Projective as vesta_G; use folding_schemes::{ commitment::pedersen::Pedersen, @@ -30,9 +30,7 @@ fn bench_protogalaxy_ivc(c: &mut Criterion) { vesta_G, ProtoGalaxy< pallas_G, - pallas_GVar, vesta_G, - vesta_GVar, CustomFCircuit, Pedersen, Pedersen, @@ -57,9 +55,7 @@ fn bench_protogalaxy_ivc(c: &mut Criterion) { grumpkin_G, ProtoGalaxy< bn_G, - bn_GVar, grumpkin_G, - grumpkin_GVar, CustomFCircuit, Pedersen, Pedersen, diff --git a/examples/circom_full_flow.rs b/examples/circom_full_flow.rs index 16748b89..b0d92fb2 100644 --- a/examples/circom_full_flow.rs +++ b/examples/circom_full_flow.rs @@ -9,10 +9,10 @@ /// - generate the Solidity contract that verifies the proof /// - verify the proof in the EVM /// -use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1}; +use ark_bn254::{Bn254, Fr, G1Projective as G1}; use ark_groth16::Groth16; -use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2}; +use ark_grumpkin::Projective as G2; use std::path::PathBuf; use std::time::Instant; @@ -67,13 +67,10 @@ fn main() -> Result<(), Error> { let f_circuit_params = (r1cs_path.into(), wasm_path.into(), 1, 2); let f_circuit = CircomFCircuit::::new(f_circuit_params)?; - pub type N = - Nova, KZG<'static, Bn254>, Pedersen, false>; + pub type N = Nova, KZG<'static, Bn254>, Pedersen, false>; pub type D = DeciderEth< G1, - GVar, G2, - GVar2, CircomFCircuit, KZG<'static, Bn254>, Pedersen, diff --git a/examples/external_inputs.rs b/examples/external_inputs.rs index 1df27ad2..60427b00 100644 --- a/examples/external_inputs.rs +++ b/examples/external_inputs.rs @@ -3,7 +3,7 @@ #![allow(non_camel_case_types)] #![allow(clippy::upper_case_acronyms)] -use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; +use ark_bn254::{Bn254, Fr, G1Projective as Projective}; use ark_crypto_primitives::{ crh::{ poseidon::constraints::{CRHGadget, CRHParametersVar}, @@ -12,7 +12,7 @@ use ark_crypto_primitives::{ sponge::{poseidon::PoseidonConfig, Absorb}, }; use ark_ff::PrimeField; -use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; +use ark_grumpkin::Projective as Projective2; use ark_r1cs_std::alloc::AllocVar; use ark_r1cs_std::fields::fp::FpVar; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; @@ -169,9 +169,7 @@ fn main() -> Result<(), Error> { /// trait, and the rest of our code would be working without needing to be updated. type N = Nova< Projective, - GVar, Projective2, - GVar2, ExternalInputsCircuit, KZG<'static, Bn254>, Pedersen, diff --git a/examples/full_flow.rs b/examples/full_flow.rs index 4c302f2e..648171f0 100644 --- a/examples/full_flow.rs +++ b/examples/full_flow.rs @@ -9,10 +9,10 @@ /// - generate the Solidity contract that verifies the proof /// - verify the proof in the EVM /// -use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1}; +use ark_bn254::{Bn254, Fr, G1Projective as G1}; use ark_ff::PrimeField; use ark_groth16::Groth16; -use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2}; +use ark_grumpkin::Projective as G2; use ark_r1cs_std::alloc::AllocVar; use ark_r1cs_std::fields::fp::FpVar; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; @@ -76,19 +76,9 @@ fn main() -> Result<(), Error> { let f_circuit = CubicFCircuit::::new(())?; - pub type N = - Nova, KZG<'static, Bn254>, Pedersen, false>; - pub type D = DeciderEth< - G1, - GVar, - G2, - GVar2, - CubicFCircuit, - KZG<'static, Bn254>, - Pedersen, - Groth16, - N, - >; + pub type N = Nova, KZG<'static, Bn254>, Pedersen, false>; + pub type D = + DeciderEth, KZG<'static, Bn254>, Pedersen, Groth16, N>; let poseidon_config = poseidon_canonical_config::(); let mut rng = ark_std::rand::rngs::OsRng; diff --git a/examples/multi_inputs.rs b/examples/multi_inputs.rs index e3cdea53..67b32cf4 100644 --- a/examples/multi_inputs.rs +++ b/examples/multi_inputs.rs @@ -10,8 +10,8 @@ use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use core::marker::PhantomData; use std::time::Instant; -use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; -use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; +use ark_bn254::{Bn254, Fr, G1Projective as Projective}; +use ark_grumpkin::Projective as Projective2; use folding_schemes::commitment::{kzg::KZG, pedersen::Pedersen}; use folding_schemes::folding::nova::{Nova, PreprocessorParam}; @@ -123,9 +123,7 @@ fn main() -> Result<(), Error> { /// trait, and the rest of our code would be working without needing to be updated. type N = Nova< Projective, - GVar, Projective2, - GVar2, MultiInputsFCircuit, KZG<'static, Bn254>, Pedersen, diff --git a/examples/noir_full_flow.rs b/examples/noir_full_flow.rs index aa2fc2da..147903e1 100644 --- a/examples/noir_full_flow.rs +++ b/examples/noir_full_flow.rs @@ -9,10 +9,10 @@ /// - generate the Solidity contract that verifies the proof /// - verify the proof in the EVM /// -use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1}; +use ark_bn254::{Bn254, Fr, G1Projective as G1}; use ark_groth16::Groth16; -use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2}; +use ark_grumpkin::Projective as G2; use experimental_frontends::noir::NoirFCircuit; use folding_schemes::{ @@ -49,18 +49,9 @@ fn main() -> Result<(), Error> { 0, ))?; - pub type N = Nova, KZG<'static, Bn254>, Pedersen>; - pub type D = DeciderEth< - G1, - GVar, - G2, - GVar2, - NoirFCircuit, - KZG<'static, Bn254>, - Pedersen, - Groth16, - N, - >; + pub type N = Nova, KZG<'static, Bn254>, Pedersen>; + pub type D = + DeciderEth, KZG<'static, Bn254>, Pedersen, Groth16, N>; let poseidon_config = poseidon_canonical_config::(); let mut rng = ark_std::rand::rngs::OsRng; diff --git a/examples/noname_full_flow.rs b/examples/noname_full_flow.rs index 0cf55e1d..6bfb80bd 100644 --- a/examples/noname_full_flow.rs +++ b/examples/noname_full_flow.rs @@ -9,11 +9,11 @@ /// - generate the Solidity contract that verifies the proof /// - verify the proof in the EVM /// -use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1}; +use ark_bn254::{Bn254, Fr, G1Projective as G1}; use noname::backends::r1cs::R1csBn254Field; use ark_groth16::Groth16; -use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2}; +use ark_grumpkin::Projective as G2; use experimental_frontends::noname::NonameFCircuit; use folding_schemes::{ @@ -61,20 +61,11 @@ fn main() -> Result<(), Error> { let f_circuit_params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2, 2); let f_circuit = NonameFCircuit::::new(f_circuit_params)?; - pub type N = Nova< - G1, - GVar, - G2, - GVar2, - NonameFCircuit, - KZG<'static, Bn254>, - Pedersen, - >; + pub type N = + Nova, KZG<'static, Bn254>, Pedersen>; pub type D = DeciderEth< G1, - GVar, G2, - GVar2, NonameFCircuit, KZG<'static, Bn254>, Pedersen, diff --git a/examples/sha256.rs b/examples/sha256.rs index 02c978be..95f75d16 100644 --- a/examples/sha256.rs +++ b/examples/sha256.rs @@ -16,8 +16,8 @@ use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use core::marker::PhantomData; use std::time::Instant; -use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; -use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; +use ark_bn254::{Bn254, Fr, G1Projective as Projective}; +use ark_grumpkin::Projective as Projective2; use folding_schemes::commitment::{kzg::KZG, pedersen::Pedersen}; use folding_schemes::folding::nova::{Nova, PreprocessorParam}; @@ -107,9 +107,7 @@ fn main() -> Result<(), Error> { /// trait, and the rest of our code would be working without needing to be updated. type N = Nova< Projective, - GVar, Projective2, - GVar2, Sha256FCircuit, KZG<'static, Bn254>, Pedersen, diff --git a/folding-schemes/src/arith/mod.rs b/folding-schemes/src/arith/mod.rs index b5ebd7b8..06c67142 100644 --- a/folding-schemes/src/arith/mod.rs +++ b/folding-schemes/src/arith/mod.rs @@ -1,8 +1,7 @@ -use ark_ec::CurveGroup; use ark_relations::r1cs::SynthesisError; use ark_std::rand::RngCore; -use crate::{commitment::CommitmentScheme, folding::traits::Dummy, Error}; +use crate::{commitment::CommitmentScheme, folding::traits::Dummy, Curve, Error}; pub mod ccs; pub mod r1cs; @@ -123,7 +122,7 @@ pub trait ArithSerializer { /// in a plain R1CS. /// /// [HyperNova]: https://eprint.iacr.org/2023/573.pdf -pub trait ArithSampler: Arith { +pub trait ArithSampler: Arith { /// Samples a random witness and instance that satisfy the constraint system. fn sample_witness_instance>( &self, diff --git a/folding-schemes/src/arith/r1cs/circuits.rs b/folding-schemes/src/arith/r1cs/circuits.rs index e870b585..70b3975b 100644 --- a/folding-schemes/src/arith/r1cs/circuits.rs +++ b/folding-schemes/src/arith/r1cs/circuits.rs @@ -95,7 +95,7 @@ pub mod tests { }, CRHScheme, CRHSchemeGadget, }; - use ark_ec::CurveGroup; + use ark_ff::BigInteger; use ark_pallas::{Fq, Fr, Projective}; use ark_r1cs_std::{eq::EqGadget, fields::fp::FpVar, uint8::UInt8}; @@ -104,7 +104,7 @@ pub mod tests { rand::{thread_rng, Rng}, One, UniformRand, }; - use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_vesta::Projective as Projective2; use super::*; use crate::arith::{ @@ -131,9 +131,9 @@ pub mod tests { }, FCircuit, }; - use crate::Error; + use crate::{Curve, Error}; - fn prepare_instances, R: Rng>( + fn prepare_instances, R: Rng>( mut rng: R, r1cs: &R1CS, z: &[C::ScalarField], @@ -295,7 +295,7 @@ pub mod tests { // non-natively let cs = ConstraintSystem::::new_ref(); let wVar = CycleFoldWitnessVar::new_witness(cs.clone(), || Ok(w))?; - let uVar = CycleFoldCommittedInstanceVar::<_, GVar2>::new_witness(cs.clone(), || Ok(u))?; + let uVar = CycleFoldCommittedInstanceVar::new_witness(cs.clone(), || Ok(u))?; let r1csVar = R1CSMatricesVar::>::new_witness(cs.clone(), || Ok(r1cs))?; r1csVar.enforce_relation(&wVar, &uVar)?; diff --git a/folding-schemes/src/commitment/ipa.rs b/folding-schemes/src/commitment/ipa.rs index a06949eb..9ec75d53 100644 --- a/folding-schemes/src/commitment/ipa.rs +++ b/folding-schemes/src/commitment/ipa.rs @@ -7,12 +7,13 @@ /// i. computation is done in log time following a modification of the equation 3 in section /// 3.2 from the paper. /// ii. s computation is done in 2^{k+1}-2 instead of k*2^k. -use ark_ec::{AffineRepr, CurveGroup}; +use ark_ec::AffineRepr; use ark_ff::{Field, PrimeField}; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, boolean::Boolean, convert::ToBitsGadget, + eq::EqGadget, fields::{emulated_fp::EmulatedFpVar, FieldVar}, prelude::CurveVar, }; @@ -23,15 +24,16 @@ use core::{borrow::Borrow, marker::PhantomData}; use rayon::iter::{IndexedParallelIterator, IntoParallelRefIterator, ParallelIterator}; use super::{pedersen::Params as PedersenParams, CommitmentScheme}; +use crate::folding::circuits::CF2; use crate::transcript::Transcript; use crate::utils::{ powers_of, vec::{vec_add, vec_scalar_mul}, }; -use crate::Error; +use crate::{Curve, Error}; #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct Proof { +pub struct Proof { a: C::ScalarField, l: Vec, r: Vec, @@ -42,12 +44,12 @@ pub struct Proof { /// IPA implements the Inner Product Argument protocol following the CommitmentScheme trait. The /// `H` parameter indicates if to use the commitment in hiding mode or not. #[derive(Debug, Clone, Eq, PartialEq)] -pub struct IPA { +pub struct IPA { _c: PhantomData, } /// Implements the CommitmentScheme trait for IPA -impl CommitmentScheme for IPA { +impl CommitmentScheme for IPA { type ProverParams = PedersenParams; type VerifierParams = PedersenParams; type Proof = (Proof, C::ScalarField, C::ScalarField); // (proof, v=p(x), r=blinding factor) @@ -434,40 +436,35 @@ fn s_b_inner_gadget( Ok(c) } -pub type CF = <::BaseField as Field>::BasePrimeField; - -pub struct ProofVar>> { - a: EmulatedFpVar>, - l: Vec>>, - r: Vec>>, - L: Vec, - R: Vec, +pub struct ProofVar { + a: EmulatedFpVar>, + l: Vec>>, + r: Vec>>, + L: Vec, + R: Vec, } -impl AllocVar, CF> for ProofVar -where - C: CurveGroup, - GC: CurveVar>, - ::BaseField: PrimeField, -{ +impl AllocVar, CF2> for ProofVar { fn new_variable>>( - cs: impl Into>>, + cs: impl Into>>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result { f().and_then(|val| { let cs = cs.into(); - let a = EmulatedFpVar::>::new_variable( + let a = EmulatedFpVar::>::new_variable( cs.clone(), || Ok(val.borrow().a), mode, )?; - let l: Vec>> = + let l: Vec>> = Vec::new_variable(cs.clone(), || Ok(val.borrow().l.clone()), mode)?; - let r: Vec>> = + let r: Vec>> = Vec::new_variable(cs.clone(), || Ok(val.borrow().r.clone()), mode)?; - let L: Vec = Vec::new_variable(cs.clone(), || Ok(val.borrow().L.clone()), mode)?; - let R: Vec = Vec::new_variable(cs.clone(), || Ok(val.borrow().R.clone()), mode)?; + let L: Vec = + Vec::new_variable(cs.clone(), || Ok(val.borrow().L.clone()), mode)?; + let R: Vec = + Vec::new_variable(cs.clone(), || Ok(val.borrow().R.clone()), mode)?; Ok(Self { a, l, r, L, R }) }) @@ -477,36 +474,26 @@ where /// IPAGadget implements the circuit that verifies an IPA Proof. The `H` parameter indicates if to /// use the commitment in hiding mode or not, reducing a bit the number of constraints needed in /// the later case. -pub struct IPAGadget -where - C: CurveGroup, - GC: CurveVar>, -{ - _cf: PhantomData>, +pub struct IPAGadget { _c: PhantomData, - _gc: PhantomData, } -impl IPAGadget -where - C: CurveGroup, - GC: CurveVar>, -{ +impl IPAGadget { /// Verify the IPA opening proof, K=log2(d), where d is the degree of the committed polynomial, /// and H indicates if the commitment is in hiding mode and thus uses blinding factors, if not, /// there are some constraints saved. #[allow(clippy::too_many_arguments)] pub fn verify( - g: &[GC], // params.generators - h: &GC, // params.h - x: &EmulatedFpVar>, // evaluation point, challenge - v: &EmulatedFpVar>, // value at evaluation point - P: &GC, // commitment - p: &ProofVar, - r: &EmulatedFpVar>, // blinding factor - u: &[EmulatedFpVar>; K], // challenges - U: &GC, // challenge - ) -> Result>, SynthesisError> { + g: &[C::Var], // params.generators + h: &C::Var, // params.h + x: &EmulatedFpVar>, // evaluation point, challenge + v: &EmulatedFpVar>, // value at evaluation point + P: &C::Var, // commitment + p: &ProofVar, + r: &EmulatedFpVar>, // blinding factor + u: &[EmulatedFpVar>; K], // challenges + U: &C::Var, // challenge + ) -> Result>, SynthesisError> { if p.L.len() != K || p.R.len() != K { return Err(SynthesisError::Unsatisfiable); } @@ -516,7 +503,7 @@ where let mut r = r.clone(); // compute u[i]^-1 once - let mut u_invs = vec![EmulatedFpVar::>::zero(); u.len()]; + let mut u_invs = vec![EmulatedFpVar::>::zero(); u.len()]; for (j, u_j) in u.iter().enumerate() { u_invs[j] = u_j.inverse()?; } @@ -531,7 +518,7 @@ where } // msm: G= - let mut G = GC::zero(); + let mut G = C::Var::zero(); for (i, s_i) in s.iter().enumerate() { G += g[i].scalar_mul_le(s_i.to_bits_le()?.iter())?; } @@ -681,7 +668,7 @@ mod tests { let challengeVar = EmulatedFpVar::::new_witness(cs.clone(), || Ok(challenge))?; let vVar = EmulatedFpVar::::new_witness(cs.clone(), || Ok(proof.1))?; let cmVar = GVar::new_witness(cs.clone(), || Ok(cm))?; - let proofVar = ProofVar::::new_witness(cs.clone(), || Ok(proof.0))?; + let proofVar = ProofVar::::new_witness(cs.clone(), || Ok(proof.0))?; let r_blindVar = EmulatedFpVar::::new_witness(cs.clone(), || Ok(r_blind))?; let uVar_vec = Vec::>::new_witness(cs.clone(), || Ok(u))?; let uVar: [EmulatedFpVar; k] = uVar_vec.try_into().map_err(|_| { @@ -693,7 +680,7 @@ mod tests { })?; let UVar = GVar::new_witness(cs.clone(), || Ok(U))?; - let v = IPAGadget::::verify::( + let v = IPAGadget::::verify::( &gVar, &hVar, &challengeVar, diff --git a/folding-schemes/src/commitment/kzg.rs b/folding-schemes/src/commitment/kzg.rs index 84bde282..eec15bb3 100644 --- a/folding-schemes/src/commitment/kzg.rs +++ b/folding-schemes/src/commitment/kzg.rs @@ -24,17 +24,17 @@ use rayon::iter::{IntoParallelRefIterator, ParallelIterator}; use super::CommitmentScheme; use crate::transcript::Transcript; use crate::utils::vec::poly_from_vec; -use crate::Error; +use crate::{Curve, Error}; /// ProverKey defines a similar struct as in ark_poly_commit::kzg10::Powers, but instead of -/// depending on the Pairing trait it depends on the CurveGroup trait. +/// depending on the Pairing trait it depends on the SonobeCurve trait. #[derive(Debug, Clone, Default, Eq, PartialEq)] -pub struct ProverKey<'a, C: CurveGroup> { +pub struct ProverKey<'a, C: Curve> { /// Group elements of the form `β^i G`, for different values of `i`. pub powers_of_g: Cow<'a, [C::Affine]>, } -impl<'a, C: CurveGroup> CanonicalSerialize for ProverKey<'a, C> { +impl<'a, C: Curve> CanonicalSerialize for ProverKey<'a, C> { fn serialize_with_mode( &self, mut writer: W, @@ -48,7 +48,7 @@ impl<'a, C: CurveGroup> CanonicalSerialize for ProverKey<'a, C> { } } -impl<'a, C: CurveGroup> CanonicalDeserialize for ProverKey<'a, C> { +impl<'a, C: Curve> CanonicalDeserialize for ProverKey<'a, C> { fn deserialize_with_mode( reader: R, compress: ark_serialize::Compress, @@ -61,7 +61,7 @@ impl<'a, C: CurveGroup> CanonicalDeserialize for ProverKey<'a, C> { } } -impl<'a, C: CurveGroup> Valid for ProverKey<'a, C> { +impl<'a, C: Curve> Valid for ProverKey<'a, C> { fn check(&self) -> Result<(), ark_serialize::SerializationError> { match self.powers_of_g.clone() { Cow::Borrowed(powers) => powers.to_vec().check(), @@ -71,7 +71,7 @@ impl<'a, C: CurveGroup> Valid for ProverKey<'a, C> { } #[derive(Debug, Clone, Default, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct Proof { +pub struct Proof { pub eval: C::ScalarField, pub proof: C, } @@ -83,10 +83,7 @@ pub struct KZG<'a, E: Pairing, const H: bool = false> { _e: PhantomData, } -impl<'a, E, const H: bool> CommitmentScheme for KZG<'a, E, H> -where - E: Pairing, -{ +impl<'a, E: Pairing, const H: bool> CommitmentScheme for KZG<'a, E, H> { type ProverParams = ProverKey<'a, E::G1>; type VerifierParams = VerifierKey; type Proof = Proof; diff --git a/folding-schemes/src/commitment/mod.rs b/folding-schemes/src/commitment/mod.rs index a6de1f7d..0c9301d6 100644 --- a/folding-schemes/src/commitment/mod.rs +++ b/folding-schemes/src/commitment/mod.rs @@ -1,10 +1,9 @@ -use ark_ec::CurveGroup; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::fmt::Debug; use ark_std::rand::RngCore; use crate::transcript::Transcript; -use crate::Error; +use crate::{Curve, Error}; pub mod ipa; pub mod kzg; @@ -12,7 +11,7 @@ pub mod pedersen; /// CommitmentScheme defines the vector commitment scheme trait. Where `H` indicates if to use the /// commitment in hiding mode or not. -pub trait CommitmentScheme: Clone + Debug { +pub trait CommitmentScheme: Clone + Debug { type ProverParams: Clone + Debug + CanonicalSerialize + CanonicalDeserialize; type VerifierParams: Clone + Debug + CanonicalSerialize + CanonicalDeserialize; type Proof: Clone + Debug + CanonicalSerialize + CanonicalDeserialize; @@ -74,7 +73,7 @@ mod tests { use ark_bn254::{Bn254, Fr, G1Projective as G1}; use ark_crypto_primitives::sponge::{ poseidon::{PoseidonConfig, PoseidonSponge}, - Absorb, CryptographicSponge, + CryptographicSponge, }; use ark_poly_commit::kzg10::VerifierKey; use ark_std::Zero; @@ -131,20 +130,14 @@ mod tests { Ok(()) } - fn test_homomorphic_property_using_Commitment_trait_opt< - C: CurveGroup, - CS: CommitmentScheme, - >( + fn test_homomorphic_property_using_Commitment_trait_opt>( poseidon_config: &PoseidonConfig, prover_params: &CS::ProverParams, verifier_params: &CS::VerifierParams, r: C::ScalarField, v_1: &[C::ScalarField], v_2: &[C::ScalarField], - ) -> Result<(), Error> - where - C::ScalarField: Absorb, - { + ) -> Result<(), Error> { // compute the commitment of the two vectors using the given CommitmentScheme let cm_1 = CS::commit(prover_params, v_1, &C::ScalarField::zero())?; let cm_2 = CS::commit(prover_params, v_2, &C::ScalarField::zero())?; diff --git a/folding-schemes/src/commitment/pedersen.rs b/folding-schemes/src/commitment/pedersen.rs index 88a2e4f9..a9e8d850 100644 --- a/folding-schemes/src/commitment/pedersen.rs +++ b/folding-schemes/src/commitment/pedersen.rs @@ -1,4 +1,3 @@ -use ark_ec::CurveGroup; use ark_r1cs_std::{boolean::Boolean, convert::ToBitsGadget, prelude::CurveVar}; use ark_relations::r1cs::SynthesisError; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -8,28 +7,28 @@ use super::CommitmentScheme; use crate::folding::circuits::CF2; use crate::transcript::Transcript; use crate::utils::vec::{vec_add, vec_scalar_mul}; -use crate::Error; +use crate::{Curve, Error}; #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct Proof { +pub struct Proof { pub R: C, pub u: Vec, pub r_u: C::ScalarField, // blind } #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct Params { +pub struct Params { pub h: C, pub generators: Vec, } #[derive(Debug, Clone, Eq, PartialEq)] -pub struct Pedersen { +pub struct Pedersen { _c: PhantomData, } /// Implements the CommitmentScheme trait for Pedersen commitments -impl CommitmentScheme for Pedersen { +impl CommitmentScheme for Pedersen { type ProverParams = Params; type VerifierParams = Params; type Proof = Proof; @@ -175,28 +174,18 @@ impl CommitmentScheme for Pedersen { } } -pub struct PedersenGadget -where - C: CurveGroup, - GC: CurveVar>, -{ - _cf: PhantomData>, +pub struct PedersenGadget { _c: PhantomData, - _gc: PhantomData, } -impl PedersenGadget -where - C: CurveGroup, - GC: CurveVar>, -{ +impl PedersenGadget { pub fn commit( - h: &GC, - g: &[GC], + h: &C::Var, + g: &[C::Var], v: &[Vec>>], r: &[Boolean>], - ) -> Result { - let mut res = GC::zero(); + ) -> Result { + let mut res = C::Var::zero(); if H { res += h.scalar_mul_le(r.iter())?; } @@ -294,7 +283,7 @@ mod tests { let expected_cmVar = GVar::new_witness(cs.clone(), || Ok(cm))?; // use the gadget - let cmVar = PedersenGadget::::commit(&hVar, &gVar, &vVar, &rVar)?; + let cmVar = PedersenGadget::::commit(&hVar, &gVar, &vVar, &rVar)?; cmVar.enforce_equal(&expected_cmVar)?; Ok(()) } diff --git a/folding-schemes/src/folding/circuits/cyclefold.rs b/folding-schemes/src/folding/circuits/cyclefold.rs index 850bfb3a..d0bc623a 100644 --- a/folding-schemes/src/folding/circuits/cyclefold.rs +++ b/folding-schemes/src/folding/circuits/cyclefold.rs @@ -1,11 +1,12 @@ /// Contains [CycleFold](https://eprint.iacr.org/2023/1192.pdf) related circuits and functions that /// are shared across the different folding schemes -use ark_crypto_primitives::sponge::{Absorb, CryptographicSponge}; -use ark_ec::{AffineRepr, CurveGroup}; -use ark_ff::{BigInteger, Field, PrimeField}; +use ark_crypto_primitives::sponge::{poseidon::PoseidonSponge, Absorb, CryptographicSponge}; +use ark_ec::AffineRepr; +use ark_ff::{BigInteger, PrimeField}; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, boolean::Boolean, + convert::ToConstraintFieldGadget, eq::EqGadget, fields::fp::FpVar, prelude::CurveVar, @@ -16,7 +17,7 @@ use ark_relations::r1cs::{ }; use ark_std::fmt::Debug; use ark_std::rand::RngCore; -use ark_std::{One, Zero}; +use ark_std::Zero; use core::{borrow::Borrow, marker::PhantomData}; use super::{nonnative::uint::NonNativeUintVar, CF1, CF2}; @@ -31,9 +32,9 @@ use crate::{ r1cs::{circuits::R1CSMatricesVar, extract_w_x, R1CS}, ArithGadget, }, - folding::traits::Inputize, + folding::traits::InputizeNonNative, + Curve, }; -use ark_crypto_primitives::sponge::poseidon::PoseidonSponge; /// Re-export the Nova committed instance as `CycleFoldCommittedInstance` and /// witness as `CycleFoldWitness`, for clarity and consistency @@ -41,47 +42,31 @@ pub use crate::folding::nova::{ CommittedInstance as CycleFoldCommittedInstance, Witness as CycleFoldWitness, }; -impl>> Inputize, CycleFoldCommittedInstanceVar> - for CycleFoldCommittedInstance -{ - fn inputize(&self) -> Vec> { - let cmE = self.cmE.into_affine(); - let cmW = self.cmW.into_affine(); - let (cmE_x, cmE_y) = cmE.xy().unwrap_or_default(); - let (cmW_x, cmW_y) = cmW.xy().unwrap_or_default(); - self.u - .inputize() - .into_iter() - .chain(self.x.iter().flat_map(|x| x.inputize())) - .chain( - [ - cmE_x, - cmE_y, - C::BaseField::one(), - cmW_x, - cmW_y, - C::BaseField::one(), - ] - .into_iter() - .flat_map(|x| x.to_base_prime_field_elements().collect::>()), - ) - .collect() +impl InputizeNonNative> for CycleFoldCommittedInstance { + /// Returns the internal representation in the same order as how the value + /// is allocated in `CycleFoldCommittedInstanceVar::new_input`. + fn inputize_nonnative(&self) -> Vec> { + [ + self.u.inputize_nonnative(), + self.x.inputize_nonnative(), + self.cmE.inputize(), + self.cmW.inputize(), + ] + .concat() } } /// CycleFoldCommittedInstanceVar is the CycleFold CommittedInstance represented /// in folding verifier circuit #[derive(Debug, Clone)] -pub struct CycleFoldCommittedInstanceVar>> { - pub cmE: GC, +pub struct CycleFoldCommittedInstanceVar { + pub cmE: C::Var, pub u: NonNativeUintVar>, - pub cmW: GC, + pub cmW: C::Var, pub x: Vec>>, } -impl AllocVar, CF2> for CycleFoldCommittedInstanceVar -where - C: CurveGroup, - GC: CurveVar>, +impl AllocVar, CF2> + for CycleFoldCommittedInstanceVar { fn new_variable>>( cs: impl Into>>, @@ -95,21 +80,18 @@ where NonNativeUintVar::>::new_variable(cs.clone(), || Ok(val.borrow().u), mode)?; let x: Vec>> = Vec::new_variable(cs.clone(), || Ok(val.borrow().x.clone()), mode)?; - let cmE = GC::new_variable(cs.clone(), || Ok(val.borrow().cmE), mode)?; - let cmW = GC::new_variable(cs.clone(), || Ok(val.borrow().cmW), mode)?; + let cmE = C::Var::new_variable(cs.clone(), || Ok(val.borrow().cmE), mode)?; + let cmW = C::Var::new_variable(cs.clone(), || Ok(val.borrow().cmW), mode)?; Ok(Self { cmE, u, cmW, x }) }) } } -impl AbsorbNonNative for CycleFoldCommittedInstance -where - C::BaseField: PrimeField + Absorb, -{ +impl AbsorbNonNative for CycleFoldCommittedInstance { // Compatible with the in-circuit `CycleFoldCommittedInstanceVar::to_native_sponge_field_elements` - fn to_native_sponge_field_elements(&self, dest: &mut Vec) { - [self.u].to_native_sponge_field_elements(dest); + fn to_native_sponge_field_elements(&self, dest: &mut Vec) { + self.u.to_native_sponge_field_elements(dest); self.x.to_native_sponge_field_elements(dest); let (cmE_x, cmE_y) = self.cmE.into_affine().xy().unwrap_or_default(); let (cmW_x, cmW_y) = self.cmW.into_affine().xy().unwrap_or_default(); @@ -120,12 +102,7 @@ where } } -impl AbsorbNonNativeGadget for CycleFoldCommittedInstanceVar -where - C: CurveGroup, - GC: CurveVar>, - C::BaseField: PrimeField + Absorb, -{ +impl AbsorbNonNativeGadget for CycleFoldCommittedInstanceVar { /// Extracts the underlying field elements from `CycleFoldCommittedInstanceVar`, in the order /// of `u`, `x`, `cmE.x`, `cmE.y`, `cmW.x`, `cmW.y`, `cmE.is_inf || cmW.is_inf` (|| is for /// concat). @@ -152,10 +129,7 @@ where } } -impl CycleFoldCommittedInstance -where - C::BaseField: PrimeField + Absorb, -{ +impl CycleFoldCommittedInstance { /// hash_cyclefold implements the committed instance hash compatible with the /// in-circuit implementation `CycleFoldCommittedInstanceVar::hash`. /// Returns `H(U_i)`, where `U_i` is a `CycleFoldCommittedInstance`. @@ -171,12 +145,7 @@ where } } -impl CycleFoldCommittedInstanceVar -where - C: CurveGroup, - GC: CurveVar>, - C::BaseField: PrimeField + Absorb, -{ +impl CycleFoldCommittedInstanceVar { /// hash implements the committed instance hash compatible with the native /// implementation `CycleFoldCommittedInstance::hash_cyclefold`. /// Returns `H(U_i)`, where `U` is a `CycleFoldCommittedInstanceVar`. @@ -202,59 +171,18 @@ where } } -/// CommittedInstanceInCycleFoldVar represents the Nova CommittedInstance in the CycleFold circuit, -/// where the commitments to E and W (cmW and cmW) from the CommittedInstance on the E2, -/// represented as native points, which are folded on the auxiliary curve constraints field (E2::Fr -/// = E1::Fq). -#[derive(Debug, Clone)] -pub struct CommittedInstanceInCycleFoldVar>> { - _c: PhantomData, - pub cmE: GC, - pub cmW: GC, -} - -impl AllocVar, CF2> - for CommittedInstanceInCycleFoldVar -where - C: CurveGroup, - GC: CurveVar>, -{ - fn new_variable>>( - cs: impl Into>>, - f: impl FnOnce() -> Result, - mode: AllocationMode, - ) -> Result { - f().and_then(|val| { - let cs = cs.into(); - - let cmE = GC::new_variable(cs.clone(), || Ok(val.borrow().cmE), mode)?; - let cmW = GC::new_variable(cs.clone(), || Ok(val.borrow().cmW), mode)?; - - Ok(Self { - _c: PhantomData, - cmE, - cmW, - }) - }) - } -} - /// In-circuit representation of the Witness associated to the CommittedInstance, but with /// non-native representation, since it is used to represent the CycleFold witness. This struct is /// used in the Decider circuit. #[derive(Debug, Clone)] -pub struct CycleFoldWitnessVar { +pub struct CycleFoldWitnessVar { pub E: Vec>>, pub rE: NonNativeUintVar>, pub W: Vec>>, pub rW: NonNativeUintVar>, } -impl AllocVar, CF2> for CycleFoldWitnessVar -where - C: CurveGroup, - C::BaseField: PrimeField, -{ +impl AllocVar, CF2> for CycleFoldWitnessVar { fn new_variable>>( cs: impl Into>>, f: impl FnOnce() -> Result, @@ -277,24 +205,18 @@ where /// This is the gadget used in the AugmentedFCircuit to verify the CycleFold instances folding, /// which checks the correct RLC of u,x,cmE,cmW (hence the name containing 'Full', since it checks /// all the RLC values, not only the native ones). It assumes that ci2.cmE=0, ci2.u=1. -pub struct NIFSFullGadget>> { +pub struct NIFSFullGadget { _c: PhantomData, - _gc: PhantomData, } -impl>> NIFSFullGadget -where - C: CurveGroup, - GC: CurveVar>, - C::BaseField: PrimeField, -{ +impl NIFSFullGadget { pub fn fold_committed_instance( r_bits: Vec>>, - cmT: GC, - ci1: CycleFoldCommittedInstanceVar, + cmT: C::Var, + ci1: CycleFoldCommittedInstanceVar, // ci2 is assumed to be always with cmE=0, u=1 (checks done previous to this method) - ci2: CycleFoldCommittedInstanceVar, - ) -> Result, SynthesisError> { + ci2: CycleFoldCommittedInstanceVar, + ) -> Result, SynthesisError> { // r_nonnat is equal to r_bits just that in a different format let r_nonnat = { let mut bits = r_bits.clone(); @@ -320,11 +242,11 @@ where pub fn verify( // assumes that r_bits is equal to r_nonnat just that in a different format r_bits: Vec>>, - cmT: GC, - ci1: CycleFoldCommittedInstanceVar, + cmT: C::Var, + ci1: CycleFoldCommittedInstanceVar, // ci2 is assumed to be always with cmE=0, u=1 (checks done previous to this method) - ci2: CycleFoldCommittedInstanceVar, - ci3: CycleFoldCommittedInstanceVar, + ci2: CycleFoldCommittedInstanceVar, + ci3: CycleFoldCommittedInstanceVar, ) -> Result<(), SynthesisError> { let ci = Self::fold_committed_instance(r_bits, cmT, ci1, ci2)?; @@ -339,8 +261,7 @@ where } } -impl>> - ArithGadget, CycleFoldCommittedInstanceVar> +impl ArithGadget, CycleFoldCommittedInstanceVar> for R1CSMatricesVar, NonNativeUintVar>> { type Evaluation = (Vec>>, Vec>>); @@ -348,14 +269,14 @@ impl>> fn eval_relation( &self, w: &CycleFoldWitnessVar, - u: &CycleFoldCommittedInstanceVar, + u: &CycleFoldCommittedInstanceVar, ) -> Result { self.eval_at_z(&[&[u.u.clone()][..], &u.x, &w.W].concat()) } fn enforce_evaluation( w: &CycleFoldWitnessVar, - _u: &CycleFoldCommittedInstanceVar, + _u: &CycleFoldCommittedInstanceVar, (AzBz, uCz): Self::Evaluation, ) -> Result<(), SynthesisError> { EquivalenceGadget::>::enforce_equivalent(&AzBz[..], &uCz.add(&w.E)?[..]) @@ -364,16 +285,10 @@ impl>> /// CycleFoldChallengeGadget computes the RO challenge used for the CycleFold instances NIFS, it contains a /// rust-native and a in-circuit compatible versions. -pub struct CycleFoldChallengeGadget>> { +pub struct CycleFoldChallengeGadget { _c: PhantomData, // Nova's Curve2, the one used for the CycleFold circuit - _gc: PhantomData, } -impl CycleFoldChallengeGadget -where - C: CurveGroup, - GC: CurveVar>, - C::BaseField: PrimeField + Absorb, -{ +impl CycleFoldChallengeGadget { pub fn get_challenge_native>( transcript: &mut T, pp_hash: C::BaseField, // public params hash @@ -393,8 +308,8 @@ where transcript: &mut T, pp_hash: FpVar, // public params hash U_i_vec: Vec>, - u_i: CycleFoldCommittedInstanceVar, - cmT: GC, + u_i: CycleFoldCommittedInstanceVar, + cmT: C::Var, ) -> Result>, SynthesisError> { transcript.absorb(&pp_hash)?; transcript.absorb(&U_i_vec)?; @@ -430,15 +345,14 @@ pub trait CycleFoldConfig { Self::RANDOMNESS_BIT_LENGTH.div_ceil(Self::FIELD_CAPACITY) + 2 * Self::N_INPUT_POINTS + 2 }; - type C: CurveGroup; + type C: Curve; } /// CycleFoldCircuit contains the constraints that check the correct fold of the committed /// instances from Curve1. Namely, it checks the random linear combinations of the elliptic curve /// (Curve1) points of u_i, U_i leading to U_{i+1} #[derive(Debug, Clone)] -pub struct CycleFoldCircuit>> { - pub _gc: PhantomData, +pub struct CycleFoldCircuit { /// r_bits is the bit representation of the r whose powers are used in the /// random-linear-combination inside the CycleFoldCircuit pub r_bits: Option>, @@ -446,20 +360,17 @@ pub struct CycleFoldCircuit>, } -impl>> CycleFoldCircuit { +impl CycleFoldCircuit { /// n_points indicates the number of points being folded in the CycleFoldCircuit pub fn empty() -> Self { Self { - _gc: PhantomData, r_bits: None, points: None, } } } -impl>> ConstraintSynthesizer> - for CycleFoldCircuit -{ +impl ConstraintSynthesizer> for CycleFoldCircuit { fn generate_constraints( self, cs: ConstraintSystemRef>, @@ -469,7 +380,7 @@ impl>> ConstraintSynthesi .r_bits .unwrap_or(vec![false; CFG::RANDOMNESS_BIT_LENGTH])) })?; - let points = Vec::::new_witness(cs.clone(), || { + let points = Vec::<::Var>::new_witness(cs.clone(), || { Ok(self .points .unwrap_or(vec![CFG::C::zero(); CFG::N_INPUT_POINTS])) @@ -490,7 +401,7 @@ impl>> ConstraintSynthesi // P_folded = p_0 + r * P_1 + r^2 * P_2 + r^3 * P_3 + ... + r^{n-2} * P_{n-2} + r^{n-1} * P_{n-1} // so in order to do it more efficiently (less constraints) we do // P_folded = (((P_{n-1} * r + P_{n-2}) * r + P_{n-3})... ) * r + P_0 - let mut p_folded: GC = points[CFG::N_INPUT_POINTS - 1].clone(); + let mut p_folded = points[CFG::N_INPUT_POINTS - 1].clone(); for i in (0..CFG::N_INPUT_POINTS - 1).rev() { p_folded = p_folded.scalar_mul_le(r_bits.iter())? + points[i].clone(); } @@ -543,31 +454,11 @@ impl>> ConstraintSynthesi /// different fields than the main NIFS impls (Nova, Mova, Ova). Could be abstracted, but it's a /// tradeoff between overcomplexity at the NIFSTrait and the (not much) need of generalization at /// the CycleFoldNIFS. -pub struct CycleFoldNIFS< - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, - CS2: CommitmentScheme, - const H: bool = false, -> where - ::BaseField: PrimeField, - ::BaseField: PrimeField, -{ - _c1: PhantomData, +pub struct CycleFoldNIFS, const H: bool = false> { _c2: PhantomData, - _gc2: PhantomData, _cs: PhantomData, } -impl, const H: bool> - CycleFoldNIFS -where - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, - GC2: CurveVar>, -{ +impl, const H: bool> CycleFoldNIFS { fn prove( cf_r_Fq: C2::ScalarField, // C2::Fr==C1::Fq cf_W_i: &CycleFoldWitness, @@ -604,80 +495,75 @@ where /// scheme struct because it is used both by Nova & HyperNova's CycleFold. #[allow(clippy::type_complexity)] #[allow(clippy::too_many_arguments)] -pub fn fold_cyclefold_circuit( - transcript: &mut impl Transcript, +pub fn fold_cyclefold_circuit( + transcript: &mut impl Transcript>, cf_r1cs: R1CS, cf_cs_params: CS2::ProverParams, - pp_hash: C1::ScalarField, // public params hash + pp_hash: CF2, // public params hash cf_W_i: CycleFoldWitness, // witness of the running instance cf_U_i: CycleFoldCommittedInstance, // running instance - cf_circuit: CycleFoldCircuit, + cf_circuit: CycleFoldCircuit, mut rng: impl RngCore, ) -> Result< ( - CycleFoldWitness, CycleFoldCommittedInstance, // u_i CycleFoldWitness, // W_i1 CycleFoldCommittedInstance, // U_i1 C2, // cmT - C2::ScalarField, // r_Fq ), Error, > where - CFG: CycleFoldConfig, - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + CFG: CycleFoldConfig, + C2: Curve, BaseField = CF1>, CS2: CommitmentScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, { - let cs2 = ConstraintSystem::::new_ref(); + let cs2 = ConstraintSystem::new_ref(); cf_circuit.generate_constraints(cs2.clone())?; let cs2 = cs2.into_inner().ok_or(Error::NoInnerConstraintSystem)?; - let (cf_w_i, cf_x_i) = extract_w_x::(&cs2); + let (cf_w_i, cf_x_i) = extract_w_x(&cs2); #[cfg(test)] assert_eq!(cf_x_i.len(), CFG::IO_LEN); // fold cyclefold instances let cf_w_i = CycleFoldWitness::::new::(cf_w_i.clone(), cf_r1cs.A.n_rows, &mut rng); - let cf_u_i: CycleFoldCommittedInstance = - cf_w_i.commit::(&cf_cs_params, cf_x_i.clone())?; + let cf_u_i = cf_w_i.commit::(&cf_cs_params, cf_x_i.clone())?; // compute T* and cmT* for CycleFoldCircuit - let (cf_T, cf_cmT) = - NIFS::, H>::compute_cyclefold_cmT( - &cf_cs_params, - &cf_r1cs, - &cf_w_i, - &cf_u_i, - &cf_W_i, - &cf_U_i, - )?; + let (cf_T, cf_cmT) = NIFS::>, H>::compute_cyclefold_cmT( + &cf_cs_params, + &cf_r1cs, + &cf_w_i, + &cf_u_i, + &cf_W_i, + &cf_U_i, + )?; - let cf_r_bits = CycleFoldChallengeGadget::::get_challenge_native( + let cf_r_bits = CycleFoldChallengeGadget::get_challenge_native( transcript, pp_hash, cf_U_i.clone(), cf_u_i.clone(), cf_cmT, ); - let cf_r_Fq = C1::BaseField::from_bigint(BigInteger::from_bits_le(&cf_r_bits)) + let cf_r_Fq = CF1::::from_bigint(BigInteger::from_bits_le(&cf_r_bits)) .expect("cf_r_bits out of bounds"); - let (cf_W_i1, cf_U_i1) = CycleFoldNIFS::::prove( + let (cf_W_i1, cf_U_i1) = CycleFoldNIFS::::prove( cf_r_Fq, &cf_W_i, &cf_U_i, &cf_w_i, &cf_u_i, &cf_T, cf_cmT, )?; - let cf_r_Fq = C1::BaseField::from_bigint(BigInteger::from_bits_le(&cf_r_bits)) - .expect("cf_r_bits out of bounds"); - Ok((cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, cf_r_Fq)) + + #[cfg(test)] + { + use crate::{arith::Arith, folding::traits::CommittedInstanceOps}; + cf_u_i.check_incoming()?; + cf_r1cs.check_relation(&cf_w_i, &cf_u_i)?; + cf_r1cs.check_relation(&cf_W_i1, &cf_U_i1)?; + } + + Ok((cf_u_i, cf_W_i1, cf_U_i1, cf_cmT)) } #[cfg(test)] @@ -696,38 +582,16 @@ pub mod tests { use crate::transcript::poseidon::poseidon_canonical_config; use crate::utils::get_cm_coordinates; - struct TestCycleFoldConfig { + struct TestCycleFoldConfig { _c: PhantomData, } - impl CycleFoldConfig for TestCycleFoldConfig { + impl CycleFoldConfig for TestCycleFoldConfig { const RANDOMNESS_BIT_LENGTH: usize = NOVA_N_BITS_RO; const N_INPUT_POINTS: usize = N; type C = C; } - #[test] - fn test_committed_instance_cyclefold_var() -> Result<(), Error> { - let mut rng = ark_std::test_rng(); - - let ci = CycleFoldCommittedInstance:: { - cmE: Projective::rand(&mut rng), - u: Fr::rand(&mut rng), - cmW: Projective::rand(&mut rng), - x: vec![Fr::rand(&mut rng); 1], - }; - - // check the instantiation of the CycleFold side: - let cs = ConstraintSystem::::new_ref(); - let ciVar = - CommittedInstanceInCycleFoldVar::::new_witness(cs.clone(), || { - Ok(ci.clone()) - })?; - assert_eq!(ciVar.cmE.value()?, ci.cmE); - assert_eq!(ciVar.cmW.value()?, ci.cmW); - Ok(()) - } - #[test] fn test_CycleFoldCircuit_n_points_constraints() -> Result<(), Error> { const n: usize = 16; @@ -763,8 +627,7 @@ pub mod tests { get_cm_coordinates(&res), ] .concat(); - let cf_circuit = CycleFoldCircuit::, GVar> { - _gc: PhantomData, + let cf_circuit = CycleFoldCircuit::> { r_bits: Some(rho_bits), points: Some(points), }; @@ -809,21 +672,18 @@ pub mod tests { let cs = ConstraintSystem::::new_ref(); let r_bitsVar = Vec::>::new_witness(cs.clone(), || Ok(r_bits))?; - let ci1Var = - CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(ci1.clone()) - })?; - let ci2Var = - CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(ci2.clone()) - })?; - let ci3Var = - CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(ci3.clone()) - })?; + let ci1Var = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { + Ok(ci1.clone()) + })?; + let ci2Var = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { + Ok(ci2.clone()) + })?; + let ci3Var = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { + Ok(ci3.clone()) + })?; let cmTVar = GVar::new_witness(cs.clone(), || Ok(cmT))?; - NIFSFullGadget::::verify(r_bitsVar, cmTVar, ci1Var, ci2Var, ci3Var)?; + NIFSFullGadget::::verify(r_bitsVar, cmTVar, ci1Var, ci2Var, ci3Var)?; assert!(cs.is_satisfied()?); Ok(()) } @@ -854,7 +714,7 @@ pub mod tests { // compute the challenge natively let pp_hash = Fq::from(42u32); // only for test - let r_bits = CycleFoldChallengeGadget::::get_challenge_native( + let r_bits = CycleFoldChallengeGadget::::get_challenge_native( &mut transcript, pp_hash, U_i.clone(), @@ -863,20 +723,18 @@ pub mod tests { ); let cs = ConstraintSystem::::new_ref(); - let u_iVar = - CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(u_i.clone()) - })?; - let U_iVar = - CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(U_i.clone()) - })?; + let u_iVar = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { + Ok(u_i.clone()) + })?; + let U_iVar = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { + Ok(U_i.clone()) + })?; let cmTVar = GVar::new_witness(cs.clone(), || Ok(cmT))?; let mut transcript_var = PoseidonSpongeVar::::new(ConstraintSystem::::new_ref(), &poseidon_config); let pp_hashVar = FpVar::::new_witness(cs.clone(), || Ok(pp_hash))?; - let r_bitsVar = CycleFoldChallengeGadget::::get_challenge_gadget( + let r_bitsVar = CycleFoldChallengeGadget::::get_challenge_gadget( &mut transcript_var, pp_hashVar, U_iVar.to_native_sponge_field_elements()?, @@ -911,10 +769,9 @@ pub mod tests { let h = U_i.hash_cyclefold(&sponge, pp_hash); let cs = ConstraintSystem::::new_ref(); - let U_iVar = - CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { - Ok(U_i.clone()) - })?; + let U_iVar = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { + Ok(U_i.clone()) + })?; let pp_hashVar = FpVar::::new_witness(cs.clone(), || Ok(pp_hash))?; let (hVar, _) = U_iVar.hash( &PoseidonSpongeVar::new(cs.clone(), &poseidon_config), diff --git a/folding-schemes/src/folding/circuits/decider/mod.rs b/folding-schemes/src/folding/circuits/decider/mod.rs index 68b8657b..fbfda6fb 100644 --- a/folding-schemes/src/folding/circuits/decider/mod.rs +++ b/folding-schemes/src/folding/circuits/decider/mod.rs @@ -1,11 +1,9 @@ use ark_crypto_primitives::sponge::{ poseidon::constraints::PoseidonSpongeVar, CryptographicSponge, }; -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_poly::Polynomial; use ark_r1cs_std::{ - convert::ToConstraintFieldGadget, fields::{fp::FpVar, FieldVar}, poly::{domain::Radix2DomainVar, evaluations::univariate::EvaluationsVar}, }; @@ -15,8 +13,8 @@ use ark_std::log2; use crate::folding::traits::{CommittedInstanceOps, CommittedInstanceVarOps, Dummy, WitnessOps}; use crate::transcript::{Transcript, TranscriptVar}; use crate::utils::vec::poly_from_vec; -use crate::Error; use crate::{arith::Arith, folding::circuits::CF1}; +use crate::{Curve, Error}; pub mod off_chain; pub mod on_chain; @@ -26,11 +24,7 @@ pub mod on_chain; pub struct KZGChallengesGadget {} impl KZGChallengesGadget { - pub fn get_challenges_native< - C: CurveGroup, - T: Transcript>, - U: CommittedInstanceOps, - >( + pub fn get_challenges_native>, U: CommittedInstanceOps>( transcript: &mut T, U_i: &U, ) -> Vec> { @@ -43,7 +37,7 @@ impl KZGChallengesGadget { } pub fn get_challenges_gadget< - C: CurveGroup, + C: Curve, S: CryptographicSponge, T: TranscriptVar, S>, U: CommittedInstanceVarOps, @@ -53,7 +47,7 @@ impl KZGChallengesGadget { ) -> Result>>, SynthesisError> { let mut challenges = vec![]; for cm in U_i.get_commitments() { - transcript.absorb(&cm.to_constraint_field()?)?; + transcript.absorb_nonnative(&cm)?; challenges.push(transcript.get_challenge()?); } Ok(challenges) @@ -101,7 +95,7 @@ impl EvalGadget { /// In the future, we may introduce a better solution that uses a trait for all /// folding schemes that specifies their native and in-circuit behaviors. pub trait DeciderEnabledNIFS< - C: CurveGroup, + C: Curve, RU: CommittedInstanceOps, // Running instance IU: CommittedInstanceOps, // Incoming instance W: WitnessOps>, diff --git a/folding-schemes/src/folding/circuits/decider/off_chain.rs b/folding-schemes/src/folding/circuits/decider/off_chain.rs index c13aecbd..1ea8c71a 100644 --- a/folding-schemes/src/folding/circuits/decider/off_chain.rs +++ b/folding-schemes/src/folding/circuits/decider/off_chain.rs @@ -5,10 +5,8 @@ use ark_crypto_primitives::sponge::{ constraints::{AbsorbGadget, CryptographicSpongeVar}, poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig}, - Absorb, }; -use ark_ec::CurveGroup; -use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::fp::FpVar, prelude::CurveVar}; +use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::fp::FpVar}; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; use ark_std::{marker::PhantomData, Zero}; @@ -29,6 +27,7 @@ use crate::{ nova::{decider_eth_circuit::WitnessVar, nifs::nova_circuits::CommittedInstanceVar}, traits::{CommittedInstanceOps, CommittedInstanceVarOps, Dummy, WitnessOps, WitnessVarOps}, }, + Curve, }; use super::DeciderEnabledNIFS; @@ -36,9 +35,8 @@ use super::DeciderEnabledNIFS; /// Circuit that implements part of the in-circuit checks needed for the offchain verification over /// the Curve2's BaseField (=Curve1's ScalarField). pub struct GenericOffchainDeciderCircuit1< - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, RU: CommittedInstanceOps, // Running instance IU: CommittedInstanceOps, // Incoming instance W: WitnessOps>, // Witness @@ -46,7 +44,6 @@ pub struct GenericOffchainDeciderCircuit1< AVar: ArithGadget, // In-circuit representation of `A` D: DeciderEnabledNIFS, > { - pub _gc2: PhantomData, pub _avar: PhantomData, /// Constraint system of the Augmented Function circuit pub arith: A, @@ -79,9 +76,8 @@ pub struct GenericOffchainDeciderCircuit1< } impl< - C1: CurveGroup, - C2: CurveGroup, BaseField = CF1>, - GC2: CurveVar>, + C1: Curve, + C2: Curve, BaseField = CF1>, RU: CommittedInstanceOps + for<'a> Dummy<&'a A>, IU: CommittedInstanceOps + for<'a> Dummy<&'a A>, W: WitnessOps> + for<'a> Dummy<&'a A>, @@ -97,7 +93,7 @@ impl< D::RandomnessDummyCfg, usize, usize, - )> for GenericOffchainDeciderCircuit1 + )> for GenericOffchainDeciderCircuit1 { fn dummy( ( @@ -119,7 +115,6 @@ impl< ), ) -> Self { Self { - _gc2: PhantomData, _avar: PhantomData, poseidon_config, pp_hash: Zero::zero(), @@ -143,9 +138,8 @@ impl< } impl< - C1: CurveGroup, - C2: CurveGroup, BaseField = CF1>, - GC2: CurveVar>, + C1: Curve, + C2: Curve, BaseField = CF1>, RU: CommittedInstanceOps, IU: CommittedInstanceOps, W: WitnessOps>, @@ -153,10 +147,9 @@ impl< AVar: ArithGadget + AllocVar>, D: DeciderEnabledNIFS, > ConstraintSynthesizer> - for GenericOffchainDeciderCircuit1 + for GenericOffchainDeciderCircuit1 where RU::Var: AbsorbGadget> + CommittedInstanceVarOps>, - CF1: Absorb, { fn generate_constraints(self, cs: ConstraintSystemRef>) -> Result<(), SynthesisError> { let arith = AVar::new_witness(cs.clone(), || Ok(&self.arith))?; @@ -177,7 +170,7 @@ where U_i1.get_commitments().enforce_equal(&U_i1_commitments)?; let cf_U_i = - CycleFoldCommittedInstanceVar::::new_input(cs.clone(), || Ok(self.cf_U_i))?; + CycleFoldCommittedInstanceVar::::new_input(cs.clone(), || Ok(self.cf_U_i))?; // allocate the inputs for the checks 7.1 and 7.2 let kzg_challenges = Vec::new_input(cs.clone(), || Ok(self.kzg_challenges))?; @@ -234,7 +227,7 @@ where /// Circuit that implements part of the in-circuit checks needed for the offchain verification over /// the Curve1's BaseField (=Curve2's ScalarField). -pub struct GenericOffchainDeciderCircuit2 { +pub struct GenericOffchainDeciderCircuit2 { /// R1CS of the CycleFold circuit pub cf_arith: R1CS>, pub poseidon_config: PoseidonConfig>, @@ -250,7 +243,7 @@ pub struct GenericOffchainDeciderCircuit2 { pub kzg_evaluations: Vec>, } -impl Dummy<(R1CS>, PoseidonConfig>, usize)> +impl Dummy<(R1CS>, PoseidonConfig>, usize)> for GenericOffchainDeciderCircuit2 { fn dummy( @@ -272,7 +265,7 @@ impl Dummy<(R1CS>, PoseidonConfig>, usize)> } } -impl ConstraintSynthesizer> for GenericOffchainDeciderCircuit2 { +impl ConstraintSynthesizer> for GenericOffchainDeciderCircuit2 { fn generate_constraints(self, cs: ConstraintSystemRef>) -> Result<(), SynthesisError> { let cf_r1cs = R1CSMatricesVar::, FpVar>>::new_witness(cs.clone(), || { Ok(self.cf_arith.clone()) diff --git a/folding-schemes/src/folding/circuits/decider/on_chain.rs b/folding-schemes/src/folding/circuits/decider/on_chain.rs index fa116e98..8c692229 100644 --- a/folding-schemes/src/folding/circuits/decider/on_chain.rs +++ b/folding-schemes/src/folding/circuits/decider/on_chain.rs @@ -3,10 +3,8 @@ use ark_crypto_primitives::sponge::{ constraints::{AbsorbGadget, CryptographicSpongeVar}, poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig}, - Absorb, }; -use ark_ec::CurveGroup; -use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::fp::FpVar, prelude::CurveVar}; +use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::fp::FpVar}; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; use ark_std::{marker::PhantomData, Zero}; @@ -24,6 +22,7 @@ use crate::{ }, traits::{CommittedInstanceOps, CommittedInstanceVarOps, Dummy, WitnessOps, WitnessVarOps}, }, + Curve, }; use super::DeciderEnabledNIFS; @@ -60,9 +59,8 @@ use super::DeciderEnabledNIFS; /// /// For more details, see [https://privacy-scaling-explorations.github.io/sonobe-docs/design/nova-decider-onchain.html]. pub struct GenericOnchainDeciderCircuit< - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, RU: CommittedInstanceOps, // Running instance IU: CommittedInstanceOps, // Incoming instance W: WitnessOps>, // Witness @@ -70,7 +68,6 @@ pub struct GenericOnchainDeciderCircuit< AVar: ArithGadget, // In-circuit representation of `A` D: DeciderEnabledNIFS, > { - pub _gc2: PhantomData, pub _avar: PhantomData, /// Constraint system of the Augmented Function circuit pub arith: A, @@ -108,9 +105,8 @@ pub struct GenericOnchainDeciderCircuit< } impl< - C1: CurveGroup, - C2: CurveGroup, BaseField = CF1>, - GC2: CurveVar>, + C1: Curve, + C2: Curve, BaseField = CF1>, RU: CommittedInstanceOps + for<'a> Dummy<&'a A>, IU: CommittedInstanceOps + for<'a> Dummy<&'a A>, W: WitnessOps> + for<'a> Dummy<&'a A>, @@ -127,7 +123,7 @@ impl< D::RandomnessDummyCfg, usize, usize, - )> for GenericOnchainDeciderCircuit + )> for GenericOnchainDeciderCircuit { fn dummy( ( @@ -151,7 +147,6 @@ impl< ), ) -> Self { Self { - _gc2: PhantomData, _avar: PhantomData, cf_pedersen_params, poseidon_config, @@ -178,20 +173,17 @@ impl< } impl< - C1: CurveGroup, - C2: CurveGroup, BaseField = CF1>, - GC2: CurveVar>, + C1: Curve, + C2: Curve, BaseField = CF1>, RU: CommittedInstanceOps, IU: CommittedInstanceOps, W: WitnessOps>, A: Arith, AVar: ArithGadget + AllocVar>, D: DeciderEnabledNIFS, - > ConstraintSynthesizer> - for GenericOnchainDeciderCircuit + > ConstraintSynthesizer> for GenericOnchainDeciderCircuit where RU::Var: AbsorbGadget> + CommittedInstanceVarOps>, - CF1: Absorb, { fn generate_constraints(self, cs: ConstraintSystemRef>) -> Result<(), SynthesisError> { let arith = AVar::new_witness(cs.clone(), || Ok(&self.arith))?; @@ -212,7 +204,7 @@ where U_i1.get_commitments().enforce_equal(&U_i1_commitments)?; let cf_U_i = - CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || Ok(self.cf_U_i))?; + CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || Ok(self.cf_U_i))?; // allocate the inputs for the check 7.1 and 7.2 let kzg_challenges = Vec::new_input(cs.clone(), || Ok(self.kzg_challenges))?; @@ -256,15 +248,15 @@ where cyclefold::CycleFoldWitnessVar, nonnative::uint::NonNativeUintVar, }, }; - use ark_r1cs_std::convert::ToBitsGadget; + use ark_r1cs_std::{convert::ToBitsGadget, groups::CurveVar}; let cf_W_i = CycleFoldWitnessVar::::new_witness(cs.clone(), || Ok(self.cf_W_i))?; // 4. check Pedersen commitments of cf_U_i.{cmE, cmW} - let H = GC2::constant(self.cf_pedersen_params.h); + let H = C2::Var::constant(self.cf_pedersen_params.h); let G = self .cf_pedersen_params .generators .iter() - .map(|&g| GC2::constant(g.into())) + .map(|&g| C2::Var::constant(g.into())) .collect::>(); let cf_W_i_E_bits = cf_W_i .E @@ -276,9 +268,9 @@ where .iter() .map(|W_i| W_i.to_bits_le()) .collect::, _>>()?; - PedersenGadget::::commit(&H, &G, &cf_W_i_E_bits, &cf_W_i.rE.to_bits_le()?)? + PedersenGadget::::commit(&H, &G, &cf_W_i_E_bits, &cf_W_i.rE.to_bits_le()?)? .enforce_equal(&cf_U_i.cmE)?; - PedersenGadget::::commit(&H, &G, &cf_W_i_W_bits, &cf_W_i.rW.to_bits_le()?)? + PedersenGadget::::commit(&H, &G, &cf_W_i_W_bits, &cf_W_i.rW.to_bits_le()?)? .enforce_equal(&cf_U_i.cmW)?; let cf_r1cs = R1CSMatricesVar::, NonNativeUintVar>>::new_constant( diff --git a/folding-schemes/src/folding/circuits/nonnative/affine.rs b/folding-schemes/src/folding/circuits/nonnative/affine.rs index 91392b30..6fcce652 100644 --- a/folding-schemes/src/folding/circuits/nonnative/affine.rs +++ b/folding-schemes/src/folding/circuits/nonnative/affine.rs @@ -1,8 +1,10 @@ -use ark_ec::{short_weierstrass::SWFlags, AffineRepr, CurveGroup}; -use ark_ff::{Field, PrimeField}; +use ark_ec::{ + short_weierstrass::{Projective, SWCurveConfig, SWFlags}, + AffineRepr, CurveGroup, +}; +use ark_ff::PrimeField; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, - convert::ToConstraintFieldGadget, eq::EqGadget, fields::fp::FpVar, prelude::Boolean, @@ -10,28 +12,26 @@ use ark_r1cs_std::{ }; use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError}; use ark_serialize::{CanonicalSerialize, CanonicalSerializeWithFlags}; -use ark_std::{borrow::Borrow, Zero}; +use ark_std::{borrow::Borrow, One, Zero}; use crate::{ - folding::traits::Inputize, + folding::traits::{Inputize, InputizeNonNative}, transcript::{AbsorbNonNative, AbsorbNonNativeGadget}, + Curve, Field, }; -use super::uint::{nonnative_field_to_field_elements, NonNativeUintVar}; +use super::uint::NonNativeUintVar; /// NonNativeAffineVar represents an elliptic curve point in Affine representation in the non-native /// field, over the constraint field. It is not intended to perform operations, but just to contain /// the affine coordinates in order to perform hash operations of the point. #[derive(Debug, Clone)] -pub struct NonNativeAffineVar { +pub struct NonNativeAffineVar { pub x: NonNativeUintVar, pub y: NonNativeUintVar, } -impl AllocVar for NonNativeAffineVar -where - C: CurveGroup, -{ +impl AllocVar for NonNativeAffineVar { fn new_variable>( cs: impl Into>, f: impl FnOnce() -> Result, @@ -51,7 +51,7 @@ where } } -impl R1CSVar for NonNativeAffineVar { +impl R1CSVar for NonNativeAffineVar { type Value = C; fn cs(&self) -> ConstraintSystemRef { @@ -59,16 +59,10 @@ impl R1CSVar for NonNativeAffineVar { } fn value(&self) -> Result { - debug_assert_eq!(C::BaseField::extension_degree(), 1); - - let x = ::BasePrimeField::from_le_bytes_mod_order( - &self.x.value()?.to_bytes_le(), - ); - let y = ::BasePrimeField::from_le_bytes_mod_order( - &self.y.value()?.to_bytes_le(), - ); + let x = C::BaseField::from_le_bytes_mod_order(&self.x.value()?.to_bytes_le()); + let y = C::BaseField::from_le_bytes_mod_order(&self.y.value()?.to_bytes_le()); // Below is a workaround to convert the `x` and `y` coordinates to a - // point. This is because the `CurveGroup` trait does not provide a + // point. This is because the `SonobeCurve` trait does not provide a // method to construct a point from `BaseField` elements. let mut bytes = vec![]; // `unwrap` below is safe because serialization of a `PrimeField` value @@ -89,22 +83,12 @@ impl R1CSVar for NonNativeAffineVar { .unwrap(); // `unwrap` below is safe because `bytes` is constructed from the `x` // and `y` coordinates of a valid point, and these coordinates are - // serialized in the same way as the `CurveGroup` implementation. + // serialized in the same way as the `SonobeCurve` implementation. Ok(C::deserialize_uncompressed_unchecked(&bytes[..]).unwrap()) } } -impl ToConstraintFieldGadget for NonNativeAffineVar { - // Used for converting `NonNativeAffineVar` to a vector of `FpVar` with minimum length in - // the circuit. - fn to_constraint_field(&self) -> Result>, SynthesisError> { - let x = self.x.to_constraint_field()?; - let y = self.y.to_constraint_field()?; - Ok([x, y].concat()) - } -} - -impl EqGadget for NonNativeAffineVar { +impl EqGadget for NonNativeAffineVar { fn is_eq(&self, other: &Self) -> Result, SynthesisError> { let mut result = Boolean::TRUE; if self.x.0.len() != other.x.0.len() { @@ -151,57 +135,58 @@ impl EqGadget for NonNativeAffineVar { } } -/// The out-circuit counterpart of `NonNativeAffineVar::to_constraint_field` -#[allow(clippy::type_complexity)] -pub(crate) fn nonnative_affine_to_field_elements( - p: C, -) -> (Vec, Vec) { - let affine = p.into_affine(); - let (x, y) = affine.xy().unwrap_or_default(); - - let x = nonnative_field_to_field_elements(&x); - let y = nonnative_field_to_field_elements(&y); - (x, y) +impl NonNativeAffineVar { + pub fn zero() -> Self { + // `unwrap` below is safe because we are allocating a constant value, + // which is guaranteed to succeed. + Self::new_constant(ConstraintSystemRef::None, C::zero()).unwrap() + } } -impl Inputize> for C { - fn inputize(&self) -> Vec { +impl> AbsorbNonNative for Projective

{ + fn to_native_sponge_field_elements(&self, dest: &mut Vec) { let affine = self.into_affine(); let (x, y) = affine.xy().unwrap_or_default(); - let x = x.inputize(); - let y = y.inputize(); - [x, y].concat() + [x, y].to_native_sponge_field_elements(dest); } } -impl NonNativeAffineVar { - pub fn zero() -> Self { - // `unwrap` below is safe because we are allocating a constant value, - // which is guaranteed to succeed. - Self::new_constant(ConstraintSystemRef::None, C::zero()).unwrap() +impl AbsorbNonNativeGadget for NonNativeAffineVar { + fn to_native_sponge_field_elements( + &self, + ) -> Result>, SynthesisError> { + [&self.x, &self.y].to_native_sponge_field_elements() } } -impl AbsorbNonNative for C { - fn to_native_sponge_field_elements(&self, dest: &mut Vec) { - let (x, y) = nonnative_affine_to_field_elements(*self); - dest.extend(x); - dest.extend(y); +impl> Inputize for Projective

{ + /// Returns the internal representation in the same order as how the value + /// is allocated in `ProjectiveVar::new_input`. + fn inputize(&self) -> Vec { + let affine = self.into_affine(); + match affine.xy() { + Some((x, y)) => vec![x, y, One::one()], + None => vec![Zero::zero(), One::one(), Zero::zero()], + } } } -impl AbsorbNonNativeGadget for NonNativeAffineVar { - fn to_native_sponge_field_elements( - &self, - ) -> Result>, SynthesisError> { - self.to_constraint_field() +impl> InputizeNonNative for Projective

{ + /// Returns the internal representation in the same order as how the value + /// is allocated in `NonNativeAffineVar::new_input`. + fn inputize_nonnative(&self) -> Vec { + let affine = self.into_affine(); + let (x, y) = affine.xy().unwrap_or_default(); + + [x, y].inputize_nonnative() } } #[cfg(test)] mod tests { - use ark_pallas::{Fr, Projective}; + use ark_pallas::{Fq, Fr, PallasConfig, Projective}; + use ark_r1cs_std::groups::curves::short_weierstrass::ProjectiveVar; use ark_relations::r1cs::ConstraintSystem; use ark_std::UniformRand; @@ -218,29 +203,39 @@ mod tests { } #[test] - fn test_improved_to_constraint_field() -> Result<(), Error> { + fn test_improved_to_hash_preimage() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); // check that point_to_nonnative_limbs returns the expected values let mut rng = ark_std::test_rng(); let p = Projective::rand(&mut rng); let pVar = NonNativeAffineVar::::new_witness(cs.clone(), || Ok(p))?; - let (x, y) = nonnative_affine_to_field_elements(p); - assert_eq!(pVar.to_constraint_field()?.value()?, [x, y].concat()); + assert_eq!( + pVar.to_native_sponge_field_elements()?.value()?, + p.to_native_sponge_field_elements_as_vec() + ); Ok(()) } #[test] fn test_inputize() -> Result<(), Error> { - let cs = ConstraintSystem::::new_ref(); - // check that point_to_nonnative_limbs returns the expected values let mut rng = ark_std::test_rng(); let p = Projective::rand(&mut rng); + + let cs = ConstraintSystem::::new_ref(); let pVar = NonNativeAffineVar::::new_witness(cs.clone(), || Ok(p))?; - let xy = p.inputize(); + assert_eq!( + [pVar.x.0.value()?, pVar.y.0.value()?].concat(), + p.inputize_nonnative() + ); - assert_eq!([pVar.x.0.value()?, pVar.y.0.value()?].concat(), xy); + let cs = ConstraintSystem::::new_ref(); + let pVar = ProjectiveVar::>::new_witness(cs.clone(), || Ok(p))?; + assert_eq!( + vec![pVar.x.value()?, pVar.y.value()?, pVar.z.value()?], + p.inputize() + ); Ok(()) } } diff --git a/folding-schemes/src/folding/circuits/nonnative/uint.rs b/folding-schemes/src/folding/circuits/nonnative/uint.rs index d2193177..033244f2 100644 --- a/folding-schemes/src/folding/circuits/nonnative/uint.rs +++ b/folding-schemes/src/folding/circuits/nonnative/uint.rs @@ -3,12 +3,11 @@ use std::{ cmp::{max, min}, }; -use ark_ff::{BigInteger, Field, One, PrimeField, Zero}; +use ark_ff::{BigInteger, Fp, FpConfig, One, PrimeField, Zero}; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, boolean::Boolean, convert::ToBitsGadget, - convert::ToConstraintFieldGadget, fields::{fp::FpVar, FieldVar}, prelude::EqGadget, select::CondSelectGadget, @@ -19,9 +18,10 @@ use num_bigint::BigUint; use num_integer::Integer; use crate::{ - folding::traits::Inputize, + folding::traits::{Inputize, InputizeNonNative}, transcript::{AbsorbNonNative, AbsorbNonNativeGadget}, utils::gadgets::{EquivalenceGadget, MatrixGadget, SparseMatrixVar, VectorGadget}, + Field, }; /// `LimbVar` represents a single limb of a non-native unsigned integer in the @@ -270,23 +270,6 @@ impl AllocVar for NonNativeUintVar { } } -impl Inputize> for T { - fn inputize(&self) -> Vec { - assert_eq!(T::extension_degree(), 1); - // `unwrap` is safe because `T` is a field with extension degree 1, and - // thus `T::to_base_prime_field_elements` should return an iterator with - // exactly one element. - self.to_base_prime_field_elements() - .next() - .unwrap() - .into_bigint() - .to_bits_le() - .chunks(NonNativeUintVar::::bits_per_limb()) - .map(|chunk| F::from(F::BigInt::from_bits_le(chunk))) - .collect() - } -} - impl R1CSVar for NonNativeUintVar { type Value = BigUint; @@ -520,20 +503,6 @@ impl ToBitsGadget for NonNativeUintVar { } } -impl ToConstraintFieldGadget for NonNativeUintVar { - fn to_constraint_field(&self) -> Result>, SynthesisError> { - let bits_per_limb = F::MODULUS_BIT_SIZE as usize - 1; - - let limbs = self - .to_bits_le()? - .chunks(bits_per_limb) - .map(Boolean::le_bits_to_fp) - .collect::, _>>()?; - - Ok(limbs) - } -} - impl CondSelectGadget for NonNativeUintVar { fn conditionally_select( cond: &Boolean, @@ -830,59 +799,55 @@ impl]>> From for NonNativeUintVar { } } -// If we impl `AbsorbNonNative` directly for `PrimeField`, rustc will complain -// that this impl conflicts with the impl for `CurveGroup`. -// Therefore, we instead impl `AbsorbNonNative` for a slice of `PrimeField` as a -// workaround. -impl AbsorbNonNative - for [TargetField] -{ - fn to_native_sponge_field_elements(&self, dest: &mut Vec) { - self.iter() - .for_each(|x| dest.extend(&nonnative_field_to_field_elements(x))); +impl, const N: usize> AbsorbNonNative for Fp { + fn to_native_sponge_field_elements(&self, dest: &mut Vec) { + let bits_per_limb = F::MODULUS_BIT_SIZE as usize - 1; + let num_limbs = (Fp::::MODULUS_BIT_SIZE as usize).div_ceil(bits_per_limb); + + let mut limbs = self + .into_bigint() + .to_bits_le() + .chunks(bits_per_limb) + .map(|chunk| F::from(F::BigInt::from_bits_le(chunk))) + .collect::>(); + limbs.resize(num_limbs, F::zero()); + + dest.extend(&limbs) } } impl AbsorbNonNativeGadget for NonNativeUintVar { fn to_native_sponge_field_elements(&self) -> Result>, SynthesisError> { - self.to_constraint_field() + let bits_per_limb = F::MODULUS_BIT_SIZE as usize - 1; + + let limbs = self + .to_bits_le()? + .chunks(bits_per_limb) + .map(Boolean::le_bits_to_fp) + .collect::, _>>()?; + + Ok(limbs) } } -/// The out-circuit counterpart of `NonNativeUintVar::to_constraint_field` -pub(super) fn nonnative_field_to_field_elements( - f: &TargetField, -) -> Vec { - assert_eq!(TargetField::extension_degree(), 1); - // `unwrap` is safe because `TargetField` is a field with extension degree - // 1, and thus `TargetField::to_base_prime_field_elements` should return an - // iterator with exactly one element. - let bits = f - .to_base_prime_field_elements() - .next() - .unwrap() - .into_bigint() - .to_bits_le(); - - let bits_per_limb = BaseField::MODULUS_BIT_SIZE as usize - 1; - let num_limbs = - (TargetField::BasePrimeField::MODULUS_BIT_SIZE as usize).div_ceil(bits_per_limb); - - let mut limbs = bits - .chunks(bits_per_limb) - .map(|chunk| { - let mut limb = BaseField::zero(); - let mut w = BaseField::one(); - for &b in chunk.iter() { - limb += BaseField::from(b) * w; - w.double_in_place(); - } - limb - }) - .collect::>(); - limbs.resize(num_limbs, BaseField::zero()); +impl, const N: usize> Inputize for Fp { + /// Returns the internal representation in the same order as how the value + /// is allocated in `FpVar::new_input`. + fn inputize(&self) -> Vec { + vec![*self] + } +} - limbs +impl InputizeNonNative for P { + /// Returns the internal representation in the same order as how the value + /// is allocated in `NonNativeUintVar::new_input`. + fn inputize_nonnative(&self) -> Vec { + self.into_bigint() + .to_bits_le() + .chunks(NonNativeUintVar::::bits_per_limb()) + .map(|chunk| F::from(F::BigInt::from_bits_le(chunk))) + .collect() + } } impl VectorGadget> for [NonNativeUintVar] { @@ -947,6 +912,7 @@ impl MatrixGadget> for SparseMatrixVar { +pub struct CCCS { // Commitment to witness pub C: C, // Public input/output @@ -32,19 +30,19 @@ impl CCS { &self, rng: &mut R, cs_params: &CS::ProverParams, - z: &[C::ScalarField], - ) -> Result<(CCCS, Witness), Error> + z: &[F], + ) -> Result<(CCCS, Witness), Error> where // enforce that CCS's F is the C::ScalarField - C: CurveGroup, + C: Curve, { - let w: Vec = z[(1 + self.l)..].to_vec(); + let w: Vec = z[(1 + self.l)..].to_vec(); // if the commitment scheme is set to be hiding, set the random blinding parameter let r_w = if CS::is_hiding() { - C::ScalarField::rand(rng) + F::rand(rng) } else { - C::ScalarField::zero() + F::zero() }; let C = CS::commit(cs_params, &w, &r_w)?; @@ -53,7 +51,7 @@ impl CCS { C, x: z[1..(1 + self.l)].to_vec(), }, - Witness:: { w, r_w }, + Witness:: { w, r_w }, )) } @@ -91,7 +89,7 @@ impl CCS { } } -impl Dummy<&CCS>> for CCCS { +impl Dummy<&CCS>> for CCCS { fn dummy(ccs: &CCS>) -> Self { Self { C: C::zero(), @@ -100,7 +98,7 @@ impl Dummy<&CCS>> for CCCS { } } -impl Arith>, CCCS> for CCS> { +impl Arith>, CCCS> for CCS> { type Evaluation = Vec>; fn eval_relation(&self, w: &Witness>, u: &CCCS) -> Result { @@ -122,26 +120,18 @@ impl Arith>, CCCS> for CCS> { } } -impl Absorb for CCCS -where - C::ScalarField: Absorb, -{ +impl Absorb for CCCS { fn to_sponge_bytes(&self, dest: &mut Vec) { C::ScalarField::batch_to_sponge_bytes(&self.to_sponge_field_elements_as_vec(), dest); } fn to_sponge_field_elements(&self, dest: &mut Vec) { - // We cannot call `to_native_sponge_field_elements(dest)` directly, as - // `to_native_sponge_field_elements` needs `F` to be `C::ScalarField`, - // but here `F` is a generic `PrimeField`. - self.C - .to_native_sponge_field_elements_as_vec() - .to_sponge_field_elements(dest); + self.C.to_native_sponge_field_elements(dest); self.x.to_sponge_field_elements(dest); } } -impl CommittedInstanceOps for CCCS { +impl CommittedInstanceOps for CCCS { type Var = CCCSVar; fn get_commitments(&self) -> Vec { @@ -153,9 +143,11 @@ impl CommittedInstanceOps for CCCS { } } -impl Inputize> for CCCS { - fn inputize(&self) -> Vec { - [&self.C.inputize()[..], &self.x].concat() +impl Inputize> for CCCS { + /// Returns the internal representation in the same order as how the value + /// is allocated in `CCCSVar::new_input`. + fn inputize(&self) -> Vec> { + [&self.C.inputize_nonnative()[..], &self.x].concat() } } diff --git a/folding-schemes/src/folding/hypernova/circuits.rs b/folding-schemes/src/folding/hypernova/circuits.rs index 3db07806..f7b34690 100644 --- a/folding-schemes/src/folding/hypernova/circuits.rs +++ b/folding-schemes/src/folding/hypernova/circuits.rs @@ -1,16 +1,13 @@ /// Implementation of [HyperNova](https://eprint.iacr.org/2023/573.pdf) circuits use ark_crypto_primitives::sponge::{ constraints::{AbsorbGadget, CryptographicSpongeVar}, - poseidon::{constraints::PoseidonSpongeVar, PoseidonSponge}, + poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig, PoseidonSponge}, CryptographicSponge, }; -use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb}; -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, boolean::Boolean, - convert::ToConstraintFieldGadget, eq::EqGadget, fields::{fp::FpVar, FieldVar}, prelude::CurveVar, @@ -46,25 +43,22 @@ use crate::folding::{ }; use crate::frontend::FCircuit; use crate::utils::virtual_polynomial::VPAuxInfo; -use crate::Error; use crate::{ arith::{ccs::CCS, r1cs::extract_r1cs}, - transcript::TranscriptVar, + transcript::{AbsorbNonNativeGadget, TranscriptVar}, }; +use crate::{Curve, Error}; /// Committed CCS instance #[derive(Debug, Clone)] -pub struct CCCSVar { +pub struct CCCSVar { // Commitment to witness pub C: NonNativeAffineVar, // Public io pub x: Vec>>, } -impl AllocVar, CF1> for CCCSVar -where - C: CurveGroup, -{ +impl AllocVar, CF1> for CCCSVar { fn new_variable>>( cs: impl Into>>, f: impl FnOnce() -> Result, @@ -82,7 +76,7 @@ where } } -impl CommittedInstanceVarOps for CCCSVar { +impl CommittedInstanceVarOps for CCCSVar { type PointVar = NonNativeAffineVar; fn get_commitments(&self) -> Vec { @@ -103,9 +97,19 @@ impl CommittedInstanceVarOps for CCCSVar { } } +impl AbsorbGadget for CCCSVar { + fn to_sponge_bytes(&self) -> Result>, SynthesisError> { + FpVar::batch_to_sponge_bytes(&self.to_sponge_field_elements()?) + } + + fn to_sponge_field_elements(&self) -> Result>, SynthesisError> { + Ok([&self.C.to_native_sponge_field_elements()?, &self.x[..]].concat()) + } +} + /// Linearized Committed CCS instance #[derive(Debug, Clone)] -pub struct LCCCSVar { +pub struct LCCCSVar { // Commitment to witness pub C: NonNativeAffineVar, // Relaxation factor of z for folded LCCCS @@ -118,10 +122,7 @@ pub struct LCCCSVar { pub v: Vec>>, } -impl AllocVar, CF1> for LCCCSVar -where - C: CurveGroup, -{ +impl AllocVar, CF1> for LCCCSVar { fn new_variable>>( cs: impl Into>>, f: impl FnOnce() -> Result, @@ -144,14 +145,14 @@ where } } -impl AbsorbGadget for LCCCSVar { +impl AbsorbGadget for LCCCSVar { fn to_sponge_bytes(&self) -> Result>, SynthesisError> { FpVar::batch_to_sponge_bytes(&self.to_sponge_field_elements()?) } fn to_sponge_field_elements(&self) -> Result>, SynthesisError> { Ok([ - &self.C.to_constraint_field()?, + &self.C.to_native_sponge_field_elements()?, &[self.u.clone()][..], &self.x, &self.r_x, @@ -161,7 +162,7 @@ impl AbsorbGadget for LCCCSVar { } } -impl CommittedInstanceVarOps for LCCCSVar { +impl CommittedInstanceVarOps for LCCCSVar { type PointVar = NonNativeAffineVar; fn get_commitments(&self) -> Vec { @@ -187,16 +188,12 @@ impl CommittedInstanceVarOps for LCCCSVar { /// ProofVar defines a multifolding proof #[derive(Debug)] -pub struct ProofVar { +pub struct ProofVar { pub sc_proof: IOPProofVar, #[allow(clippy::type_complexity)] pub sigmas_thetas: (Vec>>>, Vec>>>), } -impl AllocVar, CF1> for ProofVar -where - C: CurveGroup, - C::ScalarField: Absorb, -{ +impl AllocVar, CF1> for ProofVar { fn new_variable>>( cs: impl Into>>, f: impl FnOnce() -> Result, @@ -233,10 +230,10 @@ where } } -pub struct NIMFSGadget { +pub struct NIMFSGadget { _c: PhantomData, } -impl NIMFSGadget { +impl NIMFSGadget { /// Runs (in-circuit) the NIMFS.V, which outputs the new folded LCCCS instance together with /// the rho_powers, which will be used in other parts of the AugmentedFCircuit #[allow(clippy::type_complexity)] @@ -252,21 +249,8 @@ impl NIMFSGadget { enabled: Boolean, ) -> Result<(LCCCSVar, Vec>>), SynthesisError> { // absorb instances to transcript - for U_i in running_instances { - let v = [ - U_i.C.to_constraint_field()?, - vec![U_i.u.clone()], - U_i.x.clone(), - U_i.r_x.clone(), - U_i.v.clone(), - ] - .concat(); - transcript.absorb(&v)?; - } - for u_i in new_instances { - let v = [u_i.C.to_constraint_field()?, u_i.x.clone()].concat(); - transcript.absorb(&v)?; - } + transcript.absorb(&running_instances)?; + transcript.absorb(&new_instances)?; // get the challenges let gamma_scalar_raw = C::ScalarField::from_le_bytes_mod_order(b"gamma"); @@ -482,15 +466,12 @@ fn compute_c_gadget( /// * `NU` - the number of CCCS instances to be folded #[derive(Debug, Clone)] pub struct AugmentedFCircuit< - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit>, const MU: usize, const NU: usize, > { - pub(super) _c2: PhantomData, - pub(super) _gc2: PhantomData, pub(super) poseidon_config: PoseidonConfig>, pub(super) ccs: CCS, // CCS of the AugmentedFCircuit pub(super) pp_hash: Option>, @@ -513,17 +494,11 @@ pub struct AugmentedFCircuit< pub(super) cf_cmT: Option, } -impl AugmentedFCircuit +impl AugmentedFCircuit where - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit>, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, { pub fn default( poseidon_config: &PoseidonConfig>, @@ -534,8 +509,6 @@ where return Err(Error::CantBeZero("mu,nu".to_string())); } Ok(Self { - _c2: PhantomData, - _gc2: PhantomData, poseidon_config: poseidon_config.clone(), ccs, pp_hash: None, @@ -622,8 +595,6 @@ where )?; let augmented_f_circuit = Self { - _c2: PhantomData, - _gc2: PhantomData, poseidon_config: self.poseidon_config.clone(), ccs: ccs.clone(), pp_hash: Some(C1::ScalarField::zero()), @@ -684,13 +655,11 @@ where } } -impl AugmentedFCircuit +impl AugmentedFCircuit where - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit>, - C2::BaseField: PrimeField + Absorb, { pub fn compute_next_state( self, @@ -739,10 +708,10 @@ where let cf_u_dummy = CycleFoldCommittedInstance::dummy(HyperNovaCycleFoldConfig::::IO_LEN); - let cf_U_i = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { + let cf_U_i = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { Ok(self.cf_U_i.unwrap_or(cf_u_dummy.clone())) })?; - let cf_cmT = GC2::new_witness(cs.clone(), || Ok(self.cf_cmT.unwrap_or_else(C2::zero)))?; + let cf_cmT = C2::Var::new_witness(cs.clone(), || Ok(self.cf_cmT.unwrap_or_else(C2::zero)))?; let sponge = PoseidonSpongeVar::::new(cs.clone(), &self.poseidon_config); @@ -844,14 +813,14 @@ where // ensure that cf_u has as public inputs the C from main instances U_i, u_i, U_i+1 // coordinates of the commitments. // C.2. Construct `cf_u_i` - let cf_u_i = CycleFoldCommittedInstanceVar:: { + let cf_u_i = CycleFoldCommittedInstanceVar:: { // cf1_u_i.cmE = 0. Notice that we enforce cmE to be equal to 0 since it is allocated // as 0. - cmE: GC2::zero(), + cmE: C2::Var::zero(), // cf1_u_i.u = 1 u: NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::one())?, // cf_u_i.cmW is provided by the prover as witness - cmW: GC2::new_witness(cs.clone(), || Ok(self.cf_u_i_cmW.unwrap_or(C2::zero())))?, + cmW: C2::Var::new_witness(cs.clone(), || Ok(self.cf_u_i_cmW.unwrap_or(C2::zero())))?, // cf_u_i.x is computed in step 1 x: cf_x, }; @@ -859,7 +828,7 @@ where // C.3. nifs.verify (fold_committed_instance), obtains cf_U_{i+1} by folding cf_u_i & cf_U_i. // compute cf_r = H(cf_u_i, cf_U_i, cf_cmT) // cf_r_bits is denoted by rho* in the paper. - let cf_r_bits = CycleFoldChallengeGadget::::get_challenge_gadget( + let cf_r_bits = CycleFoldChallengeGadget::::get_challenge_gadget( &mut transcript, pp_hash.clone(), cf_U_i_vec, @@ -868,7 +837,7 @@ where )?; // Fold cf1_u_i & cf_U_i into cf1_U_{i+1} let cf_U_i1 = - NIFSFullGadget::::fold_committed_instance(cf_r_bits, cf_cmT, cf_U_i, cf_u_i)?; + NIFSFullGadget::::fold_committed_instance(cf_r_bits, cf_cmT, cf_U_i, cf_u_i)?; // Back to Primary Part // P.4.b compute and check the second output of F' @@ -876,7 +845,7 @@ where // Non-base case: u_{i+1}.x[1] == H(cf_U_{i+1}) let (cf_u_i1_x, _) = cf_U_i1.clone().hash(&sponge, pp_hash.clone())?; let (cf_u_i1_x_base, _) = - CycleFoldCommittedInstanceVar::::new_constant(cs.clone(), cf_u_dummy)? + CycleFoldCommittedInstanceVar::::new_constant(cs.clone(), cf_u_dummy)? .hash(&sponge, pp_hash)?; let cf_x = is_basecase.select(&cf_u_i1_x_base, &cf_u_i1_x)?; // This line "converts" `cf_x` from a witness to a public input. @@ -894,14 +863,12 @@ where } } -impl ConstraintSynthesizer> - for AugmentedFCircuit +impl ConstraintSynthesizer> + for AugmentedFCircuit where - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit>, - C2::BaseField: PrimeField + Absorb, { fn generate_constraints(self, cs: ConstraintSystemRef>) -> Result<(), SynthesisError> { self.compute_next_state(cs).map(|_| ()) @@ -910,9 +877,10 @@ where #[cfg(test)] mod tests { - use ark_bn254::{constraints::GVar, Fq, Fr, G1Projective as Projective}; + use ark_bn254::{Fq, Fr, G1Projective as Projective}; + use ark_crypto_primitives::sponge::Absorb; use ark_ff::BigInteger; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_grumpkin::Projective as Projective2; use ark_std::{test_rng, UniformRand}; use std::time::Instant; @@ -1218,7 +1186,7 @@ mod tests { let start = Instant::now(); let F_circuit = CubicFCircuit::::new(())?; let mut augmented_f_circuit = - AugmentedFCircuit::, MU, NU>::empty( + AugmentedFCircuit::, MU, NU>::empty( &poseidon_config, F_circuit, None, @@ -1229,7 +1197,7 @@ mod tests { // CycleFold circuit let cs2 = ConstraintSystem::::new_ref(); - let cf_circuit = HyperNovaCycleFoldCircuit::::empty(); + let cf_circuit = HyperNovaCycleFoldCircuit::::empty(); cf_circuit.generate_constraints(cs2.clone())?; cs2.finalize(); let cs2 = cs2.into_inner().ok_or(Error::NoInnerConstraintSystem)?; @@ -1301,37 +1269,29 @@ mod tests { // input in the AugmentedFCircuit cf_u_i1_x = cf_U_i.hash_cyclefold(&sponge, pp_hash); - augmented_f_circuit = AugmentedFCircuit::< - Projective, - Projective2, - GVar2, - CubicFCircuit, - MU, - NU, - > { - _c2: PhantomData, - _gc2: PhantomData, - poseidon_config: poseidon_config.clone(), - ccs: ccs.clone(), - pp_hash: Some(pp_hash), - i: Some(Fr::zero()), - i_usize: Some(0), - z_0: Some(z_0.clone()), - z_i: Some(z_i.clone()), - external_inputs: Some(vec![]), - U_i: Some(U_i.clone()), - Us: Some(Us.clone()), - u_i_C: Some(u_i.C), - us: Some(us.clone()), - U_i1_C: Some(U_i1.C), - F: F_circuit, - nimfs_proof: None, - - // cyclefold values - cf_u_i_cmW: None, - cf_U_i: None, - cf_cmT: None, - }; + augmented_f_circuit = + AugmentedFCircuit::, MU, NU> { + poseidon_config: poseidon_config.clone(), + ccs: ccs.clone(), + pp_hash: Some(pp_hash), + i: Some(Fr::zero()), + i_usize: Some(0), + z_0: Some(z_0.clone()), + z_i: Some(z_i.clone()), + external_inputs: Some(vec![]), + U_i: Some(U_i.clone()), + Us: Some(Us.clone()), + u_i_C: Some(u_i.C), + us: Some(us.clone()), + U_i1_C: Some(U_i1.C), + F: F_circuit, + nimfs_proof: None, + + // cyclefold values + cf_u_i_cmW: None, + cf_U_i: None, + cf_cmT: None, + }; } else { let mut transcript_p: PoseidonSponge = PoseidonSponge::::new(&poseidon_config.clone()); @@ -1354,8 +1314,7 @@ mod tests { let rho_bits = rho.into_bigint().to_bits_le()[..NOVA_N_BITS_RO].to_vec(); // CycleFold part: - let cf_circuit = HyperNovaCycleFoldCircuit:: { - _gc: PhantomData, + let cf_circuit = HyperNovaCycleFoldCircuit:: { r_bits: Some(rho_bits.clone()), points: Some( [ @@ -1374,12 +1333,9 @@ mod tests { HyperNovaCycleFoldConfig::::N_INPUT_POINTS ); - let (_cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = fold_cyclefold_circuit::< + let (cf_u_i, cf_W_i1, cf_U_i1, cf_cmT) = fold_cyclefold_circuit::< HyperNovaCycleFoldConfig, - Projective, - GVar, Projective2, - GVar2, Pedersen, false, >( @@ -1397,37 +1353,29 @@ mod tests { // AugmentedFCircuit cf_u_i1_x = cf_U_i1.hash_cyclefold(&sponge, pp_hash); - augmented_f_circuit = AugmentedFCircuit::< - Projective, - Projective2, - GVar2, - CubicFCircuit, - MU, - NU, - > { - _c2: PhantomData, - _gc2: PhantomData, - poseidon_config: poseidon_config.clone(), - ccs: ccs.clone(), - pp_hash: Some(pp_hash), - i: Some(iFr), - i_usize: Some(i), - z_0: Some(z_0.clone()), - z_i: Some(z_i.clone()), - external_inputs: Some(vec![]), - U_i: Some(U_i.clone()), - Us: Some(Us.clone()), - u_i_C: Some(u_i.C), - us: Some(us.clone()), - U_i1_C: Some(U_i1.C), - F: F_circuit, - nimfs_proof: Some(nimfs_proof), - - // cyclefold values - cf_u_i_cmW: Some(cf_u_i.cmW), - cf_U_i: Some(cf_U_i), - cf_cmT: Some(cf_cmT), - }; + augmented_f_circuit = + AugmentedFCircuit::, MU, NU> { + poseidon_config: poseidon_config.clone(), + ccs: ccs.clone(), + pp_hash: Some(pp_hash), + i: Some(iFr), + i_usize: Some(i), + z_0: Some(z_0.clone()), + z_i: Some(z_i.clone()), + external_inputs: Some(vec![]), + U_i: Some(U_i.clone()), + Us: Some(Us.clone()), + u_i_C: Some(u_i.C), + us: Some(us.clone()), + U_i1_C: Some(U_i1.C), + F: F_circuit, + nimfs_proof: Some(nimfs_proof), + + // cyclefold values + cf_u_i_cmW: Some(cf_u_i.cmW), + cf_U_i: Some(cf_U_i), + cf_cmT: Some(cf_cmT), + }; // assign the next round instances cf_W_i = cf_W_i1; diff --git a/folding-schemes/src/folding/hypernova/decider_eth.rs b/folding-schemes/src/folding/hypernova/decider_eth.rs index 51dddfde..1a3346fc 100644 --- a/folding-schemes/src/folding/hypernova/decider_eth.rs +++ b/folding-schemes/src/folding/hypernova/decider_eth.rs @@ -1,8 +1,4 @@ /// This file implements the HyperNova's onchain (Ethereum's EVM) decider. -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::CurveGroup; -use ark_ff::PrimeField; -use ark_r1cs_std::prelude::CurveVar; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_snark::SNARK; use ark_std::rand::{CryptoRng, RngCore}; @@ -16,17 +12,16 @@ use crate::commitment::{ kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme, }; use crate::folding::circuits::decider::DeciderEnabledNIFS; -use crate::folding::circuits::CF2; use crate::folding::nova::decider_eth::VerifierParam; -use crate::folding::traits::{Inputize, WitnessOps}; +use crate::folding::traits::WitnessOps; use crate::frontend::FCircuit; -use crate::Error; +use crate::{Curve, Error}; use crate::{Decider as DeciderTrait, FoldingScheme}; #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct Proof where - C1: CurveGroup, + C1: Curve, CS1: CommitmentScheme, S: SNARK, { @@ -41,11 +36,9 @@ where /// Onchain Decider, for ethereum use cases #[derive(Clone, Debug)] -pub struct Decider { +pub struct Decider { _c1: PhantomData, - _gc1: PhantomData, _c2: PhantomData, - _gc2: PhantomData, _fc: PhantomData, _cs1: PhantomData, _cs2: PhantomData, @@ -53,13 +46,11 @@ pub struct Decider, } -impl - DeciderTrait for Decider +impl DeciderTrait + for Decider where - C1: CurveGroup, - C2: CurveGroup, - GC1: CurveVar>, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, // CS1 is a KZG commitment, where challenge is C1::Fr elem CS1: CommitmentScheme< @@ -72,13 +63,8 @@ where CS2: CommitmentScheme>, S: SNARK, FS: FoldingScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, // constrain FS into HyperNova, since this is a Decider specifically for HyperNova - HyperNova: From, + HyperNova: From, crate::folding::hypernova::ProverParams: From<>::ProverParam>, crate::folding::hypernova::VerifierParams: @@ -96,7 +82,7 @@ where prep_param: Self::PreprocessorParam, fs: FS, ) -> Result<(Self::ProverParam, Self::VerifierParam), Error> { - let circuit = DeciderEthCircuit::::try_from(HyperNova::from(fs))?; + let circuit = DeciderEthCircuit::::try_from(HyperNova::from(fs))?; // get the Groth16 specific setup for the circuit let (g16_pk, g16_vk) = S::circuit_specific_setup(circuit, &mut rng) @@ -104,13 +90,13 @@ where // get the FoldingScheme prover & verifier params from HyperNova #[allow(clippy::type_complexity)] - let hypernova_pp: as FoldingScheme< + let hypernova_pp: as FoldingScheme< C1, C2, FC, >>::ProverParam = prep_param.0.into(); #[allow(clippy::type_complexity)] - let hypernova_vp: as FoldingScheme< + let hypernova_vp: as FoldingScheme< C1, C2, FC, @@ -134,7 +120,7 @@ where ) -> Result { let (snark_pk, cs_pk): (S::ProvingKey, CS1::ProverParams) = pp; - let circuit = DeciderEthCircuit::::try_from(HyperNova::from(folding_scheme))?; + let circuit = DeciderEthCircuit::::try_from(HyperNova::from(folding_scheme))?; let rho = circuit.randomness; @@ -202,7 +188,7 @@ where &[pp_hash, i][..], &z_0, &z_i, - &C.inputize(), + &C.inputize_nonnative(), &[proof.kzg_challenge, proof.kzg_proof.eval, proof.rho], ] .concat(); @@ -223,9 +209,9 @@ where #[cfg(test)] pub mod tests { - use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; + use ark_bn254::{Bn254, Fr, G1Projective as Projective}; use ark_groth16::Groth16; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_grumpkin::Projective as Projective2; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; use super::*; @@ -244,9 +230,7 @@ pub mod tests { // use HyperNova as FoldingScheme type HN = HyperNova< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, @@ -256,9 +240,7 @@ pub mod tests { >; type D = Decider< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, @@ -309,9 +291,7 @@ pub mod tests { // use HyperNova as FoldingScheme type HN = HyperNova< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, @@ -321,9 +301,7 @@ pub mod tests { >; type D = Decider< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, diff --git a/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs b/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs index 03c016e2..067c5501 100644 --- a/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs @@ -3,16 +3,14 @@ use ark_crypto_primitives::sponge::{ constraints::CryptographicSpongeVar, poseidon::{constraints::PoseidonSpongeVar, PoseidonSponge}, - Absorb, CryptographicSponge, + CryptographicSponge, }; -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, boolean::Boolean, eq::EqGadget, fields::fp::FpVar, - prelude::CurveVar, }; use ark_relations::r1cs::{Namespace, SynthesisError}; use ark_std::{borrow::Borrow, log2, marker::PhantomData}; @@ -22,7 +20,7 @@ use super::{ nimfs::{NIMFSProof, NIMFS}, HyperNova, Witness, CCCS, LCCCS, }; -use crate::folding::circuits::{decider::on_chain::GenericOnchainDeciderCircuit, CF1, CF2}; +use crate::folding::circuits::{decider::on_chain::GenericOnchainDeciderCircuit, CF1}; use crate::folding::traits::{WitnessOps, WitnessVarOps}; use crate::frontend::FCircuit; use crate::utils::gadgets::{eval_mle, MatrixGadget}; @@ -37,9 +35,10 @@ use crate::{ use crate::{ commitment::{pedersen::Params as PedersenParams, CommitmentScheme}, folding::circuits::decider::DeciderEnabledNIFS, + Curve, }; -impl ArithGadget>, LCCCSVar> for CCSMatricesVar> { +impl ArithGadget>, LCCCSVar> for CCSMatricesVar> { type Evaluation = Vec>>; fn eval_relation( @@ -99,10 +98,9 @@ impl WitnessVarOps for WitnessVar { } } -pub type DeciderEthCircuit = GenericOnchainDeciderCircuit< +pub type DeciderEthCircuit = GenericOnchainDeciderCircuit< C1, C2, - GC2, LCCCS, CCCS, Witness>, @@ -112,10 +110,8 @@ pub type DeciderEthCircuit = GenericOnchainDeciderCircuit< >; impl< - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, // enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider @@ -123,14 +119,11 @@ impl< const MU: usize, const NU: usize, const H: bool, - > TryFrom> - for DeciderEthCircuit -where - CF1: Absorb, + > TryFrom> for DeciderEthCircuit { type Error = Error; - fn try_from(hn: HyperNova) -> Result { + fn try_from(hn: HyperNova) -> Result { // compute the U_{i+1}, W_{i+1}, by folding the last running & incoming instances let mut transcript = PoseidonSponge::::new(&hn.poseidon_config); transcript.absorb(&hn.pp_hash); @@ -155,7 +148,6 @@ where .collect::, _>>()?; Ok(Self { - _gc2: PhantomData, _avar: PhantomData, arith: hn.ccs, cf_arith: hn.cf_r1cs, @@ -183,10 +175,8 @@ where pub struct DeciderHyperNovaGadget; -impl DeciderEnabledNIFS, CCCS, Witness, CCS>> +impl DeciderEnabledNIFS, CCCS, Witness, CCS>> for DeciderHyperNovaGadget -where - CF1: Absorb, { type ProofDummyCfg = (usize, usize, usize, usize); type Proof = NIMFSProof; @@ -235,8 +225,8 @@ where #[cfg(test)] pub mod tests { - use ark_bn254::{constraints::GVar, Fr, G1Projective as Projective}; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_bn254::{Fr, G1Projective as Projective}; + use ark_grumpkin::Projective as Projective2; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; use ark_std::{test_rng, UniformRand}; @@ -291,9 +281,7 @@ pub mod tests { type HN = HyperNova< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, Pedersen, Pedersen, @@ -319,8 +307,7 @@ pub mod tests { HN::verify(hn_params.1, ivc_proof)?; // load the DeciderEthCircuit from the generated Nova instance - let decider_circuit = - DeciderEthCircuit::::try_from(hypernova)?; + let decider_circuit = DeciderEthCircuit::::try_from(hypernova)?; let cs = ConstraintSystem::::new_ref(); diff --git a/folding-schemes/src/folding/hypernova/lcccs.rs b/folding-schemes/src/folding/hypernova/lcccs.rs index 1393d84f..0406c1fc 100644 --- a/folding-schemes/src/folding/hypernova/lcccs.rs +++ b/folding-schemes/src/folding/hypernova/lcccs.rs @@ -1,5 +1,4 @@ use ark_crypto_primitives::sponge::Absorb; -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_poly::{DenseMultilinearExtension, Polynomial}; use ark_serialize::CanonicalDeserialize; @@ -15,14 +14,13 @@ use crate::commitment::CommitmentScheme; use crate::folding::circuits::CF1; use crate::folding::traits::Inputize; use crate::folding::traits::{CommittedInstanceOps, Dummy}; -use crate::transcript::AbsorbNonNative; use crate::utils::mle::dense_vec_to_dense_mle; use crate::utils::vec::mat_vec_mul; -use crate::Error; +use crate::{Curve, Error}; /// Linearized Committed CCS instance #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct LCCCS { +pub struct LCCCS { // Commitment to witness pub C: C, // Relaxation factor of z for folded LCCCS @@ -40,22 +38,22 @@ impl CCS { &self, rng: &mut R, cs_params: &CS::ProverParams, - z: &[C::ScalarField], - ) -> Result<(LCCCS, Witness), Error> + z: &[F], + ) -> Result<(LCCCS, Witness), Error> where // enforce that CCS's F is the C::ScalarField - C: CurveGroup, + C: Curve, { - let w: Vec = z[(1 + self.l)..].to_vec(); + let w: Vec = z[(1 + self.l)..].to_vec(); // if the commitment scheme is set to be hiding, set the random blinding parameter let r_w = if CS::is_hiding() { - C::ScalarField::rand(rng) + F::rand(rng) } else { - C::ScalarField::zero() + F::zero() }; let C = CS::commit(cs_params, &w, &r_w)?; - let r_x: Vec = (0..self.s).map(|_| C::ScalarField::rand(rng)).collect(); + let r_x: Vec = (0..self.s).map(|_| F::rand(rng)).collect(); let Mzs: Vec> = self .M @@ -74,12 +72,12 @@ impl CCS { r_x, v, }, - Witness:: { w, r_w }, + Witness:: { w, r_w }, )) } } -impl Dummy<&CCS>> for LCCCS { +impl Dummy<&CCS>> for LCCCS { fn dummy(ccs: &CCS>) -> Self { Self { C: C::zero(), @@ -91,7 +89,7 @@ impl Dummy<&CCS>> for LCCCS { } } -impl Arith>, LCCCS> for CCS> { +impl Arith>, LCCCS> for CCS> { type Evaluation = Vec>; /// Perform the check of the LCCCS instance described at section 4.2, @@ -117,21 +115,13 @@ impl Arith>, LCCCS> for CCS> { } } -impl Absorb for LCCCS -where - C::ScalarField: Absorb, -{ +impl Absorb for LCCCS { fn to_sponge_bytes(&self, dest: &mut Vec) { C::ScalarField::batch_to_sponge_bytes(&self.to_sponge_field_elements_as_vec(), dest); } fn to_sponge_field_elements(&self, dest: &mut Vec) { - // We cannot call `to_native_sponge_field_elements(dest)` directly, as - // `to_native_sponge_field_elements` needs `F` to be `C::ScalarField`, - // but here `F` is a generic `PrimeField`. - self.C - .to_native_sponge_field_elements_as_vec() - .to_sponge_field_elements(dest); + self.C.to_native_sponge_field_elements(dest); self.u.to_sponge_field_elements(dest); self.x.to_sponge_field_elements(dest); self.r_x.to_sponge_field_elements(dest); @@ -139,7 +129,7 @@ where } } -impl CommittedInstanceOps for LCCCS { +impl CommittedInstanceOps for LCCCS { type Var = LCCCSVar; fn get_commitments(&self) -> Vec { @@ -151,10 +141,12 @@ impl CommittedInstanceOps for LCCCS { } } -impl Inputize> for LCCCS { - fn inputize(&self) -> Vec { +impl Inputize> for LCCCS { + /// Returns the internal representation in the same order as how the value + /// is allocated in `LCCCS::new_input`. + fn inputize(&self) -> Vec> { [ - &self.C.inputize(), + &self.C.inputize_nonnative(), &[self.u][..], &self.x, &self.r_x, @@ -183,7 +175,7 @@ pub mod tests { use crate::utils::virtual_polynomial::{build_eq_x_r_vec, VirtualPolynomial}; // method for testing - pub fn compute_Ls( + pub fn compute_Ls( ccs: &CCS, lcccs: &LCCCS, z: &[C::ScalarField], diff --git a/folding-schemes/src/folding/hypernova/mod.rs b/folding-schemes/src/folding/hypernova/mod.rs index 09c2790c..ecba05a4 100644 --- a/folding-schemes/src/folding/hypernova/mod.rs +++ b/folding-schemes/src/folding/hypernova/mod.rs @@ -1,11 +1,10 @@ /// Implements the scheme described in [HyperNova](https://eprint.iacr.org/2023/573.pdf) use ark_crypto_primitives::sponge::{ poseidon::{PoseidonConfig, PoseidonSponge}, - Absorb, CryptographicSponge, + CryptographicSponge, }; -use ark_ec::CurveGroup; use ark_ff::{BigInteger, PrimeField}; -use ark_r1cs_std::{prelude::CurveVar, R1CSVar}; +use ark_r1cs_std::R1CSVar; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, SerializationError}; use ark_std::{fmt::Debug, marker::PhantomData, rand::RngCore, One, Zero}; @@ -27,12 +26,9 @@ use nimfs::NIMFS; use crate::commitment::CommitmentScheme; use crate::constants::NOVA_N_BITS_RO; use crate::folding::{ - circuits::{ - cyclefold::{ - fold_cyclefold_circuit, CycleFoldCircuit, CycleFoldCommittedInstance, CycleFoldConfig, - CycleFoldWitness, - }, - CF2, + circuits::cyclefold::{ + fold_cyclefold_circuit, CycleFoldCircuit, CycleFoldCommittedInstance, CycleFoldConfig, + CycleFoldWitness, }, nova::{get_r1cs_from_cs, PreprocessorParam}, traits::{CommittedInstanceOps, Dummy, WitnessOps}, @@ -47,15 +43,15 @@ use crate::{ r1cs::{extract_w_x, R1CS}, Arith, }, - FoldingScheme, MultiFolding, + Curve, FoldingScheme, MultiFolding, }; /// Configuration for HyperNova's CycleFold circuit -pub struct HyperNovaCycleFoldConfig { +pub struct HyperNovaCycleFoldConfig { _c: PhantomData, } -impl CycleFoldConfig +impl CycleFoldConfig for HyperNovaCycleFoldConfig { const RANDOMNESS_BIT_LENGTH: usize = NOVA_N_BITS_RO; @@ -65,8 +61,8 @@ impl CycleFoldConfig /// CycleFold circuit for computing random linear combinations of group elements /// in HyperNova instances. -pub type HyperNovaCycleFoldCircuit = - CycleFoldCircuit, GC>; +pub type HyperNovaCycleFoldCircuit = + CycleFoldCircuit>; /// Witness for the LCCCS & CCCS, containing the w vector, and the r_w used as randomness in the Pedersen commitment. #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] @@ -101,8 +97,8 @@ impl WitnessOps for Witness { #[derive(Debug, Clone)] pub struct ProverParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -118,8 +114,8 @@ where } impl< - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, const H: bool, @@ -142,8 +138,8 @@ impl< /// Verification parameters for HyperNova-based IVC #[derive(Debug, Clone)] pub struct VerifierParams< - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, const H: bool, @@ -162,8 +158,8 @@ pub struct VerifierParams< impl CanonicalSerialize for VerifierParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -183,8 +179,8 @@ where impl VerifierParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -203,8 +199,8 @@ where #[derive(PartialEq, Eq, Debug, Clone, CanonicalSerialize, CanonicalDeserialize)] pub struct IVCProof where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, { pub i: C1::ScalarField, pub z_0: Vec, @@ -225,30 +221,14 @@ where /// * `MU` - the number of LCCCS instances to be folded /// * `NU` - the number of CCCS instances to be folded #[derive(Clone, Debug)] -pub struct HyperNova< - C1, - GC1, - C2, - GC2, - FC, - CS1, - CS2, - const MU: usize, - const NU: usize, - const H: bool, -> where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, +pub struct HyperNova +where + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, { - _gc1: PhantomData, - _c2: PhantomData, - _gc2: PhantomData, - /// CCS of the Augmented Function circuit pub ccs: CCS, /// R1CS of the CycleFold circuit @@ -278,21 +258,15 @@ pub struct HyperNova< pub cf_U_i: CycleFoldCommittedInstance, } -impl - MultiFolding for HyperNova +impl MultiFolding + for HyperNova where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, + C1: Curve, { type RunningInstance = (LCCCS, Witness); type IncomingInstance = (CCCS, Witness); @@ -343,21 +317,15 @@ where } } -impl - HyperNova +impl + HyperNova where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, + C1: Curve, { /// internal helper for new_running_instance & new_incoming_instance methods, returns the R1CS /// z=[u,x,w] vector to be used to create the LCCCS & CCCS fresh instances. @@ -389,9 +357,7 @@ where // compute u_{i+1}.x let U_i1 = LCCCS::dummy(&self.ccs); - let augmented_f_circuit = AugmentedFCircuit:: { - _c2: PhantomData, - _gc2: PhantomData, + let augmented_f_circuit = AugmentedFCircuit:: { poseidon_config: self.poseidon_config.clone(), ccs: self.ccs.clone(), pp_hash: Some(self.pp_hash), @@ -433,21 +399,15 @@ where } } -impl - FoldingScheme for HyperNova +impl + FoldingScheme for HyperNova where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, + C1: Curve, { /// Reuse Nova's PreprocessorParam. type PreprocessorParam = PreprocessorParam; @@ -473,7 +433,7 @@ where // main circuit R1CS: let f_circuit = FC::new(fc_params)?; - let augmented_F_circuit = AugmentedFCircuit::::empty( + let augmented_F_circuit = AugmentedFCircuit::::empty( &poseidon_config, f_circuit.clone(), None, @@ -504,7 +464,7 @@ where // main circuit R1CS: let f_circuit = FC::new(fc_params)?; - let augmented_F_circuit = AugmentedFCircuit::::empty( + let augmented_F_circuit = AugmentedFCircuit::::empty( &poseidon_config, f_circuit.clone(), None, @@ -512,7 +472,7 @@ where let ccs = augmented_F_circuit.ccs; // CycleFold circuit R1CS - let cf_circuit = HyperNovaCycleFoldCircuit::::empty(); + let cf_circuit = HyperNovaCycleFoldCircuit::::empty(); let cf_r1cs = get_r1cs_from_cs::(cf_circuit)?; let cs_vp = CS1::VerifierParams::deserialize_with_mode(&mut reader, compress, validate)?; @@ -535,14 +495,14 @@ where return Err(Error::CantBeZero("mu,nu".to_string())); } - let augmented_f_circuit = AugmentedFCircuit::::empty( + let augmented_f_circuit = AugmentedFCircuit::::empty( &prep_param.poseidon_config, prep_param.F.clone(), None, )?; let ccs = augmented_f_circuit.ccs.clone(); - let cf_circuit = HyperNovaCycleFoldCircuit::::empty(); + let cf_circuit = HyperNovaCycleFoldCircuit::::empty(); let cf_r1cs = get_r1cs_from_cs::(cf_circuit)?; // if cs params exist, use them, if not, generate new ones @@ -587,14 +547,14 @@ where // prepare the HyperNova's AugmentedFCircuit and CycleFold's circuits and obtain its CCS // and R1CS respectively - let augmented_f_circuit = AugmentedFCircuit::::empty( + let augmented_f_circuit = AugmentedFCircuit::::empty( &pp.poseidon_config, F.clone(), pp.ccs.clone(), )?; let ccs = augmented_f_circuit.ccs.clone(); - let cf_circuit = HyperNovaCycleFoldCircuit::::empty(); + let cf_circuit = HyperNovaCycleFoldCircuit::::empty(); let cf_r1cs = get_r1cs_from_cs::(cf_circuit)?; // compute the public params hash @@ -615,9 +575,6 @@ where // W_dummy=W_0 is a 'dummy witness', all zeroes, but with the size corresponding to the // R1CS that we're working with. Ok(Self { - _gc1: PhantomData, - _c2: PhantomData, - _gc2: PhantomData, ccs, cf_r1cs, poseidon_config: pp.poseidon_config.clone(), @@ -698,7 +655,7 @@ where (vec![], vec![], vec![], vec![]) }; - let augmented_f_circuit: AugmentedFCircuit; + let augmented_f_circuit: AugmentedFCircuit; if self.z_i.len() != self.F.state_len() { return Err(Error::NotSameLength( @@ -744,9 +701,7 @@ where W_i1.r_w = self.W_i.r_w; U_i1 = LCCCS::dummy(&self.ccs); - augmented_f_circuit = AugmentedFCircuit:: { - _c2: PhantomData, - _gc2: PhantomData, + augmented_f_circuit = AugmentedFCircuit:: { poseidon_config: self.poseidon_config.clone(), ccs: self.ccs.clone(), pp_hash: Some(self.pp_hash), @@ -797,8 +752,7 @@ where let rho_bits = rho.into_bigint().to_bits_le()[..NOVA_N_BITS_RO].to_vec(); // CycleFold part: - let cf_circuit = HyperNovaCycleFoldCircuit:: { - _gc: PhantomData, + let cf_circuit = HyperNovaCycleFoldCircuit:: { r_bits: Some(rho_bits), points: Some( [ @@ -809,28 +763,19 @@ where ), }; - let (_cf_w_i, cf_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = fold_cyclefold_circuit::< - HyperNovaCycleFoldConfig, - C1, - GC1, - C2, - GC2, - CS2, - H, - >( - &mut transcript_p, - self.cf_r1cs.clone(), - self.cf_cs_pp.clone(), - self.pp_hash, - self.cf_W_i.clone(), // CycleFold running instance witness - self.cf_U_i.clone(), // CycleFold running instance - cf_circuit, - &mut rng, - )?; - - augmented_f_circuit = AugmentedFCircuit:: { - _c2: PhantomData, - _gc2: PhantomData, + let (cf_u_i, cf_W_i1, cf_U_i1, cf_cmT) = + fold_cyclefold_circuit::, C2, CS2, H>( + &mut transcript_p, + self.cf_r1cs.clone(), + self.cf_cs_pp.clone(), + self.pp_hash, + self.cf_W_i.clone(), // CycleFold running instance witness + self.cf_U_i.clone(), // CycleFold running instance + cf_circuit, + &mut rng, + )?; + + augmented_f_circuit = AugmentedFCircuit:: { poseidon_config: self.poseidon_config.clone(), ccs: self.ccs.clone(), pp_hash: Some(self.pp_hash), @@ -938,20 +883,17 @@ where let (pp, vp) = params; let f_circuit = FC::new(fcircuit_params)?; - let augmented_f_circuit = AugmentedFCircuit::::empty( + let augmented_f_circuit = AugmentedFCircuit::::empty( &pp.poseidon_config, f_circuit.clone(), None, )?; - let cf_circuit = HyperNovaCycleFoldCircuit::::empty(); + let cf_circuit = HyperNovaCycleFoldCircuit::::empty(); let ccs = augmented_f_circuit.ccs.clone(); let cf_r1cs = get_r1cs_from_cs::(cf_circuit)?; Ok(Self { - _gc1: PhantomData, - _c2: PhantomData, - _gc2: PhantomData, ccs, cf_r1cs, poseidon_config: pp.poseidon_config, @@ -1028,8 +970,8 @@ where #[cfg(test)] mod tests { use crate::commitment::kzg::KZG; - use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_bn254::{Bn254, Fr, G1Projective as Projective}; + use ark_grumpkin::Projective as Projective2; use ark_std::UniformRand; use super::*; @@ -1077,7 +1019,7 @@ mod tests { const NU: usize = 3; type HN = - HyperNova, CS1, CS2, MU, NU, H>; + HyperNova, CS1, CS2, MU, NU, H>; let prep_param = PreprocessorParam::, CS1, CS2, H>::new( diff --git a/folding-schemes/src/folding/hypernova/nimfs.rs b/folding-schemes/src/folding/hypernova/nimfs.rs index 9e1e944e..c126d18d 100644 --- a/folding-schemes/src/folding/hypernova/nimfs.rs +++ b/folding-schemes/src/folding/hypernova/nimfs.rs @@ -1,5 +1,3 @@ -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::CurveGroup; use ark_ff::{BigInteger, Field, PrimeField}; use ark_poly::univariate::DensePolynomial; use ark_poly::{DenseUVPolynomial, Polynomial}; @@ -19,19 +17,19 @@ use crate::transcript::Transcript; use crate::utils::sum_check::structs::{IOPProof as SumCheckProof, IOPProverMessage}; use crate::utils::sum_check::{IOPSumCheck, SumCheck}; use crate::utils::virtual_polynomial::VPAuxInfo; -use crate::Error; +use crate::{Curve, Error}; use std::fmt::Debug; use std::marker::PhantomData; /// NIMFSProof defines a multifolding proof #[derive(Clone, Debug, Eq, PartialEq)] -pub struct NIMFSProof { +pub struct NIMFSProof { pub sc_proof: SumCheckProof, pub sigmas_thetas: SigmasThetas, } -impl Dummy<(usize, usize, usize, usize)> for NIMFSProof { +impl Dummy<(usize, usize, usize, usize)> for NIMFSProof { fn dummy((s, t, mu, nu): (usize, usize, usize, usize)) -> Self { // use 'C::ScalarField::one()' instead of 'zero()' to enforce the NIMFSProof to have the // same in-circuit representation to match the number of constraints of an actual proof. @@ -53,7 +51,7 @@ impl Dummy<(usize, usize, usize, usize)> for NIMFSProof { } } -impl Dummy<(&CCS>, usize, usize)> for NIMFSProof { +impl Dummy<(&CCS>, usize, usize)> for NIMFSProof { fn dummy((ccs, mu, nu): (&CCS>, usize, usize)) -> Self { NIMFSProof::dummy((ccs.s, ccs.t, mu, nu)) } @@ -65,15 +63,12 @@ pub struct SigmasThetas(pub Vec>, pub Vec>); #[derive(Debug)] /// Implements the Non-Interactive Multi Folding Scheme described in section 5 of /// [HyperNova](https://eprint.iacr.org/2023/573.pdf) -pub struct NIMFS> { +pub struct NIMFS> { pub _c: PhantomData, pub _t: PhantomData, } -impl> NIMFS -where - C::ScalarField: Absorb, -{ +impl> NIMFS { pub fn fold( lcccs: &[LCCCS], cccs: &[CCCS], diff --git a/folding-schemes/src/folding/hypernova/utils.rs b/folding-schemes/src/folding/hypernova/utils.rs index 40f256e4..449b4b13 100644 --- a/folding-schemes/src/folding/hypernova/utils.rs +++ b/folding-schemes/src/folding/hypernova/utils.rs @@ -1,4 +1,3 @@ -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_poly::{DenseMultilinearExtension, MultilinearExtension}; use ark_std::One; @@ -10,7 +9,7 @@ use crate::arith::ccs::CCS; use crate::utils::mle::dense_vec_to_dense_mle; use crate::utils::vec::mat_vec_mul; use crate::utils::virtual_polynomial::{build_eq_x_r_vec, eq_eval, VirtualPolynomial}; -use crate::Error; +use crate::{Curve, Error}; /// Compute the arrays of sigma_i and theta_i from step 4 corresponding to the LCCCS and CCCS /// instances @@ -97,17 +96,14 @@ pub fn compute_c( } /// Compute g(x) polynomial for the given inputs. -pub fn compute_g( +pub fn compute_g( ccs: &CCS, running_instances: &[LCCCS], z_lcccs: &[Vec], z_cccs: &[Vec], gamma: C::ScalarField, beta: &[C::ScalarField], -) -> Result, Error> -where - C::ScalarField: PrimeField, -{ +) -> Result, Error> { assert_eq!(running_instances.len(), z_lcccs.len()); let mut g = VirtualPolynomial::::new(ccs.s); diff --git a/folding-schemes/src/folding/mod.rs b/folding-schemes/src/folding/mod.rs index 255ca54f..3de2751c 100644 --- a/folding-schemes/src/folding/mod.rs +++ b/folding-schemes/src/folding/mod.rs @@ -6,11 +6,10 @@ pub mod traits; #[cfg(test)] pub mod tests { - use ark_ec::CurveGroup; - use ark_ff::PrimeField; - use ark_pallas::{constraints::GVar as GVar1, Fr, Projective as G1}; + + use ark_pallas::{Fr, Projective as G1}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; - use ark_vesta::{constraints::GVar as GVar2, Projective as G2}; + use ark_vesta::Projective as G2; use std::io::Write; use crate::commitment::pedersen::Pedersen; @@ -22,8 +21,8 @@ pub mod tests { use crate::frontend::utils::CubicFCircuit; use crate::frontend::FCircuit; use crate::transcript::poseidon::poseidon_canonical_config; - use crate::Error; use crate::FoldingScheme; + use crate::{Curve, Error}; /// tests the IVC proofs and its serializers for the 3 implemented IVCs: Nova, HyperNova and /// ProtoGalaxy. @@ -34,16 +33,14 @@ pub mod tests { let f_circuit = FC::new(())?; // test Nova - type N = Nova, Pedersen, false>; + type N = Nova, Pedersen, false>; let prep_param = NovaPreprocessorParam::new(poseidon_config.clone(), f_circuit); test_serialize_ivc_opt::("nova".to_string(), prep_param.clone())?; // test HyperNova type HN = HyperNova< G1, - GVar1, G2, - GVar2, FC, Pedersen, Pedersen, @@ -54,26 +51,21 @@ pub mod tests { test_serialize_ivc_opt::("hypernova".to_string(), prep_param)?; // test ProtoGalaxy - type P = ProtoGalaxy, Pedersen>; + type P = ProtoGalaxy, Pedersen>; let prep_param = (poseidon_config, f_circuit); test_serialize_ivc_opt::("protogalaxy".to_string(), prep_param)?; Ok(()) } fn test_serialize_ivc_opt< - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, FC: FCircuit, FS: FoldingScheme, >( name: String, prep_param: FS::PreprocessorParam, - ) -> Result<(), Error> - where - C1: CurveGroup, - C2::BaseField: PrimeField, - FC: FCircuit, - { + ) -> Result<(), Error> { let mut rng = ark_std::test_rng(); let F_circuit = FC::new(())?; diff --git a/folding-schemes/src/folding/nova/circuits.rs b/folding-schemes/src/folding/nova/circuits.rs index 38fb0333..1989148c 100644 --- a/folding-schemes/src/folding/nova/circuits.rs +++ b/folding-schemes/src/folding/nova/circuits.rs @@ -2,9 +2,7 @@ use ark_crypto_primitives::sponge::{ constraints::CryptographicSpongeVar, poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig, PoseidonSponge}, - Absorb, }; -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_r1cs_std::{ alloc::AllocVar, @@ -16,7 +14,6 @@ use ark_r1cs_std::{ }; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; use ark_std::{fmt::Debug, One, Zero}; -use core::marker::PhantomData; use super::{ nifs::{ @@ -31,11 +28,12 @@ use crate::folding::circuits::{ CycleFoldConfig, NIFSFullGadget, }, nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar}, - CF1, CF2, + CF1, }; use crate::folding::traits::{CommittedInstanceVarOps, Dummy}; use crate::frontend::FCircuit; use crate::transcript::AbsorbNonNativeGadget; +use crate::Curve; /// `AugmentedFCircuit` enhances the original step function `F`, so that it can /// be used in recursive arguments such as IVC. @@ -50,13 +48,7 @@ use crate::transcript::AbsorbNonNativeGadget; /// defined in [CycleFold](https://eprint.iacr.org/2023/1192.pdf). These extra /// constraints verify the correct folding of CycleFold instances. #[derive(Debug, Clone)] -pub struct AugmentedFCircuit< - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, - FC: FCircuit>, -> { - pub(super) _gc2: PhantomData, +pub struct AugmentedFCircuit>> { pub(super) poseidon_config: PoseidonConfig>, pub(super) pp_hash: Option>, pub(super) i: Option>, @@ -81,12 +73,9 @@ pub struct AugmentedFCircuit< pub(super) cf2_cmT: Option, } -impl>, FC: FCircuit>> - AugmentedFCircuit -{ +impl>> AugmentedFCircuit { pub fn empty(poseidon_config: &PoseidonConfig>, F_circuit: FC) -> Self { Self { - _gc2: PhantomData, poseidon_config: poseidon_config.clone(), pp_hash: None, i: None, @@ -110,13 +99,11 @@ impl>, FC: FCircuit AugmentedFCircuit +impl AugmentedFCircuit where - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit>, - C2::BaseField: PrimeField + Absorb, { pub fn compute_next_state( self, @@ -159,11 +146,13 @@ where NonNativeAffineVar::new_witness(cs.clone(), || Ok(self.cmT.unwrap_or_else(C1::zero)))?; let cf_u_dummy = CycleFoldCommittedInstance::dummy(NovaCycleFoldConfig::::IO_LEN); - let cf_U_i = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { + let cf_U_i = CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || { Ok(self.cf_U_i.unwrap_or(cf_u_dummy.clone())) })?; - let cf1_cmT = GC2::new_witness(cs.clone(), || Ok(self.cf1_cmT.unwrap_or_else(C2::zero)))?; - let cf2_cmT = GC2::new_witness(cs.clone(), || Ok(self.cf2_cmT.unwrap_or_else(C2::zero)))?; + let cf1_cmT = + C2::Var::new_witness(cs.clone(), || Ok(self.cf1_cmT.unwrap_or_else(C2::zero)))?; + let cf2_cmT = + C2::Var::new_witness(cs.clone(), || Ok(self.cf2_cmT.unwrap_or_else(C2::zero)))?; // `sponge` is for digest computation. let sponge = PoseidonSpongeVar::::new(cs.clone(), &self.poseidon_config); @@ -276,21 +265,21 @@ where // C.2. Construct `cf1_u_i` and `cf2_u_i` let cf1_u_i = CycleFoldCommittedInstanceVar { // cf1_u_i.cmE = 0 - cmE: GC2::zero(), + cmE: C2::Var::zero(), // cf1_u_i.u = 1 u: NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::one())?, // cf1_u_i.cmW is provided by the prover as witness - cmW: GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW.unwrap_or(C2::zero())))?, + cmW: C2::Var::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW.unwrap_or(C2::zero())))?, // cf1_u_i.x is computed in step 1 x: cfW_x, }; let cf2_u_i = CycleFoldCommittedInstanceVar { // cf2_u_i.cmE = 0 - cmE: GC2::zero(), + cmE: C2::Var::zero(), // cf2_u_i.u = 1 u: NonNativeUintVar::new_constant(cs.clone(), C1::BaseField::one())?, // cf2_u_i.cmW is provided by the prover as witness - cmW: GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW.unwrap_or(C2::zero())))?, + cmW: C2::Var::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW.unwrap_or(C2::zero())))?, // cf2_u_i.x is computed in step 1 x: cfE_x, }; @@ -300,7 +289,7 @@ where // compute cf1_r = H(cf1_u_i, cf_U_i, cf1_cmT) // cf_r_bits is denoted by rho* in the paper. - let cf1_r_bits = CycleFoldChallengeGadget::::get_challenge_gadget( + let cf1_r_bits = CycleFoldChallengeGadget::::get_challenge_gadget( &mut transcript, pp_hash.clone(), cf_U_i_vec, @@ -308,19 +297,18 @@ where cf1_cmT.clone(), )?; // Fold cf1_u_i & cf_U_i into cf1_U_{i+1} - let cf1_U_i1 = NIFSFullGadget::::fold_committed_instance( - cf1_r_bits, cf1_cmT, cf_U_i, cf1_u_i, - )?; + let cf1_U_i1 = + NIFSFullGadget::::fold_committed_instance(cf1_r_bits, cf1_cmT, cf_U_i, cf1_u_i)?; // same for cf2_r: - let cf2_r_bits = CycleFoldChallengeGadget::::get_challenge_gadget( + let cf2_r_bits = CycleFoldChallengeGadget::::get_challenge_gadget( &mut transcript, pp_hash.clone(), cf1_U_i1.to_native_sponge_field_elements()?, cf2_u_i.clone(), cf2_cmT.clone(), )?; - let cf_U_i1 = NIFSFullGadget::::fold_committed_instance( + let cf_U_i1 = NIFSFullGadget::::fold_committed_instance( cf2_r_bits, cf2_cmT, cf1_U_i1, // the output from NIFS.V(cf1_r, cf_U, cfE_u) cf2_u_i, )?; @@ -331,7 +319,7 @@ where // Non-base case: u_{i+1}.x[1] == H(cf_U_{i+1}) let (cf_u_i1_x, _) = cf_U_i1.clone().hash(&sponge, pp_hash.clone())?; let (cf_u_i1_x_base, _) = - CycleFoldCommittedInstanceVar::::new_constant(cs.clone(), cf_u_dummy)? + CycleFoldCommittedInstanceVar::::new_constant(cs.clone(), cf_u_dummy)? .hash(&sponge, pp_hash)?; let cf_x = is_basecase.select(&cf_u_i1_x_base, &cf_u_i1_x)?; // This line "converts" `cf_x` from a witness to a public input. @@ -349,13 +337,11 @@ where } } -impl ConstraintSynthesizer> for AugmentedFCircuit +impl ConstraintSynthesizer> for AugmentedFCircuit where - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit>, - C2::BaseField: PrimeField + Absorb, { fn generate_constraints(self, cs: ConstraintSystemRef>) -> Result<(), SynthesisError> { self.compute_next_state(cs).map(|_| ()) @@ -366,9 +352,11 @@ where pub mod tests { use super::*; use ark_bn254::{Fr, G1Projective as Projective}; - use ark_crypto_primitives::sponge::{poseidon::PoseidonSponge, CryptographicSponge}; + use ark_crypto_primitives::sponge::{ + constraints::AbsorbGadget, poseidon::PoseidonSponge, CryptographicSponge, + }; use ark_ff::BigInteger; - use ark_r1cs_std::convert::ToConstraintFieldGadget; + use ark_relations::r1cs::ConstraintSystem; use ark_std::UniformRand; @@ -420,18 +408,11 @@ pub mod tests { let mut transcriptVar = PoseidonSpongeVar::::new(cs.clone(), &poseidon_config); // compute the challenge in-circuit - let U_iVar_vec = [ - vec![U_iVar.u.clone()], - U_iVar.x.clone(), - U_iVar.cmE.to_constraint_field()?, - U_iVar.cmW.to_constraint_field()?, - ] - .concat(); let r_bitsVar = ChallengeGadget::>::get_challenge_gadget( &mut transcriptVar, pp_hashVar, - U_iVar_vec, + U_iVar.to_sponge_field_elements()?, u_iVar, Some(cmTVar), )?; diff --git a/folding-schemes/src/folding/nova/decider.rs b/folding-schemes/src/folding/nova/decider.rs index ef24d928..f270aefa 100644 --- a/folding-schemes/src/folding/nova/decider.rs +++ b/folding-schemes/src/folding/nova/decider.rs @@ -2,10 +2,7 @@ /// DeciderEth from decider_eth.rs file. /// More details can be found at the documentation page: /// https://privacy-scaling-explorations.github.io/sonobe-docs/design/nova-decider-offchain.html -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::CurveGroup; use ark_ff::{BigInteger, PrimeField}; -use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_snark::SNARK; use ark_std::rand::{CryptoRng, RngCore}; @@ -16,21 +13,18 @@ use super::decider_circuits::{DeciderCircuit1, DeciderCircuit2}; use super::decider_eth_circuit::DeciderNovaGadget; use super::Nova; use crate::commitment::CommitmentScheme; +use crate::folding::circuits::cyclefold::CycleFoldCommittedInstance; use crate::folding::circuits::decider::DeciderEnabledNIFS; -use crate::folding::circuits::{ - cyclefold::{CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar}, - CF2, -}; -use crate::folding::traits::{CommittedInstanceOps, Inputize, WitnessOps}; +use crate::folding::traits::{CommittedInstanceOps, Inputize, InputizeNonNative, WitnessOps}; use crate::frontend::FCircuit; -use crate::Error; +use crate::{Curve, Error}; use crate::{Decider as DeciderTrait, FoldingScheme}; #[derive(Debug, Clone, Eq, PartialEq)] pub struct Proof where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, S1: SNARK, @@ -69,7 +63,7 @@ where #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct VerifierParam where - C1: CurveGroup, + C1: Curve, CS1_VerifyingKey: Clone + CanonicalSerialize + CanonicalDeserialize, S1_VerifyingKey: Clone + CanonicalSerialize + CanonicalDeserialize, CS2_VerifyingKey: Clone + CanonicalSerialize + CanonicalDeserialize, @@ -84,11 +78,9 @@ where /// Onchain Decider, for ethereum use cases #[derive(Clone, Debug)] -pub struct Decider { +pub struct Decider { _c1: PhantomData, - _gc1: PhantomData, _c2: PhantomData, - _gc2: PhantomData, _fc: PhantomData, _cs1: PhantomData, _cs2: PhantomData, @@ -97,13 +89,11 @@ pub struct Decider { _fs: PhantomData, } -impl DeciderTrait - for Decider +impl DeciderTrait + for Decider where - C1: CurveGroup, - C2: CurveGroup, - GC1: CurveVar>, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme< C1, @@ -120,15 +110,8 @@ where S1: SNARK, S2: SNARK, FS: FoldingScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, - for<'b> &'b GC1: GroupOpsBounds<'b, C1, GC1>, - for<'b> &'b GC2: GroupOpsBounds<'b, C2, GC2>, // constrain FS into Nova, since this is a Decider specifically for Nova - Nova: From, + Nova: From, crate::folding::nova::ProverParams: From<>::ProverParam>, crate::folding::nova::VerifierParams: @@ -153,7 +136,7 @@ where prep_param: Self::PreprocessorParam, fs: FS, ) -> Result<(Self::ProverParam, Self::VerifierParam), Error> { - let circuit1 = DeciderCircuit1::::try_from(Nova::from(fs.clone()))?; + let circuit1 = DeciderCircuit1::::try_from(Nova::from(fs.clone()))?; let circuit2 = DeciderCircuit2::::try_from(Nova::from(fs))?; // get the Groth16 specific setup for the circuits @@ -164,13 +147,13 @@ where // get the FoldingScheme prover & verifier params from Nova #[allow(clippy::type_complexity)] - let nova_pp: as FoldingScheme< + let nova_pp: as FoldingScheme< C1, C2, FC, >>::ProverParam = prep_param.0.clone().into(); #[allow(clippy::type_complexity)] - let nova_vp: as FoldingScheme< + let nova_vp: as FoldingScheme< C1, C2, FC, @@ -198,7 +181,7 @@ where pp: Self::ProverParam, fs: FS, ) -> Result { - let circuit1 = DeciderCircuit1::::try_from(Nova::from(fs.clone()))?; + let circuit1 = DeciderCircuit1::::try_from(Nova::from(fs.clone()))?; let circuit2 = DeciderCircuit2::::try_from(Nova::from(fs))?; let cmT = circuit1.proof; @@ -280,14 +263,11 @@ where &[vp.pp_hash, i][..], &z_0, &z_i, - &U_final_commitments - .iter() - .flat_map(|c| c.inputize()) - .collect::>(), - &Inputize::, CycleFoldCommittedInstanceVar>::inputize(&cf_U), + &U_final_commitments.inputize_nonnative(), + &cf_U.inputize_nonnative(), &proof.cs1_challenges, &proof.cs1_proofs.iter().map(|p| p.eval).collect::>(), - &proof.cmT.inputize(), + &proof.cmT.inputize_nonnative(), ] .concat(); @@ -344,12 +324,8 @@ pub mod tests { // Note: do not use the MNTx_298 curves in practice, these are just for tests. Use the MNTx_753 // curves instead. - use ark_mnt4_298::{ - constraints::G1Var as GVar, Fr, G1Projective as Projective, MNT4_298 as MNT4, - }; - use ark_mnt6_298::{ - constraints::G1Var as GVar2, G1Projective as Projective2, MNT6_298 as MNT6, - }; + use ark_mnt4_298::{Fr, G1Projective as Projective, MNT4_298 as MNT4}; + use ark_mnt6_298::{G1Projective as Projective2, MNT6_298 as MNT6}; use std::time::Instant; use super::*; @@ -363,9 +339,7 @@ pub mod tests { // use Nova as FoldingScheme type N = Nova< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, MNT4>, KZG<'static, MNT6>, @@ -373,9 +347,7 @@ pub mod tests { >; type D = Decider< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, MNT4>, KZG<'static, MNT6>, diff --git a/folding-schemes/src/folding/nova/decider_circuits.rs b/folding-schemes/src/folding/nova/decider_circuits.rs index 95825475..f91537fa 100644 --- a/folding-schemes/src/folding/nova/decider_circuits.rs +++ b/folding-schemes/src/folding/nova/decider_circuits.rs @@ -2,10 +2,9 @@ /// DeciderEthCircuit. /// More details can be found at the documentation page: /// https://privacy-scaling-explorations.github.io/sonobe-docs/design/nova-decider-offchain.html -use ark_crypto_primitives::sponge::{poseidon::PoseidonSponge, Absorb, CryptographicSponge}; -use ark_ec::CurveGroup; +use ark_crypto_primitives::sponge::{poseidon::PoseidonSponge, CryptographicSponge}; use ark_ff::{BigInteger, PrimeField}; -use ark_r1cs_std::{fields::fp::FpVar, prelude::CurveVar}; +use ark_r1cs_std::fields::fp::FpVar; use core::marker::PhantomData; use super::{ @@ -13,12 +12,8 @@ use super::{ nifs::{nova::NIFS, NIFSTrait}, CommittedInstance, Nova, Witness, }; -use crate::folding::{ - circuits::{CF1, CF2}, - traits::WitnessOps, -}; +use crate::folding::{circuits::CF1, traits::WitnessOps}; use crate::frontend::FCircuit; -use crate::Error; use crate::{ arith::r1cs::{circuits::R1CSMatricesVar, R1CS}, folding::circuits::decider::{ @@ -27,14 +22,14 @@ use crate::{ }, }; use crate::{commitment::CommitmentScheme, transcript::poseidon::poseidon_canonical_config}; +use crate::{Curve, Error}; /// Circuit that implements part of the in-circuit checks needed for the offchain verification over /// the Curve2's BaseField (=Curve1's ScalarField). -pub type DeciderCircuit1 = GenericOffchainDeciderCircuit1< +pub type DeciderCircuit1 = GenericOffchainDeciderCircuit1< C1, C2, - GC2, CommittedInstance, CommittedInstance, Witness, @@ -44,22 +39,17 @@ pub type DeciderCircuit1 = GenericOffchainDeciderCircuit1< >; impl< - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, const H: bool, - > TryFrom> for DeciderCircuit1 -where - CF1: Absorb, - ::BaseField: PrimeField, + > TryFrom> for DeciderCircuit1 { type Error = Error; - fn try_from(nova: Nova) -> Result { + fn try_from(nova: Nova) -> Result { let mut transcript = PoseidonSponge::::new(&nova.poseidon_config); // pp_hash is absorbed to transcript at the NIFS::prove call @@ -89,7 +79,6 @@ where .collect::, _>>()?; Ok(Self { - _gc2: PhantomData, _avar: PhantomData, arith: nova.r1cs, poseidon_config: nova.poseidon_config, @@ -117,21 +106,17 @@ where pub type DeciderCircuit2 = GenericOffchainDeciderCircuit2; impl< - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, const H: bool, - > TryFrom> for DeciderCircuit2 -where - CF1: Absorb, + > TryFrom> for DeciderCircuit2 { type Error = Error; - fn try_from(nova: Nova) -> Result { + fn try_from(nova: Nova) -> Result { // compute the Commitment Scheme challenges of the CycleFold instance commitments, used as // inputs in the circuit let poseidon_config = poseidon_canonical_config::(); @@ -167,9 +152,9 @@ where #[cfg(test)] pub mod tests { - use ark_pallas::{constraints::GVar, Fq, Fr, Projective}; + use ark_pallas::{Fq, Fr, Projective}; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; - use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_vesta::Projective as Projective2; use super::*; use crate::commitment::pedersen::Pedersen; @@ -188,9 +173,7 @@ pub mod tests { type N = Nova< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, Pedersen, Pedersen, @@ -215,8 +198,7 @@ pub mod tests { N::verify(nova_params.1, ivc_proof)?; // load the DeciderCircuit 1 & 2 from the Nova instance - let decider_circuit1 = - DeciderCircuit1::::try_from(nova.clone())?; + let decider_circuit1 = DeciderCircuit1::::try_from(nova.clone())?; let decider_circuit2 = DeciderCircuit2::::try_from(nova)?; // generate the constraints of both circuits and check that are satisfied by the inputs diff --git a/folding-schemes/src/folding/nova/decider_eth.rs b/folding-schemes/src/folding/nova/decider_eth.rs index e5c0fb69..b7a4a79c 100644 --- a/folding-schemes/src/folding/nova/decider_eth.rs +++ b/folding-schemes/src/folding/nova/decider_eth.rs @@ -3,15 +3,13 @@ /// More details can be found at the documentation page: /// https://privacy-scaling-explorations.github.io/sonobe-docs/design/nova-decider-onchain.html use ark_bn254::Bn254; -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::{AffineRepr, CurveGroup}; -use ark_ff::{BigInteger, PrimeField}; use ark_groth16::Groth16; -use ark_r1cs_std::prelude::CurveVar; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_snark::SNARK; -use ark_std::rand::{CryptoRng, RngCore}; -use ark_std::{One, Zero}; +use ark_std::{ + rand::{CryptoRng, RngCore}, + One, Zero, +}; use core::marker::PhantomData; pub use super::decider_eth_circuit::DeciderEthCircuit; @@ -22,16 +20,17 @@ use crate::commitment::{ pedersen::Params as PedersenParams, CommitmentScheme, }; -use crate::folding::circuits::{decider::DeciderEnabledNIFS, CF2}; -use crate::folding::traits::{Inputize, WitnessOps}; +use crate::folding::circuits::decider::DeciderEnabledNIFS; +use crate::folding::traits::{InputizeNonNative, WitnessOps}; use crate::frontend::FCircuit; -use crate::Error; +use crate::utils::eth::ToEth; +use crate::{Curve, Error}; use crate::{Decider as DeciderTrait, FoldingScheme}; #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct Proof where - C: CurveGroup, + C: Curve, CS: CommitmentScheme, S: SNARK, { @@ -49,7 +48,7 @@ where #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct VerifierParam where - C1: CurveGroup, + C1: Curve, CS_VerifyingKey: Clone + CanonicalSerialize + CanonicalDeserialize, S_VerifyingKey: Clone + CanonicalSerialize + CanonicalDeserialize, { @@ -60,11 +59,9 @@ where /// Onchain Decider, for ethereum use cases #[derive(Clone, Debug)] -pub struct Decider { +pub struct Decider { _c1: PhantomData, - _gc1: PhantomData, _c2: PhantomData, - _gc2: PhantomData, _fc: PhantomData, _cs1: PhantomData, _cs2: PhantomData, @@ -72,13 +69,11 @@ pub struct Decider { _fs: PhantomData, } -impl DeciderTrait - for Decider +impl DeciderTrait + for Decider where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, // CS1 is a KZG commitment, where challenge is C1::Fr elem CS1: CommitmentScheme< @@ -91,13 +86,8 @@ where CS2: CommitmentScheme>, S: SNARK, FS: FoldingScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, // constrain FS into Nova, since this is a Decider specifically for Nova - Nova: From, + Nova: From, crate::folding::nova::ProverParams: From<>::ProverParam>, crate::folding::nova::VerifierParams: @@ -115,7 +105,7 @@ where prep_param: Self::PreprocessorParam, fs: FS, ) -> Result<(Self::ProverParam, Self::VerifierParam), Error> { - let circuit = DeciderEthCircuit::::try_from(Nova::from(fs))?; + let circuit = DeciderEthCircuit::::try_from(Nova::from(fs))?; // get the Groth16 specific setup for the circuit let (g16_pk, g16_vk) = S::circuit_specific_setup(circuit, &mut rng) @@ -123,13 +113,13 @@ where // get the FoldingScheme prover & verifier params from Nova #[allow(clippy::type_complexity)] - let nova_pp: as FoldingScheme< + let nova_pp: as FoldingScheme< C1, C2, FC, >>::ProverParam = prep_param.0.clone().into(); #[allow(clippy::type_complexity)] - let nova_vp: as FoldingScheme< + let nova_vp: as FoldingScheme< C1, C2, FC, @@ -152,7 +142,7 @@ where ) -> Result { let (snark_pk, cs_pk): (S::ProvingKey, CS1::ProverParams) = pp; - let circuit = DeciderEthCircuit::::try_from(Nova::from(folding_scheme))?; + let circuit = DeciderEthCircuit::::try_from(Nova::from(folding_scheme))?; let cmT = circuit.proof; let r = circuit.randomness; @@ -220,13 +210,10 @@ where &[pp_hash, i][..], &z_0, &z_i, - &U_final_commitments - .iter() - .flat_map(|c| c.inputize()) - .collect::>(), + &U_final_commitments.inputize_nonnative(), &proof.kzg_challenges, &proof.kzg_proofs.iter().map(|p| p.eval).collect::>(), - &proof.cmT.inputize(), + &proof.cmT.inputize_nonnative(), ] .concat(); @@ -261,58 +248,30 @@ pub fn prepare_calldata( incoming_instance: &CommittedInstance, proof: Proof, Groth16>, ) -> Result, Error> { - Ok(vec![ - function_signature_check.to_vec(), - i.into_bigint().to_bytes_be(), // i - z_0.iter() - .flat_map(|v| v.into_bigint().to_bytes_be()) - .collect::>(), // z_0 - z_i.iter() - .flat_map(|v| v.into_bigint().to_bytes_be()) - .collect::>(), // z_i - point_to_eth_format(running_instance.cmW.into_affine())?, - point_to_eth_format(running_instance.cmE.into_affine())?, - point_to_eth_format(incoming_instance.cmW.into_affine())?, - point_to_eth_format(proof.cmT.into_affine())?, // cmT - proof.r.into_bigint().to_bytes_be(), // r - point_to_eth_format(proof.snark_proof.a)?, // pA - point2_to_eth_format(proof.snark_proof.b)?, // pB - point_to_eth_format(proof.snark_proof.c)?, // pC - proof.kzg_challenges[0].into_bigint().to_bytes_be(), // challenge_W - proof.kzg_challenges[1].into_bigint().to_bytes_be(), // challenge_E - proof.kzg_proofs[0].eval.into_bigint().to_bytes_be(), // eval W - proof.kzg_proofs[1].eval.into_bigint().to_bytes_be(), // eval E - point_to_eth_format(proof.kzg_proofs[0].proof.into_affine())?, // W kzg_proof - point_to_eth_format(proof.kzg_proofs[1].proof.into_affine())?, // E kzg_proof - ] - .concat()) -} - -fn point_to_eth_format(p: C) -> Result, Error> -where - C::BaseField: PrimeField, -{ - // the encoding of the additive identity is [0, 0] on the EVM - let (x, y) = p.xy().unwrap_or_default(); - - Ok([x.into_bigint().to_bytes_be(), y.into_bigint().to_bytes_be()].concat()) -} -fn point2_to_eth_format(p: ark_bn254::G2Affine) -> Result, Error> { - let (x, y) = p.xy().unwrap_or_default(); - Ok([ - x.c1.into_bigint().to_bytes_be(), - x.c0.into_bigint().to_bytes_be(), - y.c1.into_bigint().to_bytes_be(), - y.c0.into_bigint().to_bytes_be(), + function_signature_check.to_eth(), + i.to_eth(), // i + z_0.to_eth(), // z_0 + z_i.to_eth(), // z_i + running_instance.cmW.to_eth(), + running_instance.cmE.to_eth(), + incoming_instance.cmW.to_eth(), + proof.cmT.to_eth(), // cmT + proof.r.to_eth(), // r + proof.snark_proof.to_eth(), // pA, pB, pC + proof.kzg_challenges.to_eth(), // challenge_W, challenge_E + proof.kzg_proofs[0].eval.to_eth(), // eval W + proof.kzg_proofs[1].eval.to_eth(), // eval E + proof.kzg_proofs[0].proof.to_eth(), // W kzg_proof + proof.kzg_proofs[1].proof.to_eth(), // E kzg_proof ] .concat()) } #[cfg(test)] pub mod tests { - use ark_bn254::{constraints::GVar, Fr, G1Projective as Projective}; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_bn254::{Fr, G1Projective as Projective}; + use ark_grumpkin::Projective as Projective2; use std::time::Instant; use super::*; @@ -327,9 +286,7 @@ pub mod tests { // use Nova as FoldingScheme type N = Nova< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, @@ -337,9 +294,7 @@ pub mod tests { >; type D = Decider< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, @@ -409,9 +364,7 @@ pub mod tests { // use Nova as FoldingScheme type N = Nova< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, @@ -419,9 +372,7 @@ pub mod tests { >; type D = Decider< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, diff --git a/folding-schemes/src/folding/nova/decider_eth_circuit.rs b/folding-schemes/src/folding/nova/decider_eth_circuit.rs index 745aecd9..b11c9b05 100644 --- a/folding-schemes/src/folding/nova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/nova/decider_eth_circuit.rs @@ -5,14 +5,12 @@ use ark_crypto_primitives::sponge::{ constraints::CryptographicSpongeVar, poseidon::{constraints::PoseidonSpongeVar, PoseidonSponge}, - Absorb, CryptographicSponge, + CryptographicSponge, }; -use ark_ec::CurveGroup; use ark_ff::{BigInteger, PrimeField}; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, fields::fp::FpVar, - prelude::CurveVar, }; use ark_relations::r1cs::{Namespace, SynthesisError}; use ark_std::{borrow::Borrow, marker::PhantomData}; @@ -25,31 +23,27 @@ use super::{ use crate::commitment::{pedersen::Params as PedersenParams, CommitmentScheme}; use crate::folding::{ circuits::{ - decider::on_chain::GenericOnchainDeciderCircuit, nonnative::affine::NonNativeAffineVar, - CF1, CF2, + decider::on_chain::GenericOnchainDeciderCircuit, nonnative::affine::NonNativeAffineVar, CF1, }, traits::{WitnessOps, WitnessVarOps}, }; use crate::frontend::FCircuit; -use crate::Error; use crate::{ arith::r1cs::{circuits::R1CSMatricesVar, R1CS}, folding::circuits::decider::{DeciderEnabledNIFS, EvalGadget, KZGChallengesGadget}, }; +use crate::{Curve, Error}; /// In-circuit representation of the Witness associated to the CommittedInstance. #[derive(Debug, Clone)] -pub struct WitnessVar { +pub struct WitnessVar { pub E: Vec>, pub rE: FpVar, pub W: Vec>, pub rW: FpVar, } -impl AllocVar, CF1> for WitnessVar -where - C: CurveGroup, -{ +impl AllocVar, CF1> for WitnessVar { fn new_variable>>( cs: impl Into>>, f: impl FnOnce() -> Result, @@ -73,16 +67,15 @@ where } } -impl WitnessVarOps for WitnessVar { +impl WitnessVarOps for WitnessVar { fn get_openings(&self) -> Vec<(&[FpVar], FpVar)> { vec![(&self.W, self.rW.clone()), (&self.E, self.rE.clone())] } } -pub type DeciderEthCircuit = GenericOnchainDeciderCircuit< +pub type DeciderEthCircuit = GenericOnchainDeciderCircuit< C1, C2, - GC2, CommittedInstance, CommittedInstance, Witness, @@ -93,23 +86,18 @@ pub type DeciderEthCircuit = GenericOnchainDeciderCircuit< /// returns an instance of the DeciderEthCircuit from the given Nova struct impl< - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, // enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider CS2: CommitmentScheme>, const H: bool, - > TryFrom> for DeciderEthCircuit -where - CF1: Absorb, - ::BaseField: PrimeField, + > TryFrom> for DeciderEthCircuit { type Error = Error; - fn try_from(nova: Nova) -> Result { + fn try_from(nova: Nova) -> Result { let mut transcript = PoseidonSponge::::new(&nova.poseidon_config); // compute the U_{i+1}, W_{i+1} @@ -138,7 +126,6 @@ where .collect::, _>>()?; Ok(Self { - _gc2: PhantomData, _avar: PhantomData, arith: nova.r1cs, cf_arith: nova.cf_r1cs, @@ -166,11 +153,9 @@ where pub struct DeciderNovaGadget; -impl +impl DeciderEnabledNIFS, CommittedInstance, Witness, R1CS>> for DeciderNovaGadget -where - CF1: Absorb, { type ProofDummyCfg = (); type Proof = C; @@ -215,9 +200,9 @@ where #[cfg(test)] pub mod tests { - use ark_pallas::{constraints::GVar, Fr, Projective}; + use ark_pallas::{Fr, Projective}; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; - use ark_vesta::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_vesta::Projective as Projective2; use super::*; use crate::commitment::pedersen::Pedersen; @@ -236,9 +221,7 @@ pub mod tests { type N = Nova< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, Pedersen, Pedersen, @@ -262,7 +245,7 @@ pub mod tests { N::verify(nova_params.1, ivc_proof)?; // load the DeciderEthCircuit from the generated Nova instance - let decider_circuit = DeciderEthCircuit::::try_from(nova)?; + let decider_circuit = DeciderEthCircuit::::try_from(nova)?; let cs = ConstraintSystem::::new_ref(); diff --git a/folding-schemes/src/folding/nova/mod.rs b/folding-schemes/src/folding/nova/mod.rs index 6389bcf2..d1e1540e 100644 --- a/folding-schemes/src/folding/nova/mod.rs +++ b/folding-schemes/src/folding/nova/mod.rs @@ -8,9 +8,8 @@ use ark_crypto_primitives::sponge::{ poseidon::{PoseidonConfig, PoseidonSponge}, Absorb, CryptographicSponge, }; -use ark_ec::CurveGroup; use ark_ff::{BigInteger, PrimeField}; -use ark_r1cs_std::{prelude::CurveVar, R1CSVar}; +use ark_r1cs_std::R1CSVar; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Valid}; use ark_std::fmt::Debug; @@ -22,14 +21,10 @@ use crate::folding::circuits::cyclefold::{ fold_cyclefold_circuit, CycleFoldCircuit, CycleFoldCommittedInstance, CycleFoldConfig, CycleFoldWitness, }; -use crate::folding::{ - circuits::{CF1, CF2}, - traits::Dummy, -}; +use crate::folding::{circuits::CF1, traits::Dummy}; use crate::frontend::FCircuit; -use crate::transcript::{poseidon::poseidon_canonical_config, AbsorbNonNative, Transcript}; +use crate::transcript::{poseidon::poseidon_canonical_config, Transcript}; use crate::utils::vec::is_zero_vec; -use crate::Error; use crate::FoldingScheme; use crate::{ arith::r1cs::{extract_r1cs, extract_w_x, R1CS}, @@ -37,6 +32,7 @@ use crate::{ utils::pp_hash, }; use crate::{arith::Arith, commitment::CommitmentScheme}; +use crate::{Curve, Error}; use decider_eth_circuit::WitnessVar; pub mod circuits; @@ -59,11 +55,11 @@ pub mod decider_eth_circuit; use super::traits::{CommittedInstanceOps, Inputize, WitnessOps}; /// Configuration for Nova's CycleFold circuit -pub struct NovaCycleFoldConfig { +pub struct NovaCycleFoldConfig { _c: PhantomData, } -impl CycleFoldConfig for NovaCycleFoldConfig { +impl CycleFoldConfig for NovaCycleFoldConfig { const RANDOMNESS_BIT_LENGTH: usize = NOVA_N_BITS_RO; // Number of points to be folded in the CycleFold circuit, in Nova's case, this is a fixed // amount: @@ -74,17 +70,17 @@ impl CycleFoldConfig for NovaCycleFoldConfig { /// CycleFold circuit for computing random linear combinations of group elements /// in Nova instances. -pub type NovaCycleFoldCircuit = CycleFoldCircuit, GC>; +pub type NovaCycleFoldCircuit = CycleFoldCircuit>; #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct CommittedInstance { +pub struct CommittedInstance { pub cmE: C, pub u: C::ScalarField, pub cmW: C, pub x: Vec, } -impl Dummy for CommittedInstance { +impl Dummy for CommittedInstance { fn dummy(io_len: usize) -> Self { Self { cmE: C::zero(), @@ -95,16 +91,13 @@ impl Dummy for CommittedInstance { } } -impl Dummy<&R1CS>> for CommittedInstance { +impl Dummy<&R1CS>> for CommittedInstance { fn dummy(r1cs: &R1CS>) -> Self { Self::dummy(r1cs.l) } } -impl Absorb for CommittedInstance -where - C::ScalarField: Absorb, -{ +impl Absorb for CommittedInstance { fn to_sponge_bytes(&self, dest: &mut Vec) { C::ScalarField::batch_to_sponge_bytes(&self.to_sponge_field_elements_as_vec(), dest); } @@ -112,19 +105,12 @@ where fn to_sponge_field_elements(&self, dest: &mut Vec) { self.u.to_sponge_field_elements(dest); self.x.to_sponge_field_elements(dest); - // We cannot call `to_native_sponge_field_elements(dest)` directly, as - // `to_native_sponge_field_elements` needs `F` to be `C::ScalarField`, - // but here `F` is a generic `PrimeField`. - self.cmE - .to_native_sponge_field_elements_as_vec() - .to_sponge_field_elements(dest); - self.cmW - .to_native_sponge_field_elements_as_vec() - .to_sponge_field_elements(dest); + self.cmE.to_native_sponge_field_elements(dest); + self.cmW.to_native_sponge_field_elements(dest); } } -impl CommittedInstanceOps for CommittedInstance { +impl CommittedInstanceOps for CommittedInstance { type Var = CommittedInstanceVar; fn get_commitments(&self) -> Vec { @@ -136,27 +122,29 @@ impl CommittedInstanceOps for CommittedInstance { } } -impl Inputize> for CommittedInstance { - fn inputize(&self) -> Vec { +impl Inputize> for CommittedInstance { + /// Returns the internal representation in the same order as how the value + /// is allocated in `CommittedInstanceVar::new_input`. + fn inputize(&self) -> Vec> { [ &[self.u][..], &self.x, - &self.cmE.inputize(), - &self.cmW.inputize(), + &self.cmE.inputize_nonnative(), + &self.cmW.inputize_nonnative(), ] .concat() } } #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct Witness { +pub struct Witness { pub E: Vec, pub rE: C::ScalarField, pub W: Vec, pub rW: C::ScalarField, } -impl Witness { +impl Witness { pub fn new(w: Vec, e_len: usize, mut rng: impl RngCore) -> Self { let (rW, rE) = if H { ( @@ -194,7 +182,7 @@ impl Witness { } } -impl Dummy<&R1CS>> for Witness { +impl Dummy<&R1CS>> for Witness { fn dummy(r1cs: &R1CS>) -> Self { Self { E: vec![C::ScalarField::zero(); r1cs.A.n_rows], @@ -205,7 +193,7 @@ impl Dummy<&R1CS>> for Witness { } } -impl WitnessOps for Witness { +impl WitnessOps for Witness { type Var = WitnessVar; fn get_openings(&self) -> Vec<(&[C::ScalarField], C::ScalarField)> { @@ -216,8 +204,8 @@ impl WitnessOps for Witness { #[derive(Debug, Clone)] pub struct PreprocessorParam where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, @@ -233,8 +221,8 @@ where impl PreprocessorParam where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, @@ -255,8 +243,8 @@ where #[derive(Debug, Clone)] pub struct ProverParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -270,8 +258,8 @@ where impl Valid for ProverParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -290,8 +278,8 @@ where } impl CanonicalSerialize for ProverParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -310,8 +298,8 @@ where } impl CanonicalDeserialize for ProverParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -334,8 +322,8 @@ where #[derive(Debug, Clone)] pub struct VerifierParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -353,8 +341,8 @@ where impl Valid for VerifierParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -366,8 +354,8 @@ where } impl CanonicalSerialize for VerifierParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -387,8 +375,8 @@ where impl VerifierParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -407,8 +395,8 @@ where #[derive(PartialEq, Eq, Debug, Clone, CanonicalSerialize, CanonicalDeserialize)] pub struct IVCProof where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, { // current step of the IVC pub i: C1::ScalarField, @@ -431,19 +419,14 @@ where /// [CycleFold](https://eprint.iacr.org/2023/1192.pdf), following the FoldingScheme trait /// The `H` const generic specifies whether the homorphic commitment scheme is blinding #[derive(Clone, Debug)] -pub struct Nova +pub struct Nova where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, { - _gc1: PhantomData, - _c2: PhantomData, - _gc2: PhantomData, /// R1CS of the Augmented Function circuit pub r1cs: R1CS, /// R1CS of the CycleFold circuit @@ -473,21 +456,15 @@ where pub cf_U_i: CycleFoldCommittedInstance, } -impl FoldingScheme - for Nova +impl FoldingScheme + for Nova where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, + C1: Curve, { type PreprocessorParam = PreprocessorParam; type ProverParam = ProverParams; @@ -523,7 +500,7 @@ where let f_circuit = FC::new(fc_params)?; let cs = ConstraintSystem::::new_ref(); let augmented_F_circuit = - AugmentedFCircuit::::empty(&poseidon_config, f_circuit.clone()); + AugmentedFCircuit::::empty(&poseidon_config, f_circuit.clone()); augmented_F_circuit.generate_constraints(cs.clone())?; cs.finalize(); let cs = cs.into_inner().ok_or(Error::NoInnerConstraintSystem)?; @@ -531,7 +508,7 @@ where // CycleFold circuit R1CS let cs2 = ConstraintSystem::::new_ref(); - let cf_circuit = NovaCycleFoldCircuit::::empty(); + let cf_circuit = NovaCycleFoldCircuit::::empty(); cf_circuit.generate_constraints(cs2.clone())?; cs2.finalize(); let cs2 = cs2.into_inner().ok_or(Error::NoInnerConstraintSystem)?; @@ -554,7 +531,7 @@ where prep_param: &Self::PreprocessorParam, ) -> Result<(Self::ProverParam, Self::VerifierParam), Error> { let (r1cs, cf_r1cs) = - get_r1cs::(&prep_param.poseidon_config, prep_param.F.clone())?; + get_r1cs::(&prep_param.poseidon_config, prep_param.F.clone())?; // if cs params exist, use them, if not, generate new ones let (cs_pp, cs_vp) = match (&prep_param.cs_pp, &prep_param.cs_vp) { @@ -595,8 +572,8 @@ where let cs2 = ConstraintSystem::::new_ref(); let augmented_F_circuit = - AugmentedFCircuit::::empty(&pp.poseidon_config, F.clone()); - let cf_circuit = NovaCycleFoldCircuit::::empty(); + AugmentedFCircuit::::empty(&pp.poseidon_config, F.clone()); + let cf_circuit = NovaCycleFoldCircuit::::empty(); augmented_F_circuit.generate_constraints(cs.clone())?; cs.finalize(); @@ -619,9 +596,6 @@ where // W_dummy=W_0 is a 'dummy witness', all zeroes, but with the size corresponding to the // R1CS that we're working with. Ok(Self { - _gc1: PhantomData, - _c2: PhantomData, - _gc2: PhantomData, r1cs, cf_r1cs, poseidon_config: pp.poseidon_config.clone(), @@ -670,7 +644,7 @@ where // `transcript` is for challenge generation. let mut transcript = sponge.clone(); - let augmented_F_circuit: AugmentedFCircuit; + let augmented_F_circuit: AugmentedFCircuit; // Nova does not support (by design) multi-instances folding if _other_instances.is_some() { @@ -729,8 +703,7 @@ where if self.i == C1::ScalarField::zero() { // base case - augmented_F_circuit = AugmentedFCircuit:: { - _gc2: PhantomData, + augmented_F_circuit = AugmentedFCircuit:: { poseidon_config: self.poseidon_config.clone(), pp_hash: Some(self.pp_hash), i: Some(C1::ScalarField::zero()), // = i=0 @@ -763,19 +736,17 @@ where } } else { // CycleFold part: - let cfW_circuit = NovaCycleFoldCircuit:: { - _gc: PhantomData, + let cfW_circuit = NovaCycleFoldCircuit:: { r_bits: Some(r_bits.clone()), points: Some(vec![self.U_i.clone().cmW, self.u_i.clone().cmW]), }; - let cfE_circuit = NovaCycleFoldCircuit:: { - _gc: PhantomData, + let cfE_circuit = NovaCycleFoldCircuit:: { r_bits: Some(r_bits.clone()), points: Some(vec![self.U_i.clone().cmE, cmT]), }; // fold self.cf_U_i + cfW_U -> folded running with cfW - let (_cfW_w_i, cfW_u_i, cfW_W_i1, cfW_U_i1, cfW_cmT, _) = self.fold_cyclefold_circuit( + let (cfW_u_i, cfW_W_i1, cfW_U_i1, cfW_cmT) = self.fold_cyclefold_circuit( &mut transcript, self.cf_W_i.clone(), // CycleFold running instance witness self.cf_U_i.clone(), // CycleFold running instance @@ -783,7 +754,7 @@ where &mut rng, )?; // fold [the output from folding self.cf_U_i + cfW_U] + cfE_U = folded_running_with_cfW + cfE - let (_cfE_w_i, cfE_u_i, cf_W_i1, cf_U_i1, cf_cmT, _) = self.fold_cyclefold_circuit( + let (cfE_u_i, cf_W_i1, cf_U_i1, cf_cmT) = self.fold_cyclefold_circuit( &mut transcript, cfW_W_i1, cfW_U_i1.clone(), @@ -791,8 +762,7 @@ where &mut rng, )?; - augmented_F_circuit = AugmentedFCircuit:: { - _gc2: PhantomData, + augmented_F_circuit = AugmentedFCircuit:: { poseidon_config: self.poseidon_config.clone(), pp_hash: Some(self.pp_hash), i: Some(self.i), @@ -816,15 +786,6 @@ where self.cf_W_i = cf_W_i1; self.cf_U_i = cf_U_i1; - - #[cfg(test)] - { - cfW_u_i.check_incoming()?; - cfE_u_i.check_incoming()?; - self.cf_r1cs.check_relation(&_cfW_w_i, &cfW_u_i)?; - self.cf_r1cs.check_relation(&_cfE_w_i, &cfE_u_i)?; - self.cf_r1cs.check_relation(&self.cf_W_i, &self.cf_U_i)?; - } } let cs = ConstraintSystem::::new_ref(); @@ -902,8 +863,8 @@ where let cs = ConstraintSystem::::new_ref(); let cs2 = ConstraintSystem::::new_ref(); let augmented_F_circuit = - AugmentedFCircuit::::empty(&pp.poseidon_config, f_circuit.clone()); - let cf_circuit = NovaCycleFoldCircuit::::empty(); + AugmentedFCircuit::::empty(&pp.poseidon_config, f_circuit.clone()); + let cf_circuit = NovaCycleFoldCircuit::::empty(); augmented_F_circuit.generate_constraints(cs.clone())?; cs.finalize(); @@ -916,9 +877,6 @@ where let cf_r1cs = extract_r1cs::(&cs2)?; Ok(Self { - _gc1: PhantomData, - _c2: PhantomData, - _gc2: PhantomData, r1cs, cf_r1cs, poseidon_config: pp.poseidon_config, @@ -994,20 +952,14 @@ where } } -impl Nova +impl Nova where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, + C1: Curve, { // folds the given cyclefold circuit and its instances #[allow(clippy::type_complexity)] @@ -1016,20 +968,18 @@ where transcript: &mut T, cf_W_i: CycleFoldWitness, // witness of the running instance cf_U_i: CycleFoldCommittedInstance, // running instance - cf_circuit: NovaCycleFoldCircuit, + cf_circuit: NovaCycleFoldCircuit, rng: &mut impl RngCore, ) -> Result< ( - CycleFoldWitness, CycleFoldCommittedInstance, // u_i CycleFoldWitness, // W_i1 CycleFoldCommittedInstance, // U_i1 C2, // cmT - C2::ScalarField, // r_Fq ), Error, > { - fold_cyclefold_circuit::, C1, GC1, C2, GC2, CS2, H>( + fold_cyclefold_circuit::, C2, CS2, H>( transcript, self.cf_r1cs.clone(), self.cf_cs_pp.clone(), @@ -1056,25 +1006,18 @@ pub fn get_r1cs_from_cs( /// helper method to get the R1CS for both the AugmentedFCircuit and the CycleFold circuit #[allow(clippy::type_complexity)] -pub fn get_r1cs( +pub fn get_r1cs( poseidon_config: &PoseidonConfig, F_circuit: FC, ) -> Result<(R1CS, R1CS), Error> where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, + C1: Curve, { - let augmented_F_circuit = - AugmentedFCircuit::::empty(poseidon_config, F_circuit); - let cf_circuit = NovaCycleFoldCircuit::::empty(); + let augmented_F_circuit = AugmentedFCircuit::::empty(poseidon_config, F_circuit); + let cf_circuit = NovaCycleFoldCircuit::::empty(); let r1cs = get_r1cs_from_cs::(augmented_F_circuit)?; let cf_r1cs = get_r1cs_from_cs::(cf_circuit)?; Ok((r1cs, cf_r1cs)) @@ -1082,31 +1025,25 @@ where /// helper method to get the pedersen params length for both the AugmentedFCircuit and the /// CycleFold circuit -pub fn get_cs_params_len( +pub fn get_cs_params_len( poseidon_config: &PoseidonConfig, F_circuit: FC, ) -> Result<(usize, usize), Error> where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, + C1: Curve, { - let (r1cs, cf_r1cs) = get_r1cs::(poseidon_config, F_circuit)?; + let (r1cs, cf_r1cs) = get_r1cs::(poseidon_config, F_circuit)?; Ok((r1cs.A.n_rows, cf_r1cs.A.n_rows)) } #[cfg(test)] pub mod tests { use crate::commitment::kzg::KZG; - use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_bn254::{Bn254, Fr, G1Projective as Projective}; + use ark_grumpkin::Projective as Projective2; use super::*; use crate::commitment::pedersen::Pedersen; @@ -1157,7 +1094,7 @@ pub mod tests { ) -> Result< ( Vec, - Nova, CS1, CS2, H>, + Nova, CS1, CS2, H>, ), Error, > { @@ -1172,24 +1109,18 @@ pub mod tests { cf_cs_pp: None, cf_cs_vp: None, }; - let nova_params = Nova::< - Projective, - GVar, - Projective2, - GVar2, - CubicFCircuit, - CS1, - CS2, - H, - >::preprocess(&mut rng, &prep_param)?; + let nova_params = + Nova::, CS1, CS2, H>::preprocess( + &mut rng, + &prep_param, + )?; let z_0 = vec![Fr::from(3_u32)]; - let mut nova = - Nova::, CS1, CS2, H>::init( - &nova_params, - F_circuit, - z_0.clone(), - )?; + let mut nova = Nova::, CS1, CS2, H>::init( + &nova_params, + F_circuit, + z_0.clone(), + )?; for _ in 0..num_steps { nova.prove_step(&mut rng, vec![], None)?; @@ -1213,9 +1144,7 @@ pub mod tests { )?; let nova_vp_deserialized = Nova::< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, CS1, CS2, @@ -1235,22 +1164,15 @@ pub mod tests { .serialize_compressed(&mut ivc_proof_serialized) .is_ok()); // deserialize IVCProof - let ivc_proof_deserialized = , - CS1, - CS2, - H, - > as FoldingScheme>>::IVCProof::deserialize_compressed( - ivc_proof_serialized.as_slice() - ) - ?; + let ivc_proof_deserialized = + , CS1, CS2, H> as FoldingScheme< + Projective, + Projective2, + CubicFCircuit, + >>::IVCProof::deserialize_compressed(ivc_proof_serialized.as_slice())?; // verify the deserialized IVCProof with the deserialized VerifierParams - Nova::, CS1, CS2, H>::verify( + Nova::, CS1, CS2, H>::verify( nova_vp_deserialized, // Nova's verifier params ivc_proof_deserialized, )?; diff --git a/folding-schemes/src/folding/nova/nifs/mod.rs b/folding-schemes/src/folding/nova/nifs/mod.rs index 1f890acf..9b9fe3b1 100644 --- a/folding-schemes/src/folding/nova/nifs/mod.rs +++ b/folding-schemes/src/folding/nova/nifs/mod.rs @@ -7,7 +7,6 @@ /// - [Ova](https://hackmd.io/V4838nnlRKal9ZiTHiGYzw) /// - [Mova](https://eprint.iacr.org/2024/1220.pdf) use ark_crypto_primitives::sponge::{constraints::AbsorbGadget, Absorb, CryptographicSponge}; -use ark_ec::CurveGroup; use ark_r1cs_std::{alloc::AllocVar, boolean::Boolean, fields::fp::FpVar}; use ark_relations::r1cs::SynthesisError; use ark_std::fmt::Debug; @@ -18,7 +17,7 @@ use crate::commitment::CommitmentScheme; use crate::folding::circuits::CF1; use crate::folding::traits::{CommittedInstanceOps, CommittedInstanceVarOps}; use crate::transcript::{Transcript, TranscriptVar}; -use crate::Error; +use crate::{Curve, Error}; pub mod mova; pub mod nova; @@ -33,7 +32,7 @@ pub mod pointvsline; /// [Mova](https://eprint.iacr.org/2024/1220.pdf). /// `H` specifies whether the NIFS will use a blinding factor. pub trait NIFSTrait< - C: CurveGroup, + C: Curve, CS: CommitmentScheme, T: Transcript, const H: bool = false, @@ -99,7 +98,7 @@ pub trait NIFSTrait< /// logic of the NIFS.Verify defined in [Nova](https://eprint.iacr.org/2021/370.pdf) and it's /// variants [Ova](https://hackmd.io/V4838nnlRKal9ZiTHiGYzw) and /// [Mova](https://eprint.iacr.org/2024/1220.pdf). -pub trait NIFSGadgetTrait, S>> { +pub trait NIFSGadgetTrait, S>> { type CommittedInstance: Debug + Clone + Absorb + CommittedInstanceOps; type CommittedInstanceVar: Debug + Clone diff --git a/folding-schemes/src/folding/nova/nifs/mova.rs b/folding-schemes/src/folding/nova/nifs/mova.rs index 2372bd8e..da3bdf7a 100644 --- a/folding-schemes/src/folding/nova/nifs/mova.rs +++ b/folding-schemes/src/folding/nova/nifs/mova.rs @@ -1,7 +1,6 @@ /// This module contains the implementation the NIFSTrait for the /// [Mova](https://eprint.iacr.org/2024/1220.pdf) NIFS (Non-Interactive Folding Scheme). use ark_crypto_primitives::sponge::Absorb; -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_poly::Polynomial; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -19,16 +18,15 @@ use crate::arith::{r1cs::R1CS, Arith}; use crate::commitment::CommitmentScheme; use crate::folding::circuits::CF1; use crate::folding::traits::Dummy; -use crate::transcript::AbsorbNonNative; use crate::transcript::Transcript; use crate::utils::{ mle::dense_vec_to_dense_mle, vec::{is_zero_vec, vec_add, vec_scalar_mul}, }; -use crate::Error; +use crate::{Curve, Error}; #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct CommittedInstance { +pub struct CommittedInstance { // Random evaluation point for the E pub rE: Vec, // mleE is the evaluation of the MLE of E at r_E @@ -38,10 +36,7 @@ pub struct CommittedInstance { pub x: Vec, } -impl Absorb for CommittedInstance -where - C::ScalarField: Absorb, -{ +impl Absorb for CommittedInstance { fn to_sponge_bytes(&self, _dest: &mut Vec) { // This is never called unimplemented!() @@ -52,16 +47,11 @@ where self.x.to_sponge_field_elements(dest); self.rE.to_sponge_field_elements(dest); self.mleE.to_sponge_field_elements(dest); - // We cannot call `to_native_sponge_field_elements(dest)` directly, as - // `to_native_sponge_field_elements` needs `F` to be `C::ScalarField`, - // but here `F` is a generic `PrimeField`. - self.cmW - .to_native_sponge_field_elements_as_vec() - .to_sponge_field_elements(dest); + self.cmW.to_native_sponge_field_elements(dest); } } -impl Dummy for CommittedInstance { +impl Dummy for CommittedInstance { fn dummy(io_len: usize) -> Self { Self { rE: vec![C::ScalarField::zero(); io_len], @@ -74,13 +64,13 @@ impl Dummy for CommittedInstance { } #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct Witness { +pub struct Witness { pub E: Vec, pub W: Vec, pub rW: C::ScalarField, } -impl Dummy<&R1CS> for Witness { +impl Dummy<&R1CS> for Witness { fn dummy(r1cs: &R1CS) -> Self { Self { E: vec![C::ScalarField::zero(); r1cs.A.n_rows], @@ -90,7 +80,7 @@ impl Dummy<&R1CS> for Witness { } } -impl Witness { +impl Witness { pub fn new(w: Vec, e_len: usize, mut rng: impl RngCore) -> Self { let rW = if H { C::ScalarField::rand(&mut rng) @@ -128,7 +118,7 @@ impl Witness { } #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct Proof { +pub struct Proof { pub h_proof: PointVsLineProof, pub mleE1_prime: C::ScalarField, pub mleE2_prime: C::ScalarField, @@ -139,7 +129,7 @@ pub struct Proof { /// [Mova](https://eprint.iacr.org/2024/1220.pdf). /// `H` specifies whether the NIFS will use a blinding factor pub struct NIFS< - C: CurveGroup, + C: Curve, CS: CommitmentScheme, T: Transcript, const H: bool = false, @@ -149,11 +139,8 @@ pub struct NIFS< _ct: PhantomData, } -impl, T: Transcript, const H: bool> +impl, T: Transcript, const H: bool> NIFSTrait for NIFS -where - C::ScalarField: Absorb, - ::BaseField: PrimeField, { type CommittedInstance = CommittedInstance; type Witness = Witness; @@ -333,7 +320,7 @@ where } } -impl, T: Transcript, const H: bool> +impl, T: Transcript, const H: bool> NIFS { // Protocol 7 - point 3 (15) @@ -367,7 +354,7 @@ impl, T: Transcript, c } } -impl Arith, CommittedInstance> for R1CS> { +impl Arith, CommittedInstance> for R1CS> { type Evaluation = Vec>; fn eval_relation( diff --git a/folding-schemes/src/folding/nova/nifs/nova.rs b/folding-schemes/src/folding/nova/nifs/nova.rs index 5c10ae54..da5c13bf 100644 --- a/folding-schemes/src/folding/nova/nifs/nova.rs +++ b/folding-schemes/src/folding/nova/nifs/nova.rs @@ -1,7 +1,6 @@ /// This module contains the implementation the NIFSTrait for the /// [Nova](https://eprint.iacr.org/2021/370.pdf) NIFS (Non-Interactive Folding Scheme). use ark_crypto_primitives::sponge::{constraints::AbsorbGadget, Absorb, CryptographicSponge}; -use ark_ec::CurveGroup; use ark_ff::{BigInteger, PrimeField}; use ark_r1cs_std::{boolean::Boolean, fields::fp::FpVar}; use ark_relations::r1cs::SynthesisError; @@ -21,20 +20,15 @@ use crate::folding::circuits::{ use crate::folding::nova::{CommittedInstance, Witness}; use crate::transcript::{Transcript, TranscriptVar}; use crate::utils::vec::{hadamard, mat_vec_mul, vec_add, vec_scalar_mul, vec_sub}; -use crate::Error; +use crate::{Curve, Error}; /// ChallengeGadget computes the RO challenge used for the Nova instances NIFS, it contains a /// rust-native and a in-circuit compatible versions. -pub struct ChallengeGadget { +pub struct ChallengeGadget { _c: PhantomData, _ci: PhantomData, } -impl ChallengeGadget -where - C: CurveGroup, - // ::BaseField: PrimeField, - C::ScalarField: Absorb, -{ +impl ChallengeGadget { pub fn get_challenge_native>( transcript: &mut T, pp_hash: C::ScalarField, // public params hash @@ -79,7 +73,7 @@ where /// [Nova](https://eprint.iacr.org/2021/370.pdf). /// `H` specifies whether the NIFS will use a blinding factor pub struct NIFS< - C: CurveGroup, + C: Curve, CS: CommitmentScheme, T: Transcript, const H: bool = false, @@ -89,10 +83,8 @@ pub struct NIFS< _t: PhantomData, } -impl, T: Transcript, const H: bool> +impl, T: Transcript, const H: bool> NIFSTrait for NIFS -where - C::ScalarField: Absorb, { type CommittedInstance = CommittedInstance; type Witness = Witness; @@ -202,10 +194,8 @@ where } } -impl, T: Transcript, const H: bool> +impl, T: Transcript, const H: bool> NIFS -where - C::ScalarField: Absorb, { /// compute_T: compute cross-terms T. We use the approach described in /// [Mova](https://eprint.iacr.org/2024/1220.pdf)'s section 5.2. @@ -238,10 +228,7 @@ where ci1: &CycleFoldCommittedInstance, w2: &CycleFoldWitness, ci2: &CycleFoldCommittedInstance, - ) -> Result<(Vec, C), Error> - where - ::BaseField: ark_ff::PrimeField, - { + ) -> Result<(Vec, C), Error> { let z1: Vec = [vec![ci1.u], ci1.x.to_vec(), w1.W.to_vec()].concat(); let z2: Vec = [vec![ci2.u], ci2.x.to_vec(), w2.W.to_vec()].concat(); diff --git a/folding-schemes/src/folding/nova/nifs/nova_circuits.rs b/folding-schemes/src/folding/nova/nifs/nova_circuits.rs index a4757648..2487c165 100644 --- a/folding-schemes/src/folding/nova/nifs/nova_circuits.rs +++ b/folding-schemes/src/folding/nova/nifs/nova_circuits.rs @@ -1,10 +1,8 @@ /// contains [Nova](https://eprint.iacr.org/2021/370.pdf) NIFS related circuits -use ark_crypto_primitives::sponge::{constraints::AbsorbGadget, Absorb, CryptographicSponge}; -use ark_ec::CurveGroup; +use ark_crypto_primitives::sponge::{constraints::AbsorbGadget, CryptographicSponge}; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, boolean::Boolean, - convert::ToConstraintFieldGadget, eq::EqGadget, fields::{fp::FpVar, FieldVar}, uint8::UInt8, @@ -14,13 +12,16 @@ use ark_std::{fmt::Debug, Zero}; use core::{borrow::Borrow, marker::PhantomData}; use super::NIFSGadgetTrait; -use crate::folding::circuits::{ - nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar}, - CF1, CF2, -}; -use crate::folding::nova::CommittedInstance; use crate::folding::traits::CommittedInstanceVarOps; use crate::transcript::TranscriptVar; +use crate::{ + folding::circuits::{ + nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar}, + CF1, CF2, + }, + Curve, +}; +use crate::{folding::nova::CommittedInstance, transcript::AbsorbNonNativeGadget}; use super::nova::ChallengeGadget; @@ -28,17 +29,14 @@ use super::nova::ChallengeGadget; /// constraints field (E1::Fr, where E1 is the main curve). The peculiarity is that cmE and cmW are /// represented non-natively over the constraint field. #[derive(Debug, Clone)] -pub struct CommittedInstanceVar { +pub struct CommittedInstanceVar { pub u: FpVar, pub x: Vec>, pub cmE: NonNativeAffineVar, pub cmW: NonNativeAffineVar, } -impl AllocVar, CF1> for CommittedInstanceVar -where - C: CurveGroup, -{ +impl AllocVar, CF1> for CommittedInstanceVar { fn new_variable>>( cs: impl Into>>, f: impl FnOnce() -> Result, @@ -61,10 +59,7 @@ where } } -impl AbsorbGadget for CommittedInstanceVar -where - C: CurveGroup, -{ +impl AbsorbGadget for CommittedInstanceVar { fn to_sponge_bytes(&self) -> Result>, SynthesisError> { FpVar::batch_to_sponge_bytes(&self.to_sponge_field_elements()?) } @@ -73,14 +68,14 @@ where Ok([ vec![self.u.clone()], self.x.clone(), - self.cmE.to_constraint_field()?, - self.cmW.to_constraint_field()?, + self.cmE.to_native_sponge_field_elements()?, + self.cmW.to_native_sponge_field_elements()?, ] .concat()) } } -impl CommittedInstanceVarOps for CommittedInstanceVar { +impl CommittedInstanceVarOps for CommittedInstanceVar { type PointVar = NonNativeAffineVar; fn get_commitments(&self) -> Vec { @@ -107,7 +102,7 @@ impl CommittedInstanceVarOps for CommittedInstanceVar { /// Implements the circuit that does the checks of the Non-Interactive Folding Scheme Verifier /// described in section 4 of [Nova](https://eprint.iacr.org/2021/370.pdf), where the cmE & cmW checks are /// delegated to the NIFSCycleFoldGadget. -pub struct NIFSGadget, S>> { +pub struct NIFSGadget, S>> { _c: PhantomData, _s: PhantomData, _t: PhantomData, @@ -115,10 +110,9 @@ pub struct NIFSGadget NIFSGadgetTrait for NIFSGadget where - C: CurveGroup, + C: Curve, S: CryptographicSponge, T: TranscriptVar, S>, - C::ScalarField: Absorb, { type CommittedInstance = CommittedInstance; type CommittedInstanceVar = CommittedInstanceVar; diff --git a/folding-schemes/src/folding/nova/nifs/ova.rs b/folding-schemes/src/folding/nova/nifs/ova.rs index a0750d05..7e6757b8 100644 --- a/folding-schemes/src/folding/nova/nifs/ova.rs +++ b/folding-schemes/src/folding/nova/nifs/ova.rs @@ -1,7 +1,6 @@ /// This module contains the implementation the NIFSTrait for the /// [Ova](https://hackmd.io/V4838nnlRKal9ZiTHiGYzw) NIFS (Non-Interactive Folding Scheme). use ark_crypto_primitives::sponge::Absorb; -use ark_ec::CurveGroup; use ark_ff::{BigInteger, PrimeField}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_std::fmt::Debug; @@ -16,9 +15,9 @@ use crate::arith::r1cs::R1CS; use crate::commitment::CommitmentScheme; use crate::folding::traits::{CommittedInstanceOps, Inputize}; use crate::folding::{circuits::CF1, traits::Dummy}; -use crate::transcript::{AbsorbNonNative, Transcript}; +use crate::transcript::Transcript; use crate::utils::vec::{hadamard, mat_vec_mul, vec_scalar_mul, vec_sub}; -use crate::Error; +use crate::{Curve, Error}; /// A CommittedInstance in [Ova](https://hackmd.io/V4838nnlRKal9ZiTHiGYzw) is represented by `W` or /// `W'`. It is the result of the commitment to a vector that contains the witness `w` concatenated @@ -26,16 +25,13 @@ use crate::Error; /// document `u` is denoted as `mu`, in this implementation we use `u` so it follows the original /// Nova notation, so code is easier to follow). #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct CommittedInstance { +pub struct CommittedInstance { pub u: C::ScalarField, // in the Ova document is denoted as `mu` pub x: Vec, pub cmWE: C, } -impl Absorb for CommittedInstance -where - C::ScalarField: Absorb, -{ +impl Absorb for CommittedInstance { fn to_sponge_bytes(&self, dest: &mut Vec) { C::ScalarField::batch_to_sponge_bytes(&self.to_sponge_field_elements_as_vec(), dest); } @@ -43,16 +39,11 @@ where fn to_sponge_field_elements(&self, dest: &mut Vec) { self.u.to_sponge_field_elements(dest); self.x.to_sponge_field_elements(dest); - // We cannot call `to_native_sponge_field_elements(dest)` directly, as - // `to_native_sponge_field_elements` needs `F` to be `C::ScalarField`, - // but here `F` is a generic `PrimeField`. - self.cmWE - .to_native_sponge_field_elements_as_vec() - .to_sponge_field_elements(dest); + self.cmWE.to_native_sponge_field_elements(dest); } } -impl CommittedInstanceOps for CommittedInstance { +impl CommittedInstanceOps for CommittedInstance { type Var = CommittedInstanceVar; fn get_commitments(&self) -> Vec { @@ -64,21 +55,23 @@ impl CommittedInstanceOps for CommittedInstance { } } -impl Inputize> for CommittedInstance { - fn inputize(&self) -> Vec { - [&[self.u][..], &self.x, &self.cmWE.inputize()].concat() +impl Inputize> for CommittedInstance { + /// Returns the internal representation in the same order as how the value + /// is allocated in `CommittedInstanceVar::new_input`. + fn inputize(&self) -> Vec> { + [&[self.u][..], &self.x, &self.cmWE.inputize_nonnative()].concat() } } /// A Witness in Ova is represented by `w`. It also contains a blinder which can or not be used /// when committing to the witness itself. #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct Witness { +pub struct Witness { pub w: Vec, pub rW: C::ScalarField, } -impl Witness { +impl Witness { /// Generates a new `Witness` instance from a given witness vector. /// If `H = true`, then we assume we want to blind it at commitment time, /// hence sampling `rW` from the randomness passed. @@ -111,7 +104,7 @@ impl Witness { } } -impl Dummy<&R1CS>> for Witness { +impl Dummy<&R1CS>> for Witness { fn dummy(r1cs: &R1CS>) -> Self { Self { w: vec![C::ScalarField::zero(); r1cs.A.n_cols - 1 - r1cs.l], @@ -122,7 +115,7 @@ impl Dummy<&R1CS>> for Witness { /// Implements the NIFS (Non-Interactive Folding Scheme) trait for Ova. pub struct NIFS< - C: CurveGroup, + C: Curve, CS: CommitmentScheme, T: Transcript, const H: bool = false, @@ -132,11 +125,8 @@ pub struct NIFS< _t: PhantomData, } -impl, T: Transcript, const H: bool> +impl, T: Transcript, const H: bool> NIFSTrait for NIFS -where - C::ScalarField: Absorb, - ::BaseField: PrimeField, { type CommittedInstance = CommittedInstance; type Witness = Witness; @@ -241,7 +231,7 @@ where /// Computes the E parameter (error terms) for the given R1CS and the instance's z and u. This /// method is used by the verifier to obtain E in order to check the RelaxedR1CS relation. -pub fn compute_E( +pub fn compute_E( r1cs: &R1CS, z: &[C::ScalarField], u: C::ScalarField, @@ -275,11 +265,11 @@ pub mod tests { // But since we don't hold `E` nor `e` within the NIFS, we create this structure to pass // `e` such that the check can be done. #[derive(Debug, Clone)] - pub(crate) struct TestingWitness { + pub(crate) struct TestingWitness { pub(crate) w: Vec, pub(crate) e: Vec, } - impl Arith, CommittedInstance> for R1CS> { + impl Arith, CommittedInstance> for R1CS> { type Evaluation = Vec>; fn eval_relation( diff --git a/folding-schemes/src/folding/nova/nifs/ova_circuits.rs b/folding-schemes/src/folding/nova/nifs/ova_circuits.rs index 64f72d49..75c3eff7 100644 --- a/folding-schemes/src/folding/nova/nifs/ova_circuits.rs +++ b/folding-schemes/src/folding/nova/nifs/ova_circuits.rs @@ -1,11 +1,8 @@ /// contains [Ova](https://hackmd.io/V4838nnlRKal9ZiTHiGYzw) NIFS related circuits -use ark_crypto_primitives::sponge::{constraints::AbsorbGadget, Absorb, CryptographicSponge}; -use ark_ec::CurveGroup; -use ark_ff::PrimeField; +use ark_crypto_primitives::sponge::{constraints::AbsorbGadget, CryptographicSponge}; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, boolean::Boolean, - convert::ToConstraintFieldGadget, eq::EqGadget, fields::{fp::FpVar, FieldVar}, uint8::UInt8, @@ -16,23 +13,24 @@ use core::{borrow::Borrow, marker::PhantomData}; use super::ova::CommittedInstance; use super::NIFSGadgetTrait; -use crate::folding::circuits::{nonnative::affine::NonNativeAffineVar, CF1}; use crate::folding::traits::CommittedInstanceVarOps; use crate::transcript::TranscriptVar; +use crate::{ + folding::circuits::{nonnative::affine::NonNativeAffineVar, CF1}, + transcript::AbsorbNonNativeGadget, +}; use crate::folding::nova::nifs::nova::ChallengeGadget; +use crate::Curve; #[derive(Debug, Clone)] -pub struct CommittedInstanceVar { +pub struct CommittedInstanceVar { pub u: FpVar, pub x: Vec>, pub cmWE: NonNativeAffineVar, } -impl AllocVar, CF1> for CommittedInstanceVar -where - C: CurveGroup, -{ +impl AllocVar, CF1> for CommittedInstanceVar { fn new_variable>>( cs: impl Into>>, f: impl FnOnce() -> Result, @@ -53,11 +51,7 @@ where } } -impl AbsorbGadget for CommittedInstanceVar -where - C: CurveGroup, - ::BaseField: ark_ff::PrimeField, -{ +impl AbsorbGadget for CommittedInstanceVar { fn to_sponge_bytes(&self) -> Result>, SynthesisError> { FpVar::batch_to_sponge_bytes(&self.to_sponge_field_elements()?) } @@ -66,13 +60,13 @@ where Ok([ vec![self.u.clone()], self.x.clone(), - self.cmWE.to_constraint_field()?, + self.cmWE.to_native_sponge_field_elements()?, ] .concat()) } } -impl CommittedInstanceVarOps for CommittedInstanceVar { +impl CommittedInstanceVarOps for CommittedInstanceVar { type PointVar = NonNativeAffineVar; fn get_commitments(&self) -> Vec { @@ -95,7 +89,7 @@ impl CommittedInstanceVarOps for CommittedInstanceVar { /// Implements the circuit that does the checks of the Non-Interactive Folding Scheme Verifier /// described of the Ova variant, where the cmWE check is delegated to the NIFSCycleFoldGadget. -pub struct NIFSGadget, S>> { +pub struct NIFSGadget, S>> { _c: PhantomData, _s: PhantomData, _t: PhantomData, @@ -103,13 +97,9 @@ pub struct NIFSGadget NIFSGadgetTrait for NIFSGadget where - C: CurveGroup, + C: Curve, S: CryptographicSponge, T: TranscriptVar, S>, - ::BaseField: ark_ff::PrimeField, - - C::ScalarField: Absorb, - ::BaseField: PrimeField, { type CommittedInstance = CommittedInstance; type CommittedInstanceVar = CommittedInstanceVar; diff --git a/folding-schemes/src/folding/nova/nifs/pointvsline.rs b/folding-schemes/src/folding/nova/nifs/pointvsline.rs index dc914e3b..62573796 100644 --- a/folding-schemes/src/folding/nova/nifs/pointvsline.rs +++ b/folding-schemes/src/folding/nova/nifs/pointvsline.rs @@ -1,5 +1,3 @@ -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::CurveGroup; use ark_ff::{One, PrimeField}; use ark_poly::univariate::DensePolynomial; use ark_poly::{DenseMultilinearExtension, DenseUVPolynomial, Polynomial}; @@ -9,35 +7,32 @@ use ark_std::{log2, Zero}; use super::mova::{CommittedInstance, Witness}; use crate::transcript::Transcript; use crate::utils::mle::dense_vec_to_dense_mle; -use crate::Error; +use crate::{Curve, Error}; /// Implements the Points vs Line as described in /// [Mova](https://eprint.iacr.org/2024/1220.pdf) and Section 4.5.2 from Thaler’s book /// Claim from step 3 protocol 6 -pub struct PointvsLineEvaluationClaim { +pub struct PointvsLineEvaluationClaim { pub mleE1_prime: C::ScalarField, pub mleE2_prime: C::ScalarField, pub rE_prime: Vec, } /// Proof from step 1 protocol 6 #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] -pub struct PointVsLineProof { +pub struct PointVsLineProof { pub h1: DensePolynomial, pub h2: DensePolynomial, } #[derive(Clone, Debug, Default)] -pub struct PointVsLine> { +pub struct PointVsLine> { _phantom_C: std::marker::PhantomData, _phantom_T: std::marker::PhantomData, } /// Protocol 6 from Mova -impl> PointVsLine -where - C::ScalarField: Absorb, -{ +impl> PointVsLine { pub fn prove( transcript: &mut T, ci1: &CommittedInstance, diff --git a/folding-schemes/src/folding/nova/traits.rs b/folding-schemes/src/folding/nova/traits.rs index 2f13464b..9e68e102 100644 --- a/folding-schemes/src/folding/nova/traits.rs +++ b/folding-schemes/src/folding/nova/traits.rs @@ -1,4 +1,3 @@ -use ark_ec::CurveGroup; use ark_r1cs_std::fields::fp::FpVar; use ark_relations::r1cs::SynthesisError; use ark_std::{rand::RngCore, UniformRand}; @@ -13,7 +12,7 @@ use crate::arith::{ use crate::commitment::CommitmentScheme; use crate::folding::circuits::CF1; use crate::utils::gadgets::{EquivalenceGadget, VectorGadget}; -use crate::Error; +use crate::{Curve, Error}; /// Implements `Arith` for R1CS, where the witness is of type [`Witness`], and /// the committed instance is of type [`CommittedInstance`]. @@ -42,7 +41,7 @@ use crate::Error; /// For R1CS, whether it is relaxed or not is now determined by the types of `W` /// and `U`: the satisfiability check is relaxed if `W` and `U` are defined by /// folding schemes, and plain if they are vectors of field elements. -impl Arith, CommittedInstance> for R1CS> { +impl Arith, CommittedInstance> for R1CS> { type Evaluation = Vec>; fn eval_relation( @@ -62,7 +61,7 @@ impl Arith, CommittedInstance> for R1CS> { } } -impl ArithSampler, CommittedInstance> for R1CS> { +impl ArithSampler, CommittedInstance> for R1CS> { fn sample_witness_instance>( &self, params: &CS::ProverParams, @@ -103,7 +102,7 @@ impl ArithSampler, CommittedInstance> for R1CS ArithGadget, CommittedInstanceVar> +impl ArithGadget, CommittedInstanceVar> for R1CSMatricesVar> { type Evaluation = (Vec>, Vec>); diff --git a/folding-schemes/src/folding/nova/zk.rs b/folding-schemes/src/folding/nova/zk.rs index b4aa63d8..2f809973 100644 --- a/folding-schemes/src/folding/nova/zk.rs +++ b/folding-schemes/src/folding/nova/zk.rs @@ -30,29 +30,25 @@ /// paper). /// And the Use-case-2 would require a modified version of the Decider circuits. /// -use ark_ff::PrimeField; -use ark_std::{One, Zero}; - -use crate::{ - arith::{r1cs::R1CS, Arith, ArithSampler}, - folding::traits::CommittedInstanceOps, - RngCore, -}; use ark_crypto_primitives::sponge::{ poseidon::{PoseidonConfig, PoseidonSponge}, - Absorb, CryptographicSponge, + CryptographicSponge, }; -use ark_ec::CurveGroup; -use ark_r1cs_std::groups::CurveVar; - -use crate::{commitment::CommitmentScheme, folding::circuits::CF2, frontend::FCircuit, Error}; +use ark_std::{rand::RngCore, One, Zero}; use super::{ nifs::{nova::NIFS, NIFSTrait}, CommittedInstance, Nova, Witness, }; +use crate::{ + arith::{r1cs::R1CS, Arith, ArithSampler}, + commitment::CommitmentScheme, + folding::traits::CommittedInstanceOps, + frontend::FCircuit, + Curve, Error, +}; -pub struct RandomizedIVCProof { +pub struct RandomizedIVCProof { pub U_i: CommittedInstance, pub u_i: CommittedInstance, pub U_r: CommittedInstance, @@ -63,32 +59,18 @@ pub struct RandomizedIVCProof { pub cf_W_i: Witness, } -impl RandomizedIVCProof -where - C1::ScalarField: Absorb, - ::BaseField: PrimeField, -{ +impl RandomizedIVCProof { /// Compute a zero-knowledge proof of a Nova IVC proof /// It implements the prover of appendix D.4.in https://eprint.iacr.org/2023/573.pdf /// For further details on why folding is hiding, see lemma 9 pub fn new< - GC1: CurveVar>, - GC2: CurveVar>, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, >( - nova: &Nova, + nova: &Nova, mut rng: impl RngCore, - ) -> Result, Error> - where - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C2::ScalarField: PrimeField, - ::BaseField: PrimeField, - ::BaseField: Absorb, - C1: CurveGroup, - { + ) -> Result, Error> { let mut transcript = PoseidonSponge::::new(&nova.poseidon_config); // I. Compute proof for 'regular' instances @@ -137,11 +119,7 @@ where /// Verify a zero-knowledge proof of a Nova IVC proof /// It implements the verifier of appendix D.4. in https://eprint.iacr.org/2023/573.pdf #[allow(clippy::too_many_arguments)] - pub fn verify< - CS1: CommitmentScheme, - GC2: CurveVar>, - CS2: CommitmentScheme, - >( + pub fn verify, CS2: CommitmentScheme>( r1cs: &R1CS, cf_r1cs: &R1CS, pp_hash: C1::ScalarField, @@ -152,11 +130,7 @@ where proof: &RandomizedIVCProof, ) -> Result<(), Error> where - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - ::BaseField: PrimeField, - ::BaseField: Absorb, - C1: CurveGroup, + C1: Curve, { // Handles case where i=0 if i == C1::ScalarField::zero() { @@ -227,7 +201,7 @@ pub mod tests { use crate::frontend::utils::CubicFCircuit; use crate::transcript::poseidon::poseidon_canonical_config; use ark_bn254::{Fr, G1Projective as Projective}; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_grumpkin::Projective as Projective2; use rand::rngs::OsRng; // Tests zk proof generation and verification for a valid nova IVC proof @@ -243,20 +217,17 @@ pub mod tests { >(poseidon_config.clone(), F_circuit, 3)?; let proof = RandomizedIVCProof::new(&nova, &mut rng)?; - let verify = RandomizedIVCProof::verify::< - Pedersen, - GVar2, - Pedersen, - >( - &nova.r1cs, - &nova.cf_r1cs, - nova.pp_hash, - &nova.poseidon_config, - nova.i, - nova.z_0, - nova.z_i, - &proof, - ); + let verify = + RandomizedIVCProof::verify::, Pedersen>( + &nova.r1cs, + &nova.cf_r1cs, + nova.pp_hash, + &nova.poseidon_config, + nova.i, + nova.z_0, + nova.z_i, + &proof, + ); assert!(verify.is_ok()); Ok(()) } @@ -273,20 +244,17 @@ pub mod tests { >(poseidon_config.clone(), F_circuit, 0)?; let proof = RandomizedIVCProof::new(&nova, &mut rng)?; - let verify = RandomizedIVCProof::verify::< - Pedersen, - GVar2, - Pedersen, - >( - &nova.r1cs, - &nova.cf_r1cs, - nova.pp_hash, - &nova.poseidon_config, - nova.i, - nova.z_0, - nova.z_i, - &proof, - ); + let verify = + RandomizedIVCProof::verify::, Pedersen>( + &nova.r1cs, + &nova.cf_r1cs, + nova.pp_hash, + &nova.poseidon_config, + nova.i, + nova.z_0, + nova.z_i, + &proof, + ); assert!(verify.is_ok()); Ok(()) } @@ -310,20 +278,17 @@ pub mod tests { nova_with_incorrect_running_instance.U_i = sampled_committed_instance; let incorrect_proof = RandomizedIVCProof::new(&nova_with_incorrect_running_instance, &mut rng)?; - let verify = RandomizedIVCProof::verify::< - Pedersen, - GVar2, - Pedersen, - >( - &nova_with_incorrect_running_instance.r1cs, - &nova_with_incorrect_running_instance.cf_r1cs, - nova_with_incorrect_running_instance.pp_hash, - &nova_with_incorrect_running_instance.poseidon_config, - nova_with_incorrect_running_instance.i, - nova_with_incorrect_running_instance.z_0, - nova_with_incorrect_running_instance.z_i, - &incorrect_proof, - ); + let verify = + RandomizedIVCProof::verify::, Pedersen>( + &nova_with_incorrect_running_instance.r1cs, + &nova_with_incorrect_running_instance.cf_r1cs, + nova_with_incorrect_running_instance.pp_hash, + &nova_with_incorrect_running_instance.poseidon_config, + nova_with_incorrect_running_instance.i, + nova_with_incorrect_running_instance.z_0, + nova_with_incorrect_running_instance.z_i, + &incorrect_proof, + ); assert!(verify.is_err()); Ok(()) } @@ -347,20 +312,17 @@ pub mod tests { nova_with_incorrect_running_witness.W_i = sampled_committed_witness; let incorrect_proof = RandomizedIVCProof::new(&nova_with_incorrect_running_witness, &mut rng)?; - let verify = RandomizedIVCProof::verify::< - Pedersen, - GVar2, - Pedersen, - >( - &nova_with_incorrect_running_witness.r1cs, - &nova_with_incorrect_running_witness.cf_r1cs, - nova_with_incorrect_running_witness.pp_hash, - &nova_with_incorrect_running_witness.poseidon_config, - nova_with_incorrect_running_witness.i, - nova_with_incorrect_running_witness.z_0, - nova_with_incorrect_running_witness.z_i, - &incorrect_proof, - ); + let verify = + RandomizedIVCProof::verify::, Pedersen>( + &nova_with_incorrect_running_witness.r1cs, + &nova_with_incorrect_running_witness.cf_r1cs, + nova_with_incorrect_running_witness.pp_hash, + &nova_with_incorrect_running_witness.poseidon_config, + nova_with_incorrect_running_witness.i, + nova_with_incorrect_running_witness.z_0, + nova_with_incorrect_running_witness.z_i, + &incorrect_proof, + ); assert!(verify.is_err()); Ok(()) } diff --git a/folding-schemes/src/folding/protogalaxy/circuits.rs b/folding-schemes/src/folding/protogalaxy/circuits.rs index 09f1a2fe..d46afac1 100644 --- a/folding-schemes/src/folding/protogalaxy/circuits.rs +++ b/folding-schemes/src/folding/protogalaxy/circuits.rs @@ -1,9 +1,8 @@ use ark_crypto_primitives::sponge::{ constraints::CryptographicSpongeVar, poseidon::{constraints::PoseidonSpongeVar, PoseidonConfig, PoseidonSponge}, - Absorb, CryptographicSponge, + CryptographicSponge, }; -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_poly::{univariate::DensePolynomial, EvaluationDomain, GeneralEvaluationDomain}; use ark_r1cs_std::{ @@ -17,7 +16,7 @@ use ark_r1cs_std::{ R1CSVar, }; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; -use ark_std::{fmt::Debug, marker::PhantomData, One, Zero}; +use ark_std::{fmt::Debug, One, Zero}; use super::{ folding::lagrange_polys, @@ -32,20 +31,21 @@ use crate::{ CycleFoldCommittedInstanceVar, CycleFoldConfig, NIFSFullGadget, }, nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar}, - CF1, CF2, + CF1, }, traits::{CommittedInstanceVarOps, Dummy}, }, frontend::FCircuit, transcript::{AbsorbNonNativeGadget, TranscriptVar}, utils::gadgets::VectorGadget, + Curve, }; pub struct FoldingGadget {} impl FoldingGadget { #[allow(clippy::type_complexity)] - pub fn fold_committed_instance( + pub fn fold_committed_instance( transcript: &mut impl TranscriptVar, // running instance instance: &CommittedInstanceVar, @@ -135,7 +135,7 @@ pub struct AugmentationGadget; impl AugmentationGadget { #[allow(clippy::type_complexity)] - pub fn prepare_and_fold_primary( + pub fn prepare_and_fold_primary( transcript: &mut impl TranscriptVar, S>, U: CommittedInstanceVar, u_phis: Vec>, @@ -171,21 +171,17 @@ impl AugmentationGadget { } pub fn prepare_and_fold_cyclefold< - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, S: CryptographicSponge, >( transcript: &mut PoseidonSpongeVar>, pp_hash: FpVar>, - mut cf_U: CycleFoldCommittedInstanceVar, - cf_u_cmWs: Vec, + mut cf_U: CycleFoldCommittedInstanceVar, + cf_u_cmWs: Vec, cf_u_xs: Vec>>>, - cf_cmTs: Vec, - ) -> Result, SynthesisError> - where - C2::BaseField: PrimeField + Absorb, - { + cf_cmTs: Vec, + ) -> Result, SynthesisError> { assert_eq!(cf_u_cmWs.len(), cf_u_xs.len()); assert_eq!(cf_u_xs.len(), cf_cmTs.len()); @@ -198,7 +194,7 @@ impl AugmentationGadget { // For each CycleFold instance `cf_u`, we have `cf_u.cmE = 0`, and // `cf_u.u = 1`. let cf_u = CycleFoldCommittedInstanceVar { - cmE: GC2::zero(), + cmE: C2::Var::zero(), u: NonNativeUintVar::new_constant(ConstraintSystemRef::None, C1::BaseField::one())?, cmW, x, @@ -235,13 +231,7 @@ impl AugmentationGadget { /// defined in [CycleFold](https://eprint.iacr.org/2023/1192.pdf). These extra /// constraints verify the correct folding of CycleFold instances. #[derive(Debug, Clone)] -pub struct AugmentedFCircuit< - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, - FC: FCircuit>, -> { - pub(super) _gc2: PhantomData, +pub struct AugmentedFCircuit>> { pub(super) poseidon_config: PoseidonConfig>, pub(super) pp_hash: CF1, pub(super) i: CF1, @@ -265,9 +255,7 @@ pub struct AugmentedFCircuit< pub(super) cf2_cmT: C2, } -impl>, FC: FCircuit>> - AugmentedFCircuit -{ +impl>> AugmentedFCircuit { pub fn empty( poseidon_config: &PoseidonConfig>, F_circuit: FC, @@ -280,7 +268,6 @@ impl>, FC: FCircuit::IO_LEN); Self { - _gc2: PhantomData, poseidon_config: poseidon_config.clone(), pp_hash: CF1::::zero(), i: CF1::::zero(), @@ -305,13 +292,11 @@ impl>, FC: FCircuit AugmentedFCircuit +impl AugmentedFCircuit where - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit>, - C2::BaseField: PrimeField + Absorb, { pub fn compute_next_state( self, @@ -334,9 +319,9 @@ where let cf_u_dummy = CycleFoldCommittedInstance::dummy(ProtoGalaxyCycleFoldConfig::::IO_LEN); let cf_U_i = - CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || Ok(self.cf_U_i))?; - let cf1_cmT = GC2::new_witness(cs.clone(), || Ok(self.cf1_cmT))?; - let cf2_cmT = GC2::new_witness(cs.clone(), || Ok(self.cf2_cmT))?; + CycleFoldCommittedInstanceVar::::new_witness(cs.clone(), || Ok(self.cf_U_i))?; + let cf1_cmT = C2::Var::new_witness(cs.clone(), || Ok(self.cf1_cmT))?; + let cf2_cmT = C2::Var::new_witness(cs.clone(), || Ok(self.cf2_cmT))?; let F_coeffs = Vec::new_witness(cs.clone(), || Ok(self.F_coeffs))?; let K_coeffs = Vec::new_witness(cs.clone(), || Ok(self.K_coeffs))?; @@ -450,13 +435,13 @@ where // C.2. Prepare incoming CycleFold instances // C.3. Fold incoming CycleFold instances into the running instance let cf_U_i1 = - AugmentationGadget::prepare_and_fold_cyclefold::>>( + AugmentationGadget::prepare_and_fold_cyclefold::>>( &mut transcript, pp_hash.clone(), cf_U_i, vec![ - GC2::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW))?, - GC2::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW))?, + C2::Var::new_witness(cs.clone(), || Ok(self.cf1_u_i_cmW))?, + C2::Var::new_witness(cs.clone(), || Ok(self.cf2_u_i_cmW))?, ], vec![cf1_x, cf2_x], vec![cf1_cmT, cf2_cmT], @@ -468,7 +453,7 @@ where // Non-base case: u_{i+1}.x[1] == H(cf_U_{i+1}) let (cf_u_i1_x, _) = cf_U_i1.clone().hash(&sponge, pp_hash.clone())?; let (cf_u_i1_x_base, _) = - CycleFoldCommittedInstanceVar::::new_constant(cs.clone(), cf_u_dummy)? + CycleFoldCommittedInstanceVar::::new_constant(cs.clone(), cf_u_dummy)? .hash(&sponge, pp_hash.clone())?; let cf_x = is_basecase.select(&cf_u_i1_x_base, &cf_u_i1_x)?; // This line "converts" `cf_x` from a witness to a public input. @@ -486,13 +471,11 @@ where } } -impl ConstraintSynthesizer> for AugmentedFCircuit +impl ConstraintSynthesizer> for AugmentedFCircuit where - C1: CurveGroup, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit>, - C2::BaseField: PrimeField + Absorb, { fn generate_constraints(self, cs: ConstraintSystemRef>) -> Result<(), SynthesisError> { self.compute_next_state(cs).map(|_| ()) diff --git a/folding-schemes/src/folding/protogalaxy/decider_eth.rs b/folding-schemes/src/folding/protogalaxy/decider_eth.rs index 08579f9d..ddb843bc 100644 --- a/folding-schemes/src/folding/protogalaxy/decider_eth.rs +++ b/folding-schemes/src/folding/protogalaxy/decider_eth.rs @@ -2,10 +2,6 @@ /// the Decider from decider.rs file will be more efficient. /// More details can be found at the documentation page: /// https://privacy-scaling-explorations.github.io/sonobe-docs/design/nova-decider-onchain.html -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::CurveGroup; -use ark_ff::PrimeField; -use ark_r1cs_std::prelude::CurveVar; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; use ark_snark::SNARK; use ark_std::{ @@ -17,20 +13,20 @@ use ark_std::{ pub use super::decider_eth_circuit::DeciderEthCircuit; use super::decider_eth_circuit::DeciderProtoGalaxyGadget; use super::ProtoGalaxy; -use crate::commitment::{ - kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme, -}; use crate::folding::circuits::decider::DeciderEnabledNIFS; -use crate::folding::circuits::CF2; -use crate::folding::traits::{Inputize, WitnessOps}; +use crate::folding::traits::{InputizeNonNative, WitnessOps}; use crate::frontend::FCircuit; use crate::Error; +use crate::{ + commitment::{kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme}, + Curve, +}; use crate::{Decider as DeciderTrait, FoldingScheme}; #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct Proof where - C: CurveGroup, + C: Curve, CS: CommitmentScheme, S: SNARK, { @@ -45,7 +41,7 @@ where #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct VerifierParam where - C1: CurveGroup, + C1: Curve, CS_VerifyingKey: Clone + CanonicalSerialize + CanonicalDeserialize, S_VerifyingKey: Clone + CanonicalSerialize + CanonicalDeserialize, { @@ -56,11 +52,9 @@ where /// Onchain Decider, for ethereum use cases #[derive(Clone, Debug)] -pub struct Decider { +pub struct Decider { _c1: PhantomData, - _gc1: PhantomData, _c2: PhantomData, - _gc2: PhantomData, _fc: PhantomData, _cs1: PhantomData, _cs2: PhantomData, @@ -68,13 +62,11 @@ pub struct Decider { _fs: PhantomData, } -impl DeciderTrait - for Decider +impl DeciderTrait + for Decider where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, // CS1 is a KZG commitment, where challenge is C1::Fr elem CS1: CommitmentScheme< @@ -87,13 +79,8 @@ where CS2: CommitmentScheme>, S: SNARK, FS: FoldingScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, // constrain FS into ProtoGalaxy, since this is a Decider specifically for ProtoGalaxy - ProtoGalaxy: From, + ProtoGalaxy: From, crate::folding::protogalaxy::ProverParams: From<>::ProverParam>, crate::folding::protogalaxy::VerifierParams: @@ -111,7 +98,7 @@ where prep_param: Self::PreprocessorParam, fs: FS, ) -> Result<(Self::ProverParam, Self::VerifierParam), Error> { - let circuit = DeciderEthCircuit::::try_from(ProtoGalaxy::from(fs))?; + let circuit = DeciderEthCircuit::::try_from(ProtoGalaxy::from(fs))?; // get the Groth16 specific setup for the circuit let (g16_pk, g16_vk) = S::circuit_specific_setup(circuit, &mut rng) @@ -119,13 +106,13 @@ where // get the FoldingScheme prover & verifier params from ProtoGalaxy #[allow(clippy::type_complexity)] - let protogalaxy_pp: as FoldingScheme< + let protogalaxy_pp: as FoldingScheme< C1, C2, FC, >>::ProverParam = prep_param.0.clone().into(); #[allow(clippy::type_complexity)] - let protogalaxy_vp: as FoldingScheme< + let protogalaxy_vp: as FoldingScheme< C1, C2, FC, @@ -148,8 +135,7 @@ where ) -> Result { let (snark_pk, cs_pk): (S::ProvingKey, CS1::ProverParams) = pp; - let circuit = - DeciderEthCircuit::::try_from(ProtoGalaxy::from(folding_scheme))?; + let circuit = DeciderEthCircuit::::try_from(ProtoGalaxy::from(folding_scheme))?; let L_X_evals = circuit.randomness.clone(); @@ -223,10 +209,7 @@ where &[pp_hash, i][..], &z_0, &z_i, - &U_final_commitments - .iter() - .flat_map(|c| c.inputize()) - .collect::>(), + &U_final_commitments.inputize_nonnative(), &proof.kzg_challenges, &proof.kzg_proofs.iter().map(|p| p.eval).collect::>(), &proof.L_X_evals, @@ -256,9 +239,9 @@ where #[cfg(test)] pub mod tests { use ark_bn254::Bn254; - use ark_bn254::{constraints::GVar, Fr, G1Projective as Projective}; + use ark_bn254::{Fr, G1Projective as Projective}; use ark_groth16::Groth16; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_grumpkin::Projective as Projective2; use std::time::Instant; use super::*; @@ -275,18 +258,14 @@ pub mod tests { // use ProtoGalaxy as FoldingScheme type PG = ProtoGalaxy< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, >; type D = Decider< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, @@ -354,18 +333,14 @@ pub mod tests { // use ProtoGalaxy as FoldingScheme type PG = ProtoGalaxy< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, >; type D = Decider< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, KZG<'static, Bn254>, Pedersen, diff --git a/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs b/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs index 6c71c57b..483d7f9b 100644 --- a/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs @@ -3,15 +3,13 @@ use ark_crypto_primitives::sponge::{ constraints::CryptographicSpongeVar, poseidon::{constraints::PoseidonSpongeVar, PoseidonSponge}, - Absorb, CryptographicSponge, + CryptographicSponge, }; -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, eq::EqGadget, fields::fp::FpVar, - groups::CurveVar, }; use ark_relations::r1cs::{Namespace, SynthesisError}; use ark_std::{borrow::Borrow, marker::PhantomData}; @@ -25,12 +23,12 @@ use crate::{ on_chain::GenericOnchainDeciderCircuit, DeciderEnabledNIFS, EvalGadget, KZGChallengesGadget, }, - CF1, CF2, + CF1, }, traits::{WitnessOps, WitnessVarOps}, }, frontend::FCircuit, - Error, + Curve, Error, }; use super::{ @@ -70,10 +68,9 @@ impl WitnessVarOps for WitnessVar { } } -pub type DeciderEthCircuit = GenericOnchainDeciderCircuit< +pub type DeciderEthCircuit = GenericOnchainDeciderCircuit< C1, C2, - GC2, CommittedInstance, CommittedInstance, Witness>, @@ -84,21 +81,17 @@ pub type DeciderEthCircuit = GenericOnchainDeciderCircuit< /// returns an instance of the DeciderEthCircuit from the given ProtoGalaxy struct impl< - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, // enforce that the CS2 is Pedersen commitment scheme, since we're at Ethereum's EVM decider CS2: CommitmentScheme>, - > TryFrom> for DeciderEthCircuit -where - CF1: Absorb, + > TryFrom> for DeciderEthCircuit { type Error = Error; - fn try_from(protogalaxy: ProtoGalaxy) -> Result { + fn try_from(protogalaxy: ProtoGalaxy) -> Result { let mut transcript = PoseidonSponge::::new(&protogalaxy.poseidon_config); let (U_i1, W_i1, proof, aux) = Folding::prove( @@ -122,7 +115,6 @@ where .collect::, _>>()?; Ok(Self { - _gc2: PhantomData, _avar: PhantomData, arith: protogalaxy.r1cs, cf_arith: protogalaxy.cf_r1cs, @@ -150,7 +142,7 @@ where pub struct DeciderProtoGalaxyGadget; -impl +impl DeciderEnabledNIFS< C, CommittedInstance, @@ -200,8 +192,8 @@ impl #[cfg(test)] pub mod tests { - use ark_bn254::{constraints::GVar, Fr, G1Projective as Projective}; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_bn254::{Fr, G1Projective as Projective}; + use ark_grumpkin::Projective as Projective2; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystem}; use super::*; @@ -221,9 +213,7 @@ pub mod tests { type PG = ProtoGalaxy< Projective, - GVar, Projective2, - GVar2, CubicFCircuit, Pedersen, Pedersen, @@ -238,8 +228,7 @@ pub mod tests { PG::verify(pg_params.1, ivc_proof)?; // load the DeciderEthCircuit from the generated Nova instance - let decider_circuit = - DeciderEthCircuit::::try_from(protogalaxy)?; + let decider_circuit = DeciderEthCircuit::::try_from(protogalaxy)?; let cs = ConstraintSystem::::new_ref(); diff --git a/folding-schemes/src/folding/protogalaxy/folding.rs b/folding-schemes/src/folding/protogalaxy/folding.rs index 93eac4ea..4fc40594 100644 --- a/folding-schemes/src/folding/protogalaxy/folding.rs +++ b/folding-schemes/src/folding/protogalaxy/folding.rs @@ -1,6 +1,4 @@ /// Implements the scheme described in [ProtoGalaxy](https://eprint.iacr.org/2023/1106.pdf) -use ark_crypto_primitives::sponge::Absorb; -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_poly::{ univariate::{DensePolynomial, SparsePolynomial}, @@ -14,11 +12,11 @@ use super::utils::{all_powers, betas_star, exponential_powers, pow_i}; use super::ProtoGalaxyError; use super::{CommittedInstance, Witness}; -use crate::arith::r1cs::R1CS; use crate::folding::traits::Dummy; use crate::transcript::Transcript; use crate::utils::vec::*; use crate::Error; +use crate::{arith::r1cs::R1CS, Curve}; #[derive(Debug, Clone)] pub struct ProtoGalaxyProof { @@ -36,7 +34,7 @@ impl Dummy<(usize, usize, usize)> for ProtoGalaxyProof { } #[derive(Debug, Clone)] -pub struct ProtoGalaxyAux { +pub struct ProtoGalaxyAux { pub L_X_evals: Vec, pub phi_stars: Vec, } @@ -44,13 +42,10 @@ pub struct ProtoGalaxyAux { #[derive(Clone, Debug)] /// Implements the protocol described in section 4 of /// [ProtoGalaxy](https://eprint.iacr.org/2023/1106.pdf) -pub struct Folding { +pub struct Folding { _phantom: PhantomData, } -impl Folding -where - C::ScalarField: Absorb, -{ +impl Folding { #![allow(clippy::type_complexity)] /// implements the non-interactive Prover from the folding scheme described in section 4 pub fn prove( @@ -434,7 +429,7 @@ pub mod tests { // k represents the number of instances to be fold, apart from the running instance #[allow(clippy::type_complexity)] - pub fn prepare_inputs( + pub fn prepare_inputs( k: usize, ) -> Result< ( diff --git a/folding-schemes/src/folding/protogalaxy/mod.rs b/folding-schemes/src/folding/protogalaxy/mod.rs index 8009bc0c..8e1e3090 100644 --- a/folding-schemes/src/folding/protogalaxy/mod.rs +++ b/folding-schemes/src/folding/protogalaxy/mod.rs @@ -1,15 +1,13 @@ /// Implements the scheme described in [ProtoGalaxy](https://eprint.iacr.org/2023/1106.pdf) use ark_crypto_primitives::sponge::{ poseidon::{PoseidonConfig, PoseidonSponge}, - Absorb, CryptographicSponge, + CryptographicSponge, }; -use ark_ec::CurveGroup; use ark_ff::{BigInteger, PrimeField}; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, eq::EqGadget, fields::{fp::FpVar, FieldVar}, - groups::CurveVar, R1CSVar, }; use ark_relations::r1cs::{ @@ -34,12 +32,12 @@ use crate::{ CycleFoldWitness, }, nonnative::affine::NonNativeAffineVar, - CF1, CF2, + CF1, }, frontend::{utils::DummyCircuit, FCircuit}, transcript::poseidon::poseidon_canonical_config, utils::pp_hash, - Error, FoldingScheme, + Curve, Error, FoldingScheme, }; pub mod circuits; @@ -58,11 +56,11 @@ use super::traits::{ }; /// Configuration for ProtoGalaxy's CycleFold circuit -pub struct ProtoGalaxyCycleFoldConfig { +pub struct ProtoGalaxyCycleFoldConfig { _c: PhantomData, } -impl CycleFoldConfig for ProtoGalaxyCycleFoldConfig { +impl CycleFoldConfig for ProtoGalaxyCycleFoldConfig { const RANDOMNESS_BIT_LENGTH: usize = C::ScalarField::MODULUS_BIT_SIZE as usize; const N_INPUT_POINTS: usize = 2; type C = C; @@ -70,7 +68,7 @@ impl CycleFoldConfig for ProtoGalaxyCycleFoldConfig { /// CycleFold circuit for computing random linear combinations of group elements /// in ProtoGalaxy instances. -pub type ProtoGalaxyCycleFoldCircuit = CycleFoldCircuit, GC>; +pub type ProtoGalaxyCycleFoldCircuit = CycleFoldCircuit>; /// The committed instance of ProtoGalaxy. /// @@ -78,14 +76,14 @@ pub type ProtoGalaxyCycleFoldCircuit = CycleFoldCircuit { +pub struct CommittedInstance { phi: C, betas: Vec, e: C::ScalarField, x: Vec, } -impl Dummy<(usize, usize)> for CommittedInstance { +impl Dummy<(usize, usize)> for CommittedInstance { fn dummy((io_len, t): (usize, usize)) -> Self { if TYPE == INCOMING { assert_eq!(t, 0); @@ -99,7 +97,7 @@ impl Dummy<(usize, usize)> for CommittedInstanc } } -impl Dummy<&R1CS>> for CommittedInstance { +impl Dummy<&R1CS>> for CommittedInstance { fn dummy(r1cs: &R1CS>) -> Self { let t = if TYPE == RUNNING { log2(r1cs.num_constraints()) as usize @@ -110,7 +108,7 @@ impl Dummy<&R1CS>> for CommittedInstance } } -impl CommittedInstanceOps for CommittedInstance { +impl CommittedInstanceOps for CommittedInstance { type Var = CommittedInstanceVar; fn get_commitments(&self) -> Vec { @@ -122,23 +120,29 @@ impl CommittedInstanceOps for CommittedInsta } } -impl Inputize> - for CommittedInstance -{ - fn inputize(&self) -> Vec { - [&self.phi.inputize(), &self.betas, &[self.e][..], &self.x].concat() +impl Inputize> for CommittedInstance { + /// Returns the internal representation in the same order as how the value + /// is allocated in `CommittedInstanceVar::new_input`. + fn inputize(&self) -> Vec> { + [ + &self.phi.inputize_nonnative(), + &self.betas, + &[self.e][..], + &self.x, + ] + .concat() } } #[derive(Clone, Debug)] -pub struct CommittedInstanceVar { +pub struct CommittedInstanceVar { phi: NonNativeAffineVar, betas: Vec>, e: FpVar, x: Vec>, } -impl AllocVar, C::ScalarField> +impl AllocVar, C::ScalarField> for CommittedInstanceVar { fn new_variable>>( @@ -165,7 +169,7 @@ impl AllocVar, C::Sc } } -impl R1CSVar for CommittedInstanceVar { +impl R1CSVar for CommittedInstanceVar { type Value = CommittedInstance; fn cs(&self) -> ConstraintSystemRef { @@ -190,7 +194,7 @@ impl R1CSVar for CommittedInsta } } -impl CommittedInstanceVarOps for CommittedInstanceVar { +impl CommittedInstanceVarOps for CommittedInstanceVar { type PointVar = NonNativeAffineVar; fn get_commitments(&self) -> Vec { @@ -232,7 +236,7 @@ impl Witness { Self { w, r_w: F::zero() } } - pub fn commit, C: CurveGroup>( + pub fn commit, C: Curve>( &self, params: &CS::ProverParams, x: Vec, @@ -312,8 +316,8 @@ pub enum ProtoGalaxyError { #[derive(Debug, Clone)] pub struct ProverParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -326,8 +330,8 @@ where } impl CanonicalSerialize for ProverParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -346,8 +350,8 @@ where } impl Valid for ProverParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -366,8 +370,8 @@ where } impl CanonicalDeserialize for ProverParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -391,8 +395,8 @@ where #[derive(Debug, Clone)] pub struct VerifierParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -410,8 +414,8 @@ where impl Valid for VerifierParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -423,8 +427,8 @@ where } impl CanonicalSerialize for VerifierParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -444,8 +448,8 @@ where impl VerifierParams where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { @@ -465,11 +469,7 @@ where } #[derive(PartialEq, Eq, Debug, Clone, CanonicalSerialize, CanonicalDeserialize)] -pub struct IVCProof -where - C1: CurveGroup, - C2: CurveGroup, -{ +pub struct IVCProof { pub i: C1::ScalarField, pub z_0: Vec, pub z_i: Vec, @@ -487,19 +487,14 @@ where /// [ProtoGalaxy]: https://eprint.iacr.org/2023/1106.pdf /// [CycleFold]: https://eprint.iacr.org/2023/1192.pdf #[derive(Clone, Debug)] -pub struct ProtoGalaxy +pub struct ProtoGalaxy where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, { - _gc1: PhantomData, - _c2: PhantomData, - _gc2: PhantomData, /// R1CS of the Augmented Function circuit pub r1cs: R1CS, /// R1CS of the CycleFold circuit @@ -529,20 +524,13 @@ where pub cf_U_i: CycleFoldCommittedInstance, } -impl ProtoGalaxy +impl ProtoGalaxy where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, { /// This method computes the parameter `t` in ProtoGalaxy for folding `F'`, /// the augmented circuit of `F` @@ -592,7 +580,7 @@ where // Compute `augmentation_constraints`, the size of `F'` without `F`. let cs = ConstraintSystem::::new_ref(); - AugmentedFCircuit::::empty( + AugmentedFCircuit::::empty( poseidon_config, dummy_circuit.clone(), 1, @@ -615,7 +603,7 @@ where for t in t_lower_bound..=t_upper_bound { let cs = ConstraintSystem::::new_ref(); - AugmentedFCircuit::::empty( + AugmentedFCircuit::::empty( poseidon_config, dummy_circuit.clone(), t, @@ -632,21 +620,13 @@ where } } -impl FoldingScheme - for ProtoGalaxy +impl FoldingScheme for ProtoGalaxy where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, { type PreprocessorParam = (PoseidonConfig>, FC); type ProverParam = ProverParams; @@ -687,13 +667,8 @@ where // main circuit R1CS: let cs = ConstraintSystem::::new_ref(); - let augmented_F_circuit = AugmentedFCircuit::::empty( - &poseidon_config, - f_circuit.clone(), - t, - d, - k, - ); + let augmented_F_circuit = + AugmentedFCircuit::::empty(&poseidon_config, f_circuit.clone(), t, d, k); augmented_F_circuit.generate_constraints(cs.clone())?; cs.finalize(); let cs = cs.into_inner().ok_or(Error::NoInnerConstraintSystem)?; @@ -701,7 +676,7 @@ where // CycleFold circuit R1CS let cs2 = ConstraintSystem::::new_ref(); - let cf_circuit = ProtoGalaxyCycleFoldCircuit::::empty(); + let cf_circuit = ProtoGalaxyCycleFoldCircuit::::empty(); cf_circuit.generate_constraints(cs2.clone())?; cs2.finalize(); let cs2 = cs2.into_inner().ok_or(Error::NoInnerConstraintSystem)?; @@ -739,8 +714,8 @@ where let cs2 = ConstraintSystem::::new_ref(); let augmented_F_circuit = - AugmentedFCircuit::::empty(poseidon_config, F.clone(), t, d, k); - let cf_circuit = ProtoGalaxyCycleFoldCircuit::::empty(); + AugmentedFCircuit::::empty(poseidon_config, F.clone(), t, d, k); + let cf_circuit = ProtoGalaxyCycleFoldCircuit::::empty(); augmented_F_circuit.generate_constraints(cs.clone())?; cs.finalize(); @@ -789,9 +764,6 @@ where // W_dummy=W_0 is a 'dummy witness', all zeroes, but with the size corresponding to the // R1CS that we're working with. Ok(Self { - _gc1: PhantomData, - _c2: PhantomData, - _gc2: PhantomData, r1cs: vp.r1cs.clone(), cf_r1cs: vp.cf_r1cs.clone(), poseidon_config: pp.poseidon_config.clone(), @@ -838,7 +810,7 @@ where // `transcript` is for challenge generation. let mut transcript_prover = sponge.clone(); - let mut augmented_F_circuit: AugmentedFCircuit; + let mut augmented_F_circuit: AugmentedFCircuit; if self.z_i.len() != self.F.state_len() { return Err(Error::NotSameLength( @@ -896,8 +868,7 @@ where // cyclefold circuit for enforcing: // 0 + U_i.phi * L_evals[0] == phi_stars[0] - let cf1_circuit = ProtoGalaxyCycleFoldCircuit:: { - _gc: PhantomData, + let cf1_circuit = ProtoGalaxyCycleFoldCircuit:: { r_bits: Some(r0_bits), points: Some(vec![C1::zero(), self.U_i.phi]), }; @@ -905,14 +876,13 @@ where // cyclefold circuit for enforcing: // phi_stars[0] + u_i.phi * L_evals[1] == U_i1.phi // i.e., U_i.phi * L_evals[0] + u_i.phi * L_evals[1] == U_i1.phi - let cf2_circuit = ProtoGalaxyCycleFoldCircuit:: { - _gc: PhantomData, + let cf2_circuit = ProtoGalaxyCycleFoldCircuit:: { r_bits: Some(r1_bits), points: Some(vec![aux.phi_stars[0], self.u_i.phi]), }; // fold self.cf_U_i + cf1_U -> folded running with cf1 - let (_cf1_w_i, cf1_u_i, cf1_W_i1, cf1_U_i1, cf1_cmT, _) = self.fold_cyclefold_circuit( + let (cf1_u_i, cf1_W_i1, cf1_U_i1, cf1_cmT) = self.fold_cyclefold_circuit( &mut transcript_prover, self.cf_W_i.clone(), // CycleFold running instance witness self.cf_U_i.clone(), // CycleFold running instance @@ -920,7 +890,7 @@ where &mut rng, )?; // fold [the output from folding self.cf_U_i + cf1_U] + cf2_U = folded_running_with_cf1 + cf2 - let (_cf2_w_i, cf2_u_i, cf_W_i1, cf_U_i1, cf2_cmT, _) = self.fold_cyclefold_circuit( + let (cf2_u_i, cf_W_i1, cf_U_i1, cf2_cmT) = self.fold_cyclefold_circuit( &mut transcript_prover, cf1_W_i1, cf1_U_i1.clone(), @@ -929,7 +899,6 @@ where )?; augmented_F_circuit = AugmentedFCircuit { - _gc2: PhantomData, poseidon_config: self.poseidon_config.clone(), pp_hash: self.pp_hash, i: self.i, @@ -964,11 +933,6 @@ where )?, U_i1 ); - cf1_u_i.check_incoming()?; - cf2_u_i.check_incoming()?; - self.cf_r1cs.check_relation(&_cf1_w_i, &cf1_u_i)?; - self.cf_r1cs.check_relation(&_cf2_w_i, &cf2_u_i)?; - self.cf_r1cs.check_relation(&self.cf_W_i, &self.cf_U_i)?; } self.W_i = W_i1; @@ -1049,9 +1013,6 @@ where let f_circuit = FC::new(fcircuit_params)?; Ok(Self { - _gc1: PhantomData, - _c2: PhantomData, - _gc2: PhantomData, r1cs: vp.r1cs.clone(), cf_r1cs: vp.cf_r1cs.clone(), poseidon_config: pp.poseidon_config, @@ -1119,20 +1080,13 @@ where } } -impl ProtoGalaxy +impl ProtoGalaxy where - C1: CurveGroup, - GC1: CurveVar>, - C2: CurveGroup, - GC2: CurveVar>, + C1: Curve, + C2: Curve, FC: FCircuit, CS1: CommitmentScheme, CS2: CommitmentScheme, - ::BaseField: PrimeField, - ::BaseField: PrimeField, - C1::ScalarField: Absorb, - C2::ScalarField: Absorb, - C1: CurveGroup, { // folds the given cyclefold circuit and its instances #[allow(clippy::type_complexity)] @@ -1141,20 +1095,18 @@ where transcript: &mut PoseidonSponge, cf_W_i: CycleFoldWitness, // witness of the running instance cf_U_i: CycleFoldCommittedInstance, // running instance - cf_circuit: ProtoGalaxyCycleFoldCircuit, + cf_circuit: ProtoGalaxyCycleFoldCircuit, rng: &mut impl RngCore, ) -> Result< ( - CycleFoldWitness, CycleFoldCommittedInstance, // u_i CycleFoldWitness, // W_i1 CycleFoldCommittedInstance, // U_i1 C2, // cmT - C2::ScalarField, // r_Fq ), Error, > { - fold_cyclefold_circuit::, C1, GC1, C2, GC2, CS2, false>( + fold_cyclefold_circuit::, C2, CS2, false>( transcript, self.cf_r1cs.clone(), self.cf_cs_params.clone(), @@ -1171,8 +1123,8 @@ where mod tests { use super::*; - use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as Projective}; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as Projective2}; + use ark_bn254::{Bn254, Fr, G1Projective as Projective}; + use ark_grumpkin::Projective as Projective2; use ark_std::test_rng; use rayon::prelude::*; @@ -1206,8 +1158,7 @@ mod tests { poseidon_config: PoseidonConfig, F_circuit: CubicFCircuit, ) -> Result<(), Error> { - type PG = - ProtoGalaxy, CS1, CS2>; + type PG = ProtoGalaxy, CS1, CS2>; let params = PG::::preprocess(&mut test_rng(), &(poseidon_config, F_circuit))?; @@ -1241,7 +1192,7 @@ mod tests { .into_par_iter() .map(|t| { let cs = ConstraintSystem::::new_ref(); - AugmentedFCircuit::::empty( + AugmentedFCircuit::::empty( &poseidon_config, dummy_circuit.clone(), t, diff --git a/folding-schemes/src/folding/protogalaxy/traits.rs b/folding-schemes/src/folding/protogalaxy/traits.rs index a4c8ee87..5cf83787 100644 --- a/folding-schemes/src/folding/protogalaxy/traits.rs +++ b/folding-schemes/src/folding/protogalaxy/traits.rs @@ -1,8 +1,6 @@ use ark_crypto_primitives::sponge::{constraints::AbsorbGadget, Absorb}; -use ark_ec::CurveGroup; use ark_ff::PrimeField; use ark_r1cs_std::{ - convert::ToConstraintFieldGadget, eq::EqGadget, fields::{fp::FpVar, FieldVar}, uint8::UInt8, @@ -22,24 +20,19 @@ use crate::{ Arith, ArithGadget, }, folding::circuits::CF1, - transcript::AbsorbNonNative, + transcript::AbsorbNonNativeGadget, utils::vec::is_zero_vec, - Error, + Curve, Error, }; // Implements the trait for absorbing ProtoGalaxy's CommittedInstance. -impl Absorb for CommittedInstance -where - C::ScalarField: Absorb, -{ +impl Absorb for CommittedInstance { fn to_sponge_bytes(&self, dest: &mut Vec) { C::ScalarField::batch_to_sponge_bytes(&self.to_sponge_field_elements_as_vec(), dest); } fn to_sponge_field_elements(&self, dest: &mut Vec) { - self.phi - .to_native_sponge_field_elements_as_vec() - .to_sponge_field_elements(dest); + self.phi.to_native_sponge_field_elements(dest); self.betas.to_sponge_field_elements(dest); self.e.to_sponge_field_elements(dest); self.x.to_sponge_field_elements(dest); @@ -47,16 +40,14 @@ where } // Implements the trait for absorbing ProtoGalaxy's CommittedInstanceVar in-circuit. -impl AbsorbGadget - for CommittedInstanceVar -{ +impl AbsorbGadget for CommittedInstanceVar { fn to_sponge_bytes(&self) -> Result>, SynthesisError> { FpVar::batch_to_sponge_bytes(&self.to_sponge_field_elements()?) } fn to_sponge_field_elements(&self) -> Result>, SynthesisError> { Ok([ - self.phi.to_constraint_field()?, + self.phi.to_native_sponge_field_elements()?, self.betas.to_sponge_field_elements()?, self.e.to_sponge_field_elements()?, self.x.to_sponge_field_elements()?, @@ -72,7 +63,7 @@ impl AbsorbGadget /// relaxed R1CS. /// /// See `nova/traits.rs` for the rationale behind the design. -impl Arith>, CommittedInstance> +impl Arith>, CommittedInstance> for R1CS> { type Evaluation = Vec>; @@ -113,7 +104,7 @@ impl Arith>, CommittedInstance ArithGadget>, CommittedInstanceVar> +impl ArithGadget>, CommittedInstanceVar> for R1CSMatricesVar, FpVar>> { type Evaluation = (Vec>>, Vec>>); diff --git a/folding-schemes/src/folding/traits.rs b/folding-schemes/src/folding/traits.rs index 20ce1924..74ab3b28 100644 --- a/folding-schemes/src/folding/traits.rs +++ b/folding-schemes/src/folding/traits.rs @@ -3,16 +3,18 @@ use ark_crypto_primitives::sponge::{ poseidon::constraints::PoseidonSpongeVar, Absorb, }; -use ark_ec::CurveGroup; use ark_ff::PrimeField; -use ark_r1cs_std::{alloc::AllocVar, convert::ToConstraintFieldGadget, fields::fp::FpVar}; +use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar}; use ark_relations::r1cs::SynthesisError; -use crate::{transcript::Transcript, Error}; +use crate::{ + transcript::{AbsorbNonNativeGadget, Transcript}, + Curve, Error, +}; use super::circuits::CF1; -pub trait CommittedInstanceOps: Inputize, Self::Var> { +pub trait CommittedInstanceOps: Inputize> { /// The in-circuit representation of the committed instance. type Var: AllocVar> + CommittedInstanceVarOps; /// `hash` implements the committed instance hash compatible with the @@ -29,7 +31,6 @@ pub trait CommittedInstanceOps: Inputize, Self::Var> { z_i: &[CF1], ) -> CF1 where - CF1: Absorb, Self: Sized + Absorb, { let mut sponge = sponge.clone(); @@ -56,8 +57,8 @@ pub trait CommittedInstanceOps: Inputize, Self::Var> { } } -pub trait CommittedInstanceVarOps { - type PointVar: ToConstraintFieldGadget>; +pub trait CommittedInstanceVarOps { + type PointVar: AbsorbNonNativeGadget>; /// `hash` implements the in-circuit committed instance hash compatible with /// the native implementation from `CommittedInstanceOps::hash`. /// Returns `H(i, z_0, z_i, U_i)`, where `i` can be `i` but also `i+1`, and @@ -141,8 +142,37 @@ impl Dummy<()> for T { } /// Converts a value `self` into a vector of field elements, ordered in the same -/// way as how a variable of type `Var` would be represented in the circuit. +/// way as how a variable of type `Var` would be represented *natively* in the +/// circuit. +/// /// This is useful for the verifier to compute the public inputs. -pub trait Inputize { +pub trait Inputize { fn inputize(&self) -> Vec; } + +/// Converts a value `self` into a vector of field elements, ordered in the same +/// way as how a variable of type `Var` would be represented *non-natively* in +/// the circuit. +/// +/// This is useful for the verifier to compute the public inputs. +/// +/// Note that we require this trait because we need to distinguish between some +/// data types that are represented both natively and non-natively in-circuit +/// (e.g., field elements can have type `FpVar` and `NonNativeUintVar`). +pub trait InputizeNonNative { + fn inputize_nonnative(&self) -> Vec; +} + +impl> Inputize for [T] { + fn inputize(&self) -> Vec { + self.iter().flat_map(Inputize::::inputize).collect() + } +} + +impl> InputizeNonNative for [T] { + fn inputize_nonnative(&self) -> Vec { + self.iter() + .flat_map(InputizeNonNative::::inputize_nonnative) + .collect() + } +} diff --git a/folding-schemes/src/frontend/utils.rs b/folding-schemes/src/frontend/utils.rs index d296301f..e4d3d749 100644 --- a/folding-schemes/src/frontend/utils.rs +++ b/folding-schemes/src/frontend/utils.rs @@ -3,7 +3,7 @@ use ark_r1cs_std::{ alloc::AllocVar, fields::{fp::FpVar, FieldVar}, }; -use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; +use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; use ark_std::marker::PhantomData; use ark_std::{fmt::Debug, Zero}; @@ -147,11 +147,7 @@ pub struct WrapperCircuit> { pub z_i1: Option>, } -impl ark_relations::r1cs::ConstraintSynthesizer for WrapperCircuit -where - F: PrimeField, - FC: FCircuit, -{ +impl> ConstraintSynthesizer for WrapperCircuit { fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { let z_i = Vec::>::new_witness(cs.clone(), || Ok(self.z_i.unwrap_or(vec![F::zero()])))?; diff --git a/folding-schemes/src/lib.rs b/folding-schemes/src/lib.rs index 2db8f711..aeb97c41 100644 --- a/folding-schemes/src/lib.rs +++ b/folding-schemes/src/lib.rs @@ -2,14 +2,27 @@ #![allow(non_upper_case_globals)] #![allow(non_camel_case_types)] -use ark_ec::{pairing::Pairing, CurveGroup}; -use ark_ff::PrimeField; +use ark_crypto_primitives::sponge::Absorb; +use ark_ec::{ + pairing::Pairing, + short_weierstrass::{Projective, SWCurveConfig}, + CurveGroup, +}; +use ark_ff::{Fp, FpConfig, PrimeField}; +use ark_r1cs_std::{ + fields::{fp::FpVar, FieldVar}, + groups::{curves::short_weierstrass::ProjectiveVar, CurveVar}, +}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; -use ark_std::rand::CryptoRng; -use ark_std::{fmt::Debug, rand::RngCore}; +use ark_std::{ + fmt::Debug, + rand::{CryptoRng, RngCore}, +}; use thiserror::Error; +use crate::folding::traits::{Inputize, InputizeNonNative}; use crate::frontend::FCircuit; +use crate::transcript::AbsorbNonNative; pub mod arith; pub mod commitment; @@ -131,11 +144,11 @@ pub enum Error { /// coordinates) are in the C1::ScalarField. /// /// In other words, C1.Fq == C2.Fr, and C1.Fr == C2.Fq. -pub trait FoldingScheme: Clone + Debug -where - C1: CurveGroup, - C2::BaseField: PrimeField, +pub trait FoldingScheme< + C1: Curve, + C2: Curve, FC: FCircuit, +>: Clone + Debug { type PreprocessorParam: Debug + Clone; type ProverParam: Debug + Clone + CanonicalSerialize; @@ -209,11 +222,11 @@ where /// Trait with auxiliary methods for multi-folding schemes (ie. HyperNova, ProtoGalaxy, etc), /// allowing to create new instances for the multifold. -pub trait MultiFolding: Clone + Debug -where - C1: CurveGroup, - C2::BaseField: PrimeField, +pub trait MultiFolding< + C1: Curve, + C2: Curve, FC: FCircuit, +>: Clone + Debug { type RunningInstance: Debug; type IncomingInstance: Debug; @@ -237,13 +250,11 @@ where } pub trait Decider< - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, FC: FCircuit, FS: FoldingScheme, -> where - C1: CurveGroup, - C2::BaseField: PrimeField, +> { type PreprocessorParam: Debug; type ProverParam: Clone; @@ -278,10 +289,11 @@ pub trait Decider< } /// DeciderOnchain extends the Decider into preparing the calldata -pub trait DeciderOnchain -where - C1: CurveGroup, - C2::BaseField: PrimeField, +pub trait DeciderOnchain< + E: Pairing, + C1: Curve, + C2: Curve, +> { type Proof; type CommittedInstance: Clone + Debug; @@ -295,3 +307,32 @@ where proof: Self::Proof, ) -> Result, Error>; } + +/// `Field` trait is a wrapper around `PrimeField` that also includes the +/// necessary bounds for the field to be used conveniently in folding schemes. +pub trait Field: + PrimeField + Absorb + AbsorbNonNative + Inputize +{ + /// The in-circuit variable type for this field. + type Var: FieldVar; +} + +impl, const N: usize> Field for Fp { + type Var = FpVar; +} + +/// `Curve` trait is a wrapper around `CurveGroup` that also includes the +/// necessary bounds for the curve to be used conveniently in folding schemes. +pub trait Curve: + CurveGroup + + AbsorbNonNative + + Inputize + + InputizeNonNative +{ + /// The in-circuit variable type for this curve. + type Var: CurveVar; +} + +impl> Curve for Projective

{ + type Var = ProjectiveVar>; +} diff --git a/folding-schemes/src/transcript/mod.rs b/folding-schemes/src/transcript/mod.rs index 806a500a..de3a0572 100644 --- a/folding-schemes/src/transcript/mod.rs +++ b/folding-schemes/src/transcript/mod.rs @@ -9,14 +9,14 @@ pub mod poseidon; /// An interface for objects that can be absorbed by a `Transcript`. /// /// Matches `Absorb` in `ark-crypto-primitives`. -pub trait AbsorbNonNative { +pub trait AbsorbNonNative { /// Converts the object into field elements that can be absorbed by a `Transcript`. /// Append the list to `dest` - fn to_native_sponge_field_elements(&self, dest: &mut Vec); + fn to_native_sponge_field_elements(&self, dest: &mut Vec); /// Converts the object into field elements that can be absorbed by a `Transcript`. /// Return the list as `Vec` - fn to_native_sponge_field_elements_as_vec(&self) -> Vec { + fn to_native_sponge_field_elements_as_vec(&self) -> Vec { let mut result = Vec::new(); self.to_native_sponge_field_elements(&mut result); result @@ -32,6 +32,30 @@ pub trait AbsorbNonNativeGadget { fn to_native_sponge_field_elements(&self) -> Result>, SynthesisError>; } +impl AbsorbNonNative for [T] { + fn to_native_sponge_field_elements(&self, dest: &mut Vec) { + for t in self.iter() { + t.to_native_sponge_field_elements(dest); + } + } +} + +impl> AbsorbNonNativeGadget for &T { + fn to_native_sponge_field_elements(&self) -> Result>, SynthesisError> { + T::to_native_sponge_field_elements(self) + } +} + +impl> AbsorbNonNativeGadget for [T] { + fn to_native_sponge_field_elements(&self) -> Result>, SynthesisError> { + let mut result = Vec::new(); + for t in self.iter() { + result.extend(t.to_native_sponge_field_elements()?); + } + Ok(result) + } +} + pub trait Transcript: CryptographicSponge { /// `absorb_point` is for absorbing points whose `BaseField` is the field of /// the sponge, i.e., the type `C` of these points should satisfy @@ -55,7 +79,7 @@ pub trait Transcript: CryptographicSponge { /// Note that although a `CommittedInstance` for `AugmentedFCircuit` on /// the primary curve also contains non-native elements, we still regard /// it as native, because the sponge is on the same curve. - fn absorb_nonnative>(&mut self, v: &V); + fn absorb_nonnative(&mut self, v: &V); fn get_challenge(&mut self) -> F; /// get_challenge_nbits returns a field element of size nbits diff --git a/folding-schemes/src/transcript/poseidon.rs b/folding-schemes/src/transcript/poseidon.rs index 10a5c30d..90709757 100644 --- a/folding-schemes/src/transcript/poseidon.rs +++ b/folding-schemes/src/transcript/poseidon.rs @@ -17,8 +17,8 @@ impl Transcript for PoseidonSponge { self.absorb(&x); self.absorb(&y); } - fn absorb_nonnative>(&mut self, v: &V) { - self.absorb(&v.to_native_sponge_field_elements_as_vec()); + fn absorb_nonnative(&mut self, v: &V) { + self.absorb(&v.to_native_sponge_field_elements_as_vec::()); } fn get_challenge(&mut self) -> F { let c = self.squeeze_field_elements(1); diff --git a/folding-schemes/src/utils/espresso/sum_check/mod.rs b/folding-schemes/src/utils/espresso/sum_check/mod.rs index 31a71fe2..2d472250 100644 --- a/folding-schemes/src/utils/espresso/sum_check/mod.rs +++ b/folding-schemes/src/utils/espresso/sum_check/mod.rs @@ -59,10 +59,7 @@ pub trait SumCheck { } /// Trait for sum check protocol prover side APIs. -pub trait SumCheckProver -where - Self: Sized, -{ +pub trait SumCheckProver: Sized { type VirtualPolynomial; type ProverMessage; diff --git a/folding-schemes/src/utils/eth.rs b/folding-schemes/src/utils/eth.rs new file mode 100644 index 00000000..765d493f --- /dev/null +++ b/folding-schemes/src/utils/eth.rs @@ -0,0 +1,58 @@ +//! This module provides a trait and implementations for converting Rust types +//! to EVM calldata. +use ark_ec::{ + pairing::Pairing, + short_weierstrass::{Affine, Projective, SWCurveConfig}, + AffineRepr, CurveGroup, +}; +use ark_ff::{BigInteger, Fp, Fp2, Fp2Config, FpConfig, PrimeField}; +use ark_groth16::Proof; + +pub trait ToEth { + fn to_eth(&self) -> Vec; +} + +impl ToEth for [T] { + fn to_eth(&self) -> Vec { + self.iter().flat_map(ToEth::to_eth).collect() + } +} + +impl ToEth for u8 { + fn to_eth(&self) -> Vec { + vec![*self] + } +} + +impl, const N: usize> ToEth for Fp { + fn to_eth(&self) -> Vec { + self.into_bigint().to_bytes_be() + } +} + +impl> ToEth for Fp2

{ + fn to_eth(&self) -> Vec { + [self.c1.to_eth(), self.c0.to_eth()].concat() + } +} + +impl> ToEth for Affine

{ + fn to_eth(&self) -> Vec { + // the encoding of the additive identity is [0, 0] on the EVM + let (x, y) = self.xy().unwrap_or_default(); + + [x.to_eth(), y.to_eth()].concat() + } +} + +impl> ToEth for Projective

{ + fn to_eth(&self) -> Vec { + self.into_affine().to_eth() + } +} + +impl> ToEth for Proof { + fn to_eth(&self) -> Vec { + [self.a.to_eth(), self.b.to_eth(), self.c.to_eth()].concat() + } +} diff --git a/folding-schemes/src/utils/gadgets.rs b/folding-schemes/src/utils/gadgets.rs index e18a9e9d..7f0f7797 100644 --- a/folding-schemes/src/utils/gadgets.rs +++ b/folding-schemes/src/utils/gadgets.rs @@ -71,11 +71,8 @@ pub struct SparseMatrixVar { pub coeffs: Vec>, } -impl AllocVar, CF> for SparseMatrixVar -where - F: PrimeField, - CF: PrimeField, - FV: AllocVar, +impl> AllocVar, CF> + for SparseMatrixVar { fn new_variable>>( cs: impl Into>, diff --git a/folding-schemes/src/utils/mod.rs b/folding-schemes/src/utils/mod.rs index 1d932711..566ca0d3 100644 --- a/folding-schemes/src/utils/mod.rs +++ b/folding-schemes/src/utils/mod.rs @@ -2,15 +2,16 @@ use std::path::Path; use std::path::PathBuf; use ark_crypto_primitives::sponge::poseidon::PoseidonConfig; -use ark_ec::{AffineRepr, CurveGroup}; +use ark_ec::AffineRepr; use ark_ff::PrimeField; use ark_serialize::CanonicalSerialize; use sha3::{Digest, Sha3_256}; use crate::arith::ArithSerializer; use crate::commitment::CommitmentScheme; -use crate::Error; +use crate::{Curve, Error}; +pub mod eth; pub mod gadgets; pub mod hypercube; pub mod lagrange_poly; @@ -35,7 +36,7 @@ pub fn powers_of(x: F, n: usize) -> Vec { /// returns the coordinates of a commitment point. This is compatible with the arkworks /// GC.to_constraint_field()[..2] -pub fn get_cm_coordinates(cm: &C) -> Vec { +pub fn get_cm_coordinates(cm: &C) -> Vec { let (cm_x, cm_y) = cm.into_affine().xy().unwrap_or_default(); vec![cm_x, cm_y] } @@ -49,8 +50,8 @@ pub fn pp_hash( poseidon_config: &PoseidonConfig, ) -> Result where - C1: CurveGroup, - C2: CurveGroup, + C1: Curve, + C2: Curve, CS1: CommitmentScheme, CS2: CommitmentScheme, { diff --git a/solidity-verifiers/src/verifiers/nova_cyclefold.rs b/solidity-verifiers/src/verifiers/nova_cyclefold.rs index 1286fd81..95a9b794 100644 --- a/solidity-verifiers/src/verifiers/nova_cyclefold.rs +++ b/solidity-verifiers/src/verifiers/nova_cyclefold.rs @@ -139,10 +139,10 @@ impl NovaCycleFoldVerifierKey { #[cfg(test)] mod tests { - use ark_bn254::{constraints::GVar, Bn254, Fr, G1Projective as G1}; + use ark_bn254::{Bn254, Fr, G1Projective as G1}; use ark_ff::PrimeField; use ark_groth16::Groth16; - use ark_grumpkin::{constraints::GVar as GVar2, Projective as G2}; + use ark_grumpkin::Projective as G2; use ark_r1cs_std::alloc::AllocVar; use ark_r1cs_std::fields::fp::FpVar; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; @@ -174,18 +174,9 @@ mod tests { NovaCycleFoldVerifierKey, ProtocolVerifierKey, }; - type NOVA = Nova, Pedersen, false>; - type DECIDER = DeciderEth< - G1, - GVar, - G2, - GVar2, - FC, - KZG<'static, Bn254>, - Pedersen, - Groth16, - NOVA, - >; + type NOVA = Nova, Pedersen, false>; + type DECIDER = + DeciderEth, Pedersen, Groth16, NOVA>; type FS_PP = as FoldingScheme>::ProverParam; type FS_VP = as FoldingScheme>::VerifierParam; From c6f1a246e0705582a75de6becf4ad21f325fa5a1 Mon Sep 17 00:00:00 2001 From: arnaucube Date: Fri, 27 Dec 2024 15:38:56 +0100 Subject: [PATCH 2/2] Update the FCircuit trait, so that it supports custom data structures for the external inputs. (#191) * Update the FCircuit trait, so that it supports custom data structures for the external inputs. This also eliminates the need of having the `external_inputs_len` method in the `FCircuit`. The motivation for this change is that in most practical use cases, the external inputs have a not-naive structure, and the old interface required that to convert the external inputs structure into a vector of finite field elements, which inside the FCircuit would be converted back into a custom data structure. This is specially tedious when dealing with curve points, which converting them from point to field elements and back to the point (both outside (rust native) and inside the circuit (constraints)) is a bit cumbersome. With this update, it's much more straight forward to define the FCircuit with custom external inputs data structures. For the experimental-frontends, the external inputs keep being an array of field elements. * remove Default from FCircuit::ExternalInputsVar, remove VecF & VecFpVar in examples/external_inputs.rs --- .gitignore | 4 +- benches/common.rs | 4 +- examples/circom_full_flow.rs | 14 +-- examples/external_inputs.rs | 22 ++--- examples/full_flow.rs | 10 +-- examples/multi_inputs.rs | 11 ++- examples/noir_full_flow.rs | 21 +++-- examples/noname_full_flow.rs | 20 +++-- examples/sha256.rs | 11 ++- experimental-frontends/src/circom/mod.rs | 59 +++++++------ experimental-frontends/src/lib.rs | 1 + experimental-frontends/src/noir/mod.rs | 56 ++++++------ experimental-frontends/src/noname/mod.rs | 61 ++++++------- experimental-frontends/src/utils.rs | 38 +++++++++ .../src/folding/circuits/nonnative/uint.rs | 4 +- .../src/folding/hypernova/circuits.rs | 14 ++- .../src/folding/hypernova/decider_eth.rs | 8 +- .../folding/hypernova/decider_eth_circuit.rs | 2 +- folding-schemes/src/folding/hypernova/mod.rs | 22 ++--- folding-schemes/src/folding/mod.rs | 6 +- folding-schemes/src/folding/nova/circuits.rs | 8 +- folding-schemes/src/folding/nova/decider.rs | 4 +- .../src/folding/nova/decider_circuits.rs | 2 +- .../src/folding/nova/decider_eth.rs | 8 +- .../src/folding/nova/decider_eth_circuit.rs | 2 +- folding-schemes/src/folding/nova/mod.rs | 14 +-- .../src/folding/protogalaxy/circuits.rs | 6 +- .../src/folding/protogalaxy/decider_eth.rs | 12 +-- .../protogalaxy/decider_eth_circuit.rs | 2 +- .../src/folding/protogalaxy/mod.rs | 85 ++++++++----------- folding-schemes/src/frontend/mod.rs | 14 +-- folding-schemes/src/frontend/utils.rs | 41 ++++----- folding-schemes/src/lib.rs | 6 +- solidity-verifiers/Cargo.toml | 4 +- .../src/verifiers/nova_cyclefold.rs | 17 ++-- 35 files changed, 319 insertions(+), 294 deletions(-) create mode 100644 experimental-frontends/src/utils.rs diff --git a/.gitignore b/.gitignore index e2e3afdc..d3ba383d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,12 +2,12 @@ Cargo.lock # Circom generated files -frontends/src/circom/test_folder/*_js/ +experimental-frontends/src/circom/test_folder/*_js/ *.r1cs *.sym # Noir generated files -frontends/src/noir/test_folder/*/target/* +experimental-frontends/src/noir/test_folder/*/target/* # generated contracts data solidity-verifiers/generated diff --git a/benches/common.rs b/benches/common.rs index 6c632b4b..163dbbfc 100644 --- a/benches/common.rs +++ b/benches/common.rs @@ -29,7 +29,7 @@ pub(crate) fn bench_ivc_opt< // warmup steps for _ in 0..5 { - fs.prove_step(rng, vec![], None)?; + fs.prove_step(rng, (), None)?; } let mut group = c.benchmark_group(format!( @@ -38,7 +38,7 @@ pub(crate) fn bench_ivc_opt< )); group.significance_level(0.1).sample_size(10); group.bench_function("prove_step", |b| { - b.iter(|| -> Result<_, _> { black_box(fs.clone()).prove_step(rng, vec![], None) }) + b.iter(|| -> Result<_, _> { black_box(fs.clone()).prove_step(rng, (), None) }) }); // verify the IVCProof diff --git a/examples/circom_full_flow.rs b/examples/circom_full_flow.rs index b0d92fb2..67aaad43 100644 --- a/examples/circom_full_flow.rs +++ b/examples/circom_full_flow.rs @@ -17,7 +17,7 @@ use ark_grumpkin::Projective as G2; use std::path::PathBuf; use std::time::Instant; -use experimental_frontends::circom::CircomFCircuit; +use experimental_frontends::{circom::CircomFCircuit, utils::VecF}; use folding_schemes::{ commitment::{kzg::KZG, pedersen::Pedersen}, folding::{ @@ -64,14 +64,16 @@ fn main() -> Result<(), Error> { "./experimental-frontends/src/circom/test_folder/with_external_inputs_js/with_external_inputs.wasm", ); - let f_circuit_params = (r1cs_path.into(), wasm_path.into(), 1, 2); - let f_circuit = CircomFCircuit::::new(f_circuit_params)?; + let f_circuit_params = (r1cs_path.into(), wasm_path.into(), 1); // state len = 1 + const EXT_INP_LEN: usize = 2; // external inputs len = 2 + let f_circuit = CircomFCircuit::::new(f_circuit_params)?; - pub type N = Nova, KZG<'static, Bn254>, Pedersen, false>; + pub type N = + Nova, KZG<'static, Bn254>, Pedersen, false>; pub type D = DeciderEth< G1, G2, - CircomFCircuit, + CircomFCircuit, KZG<'static, Bn254>, Pedersen, Groth16, @@ -94,7 +96,7 @@ fn main() -> Result<(), Error> { // run n steps of the folding iteration for (i, external_inputs_at_step) in external_inputs.iter().enumerate() { let start = Instant::now(); - nova.prove_step(rng, external_inputs_at_step.clone(), None)?; + nova.prove_step(rng, VecF(external_inputs_at_step.clone()), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/examples/external_inputs.rs b/examples/external_inputs.rs index 60427b00..79ebc86c 100644 --- a/examples/external_inputs.rs +++ b/examples/external_inputs.rs @@ -74,6 +74,8 @@ where F: Absorb, { type Params = PoseidonConfig; + type ExternalInputs = [F; 1]; + type ExternalInputsVar = [FpVar; 1]; fn new(params: Self::Params) -> Result { Ok(Self { @@ -84,9 +86,6 @@ where fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 1 - } /// generates the constraints and returns the next state value for the step of F for the given /// z_i and external_inputs fn generate_step_constraints( @@ -94,7 +93,7 @@ where cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - external_inputs: Vec>, + external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let crh_params = CRHParametersVar::::new_constant(cs.clone(), self.poseidon_config.clone())?; @@ -137,7 +136,10 @@ pub mod tests { external_inputs_step_native(z_i.clone(), external_inputs.clone(), &poseidon_config); let z_iVar = Vec::>::new_witness(cs.clone(), || Ok(z_i))?; - let external_inputsVar = Vec::>::new_witness(cs.clone(), || Ok(external_inputs))?; + let external_inputsVar: [FpVar; 1] = + Vec::>::new_witness(cs.clone(), || Ok(external_inputs))? + .try_into() + .unwrap(); let computed_z_i1Var = circuit.generate_step_constraints(cs.clone(), 0, z_iVar, external_inputsVar)?; @@ -153,11 +155,11 @@ fn main() -> Result<(), Error> { // prepare the external inputs to be used at each folding step let external_inputs = vec![ - vec![Fr::from(3_u32)], - vec![Fr::from(33_u32)], - vec![Fr::from(73_u32)], - vec![Fr::from(103_u32)], - vec![Fr::from(125_u32)], + [Fr::from(3_u32)], + [Fr::from(33_u32)], + [Fr::from(73_u32)], + [Fr::from(103_u32)], + [Fr::from(125_u32)], ]; assert_eq!(external_inputs.len(), num_steps); diff --git a/examples/full_flow.rs b/examples/full_flow.rs index 648171f0..4d84bd01 100644 --- a/examples/full_flow.rs +++ b/examples/full_flow.rs @@ -46,21 +46,21 @@ pub struct CubicFCircuit { } impl FCircuit for CubicFCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); + fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) } fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 0 - } fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let five = FpVar::::new_constant(cs.clone(), F::from(5u32))?; let z_i = z_i[0].clone(); @@ -96,7 +96,7 @@ fn main() -> Result<(), Error> { // run n steps of the folding iteration for i in 0..n_steps { let start = Instant::now(); - nova.prove_step(rng, vec![], None)?; + nova.prove_step(rng, (), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/examples/multi_inputs.rs b/examples/multi_inputs.rs index 67b32cf4..ff56bd9d 100644 --- a/examples/multi_inputs.rs +++ b/examples/multi_inputs.rs @@ -30,6 +30,8 @@ pub struct MultiInputsFCircuit { } impl FCircuit for MultiInputsFCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) @@ -37,16 +39,13 @@ impl FCircuit for MultiInputsFCircuit { fn state_len(&self) -> usize { 5 } - fn external_inputs_len(&self) -> usize { - 0 - } /// generates the constraints for the step of F for the given z_i fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let four = FpVar::::new_constant(cs.clone(), F::from(4u32))?; let forty = FpVar::::new_constant(cs.clone(), F::from(40u32))?; @@ -96,7 +95,7 @@ pub mod tests { let z_iVar = Vec::>::new_witness(cs.clone(), || Ok(z_i))?; let computed_z_i1Var = - circuit.generate_step_constraints(cs.clone(), 0, z_iVar.clone(), vec![])?; + circuit.generate_step_constraints(cs.clone(), 0, z_iVar.clone(), ())?; assert_eq!(computed_z_i1Var.value()?, z_i1); Ok(()) } @@ -140,7 +139,7 @@ fn main() -> Result<(), Error> { // compute a step of the IVC for i in 0..num_steps { let start = Instant::now(); - folding_scheme.prove_step(rng, vec![], None)?; + folding_scheme.prove_step(rng, (), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/examples/noir_full_flow.rs b/examples/noir_full_flow.rs index 147903e1..17c1f919 100644 --- a/examples/noir_full_flow.rs +++ b/examples/noir_full_flow.rs @@ -14,7 +14,7 @@ use ark_bn254::{Bn254, Fr, G1Projective as G1}; use ark_groth16::Groth16; use ark_grumpkin::Projective as G2; -use experimental_frontends::noir::NoirFCircuit; +use experimental_frontends::{noir::NoirFCircuit, utils::VecF}; use folding_schemes::{ commitment::{kzg::KZG, pedersen::Pedersen}, folding::{ @@ -42,16 +42,23 @@ fn main() -> Result<(), Error> { let z_0 = vec![Fr::from(1)]; // initialize the noir fcircuit - let f_circuit = NoirFCircuit::new(( + const EXT_INP_LEN: usize = 0; + let f_circuit = NoirFCircuit::::new(( Path::new("./experimental-frontends/src/noir/test_folder/test_mimc/target/test_mimc.json") .into(), 1, - 0, ))?; - pub type N = Nova, KZG<'static, Bn254>, Pedersen>; - pub type D = - DeciderEth, KZG<'static, Bn254>, Pedersen, Groth16, N>; + pub type N = Nova, KZG<'static, Bn254>, Pedersen>; + pub type D = DeciderEth< + G1, + G2, + NoirFCircuit, + KZG<'static, Bn254>, + Pedersen, + Groth16, + N, + >; let poseidon_config = poseidon_canonical_config::(); let mut rng = ark_std::rand::rngs::OsRng; @@ -69,7 +76,7 @@ fn main() -> Result<(), Error> { // run n steps of the folding iteration for i in 0..5 { let start = Instant::now(); - nova.prove_step(rng, vec![], None)?; + nova.prove_step(rng, VecF(vec![]), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } // verify the last IVC proof diff --git a/examples/noname_full_flow.rs b/examples/noname_full_flow.rs index 6bfb80bd..e42244ef 100644 --- a/examples/noname_full_flow.rs +++ b/examples/noname_full_flow.rs @@ -15,7 +15,7 @@ use noname::backends::r1cs::R1csBn254Field; use ark_groth16::Groth16; use ark_grumpkin::Projective as G2; -use experimental_frontends::noname::NonameFCircuit; +use experimental_frontends::{noname::NonameFCircuit, utils::VecF}; use folding_schemes::{ commitment::{kzg::KZG, pedersen::Pedersen}, folding::{ @@ -58,15 +58,21 @@ fn main() -> Result<(), Error> { ]; // initialize the noname circuit - let f_circuit_params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2, 2); - let f_circuit = NonameFCircuit::::new(f_circuit_params)?; + let f_circuit_params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2); // state len = 2 + const EXT_INP_LEN: usize = 2; + let f_circuit = NonameFCircuit::::new(f_circuit_params)?; - pub type N = - Nova, KZG<'static, Bn254>, Pedersen>; + pub type N = Nova< + G1, + G2, + NonameFCircuit, + KZG<'static, Bn254>, + Pedersen, + >; pub type D = DeciderEth< G1, G2, - NonameFCircuit, + NonameFCircuit, KZG<'static, Bn254>, Pedersen, Groth16, @@ -89,7 +95,7 @@ fn main() -> Result<(), Error> { // run n steps of the folding iteration for (i, external_inputs_at_step) in external_inputs.iter().enumerate() { let start = Instant::now(); - nova.prove_step(rng, external_inputs_at_step.clone(), None)?; + nova.prove_step(rng, VecF(external_inputs_at_step.clone()), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/examples/sha256.rs b/examples/sha256.rs index 95f75d16..22a5a104 100644 --- a/examples/sha256.rs +++ b/examples/sha256.rs @@ -36,6 +36,8 @@ pub struct Sha256FCircuit { } impl FCircuit for Sha256FCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) @@ -43,16 +45,13 @@ impl FCircuit for Sha256FCircuit { fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 0 - } /// generates the constraints for the step of F for the given z_i fn generate_step_constraints( &self, _cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let unit_var = UnitVar::default(); let out_bytes = Sha256Gadget::evaluate(&unit_var, &z_i[0].to_bytes_le()?)?; @@ -89,7 +88,7 @@ pub mod tests { let z_iVar = Vec::>::new_witness(cs.clone(), || Ok(z_i))?; let computed_z_i1Var = - circuit.generate_step_constraints(cs.clone(), 0, z_iVar.clone(), vec![])?; + circuit.generate_step_constraints(cs.clone(), 0, z_iVar.clone(), ())?; assert_eq!(computed_z_i1Var.value()?, z_i1); Ok(()) } @@ -126,7 +125,7 @@ fn main() -> Result<(), Error> { // compute a step of the IVC for i in 0..num_steps { let start = Instant::now(); - folding_scheme.prove_step(rng, vec![], None)?; + folding_scheme.prove_step(rng, (), None)?; println!("Nova::prove_step {}: {:?}", i, start.elapsed()); } diff --git a/experimental-frontends/src/circom/mod.rs b/experimental-frontends/src/circom/mod.rs index 4c62e01f..ed7a76a7 100644 --- a/experimental-frontends/src/circom/mod.rs +++ b/experimental-frontends/src/circom/mod.rs @@ -10,30 +10,32 @@ use folding_schemes::{frontend::FCircuit, utils::PathOrBin, Error}; use num_bigint::BigInt; pub mod utils; +use crate::utils::{VecF, VecFpVar}; use utils::CircomWrapper; -/// Define CircomFCircuit +/// Define CircomFCircuit. The parameter `L` indicates the length of the ExternalInputs vector of +/// field elements. #[derive(Clone, Debug)] -pub struct CircomFCircuit { +pub struct CircomFCircuit { circom_wrapper: CircomWrapper, pub state_len: usize, - pub external_inputs_len: usize, r1cs: CircomR1CS, } -impl FCircuit for CircomFCircuit { - /// (r1cs_path, wasm_path, state_len, external_inputs_len) - type Params = (PathOrBin, PathOrBin, usize, usize); +impl FCircuit for CircomFCircuit { + /// (r1cs_path, wasm_path, state_len) + type Params = (PathOrBin, PathOrBin, usize); + type ExternalInputs = VecF; + type ExternalInputsVar = VecFpVar; fn new(params: Self::Params) -> Result { - let (r1cs_path, wasm_path, state_len, external_inputs_len) = params; + let (r1cs_path, wasm_path, state_len) = params; let circom_wrapper = CircomWrapper::new(r1cs_path, wasm_path)?; let r1cs = circom_wrapper.extract_r1cs()?; Ok(Self { circom_wrapper, state_len, - external_inputs_len, r1cs, }) } @@ -41,27 +43,24 @@ impl FCircuit for CircomFCircuit { fn state_len(&self) -> usize { self.state_len } - fn external_inputs_len(&self) -> usize { - self.external_inputs_len - } fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - external_inputs: Vec>, + external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { #[cfg(test)] assert_eq!(z_i.len(), self.state_len()); #[cfg(test)] - assert_eq!(external_inputs.len(), self.external_inputs_len()); + assert_eq!(external_inputs.0.len(), L); let input_values = self.fpvars_to_bigints(&z_i)?; let mut inputs_map = vec![("ivc_input".to_string(), input_values)]; - if self.external_inputs_len() > 0 { - let external_inputs_bi = self.fpvars_to_bigints(&external_inputs)?; + if L > 0 { + let external_inputs_bi = self.fpvars_to_bigints(&external_inputs.0)?; inputs_map.push(("external_inputs".to_string(), external_inputs_bi)); } @@ -106,7 +105,7 @@ impl FCircuit for CircomFCircuit { } } -impl CircomFCircuit { +impl CircomFCircuit { fn fpvars_to_bigints(&self, fpvars: &[FpVar]) -> Result, SynthesisError> { let mut input_values = Vec::new(); // converts each FpVar to PrimeField value, then to num_bigint::BigInt. @@ -171,14 +170,15 @@ pub mod tests { PathBuf::from("./src/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); let circom_fcircuit = - CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 0))?; // state_len:1, external_inputs_len:0 + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1))?; // state_len:1, external_inputs_len:0 let cs = ConstraintSystem::::new_ref(); let z_i = vec![Fr::from(3u32)]; let z_i_var = Vec::>::new_witness(cs.clone(), || Ok(z_i))?; - let z_i1_var = circom_fcircuit.generate_step_constraints(cs.clone(), 1, z_i_var, vec![])?; + let z_i1_var = + circom_fcircuit.generate_step_constraints(cs.clone(), 1, z_i_var, VecFpVar(vec![]))?; assert_eq!(z_i1_var.value()?, vec![Fr::from(35u32)]); Ok(()) } @@ -191,7 +191,7 @@ pub mod tests { PathBuf::from("./src/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); let circom_fcircuit = - CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 0))?; // state_len:1, external_inputs_len:0 + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1))?; // state_len:1, external_inputs_len:0 // Allocates z_i1 by using step_native function. let z_i = vec![Fr::from(3_u32)]; @@ -215,7 +215,7 @@ pub mod tests { "./src/circom/test_folder/with_external_inputs_js/with_external_inputs.wasm", ); let circom_fcircuit = - CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 2))?; // state_len:1, external_inputs_len:2 + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1))?; // state_len:1, external_inputs_len:2 let cs = ConstraintSystem::::new_ref(); let z_i = vec![Fr::from(3u32)]; let external_inputs = vec![Fr::from(6u32), Fr::from(7u32)]; @@ -231,7 +231,7 @@ pub mod tests { cs.clone(), 1, z_i_var, - external_inputs_var, + VecFpVar(external_inputs_var), )?; assert_eq!(z_i1_var.value()?, z_i1_native); @@ -246,7 +246,7 @@ pub mod tests { cs.clone(), 1, wrong_z_i_var, - external_inputs_var, + VecFpVar(external_inputs_var), ); // TODO:: https://github.com/privacy-scaling-explorations/sonobe/issues/104 // Disable check for now @@ -260,7 +260,7 @@ pub mod tests { let wasm_path = PathBuf::from("./src/circom/test_folder/no_external_inputs_js/no_external_inputs.wasm"); let circom_fcircuit = - CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 3, 0))?; + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 3))?; let cs = ConstraintSystem::::new_ref(); let z_i = vec![Fr::from(3u32), Fr::from(4u32), Fr::from(5u32)]; let z_i_var = Vec::>::new_witness(cs.clone(), || Ok(z_i.clone()))?; @@ -269,7 +269,8 @@ pub mod tests { let z_i1_native = no_external_inputs_step_native(z_i.clone()); // run gadget step - let z_i1_var = circom_fcircuit.generate_step_constraints(cs.clone(), 1, z_i_var, vec![])?; + let z_i1_var = + circom_fcircuit.generate_step_constraints(cs.clone(), 1, z_i_var, VecFpVar(vec![]))?; assert_eq!(z_i1_var.value()?, z_i1_native); @@ -277,8 +278,12 @@ pub mod tests { let cs = ConstraintSystem::::new_ref(); let wrong_z_i = vec![Fr::from(0u32), Fr::from(4u32), Fr::from(5u32)]; let wrong_z_i_var = Vec::>::new_witness(cs.clone(), || Ok(wrong_z_i))?; - let _z_i1_var = - circom_fcircuit.generate_step_constraints(cs.clone(), 1, wrong_z_i_var, vec![]); + let _z_i1_var = circom_fcircuit.generate_step_constraints( + cs.clone(), + 1, + wrong_z_i_var, + VecFpVar(vec![]), + ); // TODO:: https://github.com/privacy-scaling-explorations/sonobe/issues/104 // Disable check for now // assert!(z_i1_var.is_err()) @@ -292,7 +297,7 @@ pub mod tests { PathBuf::from("./src/circom/test_folder/cubic_circuit_js/cubic_circuit.wasm"); let circom_fcircuit = - CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1, 0))?; // state_len:1, external_inputs_len:0 + CircomFCircuit::::new((r1cs_path.into(), wasm_path.into(), 1))?; // state_len:1, external_inputs_len:0 // Allocates z_i1 by using step_native function. let z_i = vec![Fr::from(3_u32)]; diff --git a/experimental-frontends/src/lib.rs b/experimental-frontends/src/lib.rs index f6b56f35..da1a1786 100644 --- a/experimental-frontends/src/lib.rs +++ b/experimental-frontends/src/lib.rs @@ -1,3 +1,4 @@ pub mod circom; pub mod noir; pub mod noname; +pub mod utils; diff --git a/experimental-frontends/src/noir/mod.rs b/experimental-frontends/src/noir/mod.rs index 1fcaa5b8..83228c8e 100644 --- a/experimental-frontends/src/noir/mod.rs +++ b/experimental-frontends/src/noir/mod.rs @@ -1,5 +1,3 @@ -use std::collections::HashMap; - use acvm::{ acir::{ acir_field::GenericFieldElement, @@ -12,18 +10,19 @@ use acvm::{ use ark_ff::PrimeField; use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar}; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; -use folding_schemes::{frontend::FCircuit, utils::PathOrBin, Error}; use serde::{self, Deserialize, Serialize}; +use std::collections::HashMap; use self::bridge::AcirCircuitSonobe; +use crate::utils::{VecF, VecFpVar}; +use folding_schemes::{frontend::FCircuit, utils::PathOrBin, Error}; mod bridge; #[derive(Clone, Debug)] -pub struct NoirFCircuit { +pub struct NoirFCircuit { pub circuit: Circuit>, pub state_len: usize, - pub external_inputs_len: usize, } #[derive(Clone, Serialize, Deserialize, Debug)] @@ -35,11 +34,13 @@ pub struct ProgramArtifactGeneric { pub bytecode: Program>, } -impl FCircuit for NoirFCircuit { - type Params = (PathOrBin, usize, usize); +impl FCircuit for NoirFCircuit { + type Params = (PathOrBin, usize); + type ExternalInputs = VecF; + type ExternalInputsVar = VecFpVar; fn new(params: Self::Params) -> Result { - let (source, state_len, external_inputs_len) = params; + let (source, state_len) = params; let input_string = match source { PathOrBin::Path(path) => { let file_path = path.with_extension("json"); @@ -62,27 +63,19 @@ impl FCircuit for NoirFCircuit { )); } - Ok(NoirFCircuit { - circuit, - state_len, - external_inputs_len, - }) + Ok(NoirFCircuit { circuit, state_len }) } fn state_len(&self) -> usize { self.state_len } - fn external_inputs_len(&self) -> usize { - self.external_inputs_len - } - fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - external_inputs: Vec>, // inputs that are not part of the state + external_inputs: Self::ExternalInputsVar, // inputs that are not part of the state ) -> Result>, SynthesisError> { let mut acvm = ACVM::new( &StubbedBlackBoxSolver, @@ -123,9 +116,9 @@ impl FCircuit for NoirFCircuit { .map(|witness| { let idx = witness.as_usize() - z_i.len(); let witness = AcvmWitness(witness.witness_index()); - already_assigned_witness_values.insert(witness, &external_inputs[idx]); + already_assigned_witness_values.insert(witness, &external_inputs.0[idx]); - let val = external_inputs[idx].value()?; + let val = external_inputs.0[idx].value()?; let value = if val == F::zero() { "0".to_string() } else { @@ -178,6 +171,7 @@ mod tests { use std::env; use crate::noir::NoirFCircuit; + use crate::utils::VecFpVar; /// Native implementation of `src/noir/test_folder/test_circuit` fn external_inputs_step_native(z_i: Vec, external_inputs: Vec) -> Vec { @@ -198,17 +192,22 @@ mod tests { fn test_step_constraints() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); let cur_path = env::current_dir()?; - let noirfcircuit = NoirFCircuit::new(( + // external inputs length: 2, state length: 2 + let noirfcircuit = NoirFCircuit::::new(( cur_path .join("src/noir/test_folder/test_circuit/target/test_circuit.json") .into(), 2, - 2, ))?; let inputs = vec![Fr::from(2), Fr::from(5)]; let z_i = Vec::>::new_witness(cs.clone(), || Ok(inputs.clone()))?; let external_inputs = Vec::>::new_witness(cs.clone(), || Ok(inputs))?; - let output = noirfcircuit.generate_step_constraints(cs.clone(), 0, z_i, external_inputs)?; + let output = noirfcircuit.generate_step_constraints( + cs.clone(), + 0, + z_i, + VecFpVar(external_inputs), + )?; assert_eq!(output[0].value()?, Fr::from(4)); assert_eq!(output[1].value()?, Fr::from(25)); Ok(()) @@ -218,18 +217,23 @@ mod tests { fn test_step_constraints_no_external_inputs() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); let cur_path = env::current_dir()?; - let noirfcircuit = NoirFCircuit::new(( + // external inputs length: 0, state length: 2 + let noirfcircuit = NoirFCircuit::::new(( cur_path .join("src/noir/test_folder/test_no_external_inputs/target/test_no_external_inputs.json") .into(), 2, - 0, )) ?; let inputs = vec![Fr::from(2), Fr::from(5)]; let z_i = Vec::>::new_witness(cs.clone(), || Ok(inputs.clone()))?; let external_inputs = vec![]; - let output = noirfcircuit.generate_step_constraints(cs.clone(), 0, z_i, external_inputs)?; + let output = noirfcircuit.generate_step_constraints( + cs.clone(), + 0, + z_i, + VecFpVar(external_inputs), + )?; assert_eq!(output[0].value()?, Fr::from(4)); assert_eq!(output[1].value()?, Fr::from(25)); Ok(()) diff --git a/experimental-frontends/src/noname/mod.rs b/experimental-frontends/src/noname/mod.rs index 5ec6ed18..897b49b0 100644 --- a/experimental-frontends/src/noname/mod.rs +++ b/experimental-frontends/src/noname/mod.rs @@ -1,39 +1,41 @@ +use ark_ff::PrimeField; use ark_r1cs_std::alloc::AllocVar; use ark_r1cs_std::fields::fp::FpVar; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; +use noname::backends::{r1cs::R1CS as R1CSNoname, BackendField}; +use noname::witness::CompiledCircuit; use num_bigint::BigUint; use std::marker::PhantomData; -use self::bridge::NonameSonobeCircuit; -use self::utils::{compile_source_code, NonameInputs}; - -use ark_ff::PrimeField; use folding_schemes::{frontend::FCircuit, Error}; -use noname::backends::{r1cs::R1CS as R1CSNoname, BackendField}; -use noname::witness::CompiledCircuit; pub mod bridge; pub mod utils; +use crate::utils::{VecF, VecFpVar}; +use self::bridge::NonameSonobeCircuit; +use self::utils::{compile_source_code, NonameInputs}; + +// `L` indicates the length of the ExternalInputs vector of field elements. #[derive(Debug, Clone)] -pub struct NonameFCircuit { +pub struct NonameFCircuit { pub state_len: usize, - pub external_inputs_len: usize, pub circuit: CompiledCircuit>, _f: PhantomData, } -impl FCircuit for NonameFCircuit { - type Params = (String, usize, usize); +impl FCircuit for NonameFCircuit { + type Params = (String, usize); + type ExternalInputs = VecF; + type ExternalInputsVar = VecFpVar; fn new(params: Self::Params) -> Result { - let (code, state_len, external_inputs_len) = params; + let (code, state_len) = params; let compiled_circuit = compile_source_code::(&code).map_err(|_| { Error::Other("Encountered an error while compiling a noname circuit".to_owned()) })?; Ok(NonameFCircuit { state_len, - external_inputs_len, circuit: compiled_circuit, _f: PhantomData, }) @@ -43,19 +45,15 @@ impl FCircuit for NonameFCircuit { self.state_len } - fn external_inputs_len(&self) -> usize { - self.external_inputs_len - } - fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - external_inputs: Vec>, + external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let wtns_external_inputs = - NonameInputs::from_fpvars((&external_inputs, "external_inputs".to_string()))?; + NonameInputs::from_fpvars((&external_inputs.0, "external_inputs".to_string()))?; let wtns_ivc_inputs = NonameInputs::from_fpvars((&z_i, "ivc_inputs".to_string()))?; let noname_witness = self .circuit @@ -78,7 +76,7 @@ impl FCircuit for NonameFCircuit { compiled_circuit: self.circuit.clone(), witness: noname_witness, assigned_z_i: &z_i, - assigned_external_inputs: &external_inputs, + assigned_external_inputs: &external_inputs.0, assigned_z_i1: &assigned_z_i1, }; noname_circuit.generate_constraints(cs.clone())?; @@ -89,16 +87,16 @@ impl FCircuit for NonameFCircuit { #[cfg(test)] mod tests { - use ark_bn254::Fr; use ark_ff::PrimeField; use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar, R1CSVar}; + use ark_relations::r1cs::ConstraintSystem; use noname::backends::r1cs::R1csBn254Field; use folding_schemes::{frontend::FCircuit, Error}; use super::NonameFCircuit; - use ark_relations::r1cs::ConstraintSystem; + use crate::utils::VecFpVar; /// Native implementation of `NONAME_CIRCUIT_EXTERNAL_INPUTS` fn external_inputs_step_native(z_i: Vec, external_inputs: Vec) -> Vec { @@ -125,8 +123,9 @@ mod tests { #[test] fn test_step_native() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); - let params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2, 2); - let circuit = NonameFCircuit::::new(params)?; + // state length = 2, external inputs length= 2 + let params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2); + let circuit = NonameFCircuit::::new(params)?; let inputs_public = vec![Fr::from(2), Fr::from(5)]; let inputs_private = vec![Fr::from(8), Fr::from(2)]; @@ -139,7 +138,7 @@ mod tests { cs.clone(), 0, ivc_inputs_var, - external_inputs_var, + VecFpVar(external_inputs_var), )?; let z_i1_native = external_inputs_step_native(inputs_public, inputs_private); @@ -151,8 +150,9 @@ mod tests { #[test] fn test_step_constraints() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); - let params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2, 2); - let circuit = NonameFCircuit::::new(params)?; + // external inputs length= 2 + let params = (NONAME_CIRCUIT_EXTERNAL_INPUTS.to_owned(), 2); + let circuit = NonameFCircuit::::new(params)?; let inputs_public = vec![Fr::from(2), Fr::from(5)]; let inputs_private = vec![Fr::from(8), Fr::from(2)]; @@ -163,7 +163,7 @@ mod tests { cs.clone(), 0, ivc_inputs_var, - external_inputs_var, + VecFpVar(external_inputs_var), )?; assert!(cs.is_satisfied()?); assert_eq!(z_i1[0].value()?, Fr::from(10_u8)); @@ -174,13 +174,14 @@ mod tests { #[test] fn test_generate_constraints_no_external_inputs() -> Result<(), Error> { let cs = ConstraintSystem::::new_ref(); - let params = (NONAME_CIRCUIT_NO_EXTERNAL_INPUTS.to_owned(), 2, 0); + let params = (NONAME_CIRCUIT_NO_EXTERNAL_INPUTS.to_owned(), 2); // state length = 2 let inputs_public = vec![Fr::from(2), Fr::from(5)]; let ivc_inputs_var = Vec::>::new_witness(cs.clone(), || Ok(inputs_public))?; - let f_circuit = NonameFCircuit::::new(params)?; - f_circuit.generate_step_constraints(cs.clone(), 0, ivc_inputs_var, vec![])?; + // external inputs length = 0 + let f_circuit = NonameFCircuit::::new(params)?; + f_circuit.generate_step_constraints(cs.clone(), 0, ivc_inputs_var, VecFpVar(vec![]))?; assert!(cs.is_satisfied()?); Ok(()) } diff --git a/experimental-frontends/src/utils.rs b/experimental-frontends/src/utils.rs new file mode 100644 index 00000000..769c5ae7 --- /dev/null +++ b/experimental-frontends/src/utils.rs @@ -0,0 +1,38 @@ +use ark_ff::PrimeField; +use ark_r1cs_std::{ + alloc::{AllocVar, AllocationMode}, + fields::fp::FpVar, +}; +use ark_relations::r1cs::{Namespace, SynthesisError}; +use ark_std::fmt::Debug; +use core::borrow::Borrow; + +#[derive(Clone, Debug)] +pub struct VecF(pub Vec); +impl Default for VecF { + fn default() -> Self { + VecF(vec![F::zero(); L]) + } +} +#[derive(Clone, Debug)] +pub struct VecFpVar(pub Vec>); +impl AllocVar, F> for VecFpVar { + fn new_variable>>( + cs: impl Into>, + f: impl FnOnce() -> Result, + mode: AllocationMode, + ) -> Result { + f().and_then(|val| { + let cs = cs.into(); + + let v = Vec::>::new_variable(cs.clone(), || Ok(val.borrow().0.clone()), mode)?; + + Ok(VecFpVar(v)) + }) + } +} +impl Default for VecFpVar { + fn default() -> Self { + VecFpVar(vec![FpVar::::Constant(F::zero()); L]) + } +} diff --git a/folding-schemes/src/folding/circuits/nonnative/uint.rs b/folding-schemes/src/folding/circuits/nonnative/uint.rs index 033244f2..eafd8fa4 100644 --- a/folding-schemes/src/folding/circuits/nonnative/uint.rs +++ b/folding-schemes/src/folding/circuits/nonnative/uint.rs @@ -203,8 +203,8 @@ impl NonNativeUintVar { // Thus, 55 allows us to compute `Az∘Bz` without the expensive alignment // operation. // - // TODO (@winderica): either make it a global const, or compute an - // optimal value based on the modulus size + // TODO: either make it a global const, or compute an optimal value + // based on the modulus size. 55 } } diff --git a/folding-schemes/src/folding/hypernova/circuits.rs b/folding-schemes/src/folding/hypernova/circuits.rs index f7b34690..808ea49f 100644 --- a/folding-schemes/src/folding/hypernova/circuits.rs +++ b/folding-schemes/src/folding/hypernova/circuits.rs @@ -479,7 +479,7 @@ pub struct AugmentedFCircuit< pub(super) i_usize: Option, pub(super) z_0: Option>, pub(super) z_i: Option>, - pub(super) external_inputs: Option>, + pub(super) external_inputs: Option, pub(super) U_i: Option>, pub(super) Us: Option>>, // other U_i's to be folded that are not the main running instance pub(super) u_i_C: Option, // u_i.C @@ -602,7 +602,7 @@ where i_usize: Some(0), z_0: Some(z_0.clone()), z_i: Some(z_0.clone()), - external_inputs: Some(vec![C1::ScalarField::zero(); self.F.external_inputs_len()]), + external_inputs: Some(FC::ExternalInputs::default()), U_i: Some(U_i.clone()), Us: Some(Us), u_i_C: Some(u_i.C), @@ -681,10 +681,8 @@ where .z_i .unwrap_or(vec![CF1::::zero(); self.F.state_len()])) })?; - let external_inputs = Vec::>>::new_witness(cs.clone(), || { - Ok(self - .external_inputs - .unwrap_or(vec![CF1::::zero(); self.F.external_inputs_len()])) + let external_inputs = FC::ExternalInputsVar::new_witness(cs.clone(), || { + Ok(self.external_inputs.unwrap_or_default()) })?; let U_dummy = LCCCS::::dummy(&self.ccs); @@ -1278,7 +1276,7 @@ mod tests { i_usize: Some(0), z_0: Some(z_0.clone()), z_i: Some(z_i.clone()), - external_inputs: Some(vec![]), + external_inputs: Some(()), U_i: Some(U_i.clone()), Us: Some(Us.clone()), u_i_C: Some(u_i.C), @@ -1362,7 +1360,7 @@ mod tests { i_usize: Some(i), z_0: Some(z_0.clone()), z_i: Some(z_i.clone()), - external_inputs: Some(vec![]), + external_inputs: Some(()), U_i: Some(U_i.clone()), Us: Some(Us.clone()), u_i_C: Some(u_i.C), diff --git a/folding-schemes/src/folding/hypernova/decider_eth.rs b/folding-schemes/src/folding/hypernova/decider_eth.rs index 1a3346fc..d4bffd77 100644 --- a/folding-schemes/src/folding/hypernova/decider_eth.rs +++ b/folding-schemes/src/folding/hypernova/decider_eth.rs @@ -260,8 +260,8 @@ pub mod tests { let hypernova_params = HN::preprocess(&mut rng, &prep_param)?; let mut hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone())?; - hypernova.prove_step(&mut rng, vec![], Some((vec![], vec![])))?; - hypernova.prove_step(&mut rng, vec![], Some((vec![], vec![])))?; // do a 2nd step + hypernova.prove_step(&mut rng, (), Some((vec![], vec![])))?; + hypernova.prove_step(&mut rng, (), Some((vec![], vec![])))?; // do a 2nd step // prepare the Decider prover & verifier params let (decider_pp, decider_vp) = @@ -356,8 +356,8 @@ pub mod tests { let hypernova_params = (hypernova_pp_deserialized, hypernova_vp_deserialized); let mut hypernova = HN::init(&hypernova_params, F_circuit, z_0.clone())?; - hypernova.prove_step(&mut rng, vec![], Some((vec![], vec![])))?; - hypernova.prove_step(&mut rng, vec![], Some((vec![], vec![])))?; + hypernova.prove_step(&mut rng, (), Some((vec![], vec![])))?; + hypernova.prove_step(&mut rng, (), Some((vec![], vec![])))?; // decider proof generation let proof = D::prove(rng, decider_pp, hypernova.clone())?; diff --git a/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs b/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs index 067c5501..099e2146 100644 --- a/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/hypernova/decider_eth_circuit.rs @@ -301,7 +301,7 @@ pub mod tests { // generate a Nova instance and do a step of it let mut hypernova = HN::init(&hn_params, F_circuit, z_0.clone())?; - hypernova.prove_step(&mut rng, vec![], None)?; + hypernova.prove_step(&mut rng, (), None)?; let ivc_proof = hypernova.ivc_proof(); HN::verify(hn_params.1, ivc_proof)?; diff --git a/folding-schemes/src/folding/hypernova/mod.rs b/folding-schemes/src/folding/hypernova/mod.rs index ecba05a4..e6b5ae31 100644 --- a/folding-schemes/src/folding/hypernova/mod.rs +++ b/folding-schemes/src/folding/hypernova/mod.rs @@ -279,7 +279,7 @@ where &self, mut rng: impl RngCore, state: Vec, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, ) -> Result { let r1cs_z = self.new_instance_generic(state, external_inputs)?; // compute committed instances, w_{i+1}, u_{i+1}, which will be used as w_i, u_i, so we @@ -301,7 +301,7 @@ where &self, mut rng: impl RngCore, state: Vec, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, ) -> Result { let r1cs_z = self.new_instance_generic(state, external_inputs)?; // compute committed instances, w_{i+1}, u_{i+1}, which will be used as w_i, u_i, so we @@ -332,7 +332,7 @@ where fn new_instance_generic( &self, state: Vec, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, ) -> Result, Error> { // prepare the initial dummy instances let U_i = LCCCS::::dummy(&self.ccs); @@ -599,7 +599,7 @@ where fn prove_step( &mut self, mut rng: impl RngCore, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, other_instances: Option, ) -> Result<(), Error> { // ensure that commitments are blinding if user has specified so. @@ -665,14 +665,6 @@ where self.F.state_len(), )); } - if external_inputs.len() != self.F.external_inputs_len() { - return Err(Error::NotSameLength( - "F.external_inputs_len()".to_string(), - self.F.external_inputs_len(), - "external_inputs.len()".to_string(), - external_inputs.len(), - )); - } if self.i > C1::ScalarField::from_le_bytes_mod_order(&usize::MAX.to_le_bytes()) { return Err(Error::MaxStep); @@ -1045,17 +1037,17 @@ mod tests { let mut lcccs = vec![]; for j in 0..MU - 1 { let instance_state = vec![Fr::from(j as u32 + 85_u32)]; - let (U, W) = hypernova.new_running_instance(&mut rng, instance_state, vec![])?; + let (U, W) = hypernova.new_running_instance(&mut rng, instance_state, ())?; lcccs.push((U, W)); } let mut cccs = vec![]; for j in 0..NU - 1 { let instance_state = vec![Fr::from(j as u32 + 15_u32)]; - let (u, w) = hypernova.new_incoming_instance(&mut rng, instance_state, vec![])?; + let (u, w) = hypernova.new_incoming_instance(&mut rng, instance_state, ())?; cccs.push((u, w)); } - hypernova.prove_step(&mut rng, vec![], Some((lcccs, cccs)))?; + hypernova.prove_step(&mut rng, (), Some((lcccs, cccs)))?; } assert_eq!(Fr::from(num_steps as u32), hypernova.i); diff --git a/folding-schemes/src/folding/mod.rs b/folding-schemes/src/folding/mod.rs index 3de2751c..a2b23a8d 100644 --- a/folding-schemes/src/folding/mod.rs +++ b/folding-schemes/src/folding/mod.rs @@ -77,7 +77,7 @@ pub mod tests { // perform multiple IVC steps (internally folding) let num_steps: usize = 3; for _ in 0..num_steps { - fs.prove_step(&mut rng, vec![], None)?; + fs.prove_step(&mut rng, FC::ExternalInputs::default(), None)?; } // verify the IVCProof @@ -121,8 +121,8 @@ pub mod tests { // serialization new FS instance let num_steps: usize = 3; for _ in 0..num_steps { - new_fs.prove_step(&mut rng, vec![], None)?; - fs.prove_step(&mut rng, vec![], None)?; + new_fs.prove_step(&mut rng, FC::ExternalInputs::default(), None)?; + fs.prove_step(&mut rng, FC::ExternalInputs::default(), None)?; } // check that the IVCProofs from both FS instances are equal diff --git a/folding-schemes/src/folding/nova/circuits.rs b/folding-schemes/src/folding/nova/circuits.rs index 1989148c..6b7f8fa1 100644 --- a/folding-schemes/src/folding/nova/circuits.rs +++ b/folding-schemes/src/folding/nova/circuits.rs @@ -55,7 +55,7 @@ pub struct AugmentedFCircuit>> { pub(super) i_usize: Option, pub(super) z_0: Option>, pub(super) z_i: Option>, - pub(super) external_inputs: Option>, + pub(super) external_inputs: Option, pub(super) u_i_cmW: Option, pub(super) U_i: Option>, pub(super) U_i1_cmE: Option, @@ -125,10 +125,8 @@ where .z_i .unwrap_or(vec![CF1::::zero(); self.F.state_len()])) })?; - let external_inputs = Vec::>>::new_witness(cs.clone(), || { - Ok(self - .external_inputs - .unwrap_or(vec![CF1::::zero(); self.F.external_inputs_len()])) + let external_inputs = FC::ExternalInputsVar::new_witness(cs.clone(), || { + Ok(self.external_inputs.unwrap_or_default()) })?; let u_dummy = CommittedInstance::dummy(2); diff --git a/folding-schemes/src/folding/nova/decider.rs b/folding-schemes/src/folding/nova/decider.rs index f270aefa..8068dec4 100644 --- a/folding-schemes/src/folding/nova/decider.rs +++ b/folding-schemes/src/folding/nova/decider.rs @@ -371,9 +371,9 @@ pub mod tests { let mut nova = N::init(&nova_params, F_circuit, z_0.clone())?; println!("Nova initialized, {:?}", start.elapsed()); let start = Instant::now(); - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; println!("prove_step, {:?}", start.elapsed()); - nova.prove_step(&mut rng, vec![], None)?; // do a 2nd step + nova.prove_step(&mut rng, (), None)?; // do a 2nd step let mut rng = rand::rngs::OsRng; diff --git a/folding-schemes/src/folding/nova/decider_circuits.rs b/folding-schemes/src/folding/nova/decider_circuits.rs index f91537fa..db9a686d 100644 --- a/folding-schemes/src/folding/nova/decider_circuits.rs +++ b/folding-schemes/src/folding/nova/decider_circuits.rs @@ -192,7 +192,7 @@ pub mod tests { // generate a Nova instance and do a step of it let mut nova = N::init(&nova_params, F_circuit, z_0.clone())?; - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; // verify the IVC let ivc_proof = nova.ivc_proof(); N::verify(nova_params.1, ivc_proof)?; diff --git a/folding-schemes/src/folding/nova/decider_eth.rs b/folding-schemes/src/folding/nova/decider_eth.rs index b7a4a79c..55d05a94 100644 --- a/folding-schemes/src/folding/nova/decider_eth.rs +++ b/folding-schemes/src/folding/nova/decider_eth.rs @@ -319,9 +319,9 @@ pub mod tests { let (decider_pp, decider_vp) = D::preprocess(&mut rng, nova_params, nova.clone())?; let start = Instant::now(); - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; println!("prove_step, {:?}", start.elapsed()); - nova.prove_step(&mut rng, vec![], None)?; // do a 2nd step + nova.prove_step(&mut rng, (), None)?; // do a 2nd step // decider proof generation let start = Instant::now(); @@ -431,9 +431,9 @@ pub mod tests { let mut nova = N::init(&nova_params, F_circuit, z_0)?; let start = Instant::now(); - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; println!("prove_step, {:?}", start.elapsed()); - nova.prove_step(&mut rng, vec![], None)?; // do a 2nd step + nova.prove_step(&mut rng, (), None)?; // do a 2nd step // decider proof generation let start = Instant::now(); diff --git a/folding-schemes/src/folding/nova/decider_eth_circuit.rs b/folding-schemes/src/folding/nova/decider_eth_circuit.rs index b11c9b05..e3f7fdba 100644 --- a/folding-schemes/src/folding/nova/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/nova/decider_eth_circuit.rs @@ -240,7 +240,7 @@ pub mod tests { // generate a Nova instance and do a step of it let mut nova = N::init(&nova_params, F_circuit, z_0.clone())?; - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; let ivc_proof = nova.ivc_proof(); N::verify(nova_params.1, ivc_proof)?; diff --git a/folding-schemes/src/folding/nova/mod.rs b/folding-schemes/src/folding/nova/mod.rs index d1e1540e..cae1782a 100644 --- a/folding-schemes/src/folding/nova/mod.rs +++ b/folding-schemes/src/folding/nova/mod.rs @@ -620,8 +620,8 @@ where fn prove_step( &mut self, mut rng: impl RngCore, - external_inputs: Vec, - // Nova does not support multi-instances folding + external_inputs: FC::ExternalInputs, + // Nova does not support multi-instances folding (by design) _other_instances: Option, ) -> Result<(), Error> { // ensure that commitments are blinding if user has specified so. @@ -659,14 +659,6 @@ where self.F.state_len(), )); } - if external_inputs.len() != self.F.external_inputs_len() { - return Err(Error::NotSameLength( - "F.external_inputs_len()".to_string(), - self.F.external_inputs_len(), - "external_inputs.len()".to_string(), - external_inputs.len(), - )); - } if self.i > C1::ScalarField::from_le_bytes_mod_order(&usize::MAX.to_le_bytes()) { return Err(Error::MaxStep); @@ -1123,7 +1115,7 @@ pub mod tests { )?; for _ in 0..num_steps { - nova.prove_step(&mut rng, vec![], None)?; + nova.prove_step(&mut rng, (), None)?; } assert_eq!(Fr::from(num_steps as u32), nova.i); diff --git a/folding-schemes/src/folding/protogalaxy/circuits.rs b/folding-schemes/src/folding/protogalaxy/circuits.rs index d46afac1..3bfac847 100644 --- a/folding-schemes/src/folding/protogalaxy/circuits.rs +++ b/folding-schemes/src/folding/protogalaxy/circuits.rs @@ -238,7 +238,7 @@ pub struct AugmentedFCircuit>> { pub(super) i_usize: usize, pub(super) z_0: Vec>, pub(super) z_i: Vec>, - pub(super) external_inputs: Vec>, + pub(super) external_inputs: FC::ExternalInputs, pub(super) F: FC, // F circuit pub(super) u_i_phi: C1, pub(super) U_i: CommittedInstance, @@ -274,7 +274,7 @@ impl>> AugmentedFCircuit i_usize: 0, z_0: vec![CF1::::zero(); F_circuit.state_len()], z_i: vec![CF1::::zero(); F_circuit.state_len()], - external_inputs: vec![CF1::::zero(); F_circuit.external_inputs_len()], + external_inputs: FC::ExternalInputs::default(), u_i_phi: C1::zero(), U_i: u_dummy, U_i1_phi: C1::zero(), @@ -307,7 +307,7 @@ where let z_0 = Vec::>>::new_witness(cs.clone(), || Ok(self.z_0))?; let z_i = Vec::>>::new_witness(cs.clone(), || Ok(self.z_i))?; let external_inputs = - Vec::>>::new_witness(cs.clone(), || Ok(self.external_inputs))?; + FC::ExternalInputsVar::new_witness(cs.clone(), || Ok(self.external_inputs))?; let u_dummy = CommittedInstance::::dummy((2, self.U_i.betas.len())); let U_i = CommittedInstanceVar::::new_witness(cs.clone(), || Ok(self.U_i))?; diff --git a/folding-schemes/src/folding/protogalaxy/decider_eth.rs b/folding-schemes/src/folding/protogalaxy/decider_eth.rs index ddb843bc..4ea7e07a 100644 --- a/folding-schemes/src/folding/protogalaxy/decider_eth.rs +++ b/folding-schemes/src/folding/protogalaxy/decider_eth.rs @@ -285,8 +285,8 @@ pub mod tests { let start = Instant::now(); let mut protogalaxy = PG::init(&protogalaxy_params, F_circuit, z_0.clone())?; println!("ProtoGalaxy initialized, {:?}", start.elapsed()); - protogalaxy.prove_step(&mut rng, vec![], None)?; - protogalaxy.prove_step(&mut rng, vec![], None)?; // do a 2nd step + protogalaxy.prove_step(&mut rng, (), None)?; + protogalaxy.prove_step(&mut rng, (), None)?; // do a 2nd step // prepare the Decider prover & verifier params let (decider_pp, decider_vp) = @@ -360,8 +360,8 @@ pub mod tests { let start = Instant::now(); let mut protogalaxy = PG::init(&protogalaxy_params, F_circuit, z_0.clone())?; println!("ProtoGalaxy initialized, {:?}", start.elapsed()); - protogalaxy.prove_step(&mut rng, vec![], None)?; - protogalaxy.prove_step(&mut rng, vec![], None)?; // do a 2nd step + protogalaxy.prove_step(&mut rng, (), None)?; + protogalaxy.prove_step(&mut rng, (), None)?; // do a 2nd step // prepare the Decider prover & verifier params let (decider_pp, decider_vp) = @@ -402,9 +402,9 @@ pub mod tests { let mut protogalaxy = PG::init(&protogalaxy_params, F_circuit, z_0)?; let start = Instant::now(); - protogalaxy.prove_step(&mut rng, vec![], None)?; + protogalaxy.prove_step(&mut rng, (), None)?; println!("prove_step, {:?}", start.elapsed()); - protogalaxy.prove_step(&mut rng, vec![], None)?; // do a 2nd step + protogalaxy.prove_step(&mut rng, (), None)?; // do a 2nd step // decider proof generation let start = Instant::now(); diff --git a/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs b/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs index 483d7f9b..da9ce4e3 100644 --- a/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs +++ b/folding-schemes/src/folding/protogalaxy/decider_eth_circuit.rs @@ -222,7 +222,7 @@ pub mod tests { // generate a Nova instance and do a step of it let mut protogalaxy = PG::init(&pg_params, F_circuit, z_0.clone())?; - protogalaxy.prove_step(&mut rng, vec![], None)?; + protogalaxy.prove_step(&mut rng, (), None)?; let ivc_proof = protogalaxy.ivc_proof(); PG::verify(pg_params.1, ivc_proof)?; diff --git a/folding-schemes/src/folding/protogalaxy/mod.rs b/folding-schemes/src/folding/protogalaxy/mod.rs index 8e1e3090..32fa797f 100644 --- a/folding-schemes/src/folding/protogalaxy/mod.rs +++ b/folding-schemes/src/folding/protogalaxy/mod.rs @@ -455,9 +455,8 @@ where { /// returns the hash of the public parameters of ProtoGalaxy pub fn pp_hash(&self) -> Result { - // TODO (@winderica): support hiding commitments in ProtoGalaxy. - // For now, `H` is set to false. - // Tracking issue: https://github.com/privacy-scaling-explorations/sonobe/issues/82 + // TODO: support hiding commitments in ProtoGalaxy. For now, `H` is set to false. Tracking + // issue: https://github.com/privacy-scaling-explorations/sonobe/issues/82 pp_hash::( &self.r1cs, &self.cf_r1cs, @@ -557,7 +556,6 @@ where // For `t_lower_bound`, we configure `F'` with `t = 1` and compute log2 // of the size of `F'`. let state_len = F.state_len(); - let external_inputs_len = F.external_inputs_len(); // `F'` includes `F` and `ProtoGalaxy.V`, where `F` might be costly. // Observing that the cost of `F` is constant with respect to `t`, we @@ -569,14 +567,13 @@ where cs.clone(), 0, Vec::new_witness(cs.clone(), || Ok(vec![Zero::zero(); state_len]))?, - Vec::new_witness(cs.clone(), || Ok(vec![Zero::zero(); external_inputs_len]))?, + FC::ExternalInputsVar::new_witness(cs.clone(), || Ok(FC::ExternalInputs::default()))?, )?; let step_constraints = cs.num_constraints(); // Create a dummy circuit with the same state length and external inputs // length as `F`, which replaces `F` in the augmented circuit `F'`. - let dummy_circuit: DummyCircuit = - FCircuit::::new((state_len, external_inputs_len))?; + let dummy_circuit: DummyCircuit = FCircuit::::new(state_len)?; // Compute `augmentation_constraints`, the size of `F'` without `F`. let cs = ConstraintSystem::::new_ref(); @@ -700,9 +697,9 @@ where ) -> Result<(Self::ProverParam, Self::VerifierParam), Error> { // We fix `k`, the number of incoming instances, to 1, because // multi-instances folding is not supported yet. - // TODO (@winderica): Support multi-instances folding and make `k` a - // constant generic parameter (as in HyperNova) - // Tracking issue: https://github.com/privacy-scaling-explorations/sonobe/issues/82 + // TODO: Support multi-instances folding and make `k` a constant generic parameter (as in + // HyperNova). Tracking issue: + // https://github.com/privacy-scaling-explorations/sonobe/issues/82 let k = 1; // `d`, the degree of the constraint system, is set to 2, as we only // support R1CS for now, whose highest degree is 2. @@ -788,7 +785,7 @@ where fn prove_step( &mut self, mut rng: impl RngCore, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, _other_instances: Option, ) -> Result<(), Error> { // Multi-instances folding is not supported yet. @@ -797,9 +794,9 @@ where } // We fix `k`, the number of incoming instances, to 1, because // multi-instances folding is not supported yet. - // TODO (@winderica): Support multi-instances folding and make `k` a - // constant generic parameter (as in HyperNova) - // Tracking issue: https://github.com/privacy-scaling-explorations/sonobe/issues/82 + // TODO: Support multi-instances folding and make `k` a constant generic parameter (as in + // HyperNova). Tracking issue: + // https://github.com/privacy-scaling-explorations/sonobe/issues/82 let k = 1; // `d`, the degree of the constraint system, is set to 2, as we only // support R1CS for now, whose highest degree is 2. @@ -820,14 +817,6 @@ where self.F.state_len(), )); } - if external_inputs.len() != self.F.external_inputs_len() { - return Err(Error::NotSameLength( - "F.external_inputs_len()".to_string(), - self.F.external_inputs_len(), - "external_inputs.len()".to_string(), - external_inputs.len(), - )); - } let i_bn: BigUint = self.i.into(); let i_usize: usize = i_bn.try_into().map_err(|_| Error::MaxStep)?; @@ -847,7 +836,7 @@ where .external_inputs .clone_from(&external_inputs); - // There is no need to update `self.U_i` etc. as they are unchanged. + // There is no need to update `self.U_i` etc. as they are unchanged. } else { // Primary part: // Compute `U_{i+1}` by folding `u_i` into `U_i`. @@ -1167,7 +1156,7 @@ mod tests { let num_steps: usize = 3; for _ in 0..num_steps { - protogalaxy.prove_step(&mut test_rng(), vec![], None)?; + protogalaxy.prove_step(&mut test_rng(), (), None)?; } assert_eq!(Fr::from(num_steps as u32), protogalaxy.i); @@ -1184,32 +1173,28 @@ mod tests { let poseidon_config = poseidon_canonical_config::(); for state_len in [1, 10, 100] { - for external_inputs_len in [1, 10, 100] { - let dummy_circuit: DummyCircuit = - FCircuit::::new((state_len, external_inputs_len))?; - - let costs: Vec = (1..32) - .into_par_iter() - .map(|t| { - let cs = ConstraintSystem::::new_ref(); - AugmentedFCircuit::::empty( - &poseidon_config, - dummy_circuit.clone(), - t, - d, - k, - ) - .generate_constraints(cs.clone())?; - Ok(cs.num_constraints()) - }) - .collect::, Error>>()?; - - for t_lower_bound in log2(costs[0]) as usize..32 { - let num_constraints = - (1 << t_lower_bound) - costs[0] + costs[t_lower_bound - 1]; - let t = log2(num_constraints) as usize; - assert!(t == t_lower_bound || t == t_lower_bound + 1); - } + let dummy_circuit: DummyCircuit = FCircuit::::new(state_len)?; + + let costs: Vec = (1..32) + .into_par_iter() + .map(|t| { + let cs = ConstraintSystem::::new_ref(); + AugmentedFCircuit::::empty( + &poseidon_config, + dummy_circuit.clone(), + t, + d, + k, + ) + .generate_constraints(cs.clone())?; + Ok(cs.num_constraints()) + }) + .collect::, Error>>()?; + + for t_lower_bound in log2(costs[0]) as usize..32 { + let num_constraints = (1 << t_lower_bound) - costs[0] + costs[t_lower_bound - 1]; + let t = log2(num_constraints) as usize; + assert!(t == t_lower_bound || t == t_lower_bound + 1); } } Ok(()) diff --git a/folding-schemes/src/frontend/mod.rs b/folding-schemes/src/frontend/mod.rs index b5a352f5..43191e61 100644 --- a/folding-schemes/src/frontend/mod.rs +++ b/folding-schemes/src/frontend/mod.rs @@ -1,6 +1,6 @@ use crate::Error; use ark_ff::PrimeField; -use ark_r1cs_std::fields::fp::FpVar; +use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar}; use ark_relations::r1cs::{ConstraintSystemRef, SynthesisError}; use ark_std::fmt::Debug; @@ -10,8 +10,14 @@ pub mod utils; /// inside the agmented F' function). /// The parameter z_i denotes the current state, and z_{i+1} denotes the next state after applying /// the step. +/// Note that the external inputs for the specific circuit are defined at the implementation of +/// both `FCircuit::ExternalInputs` and `FCircuit::ExternalInputsVar`, where the `Default` trait +/// implementation for the `ExternalInputs` returns the initialized data structure (ie. if the type +/// contains a vector, it is initialized at the expected length). pub trait FCircuit: Clone + Debug { type Params: Debug; + type ExternalInputs: Clone + Default + Debug; + type ExternalInputsVar: Clone + Debug + AllocVar; /// returns a new FCircuit instance fn new(params: Self::Params) -> Result; @@ -20,10 +26,6 @@ pub trait FCircuit: Clone + Debug { /// FCircuit inputs. fn state_len(&self) -> usize; - /// returns the number of elements in the external inputs used by the FCircuit. External inputs - /// are optional, and in case no external inputs are used, this method should return 0. - fn external_inputs_len(&self) -> usize; - /// generates the constraints for the step of F for the given z_i fn generate_step_constraints( // this method uses self, so that each FCircuit implementation (and different frontends) @@ -32,7 +34,7 @@ pub trait FCircuit: Clone + Debug { cs: ConstraintSystemRef, i: usize, z_i: Vec>, - external_inputs: Vec>, // inputs that are not part of the state + external_inputs: Self::ExternalInputsVar, // inputs that are not part of the state ) -> Result>, SynthesisError>; } diff --git a/folding-schemes/src/frontend/utils.rs b/folding-schemes/src/frontend/utils.rs index e4d3d749..51bceacc 100644 --- a/folding-schemes/src/frontend/utils.rs +++ b/folding-schemes/src/frontend/utils.rs @@ -10,35 +10,29 @@ use ark_std::{fmt::Debug, Zero}; use super::FCircuit; use crate::Error; -/// DummyCircuit is a circuit that has dummy state and external inputs whose -/// lengths are specified in the `state_len` and `external_inputs_len` -/// parameters, without any constraints. +/// DummyCircuit is a circuit that has dummy state whose length is specified in the `state_len` +/// parameter, without any constraints. #[derive(Clone, Debug)] pub struct DummyCircuit { state_len: usize, - external_inputs_len: usize, } impl FCircuit for DummyCircuit { - type Params = (usize, usize); + type Params = usize; + type ExternalInputs = (); + type ExternalInputsVar = (); - fn new((state_len, external_inputs_len): Self::Params) -> Result { - Ok(Self { - state_len, - external_inputs_len, - }) + fn new(state_len: Self::Params) -> Result { + Ok(Self { state_len }) } fn state_len(&self) -> usize { self.state_len } - fn external_inputs_len(&self) -> usize { - self.external_inputs_len - } fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, _z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { Vec::new_witness(cs.clone(), || Ok(vec![Zero::zero(); self.state_len])) } @@ -57,21 +51,21 @@ pub struct CubicFCircuit { #[cfg(test)] impl FCircuit for CubicFCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); + fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) } fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 0 - } fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let five = FpVar::::new_constant(cs.clone(), F::from(5u32))?; let z_i = z_i[0].clone(); @@ -97,6 +91,8 @@ pub struct CustomFCircuit { impl FCircuit for CustomFCircuit { type Params = usize; + type ExternalInputs = (); + type ExternalInputsVar = (); fn new(params: Self::Params) -> Result { Ok(Self { @@ -107,15 +103,12 @@ impl FCircuit for CustomFCircuit { fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 0 - } fn generate_step_constraints( &self, _cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let mut z_i1 = z_i[0].clone(); for _ in 0..self.n_constraints - 1 { @@ -153,9 +146,11 @@ impl> ConstraintSynthesizer for WrapperCircuit Vec::>::new_witness(cs.clone(), || Ok(self.z_i.unwrap_or(vec![F::zero()])))?; let z_i1 = Vec::>::new_input(cs.clone(), || Ok(self.z_i1.unwrap_or(vec![F::zero()])))?; + let external_inputs = + FC::ExternalInputsVar::new_input(cs.clone(), || Ok(FC::ExternalInputs::default()))?; let computed_z_i1 = self.FC - .generate_step_constraints(cs.clone(), 0, z_i.clone(), vec![])?; + .generate_step_constraints(cs.clone(), 0, z_i.clone(), external_inputs)?; use ark_r1cs_std::eq::EqGadget; computed_z_i1.enforce_equal(&z_i1)?; diff --git a/folding-schemes/src/lib.rs b/folding-schemes/src/lib.rs index aeb97c41..b3b132a6 100644 --- a/folding-schemes/src/lib.rs +++ b/folding-schemes/src/lib.rs @@ -197,7 +197,7 @@ pub trait FoldingScheme< fn prove_step( &mut self, rng: impl RngCore, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, other_instances: Option, ) -> Result<(), Error>; @@ -237,7 +237,7 @@ pub trait MultiFolding< &self, rng: impl RngCore, state: Vec, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, ) -> Result; /// Creates a new IncomingInstance for the given state, to be folded in the multi-folding step. @@ -245,7 +245,7 @@ pub trait MultiFolding< &self, rng: impl RngCore, state: Vec, - external_inputs: Vec, + external_inputs: FC::ExternalInputs, ) -> Result; } diff --git a/solidity-verifiers/Cargo.toml b/solidity-verifiers/Cargo.toml index 2228d5cd..db26d064 100644 --- a/solidity-verifiers/Cargo.toml +++ b/solidity-verifiers/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" [dependencies] ark-groth16 = "^0.5.0" -ark-bn254 = "^0.5.0" +ark-bn254 = { version = "^0.5.0", default-features = false, features = ["r1cs"] } ark-poly-commit = "^0.5.0" ark-serialize = "^0.5.0" askama = { version = "0.12.0", features = ["config"], default-features = false } @@ -22,7 +22,7 @@ ark-crypto-primitives = { version = "^0.5.0", default-features = false, features ark-snark = { version = "^0.5.0", default-features = false } ark-relations = { version = "^0.5.0", default-features = false } ark-r1cs-std = { version = "^0.5.0", default-features = false, features = ["parallel"] } -ark-grumpkin = { version = "^0.5.0", default-features = false } +ark-grumpkin = { version = "^0.5.0", default-features = false, features = ["r1cs"] } folding-schemes = { path = "../folding-schemes/", features=["light-test"]} experimental-frontends = { path = "../experimental-frontends/"} noname = { git = "https://github.com/dmpierre/noname" } diff --git a/solidity-verifiers/src/verifiers/nova_cyclefold.rs b/solidity-verifiers/src/verifiers/nova_cyclefold.rs index 95a9b794..26a6397a 100644 --- a/solidity-verifiers/src/verifiers/nova_cyclefold.rs +++ b/solidity-verifiers/src/verifiers/nova_cyclefold.rs @@ -190,21 +190,20 @@ mod tests { } impl FCircuit for CubicFCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) } fn state_len(&self) -> usize { 1 } - fn external_inputs_len(&self) -> usize { - 0 - } fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let five = FpVar::::new_constant(cs.clone(), F::from(5u32))?; let z_i = z_i[0].clone(); @@ -224,6 +223,8 @@ mod tests { } impl FCircuit for MultiInputsFCircuit { type Params = (); + type ExternalInputs = (); + type ExternalInputsVar = (); fn new(_params: Self::Params) -> Result { Ok(Self { _f: PhantomData }) @@ -231,16 +232,13 @@ mod tests { fn state_len(&self) -> usize { 5 } - fn external_inputs_len(&self) -> usize { - 0 - } /// generates the constraints for the step of F for the given z_i fn generate_step_constraints( &self, cs: ConstraintSystemRef, _i: usize, z_i: Vec>, - _external_inputs: Vec>, + _external_inputs: Self::ExternalInputsVar, ) -> Result>, SynthesisError> { let four = FpVar::::new_constant(cs.clone(), F::from(4u32))?; let forty = FpVar::::new_constant(cs.clone(), F::from(40u32))?; @@ -344,7 +342,8 @@ mod tests { let mut nova = NOVA::::init(&fs_params, f_circuit, z_0).unwrap(); for _ in 0..n_steps { - nova.prove_step(&mut rng, vec![], None).unwrap(); + nova.prove_step(&mut rng, FC::ExternalInputs::default(), None) + .unwrap(); } let start = Instant::now();