use ark_crypto_primitives::snark::{FromFieldElementsGadget, SNARKGadget, SNARK}; use ark_ec::AffineRepr; use ark_ec::{CurveGroup, Group}; use ark_ff::{fields::Fp256, Field, PrimeField}; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, bits::uint8::UInt8, boolean::Boolean, eq::EqGadget, fields::{ fp::{AllocatedFp, FpVar}, nonnative::NonNativeFieldVar, FieldVar, }, groups::curves::short_weierstrass::ProjectiveVar, groups::GroupOpsBounds, prelude::CurveVar, ToBitsGadget, ToBytesGadget, ToConstraintFieldGadget, }; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError}; use ark_std::ops::Mul; use core::{borrow::Borrow, marker::PhantomData}; use derivative::Derivative; use crate::nifs::Phi; pub type ConstraintF = <::BaseField as Field>::BasePrimeField; #[derive(Debug, Derivative)] #[derivative(Clone(bound = "C: CurveGroup, GC: CurveVar>"))] pub struct PhiVar>> where for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { _c: PhantomData, cmE: GC, u: NonNativeFieldVar>, cmW: GC, x: NonNativeFieldVar>, } impl AllocVar, ConstraintF> for PhiVar where C: CurveGroup, GC: CurveVar>, for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { fn new_variable>>( cs: impl Into>>, f: impl FnOnce() -> Result, mode: AllocationMode, ) -> Result { f().and_then(|val| { let cs = cs.into(); let u = NonNativeFieldVar::>::new_variable( cs.clone(), || Ok(val.borrow().u), mode, )?; let cmE = GC::new_variable(cs.clone(), || Ok(val.borrow().cmE.0), mode)?; let cmW = GC::new_variable(cs.clone(), || Ok(val.borrow().cmW.0), mode)?; let x = NonNativeFieldVar::>::new_variable( cs.clone(), || Ok(val.borrow().x), mode, )?; Ok(Self { _c: PhantomData, cmE, u, cmW, x, }) }) } } pub struct NIFSGadget>> { _c: PhantomData, _gc: PhantomData, } impl>> NIFSGadget where C: CurveGroup, GC: CurveVar>, for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { // implements the constraints for NIFS.V pub fn verify( r: NonNativeFieldVar>, cmT: GC, phi1: PhiVar, phi2: PhiVar, phi3: PhiVar, ) -> Result>, SynthesisError> { let r2 = r.square()?; phi3.cmE.is_eq( &(phi1.cmE + cmT.scalar_mul_le(r.to_bits_le()?.iter())? + phi2.cmE.scalar_mul_le(r2.to_bits_le()?.iter())?), )?; phi3.u.is_eq(&(phi1.u + r.clone() * phi2.u))?; phi3.cmW .is_eq(&(phi1.cmW + phi2.cmW.scalar_mul_le(r.to_bits_le()?.iter())?))?; // wip x's check phi3.x.is_eq(&(phi1.x + r.clone() * phi2.x)) } } //// pub trait Config { type AugmentedFunctionCircuit: SNARK; // F' type FunctionCircuit: ConstraintSynthesizer; // F type DummyStepCircuit: SNARK; } pub struct AugmentedFCircuit< Fq: PrimeField, Fr: PrimeField, C: CurveGroup, GC: CurveVar, Cfg: Config, > { pub dummystep_vk: Option<>::VerifyingKey>, _c: PhantomData, _gc: PhantomData, } impl, Cfg: Config> ConstraintSynthesizer for AugmentedFCircuit { fn generate_constraints(self, cs: ConstraintSystemRef) -> Result<(), SynthesisError> { unimplemented!(); } } #[cfg(test)] mod test { use super::*; use crate::transcript::Transcript; use ark_relations::r1cs::ConstraintSystem; use ark_std::{ rand::{Rng, RngCore}, UniformRand, }; use crate::nifs; use crate::pedersen; use ark_ec::CurveGroup; // use ark_ed_on_mnt4_298::{constraints::EdwardsVar, EdwardsProjective}; use crate::pedersen::Commitment; use ark_mnt4_298::{constraints::G1Var as MNT4G1Var, Fq, Fr, G1Projective as MNT4G1Projective}; use ark_mnt6_298::{constraints::G1Var as MNT6G1Var, G1Projective as MNT6G1Projective}; use ark_std::{One, Zero}; // mnt4's Fr is the Constraint Field, // while mnt4's Fq is the Field where we work, which is the C::ScalarField for C==MNT6G1 #[test] fn test_phi_var() { let mut rng = ark_std::test_rng(); let phi = Phi:: { cmE: Commitment(MNT6G1Projective::generator()), u: Fq::one(), cmW: Commitment(MNT6G1Projective::generator()), x: Fq::one(), }; let cs = ConstraintSystem::::new_ref(); let phiVar = PhiVar::::new_witness(cs.clone(), || Ok(phi)).unwrap(); // println!("num_constraints={:?}", cs.num_constraints()); } #[test] fn test_nifs_gadget() { let mut rng = ark_std::test_rng(); let pedersen_params = pedersen::Pedersen::::new_params(&mut rng, 100); // 100 is wip, will get it from actual vec let cs = ConstraintSystem::::new_ref(); let (r1cs, w1, w2, _, x1, x2, _) = nifs::gen_test_values::<_, Fq>(&mut rng); let (A, B, C) = (r1cs.A.clone(), r1cs.B.clone(), r1cs.C.clone()); let r = Fq::rand(&mut rng); // this would come from the transcript let fw1 = nifs::FWit::::new(w1.clone(), A.len()); let fw2 = nifs::FWit::::new(w2.clone(), A.len()); let mut transcript_p = Transcript::::new(); let (fw3, phi1, phi2, T, cmT) = nifs::NIFS::::P( &mut transcript_p, &pedersen_params, r, &r1cs, fw1, fw2, ); let phi3 = nifs::NIFS::::V(r, &phi1, &phi2, &cmT); let phi1Var = PhiVar::::new_witness(cs.clone(), || Ok(phi1)).unwrap(); let phi2Var = PhiVar::::new_witness(cs.clone(), || Ok(phi2)).unwrap(); let phi3Var = PhiVar::::new_witness(cs.clone(), || Ok(phi3)).unwrap(); let cmTVar = MNT6G1Var::new_witness(cs.clone(), || Ok(cmT.0)).unwrap(); let rVar = NonNativeFieldVar::::new_witness(cs.clone(), || Ok(r)).unwrap(); let valid = NIFSGadget::::verify( rVar, cmTVar, phi1Var, phi2Var, phi3Var, ); println!("num_constraints={:?}", cs.num_constraints()); } }