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 ark_ec::CurveGroup;
243 // use ark_ed_on_mnt4_298::{constraints::EdwardsVar, EdwardsProjective};
244 use crate::pedersen::Commitment;
245 use ark_mnt4_298::{constraints::G1Var as MNT4G1Var, Fq, Fr, G1Projective as MNT4G1Projective};
246 use ark_mnt6_298::{constraints::G1Var as MNT6G1Var, G1Projective as MNT6G1Projective};
247 use ark_std::{One, Zero};
248
249 // mnt4's Fr is the Constraint Field,
250 // while mnt4's Fq is the Field where we work, which is the C::ScalarField for C==MNT6G1
251
252 #[test]
253 fn test_phi_var() {
254 let mut rng = ark_std::test_rng();
255
256 let phi = Phi::<MNT6G1Projective> {
257 cmE: Commitment(MNT6G1Projective::generator()),
258 u: Fq::one(),
259 cmW: Commitment(MNT6G1Projective::generator()),
260 x: Fq::one(),
261 };
262
263 let cs = ConstraintSystem::<Fr>::new_ref();
264 let phiVar =
265 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi)).unwrap();
266 // println!("num_constraints={:?}", cs.num_constraints());
267 }
268
269 #[test]
270 fn test_nifs_gadget() {
271 let mut rng = ark_std::test_rng();
272 let pedersen_params = pedersen::Pedersen::<MNT6G1Projective>::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec
273
274 let cs = ConstraintSystem::<Fr>::new_ref();
275
276 let (r1cs, w1, w2, _, x1, x2, _) = nifs::gen_test_values::<_, Fq>(&mut rng);
277 let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone());
278
279 let r = Fq::rand(&mut rng); // this would come from the transcript
280
281 let fw1 = nifs::FWit::<MNT6G1Projective>::new(w1.clone(), A.len());
282 let fw2 = nifs::FWit::<MNT6G1Projective>::new(w2.clone(), A.len());
283 let mut transcript_p = Transcript::<Fq>::new();
284 let (fw3, phi1, phi2, T, cmT) = nifs::NIFS::<MNT6G1Projective>::P(
285 &mut transcript_p,
286 &pedersen_params,
287 r,
288 &r1cs,
289 fw1,
290 fw2,
291 );
292 let phi3 = nifs::NIFS::<MNT6G1Projective>::V(r, &phi1, &phi2, &cmT);
293
294 let phi1Var =
295 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi1)).unwrap();
296 let phi2Var =
297 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi2)).unwrap();
298 let phi3Var =
299 PhiVar::<MNT6G1Projective, MNT6G1Var>::new_witness(cs.clone(), || Ok(phi3)).unwrap();
300
301 let cmTVar = MNT6G1Var::new_witness(cs.clone(), || Ok(cmT.0)).unwrap();
302 let rVar = NonNativeFieldVar::<Fq, Fr>::new_witness(cs.clone(), || Ok(r)).unwrap();
303
304 let valid = NIFSGadget::<MNT6G1Projective, MNT6G1Var>::verify(
305 rVar, cmTVar, phi1Var, phi2Var, phi3Var,
306 );
307 println!("num_constraints={:?}", cs.num_constraints());
308 }
309}