From 1ef933a70707fe08865c88ca71269e87fa887855 Mon Sep 17 00:00:00 2001 From: winderica Date: Thu, 26 Dec 2024 17:00:51 +0800 Subject: [PATCH] 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;