You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
5.7 KiB

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<C> = <<C as CurveGroup>::Affine as AffineRepr>::ScalarField;
#[derive(Debug, Clone)]
pub struct GenZKCircuit<C: CurveGroup> {
pub _c: PhantomData<C>,
pub poseidon_config: PoseidonConfig<C::ScalarField>,
// 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<C: CurveGroup> ConstraintSynthesizer<CF<C>> for GenZKCircuit<C>
where
C::ScalarField: Absorb,
{
fn generate_constraints(self, cs: ConstraintSystemRef<CF<C>>) -> Result<(), SynthesisError> {
// public inputs
let cmVar = FpVar::<C::ScalarField>::new_input(cs.clone(), || Ok(self.cm))?;
let sVar = FpVar::<C::ScalarField>::new_input(cs.clone(), || Ok(self.s))?;
let r_hVar = FpVar::<C::ScalarField>::new_input(cs.clone(), || Ok(self.r_h))?;
let cVar = FpVar::<C::ScalarField>::new_input(cs.clone(), || Ok(self.c))?;
// private inputs
let xVar = FpVar::<C::ScalarField>::new_witness(cs.clone(), || Ok(self.x))?;
let rVar = FpVar::<C::ScalarField>::new_witness(cs.clone(), || Ok(self.r))?;
let o_hVar = FpVar::<C::ScalarField>::new_witness(cs.clone(), || Ok(self.o_h))?;
let crh_params =
CRHParametersVar::<C::ScalarField>::new_witness(
cs.clone(),
|| Ok(self.poseidon_config),
)
.unwrap();
Self::check(&crh_params, cmVar, sVar, r_hVar, cVar, xVar, rVar, o_hVar)?;
Ok(())
}
}
impl<C: CurveGroup> GenZKCircuit<C>
where
C::ScalarField: Absorb,
{
#[allow(clippy::too_many_arguments)]
pub fn check(
crh_params: &CRHParametersVar<C::ScalarField>,
// public inputs:
cm: FpVar<C::ScalarField>,
s: FpVar<C::ScalarField>,
r_h: FpVar<C::ScalarField>,
c: FpVar<C::ScalarField>,
// private inputs:
x: FpVar<C::ScalarField>,
r: FpVar<C::ScalarField>,
o_h: FpVar<C::ScalarField>,
) -> Result<(), SynthesisError> {
// cm == Commit(x) (Poseidon)
let computed_cm = CRHGadget::<C::ScalarField>::evaluate(crh_params, &[x.clone()]).unwrap();
computed_cm.enforce_equal(&cm)?;
// r_h == HCommit(r, o_h) (Poseidon)
let computed_r_h =
CRHGadget::<C::ScalarField>::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::<Fr>();
let mut transcript = PoseidonTranscript::<G1Projective>::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::<Fr>::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::<Fr>::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::<Fr>::new_ref();
// public inputs
let cmVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(cm)).unwrap();
let sVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(sigma_proof.s)).unwrap();
let r_hVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(sigma_proof.r_h)).unwrap();
let cVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(c)).unwrap();
// private inputs
let xVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(x)).unwrap();
let rVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(r)).unwrap();
let o_hVar = FpVar::<Fr>::new_witness(cs.clone(), || Ok(o_h)).unwrap();
let crh_params =
CRHParametersVar::<Fr>::new_witness(cs.clone(), || Ok(poseidon_config)).unwrap();
// GenZK
GenZKCircuit::<G1Projective>::check(
&crh_params,
cmVar,
sVar,
r_hVar,
cVar,
xVar,
rVar,
o_hVar,
)
.unwrap();
assert!(cs.is_satisfied().unwrap());
dbg!("num_constraints={:?}", cs.num_constraints());
}
}