use ark_crypto_primitives::crh::{ poseidon::constraints::{CRHGadget, CRHParametersVar}, CRHSchemeGadget, }; use ark_crypto_primitives::sponge::{poseidon::PoseidonConfig, Absorb}; use ark_ec::{AffineRepr, CurveGroup}; use ark_r1cs_std::{alloc::AllocVar, eq::EqGadget, fields::fp::FpVar}; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, SynthesisError}; use core::marker::PhantomData; // CF (ConstraintField) pub type CF = <::Affine as AffineRepr>::ScalarField; #[derive(Debug, Clone)] pub struct GenZKCircuit { pub _c: PhantomData, pub poseidon_config: PoseidonConfig, // public pub cm: C::ScalarField, pub s: C::ScalarField, pub r_h: C::ScalarField, pub c: C::ScalarField, // private pub x: C::ScalarField, pub r: C::ScalarField, pub o_h: C::ScalarField, } impl ConstraintSynthesizer> for GenZKCircuit where C::ScalarField: Absorb, { fn generate_constraints(self, cs: ConstraintSystemRef>) -> Result<(), SynthesisError> { // public inputs let cmVar = FpVar::::new_input(cs.clone(), || Ok(self.cm))?; let sVar = FpVar::::new_input(cs.clone(), || Ok(self.s))?; let r_hVar = FpVar::::new_input(cs.clone(), || Ok(self.r_h))?; let cVar = FpVar::::new_input(cs.clone(), || Ok(self.c))?; // private inputs let xVar = FpVar::::new_witness(cs.clone(), || Ok(self.x))?; let rVar = FpVar::::new_witness(cs.clone(), || Ok(self.r))?; let o_hVar = FpVar::::new_witness(cs.clone(), || Ok(self.o_h))?; let crh_params = CRHParametersVar::::new_witness( cs.clone(), || Ok(self.poseidon_config), ) .unwrap(); Self::check(&crh_params, cmVar, sVar, r_hVar, cVar, xVar, rVar, o_hVar)?; Ok(()) } } impl GenZKCircuit where C::ScalarField: Absorb, { #[allow(clippy::too_many_arguments)] pub fn check( crh_params: &CRHParametersVar, // public inputs: cm: FpVar, s: FpVar, r_h: FpVar, c: FpVar, // private inputs: x: FpVar, r: FpVar, o_h: FpVar, ) -> Result<(), SynthesisError> { // cm == Commit(x) (Poseidon) let computed_cm = CRHGadget::::evaluate(crh_params, &[x.clone()]).unwrap(); computed_cm.enforce_equal(&cm)?; // r_h == HCommit(r, o_h) (Poseidon) let computed_r_h = CRHGadget::::evaluate(crh_params, &[r.clone(), o_h.clone()]).unwrap(); computed_r_h.enforce_equal(&r_h)?; // s == r + c * x s.enforce_equal(&(r + (c * x)))?; Ok(()) } } #[cfg(test)] pub mod tests { use super::*; use ark_bn254::{Fr, G1Projective}; use ark_crypto_primitives::sponge::{poseidon::PoseidonSponge, CryptographicSponge}; use ark_ec::Group; use ark_r1cs_std::{alloc::AllocVar, fields::fp::FpVar}; use ark_relations::r1cs::ConstraintSystem; use ark_std::UniformRand; use std::ops::Mul; use crate::sigmabus::SigmaProof; use crate::transcript::{tests::poseidon_test_config, PoseidonTranscript}; #[test] fn test_gen_zk() { let mut rng = ark_std::test_rng(); let poseidon_config = poseidon_test_config::(); let mut transcript = PoseidonTranscript::::new(&poseidon_config); let x = Fr::rand(&mut rng); // the next lines do the same that is done in Sigmabus::prove but here in the test to have // access to the internal values: let mut sponge = PoseidonSponge::::new(&poseidon_config); sponge.absorb(&x); let cm: Fr = sponge.squeeze_field_elements(1)[0]; transcript.absorb(&cm); let r = Fr::rand(&mut rng); let o_h = Fr::rand(&mut rng); let R = G1Projective::generator().mul(r); let mut sponge = PoseidonSponge::::new(&poseidon_config); sponge.absorb(&vec![r, o_h]); let r_h: Fr = sponge.squeeze_field_elements(1)[0]; transcript.absorb_point(&R); transcript.absorb(&r_h); let c = transcript.get_challenge(); let s = r + c * x; let sigma_proof = SigmaProof { s, R, r_h }; // end of Sigmabus::prove let cs = ConstraintSystem::::new_ref(); // public inputs let cmVar = FpVar::::new_witness(cs.clone(), || Ok(cm)).unwrap(); let sVar = FpVar::::new_witness(cs.clone(), || Ok(sigma_proof.s)).unwrap(); let r_hVar = FpVar::::new_witness(cs.clone(), || Ok(sigma_proof.r_h)).unwrap(); let cVar = FpVar::::new_witness(cs.clone(), || Ok(c)).unwrap(); // private inputs let xVar = FpVar::::new_witness(cs.clone(), || Ok(x)).unwrap(); let rVar = FpVar::::new_witness(cs.clone(), || Ok(r)).unwrap(); let o_hVar = FpVar::::new_witness(cs.clone(), || Ok(o_h)).unwrap(); let crh_params = CRHParametersVar::::new_witness(cs.clone(), || Ok(poseidon_config)).unwrap(); // GenZK GenZKCircuit::::check( &crh_params, cmVar, sVar, r_hVar, cVar, xVar, rVar, o_hVar, ) .unwrap(); assert!(cs.is_satisfied().unwrap()); dbg!("num_constraints={:?}", cs.num_constraints()); } }