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 _c: PhantomData<C>,
129 _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 phi: Option<Phi<C>>, // phi in the paper sometimes appears as phi (φ) and others as 𝗎
137 pub phiBig: Option<Phi<C>>,
138 pub phiOut: Option<Phi<C>>,
139 pub cmT: Option<C>,
140 pub r: Option<C::ScalarField>, // This will not be an input and derived from a hash internally in the circuit (poseidon transcript)
141}
142
143impl<C: CurveGroup, GC: CurveVar<C, ConstraintF<C>>> ConstraintSynthesizer<ConstraintF<C>>
144 for AugmentedFCircuit<C, GC>
145where
146 C: CurveGroup,
147 GC: CurveVar<C, ConstraintF<C>>,
148 for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
149 <C as CurveGroup>::BaseField: PrimeField,
150 <<C as CurveGroup>::BaseField as Field>::BasePrimeField: Absorb,
151{
152 fn generate_constraints(
153 self,
154 cs: ConstraintSystemRef<ConstraintF<C>>,
155 ) -> Result<(), SynthesisError> {
156 let i = FpVar::<ConstraintF<C>>::new_witness(cs.clone(), || Ok(self.i.unwrap()))?;
157 let z_0 = FpVar::<ConstraintF<C>>::new_witness(cs.clone(), || Ok(self.z_0.unwrap()))?;
158 let z_i = FpVar::<ConstraintF<C>>::new_witness(cs.clone(), || Ok(self.z_i.unwrap()))?;
159
160 let phi = PhiVar::<C, GC>::new_witness(cs.clone(), || Ok(self.phi.unwrap()))?;
161 let phiBig = PhiVar::<C, GC>::new_witness(cs.clone(), || Ok(self.phiBig.unwrap()))?;
162 let phiOut = PhiVar::<C, GC>::new_witness(cs.clone(), || Ok(self.phiOut.unwrap()))?;
163
164 let cmT = GC::new_witness(cs.clone(), || Ok(self.cmT.unwrap()))?;
165 let r =
166 NonNativeFieldVar::<C::ScalarField, ConstraintF<C>>::new_witness(cs.clone(), || {
167 Ok(self.r.unwrap())
168 })?; // r will come from transcript
169
170 // 1. phi.x == H(vk_nifs, i, z_0, z_i, phiBig)
171 let mut sponge = PoseidonSpongeVar::<ConstraintF<C>>::new(cs, &self.poseidon_config);
172 let input = vec![i, z_0, z_i];
173 sponge.absorb(&input)?;
174 let input = vec![
175 phiBig.u.to_constraint_field()?,
176 phiBig.x.to_constraint_field()?,
177 ];
178 sponge.absorb(&input)?;
179 let input = vec![phiBig.cmE.to_bytes()?, phiBig.cmW.to_bytes()?];
180 sponge.absorb(&input)?;
181 let h = sponge.squeeze_field_elements(1).unwrap();
182 let x_CF = phi.x.to_constraint_field()?; // phi.x on the ConstraintF<C>
183 x_CF[0].enforce_equal(&h[0])?; // review
184
185 // // 2. phi.cmE==0, phi.u==1
186 // <GC as CurveVar<C, ConstraintF<C>>>::is_zero(&phi.cmE)?;
187 (phi.cmE.is_zero()?).enforce_equal(&Boolean::TRUE)?;
188 (phi.u.is_one()?).enforce_equal(&Boolean::TRUE)?;
189
190 // 3. nifs.verify
191 NIFSGadget::<C, GC>::verify(r, cmT, phi, phiBig, phiOut)?;
192
193 // 4. zksnark.V(vk_snark, phi_new, proof_phi)
194
195 Ok(())
196 }
197}
198
199//////////
200
201// pub struct Nova<MainField: PrimeField, SecondField: PrimeField, C1: CurveGroup, C2: CurveGroup> {}
202// pub trait SNARKs<MainField: PrimeField, SecondField: PrimeField> {
203// type AugmentedFunctionSNARK: SNARK<MainField>;
204// // type FunctionSNARK: ConstraintSynthesizer<Fr>; // F
205// type DummyStepSNARK: SNARK<SecondField>;
206//
207// type AugmentedFunctionCircuit: SNARKGadget<MainField, SecondField, Self::AugmentedFunctionSNARK>; // F'
208// type FunctionCircuit: ConstraintSynthesizer<MainField>; // F
209// type DummyStepCircuit: SNARKGadget<SecondField, MainField, Self::DummyStepSNARK>;
210// }
211// pub struct TS<
212// MainField: PrimeField,
213// SecondField: PrimeField,
214// Config: SNARKs<MainField, SecondField>,
215// > {
216// augmentedF_pk: <Config::AugmentedFunctionSNARK as SNARK<MainField>>::ProvingKey,
217// augmentedF_vk: <Config::AugmentedFunctionSNARK as SNARK<MainField>>::VerifyingKey,
218//
219// dummy_pk: <Config::DummyStepSNARK as SNARK<SecondField>>::ProvingKey,
220// dummy_vk: <Config::DummyStepSNARK as SNARK<SecondField>>::VerifyingKey,
221// }
222
223#[cfg(test)]
224mod test {
225 use super::*;
226
227 use crate::transcript::Transcript;
228 use ark_relations::r1cs::ConstraintSystem;
229 use ark_std::UniformRand;
230
231 use crate::nifs;
232 use crate::pedersen;
233 use crate::transcript::poseidon_test_config;
234 use ark_ec::Group;
235 // use ark_ed_on_mnt4_298::{constraints::EdwardsVar, EdwardsProjective};
236 use crate::pedersen::Commitment;
237 // use ark_mnt4_298::{constraints::G1Var as MNT4G1Var, G1Projective as MNT4G1Projective}
238 use ark_mnt4_298::{Fq, Fr};
239 use ark_mnt6_298::{constraints::G1Var as MNT6G1Var, G1Projective as MNT6G1Projective};
240 use ark_std::One;
241
242 // mnt4's Fr is the Constraint Field,
243 // while mnt4's Fq is the Field where we work, which is the C::ScalarField for C==MNT6G1
244
245 #[test]
246 fn test_phi_var() {
247 let phi = Phi::<MNT6G1Projective> {
248 cmE: Commitment(MNT6G1Projective::generator()),
249 u: Fq::one(),
250 cmW: Commitment(MNT6G1Projective::generator()),
251 x: Fq::one(),
252 };
253
254 let cs = ConstraintSystem::<Fr>::new_ref();
255 let _phiVar =
256 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi)).unwrap();
257 // println!("num_constraints={:?}", cs.num_constraints());
258 }
259
260 #[test]
261 fn test_nifs_gadget() {
262 let mut rng = ark_std::test_rng();
263 let pedersen_params = pedersen::Pedersen::<MNT6G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
264 let poseidon_config = poseidon_test_config::<Fq>();
265
266 let cs = ConstraintSystem::<Fr>::new_ref();
267
268 let (r1cs, ws, _) = nifs::gen_test_values::<Fq>(2);
269 let (A, _, _) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
270
271 let r = Fq::rand(&mut rng); // this would come from the transcript
272
273 let fw1 = nifs::FWit::<MNT6G1Projective>::new(ws[0].clone(), A.len());
274 let fw2 = nifs::FWit::<MNT6G1Projective>::new(ws[1].clone(), A.len());
275
276 let mut transcript_p = Transcript::<Fq, MNT6G1Projective>::new(&poseidon_config);
277
278 let (_fw3, phi1, phi2, _T, cmT) = nifs::NIFS::<MNT6G1Projective>::P(
279 &mut transcript_p,
280 &pedersen_params,
281 r,
282 &r1cs,
283 fw1,
284 fw2,
285 );
286 let phi3 = nifs::NIFS::<MNT6G1Projective>::V(r, &phi1, &phi2, &cmT);
287
288 let phi1Var =
289 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi1)).unwrap();
290 let phi2Var =
291 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi2)).unwrap();
292 let phi3Var =
293 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi3)).unwrap();
294
295 let cmTVar = MNT6G1Var::new_witness(cs.clone(), || Ok(cmT.0)).unwrap();
296 let rVar = NonNativeFieldVar::<Fq, Fr>::new_witness(cs.clone(), || Ok(r)).unwrap();
297
298 NIFSGadget::<MNT6G1Projective, MNT6G1Var>::verify(rVar, cmTVar, phi1Var, phi2Var, phi3Var)
299 .unwrap();
300 // println!("num_constraints={:?}", cs.num_constraints());
301 }
302}