nova-study/src/circuits.rs
src/circuits.rsRaw
1use ark_crypto_primitives::snark::{FromFieldElementsGadget, SNARKGadget, SNARK};
2use ark_ec::AffineRepr;
3use ark_ec::{CurveGroup, Group};
4use ark_ff::{fields::Fp256, Field, PrimeField};
5use ark_r1cs_std::{
6 alloc::{AllocVar, AllocationMode},
7 bits::uint8::UInt8,
8 boolean::Boolean,
9 eq::EqGadget,
10 fields::{
11 fp::{AllocatedFp, FpVar},
12 nonnative::NonNativeFieldVar,
13 FieldVar,
14 },
15 groups::curves::short_weierstrass::ProjectiveVar,
16 groups::GroupOpsBounds,
17 prelude::CurveVar,
18 ToBitsGadget, ToBytesGadget, ToConstraintFieldGadget,
19};
20use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError};
21use ark_std::ops::Mul;
22
23use core::{borrow::Borrow, marker::PhantomData};
24use derivative::Derivative;
25
26use crate::nifs::Phi;
27
28pub type ConstraintF<C> = <<C as CurveGroup>::BaseField as Field>::BasePrimeField;
29
30#[derive(Debug, Derivative)]
31#[derivative(Clone(bound = "C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>"))]
32pub struct PhiVar<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>>
33where
34 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
35{
36 _c: PhantomData<C>,
37 cmE: GC,
38 u: NonNativeFieldVar<C::ScalarField, ConstraintF<C>>,
39 cmW: GC,
40 x: NonNativeFieldVar<C::ScalarField, ConstraintF<C>>,
41}
42
43impl<C, GC> AllocVar<Phi<C>, ConstraintF<C>> for PhiVar<C, GC>
44where
45 C: CurveGroup,
46 GC: CurveVar<C, ConstraintF<C>>,
47 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
48{
49 fn new_variable<T: Borrow<Phi<C>>>(
50 cs: impl Into<Namespace<ConstraintF<C>>>,
51 f: impl FnOnce() -> Result<T, SynthesisError>,
52 mode: AllocationMode,
53 ) -> Result<Self, SynthesisError> {
54 f().and_then(|val| {
55 let cs = cs.into();
56
57 let u = NonNativeFieldVar::<C::ScalarField, ConstraintF<C>>::new_variable(
58 cs.clone(),
59 || Ok(val.borrow().u),
60 mode,
61 )?;
62 let cmE = GC::new_variable(cs.clone(), || Ok(val.borrow().cmE.0), mode)?;
63 let cmW = GC::new_variable(cs.clone(), || Ok(val.borrow().cmW.0), mode)?;
64
65 let x = NonNativeFieldVar::<C::ScalarField, ConstraintF<C>>::new_variable(
66 cs.clone(),
67 || Ok(val.borrow().x),
68 mode,
69 )?;
70
71 Ok(Self {
72 _c: PhantomData,
73 cmE,
74 u,
75 cmW,
76 x,
77 })
78 })
79 }
80}
81
82pub struct NIFSGadget<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>> {
83 _c: PhantomData<C>,
84 _gc: PhantomData<GC>,
85}
86
87impl<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>> NIFSGadget<C, GC>
88where
89 C: CurveGroup,
90 GC: CurveVar<C, ConstraintF<C>>,
91 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
92{
93 // implements the constraints for NIFS.V
94 pub fn verify(
95 r: NonNativeFieldVar<C::ScalarField, ConstraintF<C>>,
96 cmT: GC,
97 phi1: PhiVar<C, GC>,
98 phi2: PhiVar<C, GC>,
99 phi3: PhiVar<C, GC>,
100 ) -> Result<Boolean<ConstraintF<C>>, SynthesisError> {
101 let r2 = r.square()?;
102
103 phi3.cmE.is_eq(
104 &(phi1.cmE
105 + cmT.scalar_mul_le(r.to_bits_le()?.iter())?
106 + phi2.cmE.scalar_mul_le(r2.to_bits_le()?.iter())?),
107 )?;
108 phi3.u.is_eq(&(phi1.u + r.clone() * phi2.u))?;
109 phi3.cmW
110 .is_eq(&(phi1.cmW + phi2.cmW.scalar_mul_le(r.to_bits_le()?.iter())?))?;
111
112 // wip x's check
113 phi3.x.is_eq(&(phi1.x + r.clone() * phi2.x))
114 }
115}
116
117////
118
119pub trait Config<Fq: PrimeField, Fr: PrimeField> {
120 type AugmentedFunctionCircuit: SNARK<Fq>; // F'
121 type FunctionCircuit: ConstraintSynthesizer<Fq>; // F
122 type DummyStepCircuit: SNARK<Fr>;
123}
124
125pub struct AugmentedFCircuit<
126 Fq: PrimeField,
127 Fr: PrimeField,
128 C: CurveGroup,
129 GC: CurveVar<C, Fq>,
130 Cfg: Config<Fq, Fr>,
131> {
132 pub dummystep_vk: Option<<Cfg::DummyStepCircuit as SNARK<Fr>>::VerifyingKey>,
133 _c: PhantomData<C>,
134 _gc: PhantomData<GC>,
135}
136
137impl<Fq: PrimeField, Fr: PrimeField, C: CurveGroup, GC: CurveVar<C, Fq>, Cfg: Config<Fq, Fr>>
138 ConstraintSynthesizer<Fq> for AugmentedFCircuit<Fq, Fr, C, GC, Cfg>
139{
140 fn generate_constraints(self, cs: ConstraintSystemRef<Fq>) -> Result<(), SynthesisError> {
141 unimplemented!();
142 }
143}
144
145#[cfg(test)]
146mod test {
147 use super::*;
148
149 use crate::transcript::Transcript;
150 use ark_relations::r1cs::ConstraintSystem;
151 use ark_std::{
152 rand::{Rng, RngCore},
153 UniformRand,
154 };
155
156 use crate::nifs;
157 use crate::pedersen;
158 use ark_ec::CurveGroup;
159 // use ark_ed_on_mnt4_298::{constraints::EdwardsVar, EdwardsProjective};
160 use crate::pedersen::Commitment;
161 use ark_mnt4_298::{constraints::G1Var as MNT4G1Var, Fq, Fr, G1Projective as MNT4G1Projective};
162 use ark_mnt6_298::{constraints::G1Var as MNT6G1Var, G1Projective as MNT6G1Projective};
163 use ark_std::{One, Zero};
164
165 // mnt4's Fr is the Constraint Field,
166 // while mnt4's Fq is the Field where we work, which is the C::ScalarField for C==MNT6G1
167
168 #[test]
169 fn test_phi_var() {
170 let mut rng = ark_std::test_rng();
171
172 let phi = Phi::<MNT6G1Projective> {
173 cmE: Commitment(MNT6G1Projective::generator()),
174 u: Fq::one(),
175 cmW: Commitment(MNT6G1Projective::generator()),
176 x: Fq::one(),
177 };
178
179 let cs = ConstraintSystem::<Fr>::new_ref();
180 let phiVar =
181 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi)).unwrap();
182 // println!("num_constraints={:?}", cs.num_constraints());
183 }
184
185 #[test]
186 fn test_nifs_gadget() {
187 let mut rng = ark_std::test_rng();
188 let pedersen_params = pedersen::Pedersen::<MNT6G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
189
190 let cs = ConstraintSystem::<Fr>::new_ref();
191
192 let (r1cs, w1, w2, _, x1, x2, _) = nifs::gen_test_values::<_, Fq>(&mut rng);
193 let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
194
195 let r = Fq::rand(&mut rng); // this would come from the transcript
196
197 let fw1 = nifs::FWit::<MNT6G1Projective>::new(w1.clone(), A.len());
198 let fw2 = nifs::FWit::<MNT6G1Projective>::new(w2.clone(), A.len());
199 let mut transcript_p = Transcript::<Fq>::new();
200 let (fw3, phi1, phi2, T, cmT) = nifs::NIFS::<MNT6G1Projective>::P(
201 &mut transcript_p,
202 &pedersen_params,
203 r,
204 &r1cs,
205 fw1,
206 fw2,
207 );
208 let phi3 = nifs::NIFS::<MNT6G1Projective>::V(r, &phi1, &phi2, &cmT);
209
210 let phi1Var =
211 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi1)).unwrap();
212 let phi2Var =
213 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi2)).unwrap();
214 let phi3Var =
215 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi3)).unwrap();
216
217 let cmTVar = MNT6G1Var::new_witness(cs.clone(), || Ok(cmT.0)).unwrap();
218 let rVar = NonNativeFieldVar::<Fq, Fr>::new_witness(cs.clone(), || Ok(r)).unwrap();
219
220 let valid = NIFSGadget::<MNT6G1Projective, MNT6G1Var>::verify(
221 rVar, cmTVar, phi1Var, phi2Var, phi3Var,
222 );
223 println!("num_constraints={:?}", cs.num_constraints());
224 }
225}