constraints to work with BasePrimeField & verify constraints test done
arnaucube root@arnaucube.com
Wed, 19 Oct 2022 19:57:47 +0200
2 files changed,
101 insertions(+),
31 deletions(-)
M
src/constraints.rs
→
src/constraints.rs
@@ -1,32 +1,33 @@
-use crate::{Parameters, Signature}; +use crate::{Parameters, PublicKey, Signature}; use ark_ec::{AffineCurve, ProjectiveCurve}; use ark_ed_on_bn254::{constraints::EdwardsVar, EdwardsParameters, FqParameters}; use ark_ff::{ fields::{Field, Fp256}, - to_bytes, ToConstraintField, + to_bytes, PrimeField, ToConstraintField, }; use ark_r1cs_std::{ alloc::{AllocVar, AllocationMode}, bits::uint8::UInt8, boolean::Boolean, - fields::fp::FpVar, + eq::EqGadget, + fields::{fp::FpVar, FieldVar}, groups::{curves::twisted_edwards::AffineVar, GroupOpsBounds}, prelude::CurveVar, ToBitsGadget, }; use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError}; -use ark_std::ops::Mul; +use ark_std::ops::{Add, Mul}; use core::{borrow::Borrow, marker::PhantomData}; use derivative::Derivative; // hash +use arkworks_native_gadgets::poseidon as poseidon_native; use arkworks_r1cs_gadgets::poseidon; -use arkworks_r1cs_gadgets::poseidon::{FieldHasherGadget, PoseidonGadget}; +use arkworks_r1cs_gadgets::poseidon::{FieldHasherGadget, PoseidonGadget, PoseidonParametersVar}; -// type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField; -type ConstraintF<C> = <C as ProjectiveCurve>::ScalarField; // Fr +use crate::ConstraintF; #[derive(Derivative)] #[derivative(@@ -42,6 +43,25 @@ #[doc(hidden)]
_group: PhantomData<*const C>, } +impl<C, GC> AllocVar<PublicKey<C>, ConstraintF<C>> for PublicKeyVar<C, GC> +where + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, +{ + fn new_variable<T: Borrow<PublicKey<C>>>( + cs: impl Into<Namespace<ConstraintF<C>>>, + f: impl FnOnce() -> Result<T, SynthesisError>, + mode: AllocationMode, + ) -> Result<Self, SynthesisError> { + let pub_key = GC::new_variable(cs, f, mode)?; + Ok(Self { + pub_key, + _group: PhantomData, + }) + } +} + #[derive(Derivative)] #[derivative( Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"),@@ -51,8 +71,6 @@ pub struct SignatureVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
where for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - // s: FpVar<ConstraintF>, - // s: C::ScalarField, s: Vec<UInt8<ConstraintF<C>>>, r: GC, _curve: PhantomData<C>,@@ -61,8 +79,7 @@
impl<C, GC> AllocVar<Signature<C>, ConstraintF<C>> for SignatureVar<C, GC> where C: ProjectiveCurve, - // TODO not sure on '+ AllocVarar' - GC: CurveVar<C, ConstraintF<C>> + AllocVar<GC, ConstraintF<C>>, + GC: CurveVar<C, ConstraintF<C>>, for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { fn new_variable<T: Borrow<Signature<C>>>(@@ -86,8 +103,8 @@
let r = GC::new_variable(cs.clone(), || Ok(val.borrow().r), mode)?; Ok(Self { - s: s, // TODO not sure of FpVar::Constant - r: r, + s, + r, _curve: PhantomData, }) })@@ -129,8 +146,7 @@ pub struct BlindSigVerifyGadget<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
where for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - params: Parameters<C>, - // sig: Signature<C>, + _params: Parameters<C>, // TODO review if needed, maybe delete _gc: PhantomData<GC>, }@@ -143,8 +159,9 @@ ark_r1cs_std::groups::curves::twisted_edwards::AffineVar<
EdwardsParameters, FpVar<Fp256<FqParameters>>, >: From<GC>, - FpVar<<C as ProjectiveCurve>::ScalarField>: Mul<FpVar<Fp256<FqParameters>>>, - FpVar<<C as ProjectiveCurve>::ScalarField>: From<<C as ProjectiveCurve>::ScalarField>, + <C as ProjectiveCurve>::BaseField: PrimeField, + FpVar<<C as ProjectiveCurve>::BaseField>: Mul<FpVar<Fp256<FqParameters>>>, + FpVar<<C as ProjectiveCurve>::BaseField>: From<FpVar<Fp256<FqParameters>>>, { fn verify( parameters: &ParametersVar<C, GC>,@@ -152,32 +169,85 @@ poseidon_hash: &PoseidonGadget<ConstraintF<C>>,
m: FpVar<ConstraintF<C>>, s: &SignatureVar<C, GC>, q: &PublicKeyVar<C, GC>, - ) -> Result<Boolean<ConstraintF<C>>, SynthesisError> - where - <C as ProjectiveCurve>::ScalarField: Iterator, // WIP - <C as ProjectiveCurve>::ScalarField: From< - <FpVar<<C as ProjectiveCurve>::ScalarField> as Mul<FpVar<Fp256<FqParameters>>>>::Output, - >, - { + ) -> Result<Boolean<ConstraintF<C>>, SynthesisError> { let s_s = s.s.clone(); let sG = parameters .generator .scalar_mul_le(s_s.to_bits_le()?.iter())?; - // G * s == R + Q * (R.x * H(m)) // Note: in a circuit that aggregates multiple verifications, the hashing step could be // done outside the signature verification, once for all 1 votes and once for all 0 votes, // saving lots of constraints let hm = poseidon_hash.hash(&[m])?; let r = EdwardsVar::from(s.r.clone()); // WIP - - let rx_hm: ConstraintF<C> = ConstraintF::<C>::from(hm * r.x); - let rx_hm_fp: FpVar<ConstraintF<C>> = FpVar::<ConstraintF<C>>::from(rx_hm); + let rx_fpvar: FpVar<ConstraintF<C>> = r.x.into(); - let Q_rx_hm = q.pub_key.scalar_mul_le(rx_hm_fp.to_bits_le()?.iter())?; + // G * s == R + Q * (R.x * H(m)) + let Q_rx_hm_0 = q.pub_key.scalar_mul_le(rx_fpvar.to_bits_le()?.iter())?; + let Q_rx_hm = Q_rx_hm_0.scalar_mul_le(hm.to_bits_le()?.iter())?; let RHS = s.r.clone() + Q_rx_hm; sG.is_eq(&RHS) } } + +#[cfg(test)] +mod test { + use super::*; + use crate::{poseidon_setup_params, BlindSigScheme}; + use ark_ed_on_bn254::constraints::EdwardsVar as BabyJubJubVar; + use ark_ed_on_bn254::EdwardsProjective as BabyJubJub; + + use arkworks_native_gadgets::poseidon; + use arkworks_utils::Curve; + + use ark_relations::r1cs::ConstraintSystem; + + type Fq = <BabyJubJub as ProjectiveCurve>::BaseField; + // type Fr = <BabyJubJub as ProjectiveCurve>::ScalarField; + type S = BlindSigScheme<BabyJubJub>; + + #[test] + fn test_verify() { + let poseidon_params = poseidon_setup_params::<Fq>(Curve::Bn254, 5, 3); + let poseidon_hash = poseidon::Poseidon::new(poseidon_params); + let mut rng = ark_std::test_rng(); + + // create signature using native-rust lib + let params = S::setup(); + let (pk, sk) = S::keygen(¶ms, &mut rng); + let (k, signer_r) = S::new_request_params(¶ms, &mut rng); + let m = Fq::from(1234); + let (m_blinded, u) = S::blind(¶ms, &mut rng, &poseidon_hash, m, signer_r).unwrap(); + let s_blinded = S::blind_sign(sk, k, m_blinded); + let s = S::unblind(s_blinded, u); + let verified = S::verify(¶ms, &poseidon_hash, m, s.clone(), pk); + assert!(verified); + + // use the constraint system to verify the signature + type SG = BlindSigVerifyGadget<BabyJubJub, BabyJubJubVar>; + let cs = ConstraintSystem::<Fq>::new_ref(); + + let params_var = + ParametersVar::<BabyJubJub, BabyJubJubVar>::new_constant(cs.clone(), params).unwrap(); + let signature_var = + SignatureVar::<BabyJubJub, BabyJubJubVar>::new_witness(cs.clone(), || Ok(&s)).unwrap(); + let pk_var = + PublicKeyVar::<BabyJubJub, BabyJubJubVar>::new_witness(cs.clone(), || Ok(&pk)).unwrap(); + let m_var = FpVar::<Fq>::new_witness(cs.clone(), || Ok(&m)).unwrap(); + let poseidon_hash_var = + PoseidonGadget::<Fq>::from_native(&mut cs.clone(), poseidon_hash).unwrap(); + + let valid_sig = SG::verify( + ¶ms_var, + &poseidon_hash_var, + m_var, + &signature_var, + &pk_var, + ) + .unwrap(); + valid_sig.enforce_equal(&Boolean::<Fq>::TRUE).unwrap(); + assert!(cs.is_satisfied().unwrap()); + } +}
M
src/lib.rs
→
src/lib.rs
@@ -30,7 +30,7 @@ use ark_ed_on_bn254::{
EdwardsAffine, EdwardsParameters, EdwardsProjective, FqParameters, Fr, FrParameters, }; -type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField; +pub type ConstraintF<C> = <<C as ProjectiveCurve>::BaseField as Field>::BasePrimeField; pub type SecretKey<C> = <C as ProjectiveCurve>::ScalarField; pub type PublicKey<C> = <C as ProjectiveCurve>::Affine; pub type BlindedSignature<C> = <C as ProjectiveCurve>::ScalarField;@@ -177,7 +177,7 @@ <C as ProjectiveCurve>::ScalarField: From<BigInteger256>,
{ let sG = parameters.generator.mul(s.s.into_repr()); - // TODO hash(m) must be \in Fr + // TODO the output of hash(m) must be \in Fr let hm = poseidon_hash.hash(&[m]).unwrap(); // let hm_fr = C::ScalarField::from_repr(hm.into_repr()).unwrap(); let hm_fr = C::ScalarField::from_le_bytes_mod_order(&to_bytes!(hm).unwrap()); // WIP TMP