|
@ -1,32 +1,33 @@ |
|
|
use crate::{Parameters, Signature};
|
|
|
|
|
|
|
|
|
use crate::{Parameters, PublicKey, Signature};
|
|
|
|
|
|
|
|
|
use ark_ec::{AffineCurve, ProjectiveCurve};
|
|
|
use ark_ec::{AffineCurve, ProjectiveCurve};
|
|
|
use ark_ed_on_bn254::{constraints::EdwardsVar, EdwardsParameters, FqParameters};
|
|
|
use ark_ed_on_bn254::{constraints::EdwardsVar, EdwardsParameters, FqParameters};
|
|
|
use ark_ff::{
|
|
|
use ark_ff::{
|
|
|
fields::{Field, Fp256},
|
|
|
fields::{Field, Fp256},
|
|
|
to_bytes, ToConstraintField,
|
|
|
|
|
|
|
|
|
to_bytes, PrimeField, ToConstraintField,
|
|
|
};
|
|
|
};
|
|
|
use ark_r1cs_std::{
|
|
|
use ark_r1cs_std::{
|
|
|
alloc::{AllocVar, AllocationMode},
|
|
|
alloc::{AllocVar, AllocationMode},
|
|
|
bits::uint8::UInt8,
|
|
|
bits::uint8::UInt8,
|
|
|
boolean::Boolean,
|
|
|
boolean::Boolean,
|
|
|
fields::fp::FpVar,
|
|
|
|
|
|
|
|
|
eq::EqGadget,
|
|
|
|
|
|
fields::{fp::FpVar, FieldVar},
|
|
|
groups::{curves::twisted_edwards::AffineVar, GroupOpsBounds},
|
|
|
groups::{curves::twisted_edwards::AffineVar, GroupOpsBounds},
|
|
|
prelude::CurveVar,
|
|
|
prelude::CurveVar,
|
|
|
ToBitsGadget,
|
|
|
ToBitsGadget,
|
|
|
};
|
|
|
};
|
|
|
use ark_relations::r1cs::{ConstraintSynthesizer, ConstraintSystemRef, Namespace, SynthesisError};
|
|
|
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 core::{borrow::Borrow, marker::PhantomData};
|
|
|
use derivative::Derivative;
|
|
|
use derivative::Derivative;
|
|
|
|
|
|
|
|
|
// hash
|
|
|
// hash
|
|
|
|
|
|
use arkworks_native_gadgets::poseidon as poseidon_native;
|
|
|
use arkworks_r1cs_gadgets::poseidon;
|
|
|
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)]
|
|
|
#[derive(Derivative)]
|
|
|
#[derivative(
|
|
|
#[derivative(
|
|
@ -42,6 +43,25 @@ where |
|
|
_group: PhantomData<*const C>,
|
|
|
_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)]
|
|
|
#[derive(Derivative)]
|
|
|
#[derivative(
|
|
|
#[derivative(
|
|
|
Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"),
|
|
|
Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"),
|
|
@ -51,8 +71,6 @@ pub struct SignatureVar>> |
|
|
where
|
|
|
where
|
|
|
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
|
|
|
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
|
|
|
{
|
|
|
{
|
|
|
// s: FpVar<ConstraintF>,
|
|
|
|
|
|
// s: C::ScalarField,
|
|
|
|
|
|
s: Vec<UInt8<ConstraintF<C>>>,
|
|
|
s: Vec<UInt8<ConstraintF<C>>>,
|
|
|
r: GC,
|
|
|
r: GC,
|
|
|
_curve: PhantomData<C>,
|
|
|
_curve: PhantomData<C>,
|
|
@ -61,8 +79,7 @@ where |
|
|
impl<C, GC> AllocVar<Signature<C>, ConstraintF<C>> for SignatureVar<C, GC>
|
|
|
impl<C, GC> AllocVar<Signature<C>, ConstraintF<C>> for SignatureVar<C, GC>
|
|
|
where
|
|
|
where
|
|
|
C: ProjectiveCurve,
|
|
|
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>,
|
|
|
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
|
|
|
{
|
|
|
{
|
|
|
fn new_variable<T: Borrow<Signature<C>>>(
|
|
|
fn new_variable<T: Borrow<Signature<C>>>(
|
|
@ -86,8 +103,8 @@ where |
|
|
let r = GC::new_variable(cs.clone(), || Ok(val.borrow().r), mode)?;
|
|
|
let r = GC::new_variable(cs.clone(), || Ok(val.borrow().r), mode)?;
|
|
|
|
|
|
|
|
|
Ok(Self {
|
|
|
Ok(Self {
|
|
|
s: s, // TODO not sure of FpVar::Constant
|
|
|
|
|
|
r: r,
|
|
|
|
|
|
|
|
|
s,
|
|
|
|
|
|
r,
|
|
|
_curve: PhantomData,
|
|
|
_curve: PhantomData,
|
|
|
})
|
|
|
})
|
|
|
})
|
|
|
})
|
|
@ -129,8 +146,7 @@ pub struct BlindSigVerifyGadget |
|
|
where
|
|
|
where
|
|
|
for<'a> &'a GC: GroupOpsBounds<'a, C, GC>,
|
|
|
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>,
|
|
|
_gc: PhantomData<GC>,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
@ -143,8 +159,9 @@ where |
|
|
EdwardsParameters,
|
|
|
EdwardsParameters,
|
|
|
FpVar<Fp256<FqParameters>>,
|
|
|
FpVar<Fp256<FqParameters>>,
|
|
|
>: From<GC>,
|
|
|
>: 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(
|
|
|
fn verify(
|
|
|
parameters: &ParametersVar<C, GC>,
|
|
|
parameters: &ParametersVar<C, GC>,
|
|
@ -152,32 +169,85 @@ where |
|
|
m: FpVar<ConstraintF<C>>,
|
|
|
m: FpVar<ConstraintF<C>>,
|
|
|
s: &SignatureVar<C, GC>,
|
|
|
s: &SignatureVar<C, GC>,
|
|
|
q: &PublicKeyVar<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 s_s = s.s.clone();
|
|
|
|
|
|
|
|
|
let sG = parameters
|
|
|
let sG = parameters
|
|
|
.generator
|
|
|
.generator
|
|
|
.scalar_mul_le(s_s.to_bits_le()?.iter())?;
|
|
|
.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
|
|
|
// 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,
|
|
|
// done outside the signature verification, once for all 1 votes and once for all 0 votes,
|
|
|
// saving lots of constraints
|
|
|
// saving lots of constraints
|
|
|
let hm = poseidon_hash.hash(&[m])?;
|
|
|
let hm = poseidon_hash.hash(&[m])?;
|
|
|
let r = EdwardsVar::from(s.r.clone()); // WIP
|
|
|
let r = EdwardsVar::from(s.r.clone()); // WIP
|
|
|
|
|
|
let rx_fpvar: FpVar<ConstraintF<C>> = r.x.into();
|
|
|
|
|
|
|
|
|
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 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;
|
|
|
let RHS = s.r.clone() + Q_rx_hm;
|
|
|
|
|
|
|
|
|
sG.is_eq(&RHS)
|
|
|
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());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|