arnaucube
arnaucube/nova-studyPublic Self-hosted repository
nova-study/src/circuits.rs
src/circuits.rsRaw
  1use ark_ec::CurveGroup;
  2use ark_ff::{Field, PrimeField};
  3use ark_r1cs_std::{
  4    alloc::{AllocVar, AllocationMode},
  5    boolean::Boolean,
  6    eq::EqGadget,
  7    fields::{fp::FpVar, nonnative::NonNativeFieldVar, FieldVar},
  8    groups::GroupOpsBounds,
  9    prelude::CurveVar,
 10    ToBitsGadget,
 11    ToConstraintFieldGadget,
 12    // groups::curves::short_weierstrass::ProjectiveVar,
 13};
 14// use ark_r1cs_std::groups::curves::twisted_edwards::AffineVar;
 15use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError};
 16
 17// use ark_crypto_primitives::crh::poseidon::{
 18//     constraints::{CRHGadget, CRHParametersVar},
 19//     CRH,
 20// };
 21// use ark_crypto_primitives::crh::{CRHScheme, CRHSchemeGadget};
 22// use ark_crypto_primitives::snark::{FromFieldElementsGadget, SNARKGadget, SNARK};
 23use ark_crypto_primitives::sponge::constraints::CryptographicSpongeVar;
 24use ark_crypto_primitives::sponge::poseidon::{
 25    constraints::PoseidonSpongeVar, PoseidonConfig, PoseidonSponge,
 26};
 27
 28use core::{borrow::Borrow, marker::PhantomData};
 29use derivative::Derivative;
 30
 31use crate::nifs::Phi;
 32
 33pub type ConstraintF<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
 34
 35#[derive(Debug, Derivative)]
 36#[derivative(Clone(bound = "C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>"))]
 37pub struct PhiVar<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>>
 38where
 39    for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
 40{
 41    _c: PhantomData<C>,
 42    cmE: GC,
 43    u: NonNativeFieldVar<C::ScalarField, ConstraintF<C>>,
 44    cmW: GC,
 45    x: NonNativeFieldVar<C::ScalarField, ConstraintF<C>>,
 46}
 47
 48impl<C, GC> AllocVar<Phi<C>, ConstraintF<C>> for PhiVar<C, GC>
 49where
 50    C: CurveGroup,
 51    GC: CurveVar<C, ConstraintF<C>>,
 52    for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
 53{
 54    fn new_variable<T: Borrow<Phi<C>>>(
 55        cs: impl Into<Namespace<ConstraintF<C>>>,
 56        f: impl FnOnce() -> Result<T, SynthesisError>,
 57        mode: AllocationMode,
 58    ) -> Result<Self, SynthesisError> {
 59        f().and_then(|val| {
 60            let cs = cs.into();
 61
 62            let u = NonNativeFieldVar::<C::ScalarField, ConstraintF<C>>::new_variable(
 63                cs.clone(),
 64                || Ok(val.borrow().u),
 65                mode,
 66            )?;
 67            let cmE = GC::new_variable(cs.clone(), || Ok(val.borrow().cmE.0), mode)?;
 68            let cmW = GC::new_variable(cs.clone(), || Ok(val.borrow().cmW.0), mode)?;
 69
 70            let x = NonNativeFieldVar::<C::ScalarField, ConstraintF<C>>::new_variable(
 71                cs,
 72                || Ok(val.borrow().x),
 73                mode,
 74            )?;
 75
 76            Ok(Self {
 77                _c: PhantomData,
 78                cmE,
 79                u,
 80                cmW,
 81                x,
 82            })
 83        })
 84    }
 85}
 86
 87pub struct NIFSGadget<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>> {
 88    _c: PhantomData<C>,
 89    _gc: PhantomData<GC>,
 90}
 91
 92impl<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>> NIFSGadget<C, GC>
 93where
 94    C: CurveGroup,
 95    GC: CurveVar<C, ConstraintF<C>>,
 96    for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
 97{
 98    // implements the constraints for NIFS.V
 99    pub fn verify(
100        r: NonNativeFieldVar<C::ScalarField, ConstraintF<C>>,
101        cmT: GC,
102        phi1: PhiVar<C, GC>,
103        phi2: PhiVar<C, GC>,
104        phi3: PhiVar<C, GC>,
105    ) -> Result<(), SynthesisError> {
106        let r2 = r.square()?;
107
108        phi3.cmE.enforce_equal(
109            &(phi1.cmE
110                + cmT.scalar_mul_le(r.to_bits_le()?.iter())?
111                + phi2.cmE.scalar_mul_le(r2.to_bits_le()?.iter())?),
112        )?;
113        phi3.u.enforce_equal(&(phi1.u + r.clone() * phi2.u))?;
114        phi3.cmW
115            .enforce_equal(&(phi1.cmW + phi2.cmW.scalar_mul_le(r.to_bits_le()?.iter())?))?;
116
117        // wip x's check
118        phi3.x.enforce_equal(&(phi1.x + r * phi2.x))?;
119        Ok(())
120    }
121}
122
123use ark_crypto_primitives::sponge::Absorb;
124pub struct AugmentedFCircuit<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>>
125where
126    <<C as CurveGroup>::BaseField as Field>::BasePrimeField: Absorb,
127{
128    pub _c: PhantomData<C>,
129    pub _gc: PhantomData<GC>,
130
131    // pub poseidon_native: PoseidonSponge<ConstraintF<C>>,
132    pub poseidon_config: PoseidonConfig<ConstraintF<C>>,
133    pub i: Option<C::BaseField>,
134    pub z_0: Option<C::BaseField>,
135    pub z_i: Option<C::BaseField>,
136    pub z_i1: Option<C::BaseField>, // z_{i+1}
137    pub phi: Option<Phi<C>>, // phi_i in the paper sometimes appears as phi (φ) and others as 𝗎
138    pub phiBig: Option<Phi<C>>, // ϕ_i
139    pub phiOut: Option<Phi<C>>, // ϕ_{i+1}
140    pub cmT: Option<C>,
141    pub r: Option<C::ScalarField>, // This will not be an input and derived from a hash internally in the circuit (poseidon transcript)
142}
143
144impl<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>> ConstraintSynthesizer<ConstraintF<C>>
145    for AugmentedFCircuit<C, GC>
146where
147    C: CurveGroup,
148    GC: CurveVar<C, ConstraintF<C>>,
149    for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
150    <C as CurveGroup>::BaseField: PrimeField,
151    <<C as CurveGroup>::BaseField as Field>::BasePrimeField: Absorb,
152{
153    fn generate_constraints(
154        self,
155        cs: ConstraintSystemRef<ConstraintF<C>>,
156    ) -> Result<(), SynthesisError> {
157        let i = FpVar::<ConstraintF<C>>::new_witness(cs.clone(), || Ok(self.i.unwrap()))?;
158        let z_0 = FpVar::<ConstraintF<C>>::new_witness(cs.clone(), || Ok(self.z_0.unwrap()))?;
159        let z_i = FpVar::<ConstraintF<C>>::new_witness(cs.clone(), || Ok(self.z_i.unwrap()))?;
160        let z_i1 = FpVar::<ConstraintF<C>>::new_witness(cs.clone(), || Ok(self.z_i1.unwrap()))?;
161
162        let phi = PhiVar::<C, GC>::new_witness(cs.clone(), || Ok(self.phi.unwrap()))?;
163        let phiBig = PhiVar::<C, GC>::new_witness(cs.clone(), || Ok(self.phiBig.unwrap()))?;
164        let phiOut = PhiVar::<C, GC>::new_witness(cs.clone(), || Ok(self.phiOut.unwrap()))?;
165
166        let cmT = GC::new_witness(cs.clone(), || Ok(self.cmT.unwrap()))?;
167        let r =
168            NonNativeFieldVar::<C::ScalarField, ConstraintF<C>>::new_witness(cs.clone(), || {
169                Ok(self.r.unwrap())
170            })?; // r will come from transcript
171
172        // 1. phi.x == H(vk_nifs, i, z_0, z_i, phiBig)
173        let mut sponge =
174            PoseidonSpongeVar::<ConstraintF<C>>::new(cs.clone(), &self.poseidon_config);
175        let input = vec![i.clone(), z_0.clone(), z_i.clone()];
176        sponge.absorb(&input)?;
177        let input = vec![
178            phiBig.u.to_constraint_field()?,
179            phiBig.x.to_constraint_field()?,
180        ];
181        sponge.absorb(&input)?;
182        let input = vec![phiBig.cmE.to_bytes()?, phiBig.cmW.to_bytes()?];
183        sponge.absorb(&input)?;
184        let h = sponge.squeeze_field_elements(1).unwrap();
185        let x_CF = phi.x.to_constraint_field()?; // phi.x on the ConstraintF<C>
186        x_CF[0].enforce_equal(&h[0])?; // review
187
188        // 2. phi.cmE==0, phi.u==1
189        (phi.cmE.is_zero()?).enforce_equal(&Boolean::TRUE)?;
190        (phi.u.is_one()?).enforce_equal(&Boolean::TRUE)?;
191
192        // 3. nifs.verify, checks that folding phi & phiBig obtains phiOut
193        NIFSGadget::<C, GC>::verify(r, cmT, phi, phiBig, phiOut.clone())?;
194
195        // 4. zksnark.V(vk_snark, phi_new, proof_phi)
196        // 5. phiOut.x == H(i+1, z_0, z_i+1, phiOut)
197        // WIP
198        let mut sponge = PoseidonSpongeVar::<ConstraintF<C>>::new(cs, &self.poseidon_config);
199        let input = vec![i + FpVar::<ConstraintF<C>>::one(), z_0, z_i1];
200        sponge.absorb(&input)?;
201        let input = vec![phiOut.cmE.to_bytes()?, phiOut.cmW.to_bytes()?];
202        sponge.absorb(&input)?;
203        let h = sponge.squeeze_field_elements(1).unwrap();
204        let x_CF = phiOut.x.to_constraint_field()?; // phi.x on the ConstraintF<C>
205        x_CF[0].enforce_equal(&h[0])?; // review
206
207        Ok(())
208    }
209}
210
211//////////
212
213// pub struct Nova<MainField: PrimeField, SecondField: PrimeField, C1: CurveGroup, C2: CurveGroup> {}
214// pub trait SNARKs<MainField: PrimeField, SecondField: PrimeField> {
215//     type AugmentedFunctionSNARK: SNARK<MainField>;
216//     // type FunctionSNARK: ConstraintSynthesizer<Fr>; // F
217//     type DummyStepSNARK: SNARK<SecondField>;
218//
219//     type AugmentedFunctionCircuit: SNARKGadget<MainField, SecondField, Self::AugmentedFunctionSNARK>; // F'
220//     type FunctionCircuit: ConstraintSynthesizer<MainField>; // F
221//     type DummyStepCircuit: SNARKGadget<SecondField, MainField, Self::DummyStepSNARK>;
222// }
223// pub struct TS<
224//     MainField: PrimeField,
225//     SecondField: PrimeField,
226//     Config: SNARKs<MainField, SecondField>,
227// > {
228//     augmentedF_pk: <Config::AugmentedFunctionSNARK as SNARK<MainField>>::ProvingKey,
229//     augmentedF_vk: <Config::AugmentedFunctionSNARK as SNARK<MainField>>::VerifyingKey,
230//
231//     dummy_pk: <Config::DummyStepSNARK as SNARK<SecondField>>::ProvingKey,
232//     dummy_vk: <Config::DummyStepSNARK as SNARK<SecondField>>::VerifyingKey,
233// }
234
235#[cfg(test)]
236mod test {
237    use super::*;
238
239    use crate::transcript::Transcript;
240    use ark_relations::r1cs::ConstraintSystem;
241    use ark_std::UniformRand;
242
243    use crate::nifs;
244    use crate::pedersen;
245    use crate::transcript::poseidon_test_config;
246    use ark_ec::Group;
247    // use ark_ed_on_mnt4_298::{constraints::EdwardsVar, EdwardsProjective};
248    use crate::pedersen::Commitment;
249    // use ark_mnt4_298::{constraints::G1Var as MNT4G1Var, G1Projective as MNT4G1Projective}
250    use ark_mnt4_298::{Fq, Fr};
251    use ark_mnt6_298::{constraints::G1Var as MNT6G1Var, G1Projective as MNT6G1Projective};
252    use ark_std::One;
253
254    // mnt4's Fr is the Constraint Field,
255    // while mnt4's Fq is the Field where we work, which is the C::ScalarField for C==MNT6G1
256
257    #[test]
258    fn test_phi_var() {
259        let phi = Phi::<MNT6G1Projective> {
260            cmE: Commitment(MNT6G1Projective::generator()),
261            u: Fq::one(),
262            cmW: Commitment(MNT6G1Projective::generator()),
263            x: Fq::one(),
264        };
265
266        let cs = ConstraintSystem::<Fr>::new_ref();
267        let _phiVar =
268            PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi)).unwrap();
269        // println!("num_constraints={:?}", cs.num_constraints());
270    }
271
272    #[test]
273    fn test_nifs_gadget() {
274        let mut rng = ark_std::test_rng();
275        let pedersen_params = pedersen::Pedersen::<MNT6G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
276        let poseidon_config = poseidon_test_config::<Fq>();
277
278        let cs = ConstraintSystem::<Fr>::new_ref();
279
280        let (r1cs, ws, _) = nifs::gen_test_values::<Fq>(2);
281        let (A, _, _) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
282
283        let r = Fq::rand(&mut rng); // this would come from the transcript
284
285        let fw1 = nifs::FWit::<MNT6G1Projective>::new(ws[0].clone(), A.len());
286        let fw2 = nifs::FWit::<MNT6G1Projective>::new(ws[1].clone(), A.len());
287
288        let mut transcript_p = Transcript::<Fq, MNT6G1Projective>::new(&poseidon_config);
289
290        let (_fw3, phi1, phi2, _T, cmT) = nifs::NIFS::<MNT6G1Projective>::P(
291            &mut transcript_p,
292            &pedersen_params,
293            r,
294            &r1cs,
295            fw1,
296            fw2,
297        );
298        let phi3 = nifs::NIFS::<MNT6G1Projective>::V(r, &phi1, &phi2, &cmT);
299
300        let phi1Var =
301            PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi1)).unwrap();
302        let phi2Var =
303            PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi2)).unwrap();
304        let phi3Var =
305            PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi3)).unwrap();
306
307        let cmTVar = MNT6G1Var::new_witness(cs.clone(), || Ok(cmT.0)).unwrap();
308        let rVar = NonNativeFieldVar::<Fq, Fr>::new_witness(cs.clone(), || Ok(r)).unwrap();
309
310        NIFSGadget::<MNT6G1Projective, MNT6G1Var>::verify(rVar, cmTVar, phi1Var, phi2Var, phi3Var)
311            .unwrap();
312        // println!("num_constraints={:?}", cs.num_constraints());
313    }
314}