diff --git a/folding-schemes/src/folding/circuits/cyclefold.rs b/folding-schemes/src/folding/circuits/cyclefold.rs index c4527d71..9e86651a 100644 --- a/folding-schemes/src/folding/circuits/cyclefold.rs +++ b/folding-schemes/src/folding/circuits/cyclefold.rs @@ -16,20 +16,23 @@ use ark_relations::r1cs::{ }; use ark_std::fmt::Debug; use ark_std::rand::RngCore; -use ark_std::Zero; +use ark_std::{One, Zero}; use core::{borrow::Borrow, marker::PhantomData}; use super::{nonnative::uint::NonNativeUintVar, CF1, CF2}; -use crate::arith::{ - r1cs::{circuits::R1CSMatricesVar, extract_w_x, R1CS}, - ArithGadget, -}; use crate::commitment::CommitmentScheme; use crate::constants::NOVA_N_BITS_RO; use crate::folding::nova::{nifs::NIFS, traits::NIFSTrait}; use crate::transcript::{AbsorbNonNative, AbsorbNonNativeGadget, Transcript, TranscriptVar}; use crate::utils::gadgets::{EquivalenceGadget, VectorGadget}; use crate::Error; +use crate::{ + arith::{ + r1cs::{circuits::R1CSMatricesVar, extract_w_x, R1CS}, + ArithGadget, + }, + folding::traits::Inputize, +}; /// Re-export the Nova committed instance as `CycleFoldCommittedInstance` and /// witness as `CycleFoldWitness`, for clarity and consistency @@ -37,6 +40,35 @@ pub use crate::folding::nova::{ CommittedInstance as CycleFoldCommittedInstance, Witness as CycleFoldWitness, }; +impl>> Inputize, CycleFoldCommittedInstanceVar> + for CycleFoldCommittedInstance +{ + fn inputize(&self) -> Vec> { + let zero = (&C::BaseField::zero(), &C::BaseField::zero()); + let cmE = self.cmE.into_affine(); + let cmW = self.cmW.into_affine(); + let (cmE_x, cmE_y) = cmE.xy().unwrap_or(zero); + let (cmW_x, cmW_y) = cmW.xy().unwrap_or(zero); + 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() + } +} + /// CycleFoldCommittedInstanceVar is the CycleFold CommittedInstance represented /// in folding verifier circuit #[derive(Debug, Clone)] diff --git a/folding-schemes/src/folding/circuits/nonnative/affine.rs b/folding-schemes/src/folding/circuits/nonnative/affine.rs index da4d9e4f..58f6b2ae 100644 --- a/folding-schemes/src/folding/circuits/nonnative/affine.rs +++ b/folding-schemes/src/folding/circuits/nonnative/affine.rs @@ -10,7 +10,10 @@ use ark_serialize::{CanonicalSerialize, CanonicalSerializeWithFlags}; use ark_std::Zero; use core::borrow::Borrow; -use crate::transcript::{AbsorbNonNative, AbsorbNonNativeGadget}; +use crate::{ + folding::traits::Inputize, + transcript::{AbsorbNonNative, AbsorbNonNativeGadget}, +}; use super::uint::{nonnative_field_to_field_elements, NonNativeUintVar}; @@ -104,21 +107,19 @@ pub(crate) fn nonnative_affine_to_field_elements( (x, y) } -impl NonNativeAffineVar { - // Extracts a list of field elements of type `C::ScalarField` from the public input - // `p`, in exactly the same way as how `NonNativeAffineVar` is represented as limbs of type - // `FpVar` in-circuit. - #[allow(clippy::type_complexity)] - pub fn inputize(p: C) -> Result<(Vec, Vec), SynthesisError> { - let affine = p.into_affine(); +impl Inputize> for C { + fn inputize(&self) -> Vec { + let affine = self.into_affine(); let zero = (&C::BaseField::zero(), &C::BaseField::zero()); let (x, y) = affine.xy().unwrap_or(zero); - let x = NonNativeUintVar::inputize(*x); - let y = NonNativeUintVar::inputize(*y); - Ok((x, y)) + let x = x.inputize(); + let y = y.inputize(); + [x, y].concat() } +} +impl NonNativeAffineVar { pub fn zero() -> Self { Self::new_constant(ConstraintSystemRef::None, C::zero()).unwrap() } @@ -179,9 +180,11 @@ mod tests { let mut rng = ark_std::test_rng(); let p = Projective::rand(&mut rng); let pVar = NonNativeAffineVar::::new_witness(cs.clone(), || Ok(p)).unwrap(); - let (x, y) = NonNativeAffineVar::inputize(p).unwrap(); + let xy = p.inputize(); - assert_eq!(pVar.x.0.value().unwrap(), x); - assert_eq!(pVar.y.0.value().unwrap(), y); + assert_eq!( + [pVar.x.0.value().unwrap(), pVar.y.0.value().unwrap()].concat(), + xy + ); } } diff --git a/folding-schemes/src/folding/circuits/nonnative/uint.rs b/folding-schemes/src/folding/circuits/nonnative/uint.rs index 4624cb37..fc3c09e4 100644 --- a/folding-schemes/src/folding/circuits/nonnative/uint.rs +++ b/folding-schemes/src/folding/circuits/nonnative/uint.rs @@ -17,6 +17,7 @@ use num_bigint::BigUint; use num_integer::Integer; use crate::{ + folding::traits::Inputize, transcript::{AbsorbNonNative, AbsorbNonNativeGadget}, utils::gadgets::{EquivalenceGadget, MatrixGadget, SparseMatrixVar, VectorGadget}, }; @@ -259,15 +260,15 @@ impl AllocVar for NonNativeUintVar { } } -impl NonNativeUintVar { - pub fn inputize(x: T) -> Vec { +impl Inputize> for T { + fn inputize(&self) -> Vec { assert_eq!(T::extension_degree(), 1); - x.to_base_prime_field_elements() + self.to_base_prime_field_elements() .next() .unwrap() .into_bigint() .to_bits_le() - .chunks(Self::bits_per_limb()) + .chunks(NonNativeUintVar::::bits_per_limb()) .map(|chunk| F::from_bigint(F::BigInt::from_bits_le(chunk)).unwrap()) .collect() } diff --git a/folding-schemes/src/folding/hypernova/cccs.rs b/folding-schemes/src/folding/hypernova/cccs.rs index 5378a639..cca92def 100644 --- a/folding-schemes/src/folding/hypernova/cccs.rs +++ b/folding-schemes/src/folding/hypernova/cccs.rs @@ -10,6 +10,7 @@ use super::Witness; use crate::arith::{ccs::CCS, Arith}; 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; @@ -152,6 +153,12 @@ impl CommittedInstanceOps for CCCS { } } +impl Inputize> for CCCS { + fn inputize(&self) -> Vec { + [&self.C.inputize()[..], &self.x].concat() + } +} + #[cfg(test)] pub mod tests { use ark_pallas::Fr; diff --git a/folding-schemes/src/folding/hypernova/decider_eth.rs b/folding-schemes/src/folding/hypernova/decider_eth.rs index 0c4bdd9f..b29baff0 100644 --- a/folding-schemes/src/folding/hypernova/decider_eth.rs +++ b/folding-schemes/src/folding/hypernova/decider_eth.rs @@ -14,8 +14,9 @@ use super::{lcccs::LCCCS, HyperNova}; use crate::commitment::{ kzg::Proof as KZGProof, pedersen::Params as PedersenParams, CommitmentScheme, }; -use crate::folding::circuits::{nonnative::affine::NonNativeAffineVar, CF2}; +use crate::folding::circuits::CF2; use crate::folding::nova::decider_eth::VerifierParam; +use crate::folding::traits::Inputize; use crate::frontend::FCircuit; use crate::Error; use crate::{Decider as DeciderTrait, FoldingScheme}; @@ -192,19 +193,11 @@ where // Note: the NIMFS proof is checked inside the DeciderEthCircuit, which ensures that the // 'proof.U_i1' is correctly computed - let (cmC_x, cmC_y) = NonNativeAffineVar::inputize(proof.U_i1.C)?; - let public_input: Vec = [ vec![pp_hash, i], z_0, z_i, - // U_i+1: - cmC_x, - cmC_y, - vec![proof.U_i1.u], - proof.U_i1.x.clone(), - proof.U_i1.r_x.clone(), - proof.U_i1.v.clone(), + proof.U_i1.inputize(), vec![proof.kzg_challenge, proof.kzg_proof.eval, proof.rho], ] .concat(); diff --git a/folding-schemes/src/folding/hypernova/lcccs.rs b/folding-schemes/src/folding/hypernova/lcccs.rs index 6d2c2165..8784d21e 100644 --- a/folding-schemes/src/folding/hypernova/lcccs.rs +++ b/folding-schemes/src/folding/hypernova/lcccs.rs @@ -14,6 +14,7 @@ use crate::arith::ccs::CCS; use crate::arith::Arith; 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; @@ -154,6 +155,19 @@ impl CommittedInstanceOps for LCCCS { } } +impl Inputize> for LCCCS { + fn inputize(&self) -> Vec { + [ + &self.C.inputize(), + &[self.u][..], + &self.x, + &self.r_x, + &self.v, + ] + .concat() + } +} + #[cfg(test)] pub mod tests { use ark_pallas::{Fr, Projective}; diff --git a/folding-schemes/src/folding/nova/decider.rs b/folding-schemes/src/folding/nova/decider.rs index 901f152a..e67d77da 100644 --- a/folding-schemes/src/folding/nova/decider.rs +++ b/folding-schemes/src/folding/nova/decider.rs @@ -3,7 +3,7 @@ /// 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::{AffineRepr, CurveGroup, Group}; +use ark_ec::{CurveGroup, Group}; use ark_ff::{BigInteger, PrimeField}; use ark_r1cs_std::{groups::GroupOpsBounds, prelude::CurveVar, ToConstraintFieldGadget}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize}; @@ -16,10 +16,10 @@ use super::decider_circuits::{DeciderCircuit1, DeciderCircuit2}; use super::{nifs::NIFS, traits::NIFSTrait, CommittedInstance, Nova}; use crate::commitment::CommitmentScheme; use crate::folding::circuits::{ - cyclefold::CycleFoldCommittedInstance, - nonnative::{affine::NonNativeAffineVar, uint::NonNativeUintVar}, + cyclefold::{CycleFoldCommittedInstance, CycleFoldCommittedInstanceVar}, CF2, }; +use crate::folding::traits::Inputize; use crate::frontend::FCircuit; use crate::Error; use crate::{Decider as DeciderTrait, FoldingScheme}; @@ -288,50 +288,21 @@ where // compute U = U_{d+1}= NIFS.V(U_d, u_d, cmT) let U = NIFS::::verify(proof.r, running_instance, incoming_instance, &proof.cmT); - let (cmE_x, cmE_y) = NonNativeAffineVar::inputize(U.cmE)?; - let (cmW_x, cmW_y) = NonNativeAffineVar::inputize(U.cmW)?; - let (cmT_x, cmT_y) = NonNativeAffineVar::inputize(proof.cmT)?; - - let zero = (&C2::BaseField::zero(), &C2::BaseField::zero()); - let cmE_affine = proof.cf_U_i.cmE.into_affine(); - let cmW_affine = proof.cf_U_i.cmW.into_affine(); - let (cf_cmE_x, cf_cmE_y) = cmE_affine.xy().unwrap_or(zero); - let cf_cmE_z = C1::ScalarField::one(); - let (cf_cmW_x, cf_cmW_y) = cmW_affine.xy().unwrap_or(zero); - let cf_cmW_z = C1::ScalarField::one(); - // snark proof 1 let c1_public_input: Vec = [ vec![vp.pp_hash, i], z_0, z_i, - // U_{i+1} values: - vec![U.u], - U.x.clone(), - cmE_x, - cmE_y, - cmW_x, - cmW_y, + U.inputize(), // CS1 values: proof.cs1_challenges.to_vec(), // c_W, c_E vec![ proof.cs1_proofs[0].eval, // eval_W proof.cs1_proofs[1].eval, // eval_E ], - // cf_U_i values - NonNativeUintVar::>::inputize(proof.cf_U_i.u), - proof - .cf_U_i - .x - .iter() - .flat_map(|&x_i| NonNativeUintVar::>::inputize(x_i)) - .collect::>(), - vec![ - *cf_cmE_x, *cf_cmE_y, cf_cmE_z, *cf_cmW_x, *cf_cmW_y, cf_cmW_z, - ], + Inputize::, CycleFoldCommittedInstanceVar>::inputize(&proof.cf_U_i), // NIFS values: - cmT_x, - cmT_y, + proof.cmT.inputize(), vec![proof.r], ] .concat(); @@ -342,21 +313,13 @@ where return Err(Error::SNARKVerificationFail); } - let (cf2_cmE_x, cf2_cmE_y) = NonNativeAffineVar::inputize(proof.cf_U_i.cmE)?; - let (cf2_cmW_x, cf2_cmW_y) = NonNativeAffineVar::inputize(proof.cf_U_i.cmW)?; - // snark proof 2 // migrate pp_hash from C1::Fr to C1::Fq let pp_hash_Fq = C2::ScalarField::from_le_bytes_mod_order(&vp.pp_hash.into_bigint().to_bytes_le()); let c2_public_input: Vec = [ vec![pp_hash_Fq], - vec![proof.cf_U_i.u], - proof.cf_U_i.x.clone(), - cf2_cmE_x, - cf2_cmE_y, - cf2_cmW_x, - cf2_cmW_y, + proof.cf_U_i.inputize(), proof.cs2_challenges.to_vec(), vec![ proof.cs2_proofs[0].eval, // eval_W diff --git a/folding-schemes/src/folding/nova/decider_eth.rs b/folding-schemes/src/folding/nova/decider_eth.rs index 64f1a7cd..7bc73f5e 100644 --- a/folding-schemes/src/folding/nova/decider_eth.rs +++ b/folding-schemes/src/folding/nova/decider_eth.rs @@ -22,7 +22,8 @@ use crate::commitment::{ pedersen::Params as PedersenParams, CommitmentScheme, }; -use crate::folding::circuits::{nonnative::affine::NonNativeAffineVar, CF2}; +use crate::folding::circuits::CF2; +use crate::folding::traits::Inputize; use crate::frontend::FCircuit; use crate::Error; use crate::{Decider as DeciderTrait, FoldingScheme}; @@ -212,27 +213,17 @@ where // compute U = U_{d+1}= NIFS.V(U_d, u_d, cmT) let U = NIFS::::verify(proof.r, running_instance, incoming_instance, &proof.cmT); - let (cmE_x, cmE_y) = NonNativeAffineVar::inputize(U.cmE)?; - let (cmW_x, cmW_y) = NonNativeAffineVar::inputize(U.cmW)?; - let (cmT_x, cmT_y) = NonNativeAffineVar::inputize(proof.cmT)?; - let public_input: Vec = [ vec![vp.pp_hash, i], z_0, z_i, - vec![U.u], - U.x.clone(), - cmE_x, - cmE_y, - cmW_x, - cmW_y, + U.inputize(), proof.kzg_challenges.to_vec(), vec![ proof.kzg_proofs[0].eval, // eval_W proof.kzg_proofs[1].eval, // eval_E ], - cmT_x, - cmT_y, + proof.cmT.inputize(), vec![proof.r], ] .concat(); diff --git a/folding-schemes/src/folding/nova/mod.rs b/folding-schemes/src/folding/nova/mod.rs index 1c1985fe..e0fb818a 100644 --- a/folding-schemes/src/folding/nova/mod.rs +++ b/folding-schemes/src/folding/nova/mod.rs @@ -53,7 +53,7 @@ pub mod decider_circuits; pub mod decider_eth; pub mod decider_eth_circuit; -use super::traits::{CommittedInstanceOps, WitnessOps}; +use super::traits::{CommittedInstanceOps, Inputize, WitnessOps}; /// Configuration for Nova's CycleFold circuit pub struct NovaCycleFoldConfig { @@ -134,6 +134,18 @@ impl CommittedInstanceOps for CommittedInstance { } } +impl Inputize> for CommittedInstance { + fn inputize(&self) -> Vec { + [ + &[self.u][..], + &self.x, + &self.cmE.inputize(), + &self.cmW.inputize(), + ] + .concat() + } +} + #[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)] pub struct Witness { pub E: Vec, diff --git a/folding-schemes/src/folding/protogalaxy/circuits.rs b/folding-schemes/src/folding/protogalaxy/circuits.rs index 57cba2a9..136e1238 100644 --- a/folding-schemes/src/folding/protogalaxy/circuits.rs +++ b/folding-schemes/src/folding/protogalaxy/circuits.rs @@ -503,12 +503,8 @@ mod tests { &witnesses, )?; - let folded_instance = Folding::::verify( - &mut transcript_v, - &instance, - &instances, - proof.clone(), - )?; + let folded_instance = + Folding::::verify(&mut transcript_v, &instance, &instances, proof.clone())?; let cs = ConstraintSystem::new_ref(); let mut transcript_var = PoseidonSpongeVar::new(cs.clone(), &poseidon_config); diff --git a/folding-schemes/src/folding/protogalaxy/mod.rs b/folding-schemes/src/folding/protogalaxy/mod.rs index 356c959f..28c1f0b9 100644 --- a/folding-schemes/src/folding/protogalaxy/mod.rs +++ b/folding-schemes/src/folding/protogalaxy/mod.rs @@ -50,7 +50,7 @@ use circuits::AugmentedFCircuit; use folding::Folding; use super::traits::{ - CommittedInstanceOps, CommittedInstanceVarOps, Dummy, WitnessOps, WitnessVarOps, + CommittedInstanceOps, CommittedInstanceVarOps, Dummy, Inputize, WitnessOps, WitnessVarOps, }; /// Configuration for ProtoGalaxy's CycleFold circuit @@ -119,6 +119,14 @@ impl CommittedInstanceOps for CommittedInsta } } +impl Inputize> + for CommittedInstance +{ + fn inputize(&self) -> Vec { + [&self.phi.inputize(), &self.betas, &[self.e][..], &self.x].concat() + } +} + #[derive(Clone, Debug)] pub struct CommittedInstanceVar { phi: NonNativeAffineVar, diff --git a/folding-schemes/src/folding/traits.rs b/folding-schemes/src/folding/traits.rs index 3890554b..1cae1865 100644 --- a/folding-schemes/src/folding/traits.rs +++ b/folding-schemes/src/folding/traits.rs @@ -12,7 +12,7 @@ use crate::{transcript::Transcript, Error}; use super::circuits::CF1; -pub trait CommittedInstanceOps { +pub trait CommittedInstanceOps: Inputize, Self::Var> { /// The in-circuit representation of the committed instance. type Var: AllocVar> + CommittedInstanceVarOps; /// `hash` implements the committed instance hash compatible with the @@ -129,3 +129,10 @@ impl Dummy for Vec { vec![Default::default(); cfg] } } + +/// 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. +/// This is useful for the verifier to compute the public inputs. +pub trait Inputize { + fn inputize(&self) -> Vec; +}