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