arnaucube
arnaucube/sonobePublic Self-hosted repository
sonobe/folding-schemes/src/folding/nova/nifs/ova_circuits.rs
folding-schemes/src/folding/nova/nifs/ova_circuits.rsRaw
  1/// contains [Ova](https://hackmd.io/V4838nnlRKal9ZiTHiGYzw) NIFS related circuits
  2use ark_crypto_primitives::sponge::{constraints::AbsorbGadget, Absorb, CryptographicSponge};
  3use ark_ec::{CurveGroup, Group};
  4use ark_ff::PrimeField;
  5use ark_r1cs_std::{
  6    alloc::{AllocVar, AllocationMode},
  7    boolean::Boolean,
  8    eq::EqGadget,
  9    fields::{fp::FpVar, FieldVar},
 10    uint8::UInt8,
 11    ToConstraintFieldGadget,
 12};
 13use ark_relations::r1cs::{ConstraintSystemRef, Namespace, SynthesisError};
 14use ark_std::fmt::Debug;
 15use core::{borrow::Borrow, marker::PhantomData};
 16
 17use super::ova::CommittedInstance;
 18use super::NIFSGadgetTrait;
 19use crate::folding::circuits::{nonnative::affine::NonNativeAffineVar, CF1};
 20use crate::folding::traits::CommittedInstanceVarOps;
 21use crate::transcript::TranscriptVar;
 22
 23use crate::folding::nova::nifs::nova::ChallengeGadget;
 24
 25#[derive(Debug, Clone)]
 26pub struct CommittedInstanceVar<C: CurveGroup> {
 27    pub u: FpVar<C::ScalarField>,
 28    pub x: Vec<FpVar<C::ScalarField>>,
 29    pub cmWE: NonNativeAffineVar<C>,
 30}
 31
 32impl<C> AllocVar<CommittedInstance<C>, CF1<C>> for CommittedInstanceVar<C>
 33where
 34    C: CurveGroup,
 35{
 36    fn new_variable<T: Borrow<CommittedInstance<C>>>(
 37        cs: impl Into<Namespace<CF1<C>>>,
 38        f: impl FnOnce() -> Result<T, SynthesisError>,
 39        mode: AllocationMode,
 40    ) -> Result<Self, SynthesisError> {
 41        f().and_then(|val| {
 42            let cs = cs.into();
 43
 44            let u = FpVar::<C::ScalarField>::new_variable(cs.clone(), || Ok(val.borrow().u), mode)?;
 45            let x: Vec<FpVar<C::ScalarField>> =
 46                Vec::new_variable(cs.clone(), || Ok(val.borrow().x.clone()), mode)?;
 47
 48            let cmWE =
 49                NonNativeAffineVar::<C>::new_variable(cs.clone(), || Ok(val.borrow().cmWE), mode)?;
 50
 51            Ok(Self { u, x, cmWE })
 52        })
 53    }
 54}
 55
 56impl<C> AbsorbGadget<C::ScalarField> for CommittedInstanceVar<C>
 57where
 58    C: CurveGroup,
 59    <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
 60{
 61    fn to_sponge_bytes(&self) -> Result<Vec<UInt8<C::ScalarField>>, SynthesisError> {
 62        FpVar::batch_to_sponge_bytes(&self.to_sponge_field_elements()?)
 63    }
 64
 65    fn to_sponge_field_elements(&self) -> Result<Vec<FpVar<C::ScalarField>>, SynthesisError> {
 66        Ok([
 67            vec![self.u.clone()],
 68            self.x.clone(),
 69            self.cmWE.to_constraint_field()?,
 70        ]
 71        .concat())
 72    }
 73}
 74
 75impl<C: CurveGroup> CommittedInstanceVarOps<C> for CommittedInstanceVar<C> {
 76    type PointVar = NonNativeAffineVar<C>;
 77
 78    fn get_commitments(&self) -> Vec<Self::PointVar> {
 79        vec![self.cmWE.clone()]
 80    }
 81
 82    fn get_public_inputs(&self) -> &[FpVar<CF1<C>>] {
 83        &self.x
 84    }
 85
 86    fn enforce_incoming(&self) -> Result<(), SynthesisError> {
 87        self.u.enforce_equal(&FpVar::one())
 88    }
 89
 90    fn enforce_partial_equal(&self, other: &Self) -> Result<(), SynthesisError> {
 91        self.u.enforce_equal(&other.u)?;
 92        self.x.enforce_equal(&other.x)
 93    }
 94}
 95
 96/// Implements the circuit that does the checks of the Non-Interactive Folding Scheme Verifier
 97/// described of the Ova variant, where the cmWE check is delegated to the NIFSCycleFoldGadget.
 98pub struct NIFSGadget<C: CurveGroup, S: CryptographicSponge, T: TranscriptVar<CF1<C>, S>> {
 99    _c: PhantomData<C>,
100    _s: PhantomData<S>,
101    _t: PhantomData<T>,
102}
103
104impl<C, S, T> NIFSGadgetTrait<C, S, T> for NIFSGadget<C, S, T>
105where
106    C: CurveGroup,
107    S: CryptographicSponge,
108    T: TranscriptVar<CF1<C>, S>,
109    <C as ark_ec::CurveGroup>::BaseField: ark_ff::PrimeField,
110
111    <C as Group>::ScalarField: Absorb,
112    <C as CurveGroup>::BaseField: PrimeField,
113{
114    type CommittedInstance = CommittedInstance<C>;
115    type CommittedInstanceVar = CommittedInstanceVar<C>;
116    type Proof = C::ScalarField;
117    type ProofVar = FpVar<C::ScalarField>; // unused
118
119    fn verify(
120        transcript: &mut T,
121        pp_hash: FpVar<CF1<C>>,
122        U_i: Self::CommittedInstanceVar,
123        // U_i_vec is passed to reuse the already computed U_i_vec from previous methods
124        U_i_vec: Vec<FpVar<CF1<C>>>,
125        u_i: Self::CommittedInstanceVar,
126        _proof: Option<Self::ProofVar>,
127    ) -> Result<(Self::CommittedInstanceVar, Vec<Boolean<CF1<C>>>), SynthesisError> {
128        let r_bits = ChallengeGadget::<C, CommittedInstance<C>>::get_challenge_gadget(
129            transcript,
130            pp_hash.clone(),
131            U_i_vec,
132            u_i.clone(),
133            None,
134        )?;
135        let r = Boolean::le_bits_to_fp_var(&r_bits)?;
136
137        Ok((
138            Self::CommittedInstanceVar {
139                cmWE: NonNativeAffineVar::new_constant(ConstraintSystemRef::None, C::zero())?,
140                // ci3.u = U_i.u + r * u_i.u (u_i.u is always 1 in Ova)
141                u: U_i.u + &r,
142                // ci3.x = U_i.x + r * u_i.x
143                x: U_i
144                    .x
145                    .iter()
146                    .zip(u_i.x)
147                    .map(|(a, b)| a + &r * &b)
148                    .collect::<Vec<FpVar<CF1<C>>>>(),
149            },
150            r_bits,
151        ))
152    }
153}
154
155#[cfg(test)]
156pub mod tests {
157    use super::*;
158    use ark_crypto_primitives::sponge::poseidon::constraints::PoseidonSpongeVar;
159    use ark_crypto_primitives::sponge::poseidon::PoseidonSponge;
160    use ark_pallas::{Fr, Projective};
161    use ark_r1cs_std::R1CSVar;
162    use ark_std::UniformRand;
163    use ark_std::Zero;
164
165    use crate::commitment::pedersen::Pedersen;
166    use crate::folding::nova::nifs::{
167        ova::NIFS,
168        tests::{
169            test_committed_instance_hash_opt, test_committed_instance_to_sponge_preimage_opt,
170            test_nifs_gadget_opt,
171        },
172    };
173
174    #[test]
175    fn test_nifs_gadget() {
176        let mut rng = ark_std::test_rng();
177        // prepare the committed instances to test in-circuit
178        let ci: Vec<CommittedInstance<Projective>> = (0..2)
179            .into_iter()
180            .map(|_| CommittedInstance::<Projective> {
181                u: Fr::rand(&mut rng),
182                x: vec![Fr::rand(&mut rng); 1],
183                cmWE: Projective::rand(&mut rng),
184            })
185            .collect();
186
187        let (ci_out, ciVar_out) = test_nifs_gadget_opt::<
188            NIFS<Projective, Pedersen<Projective>, PoseidonSponge<Fr>>,
189            NIFSGadget<Projective, PoseidonSponge<Fr>, PoseidonSpongeVar<Fr>>,
190        >(ci, Fr::zero())
191        .unwrap();
192        assert_eq!(ciVar_out.u.value().unwrap(), ci_out.u);
193        assert_eq!(ciVar_out.x.value().unwrap(), ci_out.x);
194    }
195
196    #[test]
197    fn test_committed_instance_to_sponge_preimage() {
198        let mut rng = ark_std::test_rng();
199        let ci = CommittedInstance::<Projective> {
200            u: Fr::rand(&mut rng),
201            x: vec![Fr::rand(&mut rng); 1],
202            cmWE: Projective::rand(&mut rng),
203        };
204
205        test_committed_instance_to_sponge_preimage_opt::<
206            NIFS<Projective, Pedersen<Projective>, PoseidonSponge<Fr>>,
207            NIFSGadget<Projective, PoseidonSponge<Fr>, PoseidonSpongeVar<Fr>>,
208        >(ci);
209    }
210
211    #[test]
212    fn test_committed_instance_hash() {
213        let mut rng = ark_std::test_rng();
214        let ci = CommittedInstance::<Projective> {
215            u: Fr::rand(&mut rng),
216            x: vec![Fr::rand(&mut rng); 1],
217            cmWE: Projective::rand(&mut rng),
218        };
219        test_committed_instance_hash_opt::<
220            NIFS<Projective, Pedersen<Projective>, PoseidonSponge<Fr>>,
221            NIFSGadget<Projective, PoseidonSponge<Fr>, PoseidonSpongeVar<Fr>>,
222        >(ci);
223    }
224}