Parametrize signed-msg length (for Poseidon input) Now message to be signed is an array of field elements that can have the length defined by the lib instantiation.
@@ -35,7 +35,7 @@ pub struct PublicKeyVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>>
where for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - pub_key: GC, + pub pub_key: GC, #[doc(hidden)] _group: PhantomData<*const C>, }@@ -59,31 +59,43 @@ })
} } -// TODO parametrize Msg & MsgVar length - #[derive(Clone, Default, Debug)] -// pub struct Msg<C: ProjectiveCurve>(pub Vec<ConstraintF<C>>); -pub struct Msg<C: ProjectiveCurve>(pub [ConstraintF<C>; 3]); +pub struct Msg<const MSG_LEN: usize, C: ProjectiveCurve>(pub [ConstraintF<C>; 3]); #[derive(Derivative)] #[derivative( Debug(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>"), Clone(bound = "C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>") )] -pub struct MsgVar<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> +pub struct MsgVar<const MSG_LEN: usize, C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> where for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - m: [FpVar<ConstraintF<C>>; 3], + m: [FpVar<ConstraintF<C>>; MSG_LEN], _gc: PhantomData<GC>, } -impl<C, GC> AllocVar<Msg<C>, ConstraintF<C>> for MsgVar<C, GC> +impl<const MSG_LEN: usize, C, GC> MsgVar<MSG_LEN, C, GC> +where + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, + for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, +{ + pub fn new(m: [FpVar<ConstraintF<C>>; MSG_LEN]) -> Self { + Self { + m, + _gc: PhantomData, + } + } +} + +impl<const MSG_LEN: usize, C, GC> AllocVar<Msg<MSG_LEN, C>, ConstraintF<C>> + for MsgVar<MSG_LEN, C, GC> where C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>, for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { - fn new_variable<T: Borrow<Msg<C>>>( + fn new_variable<T: Borrow<Msg<MSG_LEN, C>>>( cs: impl Into<Namespace<ConstraintF<C>>>, f: impl FnOnce() -> Result<T, SynthesisError>, mode: AllocationMode,@@ -91,9 +103,21 @@ ) -> Result<Self, SynthesisError> {
f().and_then(|m| { let m = m.borrow(); let cs = cs.into(); - let msg: Vec<FpVar<ConstraintF<C>>> = Vec::new_variable(cs, || Ok(m.clone().0), mode)?; + let msg_vec: Vec<FpVar<ConstraintF<C>>> = + Vec::new_variable(cs, || Ok(m.clone().0), mode)?; + let m: [FpVar<ConstraintF<C>>; MSG_LEN] = + msg_vec + .try_into() + .unwrap_or_else(|v: Vec<FpVar<ConstraintF<C>>>| { + // WIP + panic!( + "Expected Vec of length: {}, actual length: {}", + MSG_LEN, + v.len() + ) + }); Ok(Self { - m: [msg[0].clone(), msg[1].clone(), msg[2].clone()], + m, _gc: PhantomData, }) })@@ -181,15 +205,19 @@ })
} } -pub struct BlindSigVerifyGadget<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> -where +pub struct BlindSigVerifyGadget< + const MSG_LEN: usize, + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, +> where for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, { _params: Parameters<C>, // TODO review if needed, maybe delete _gc: PhantomData<GC>, } -impl<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> BlindSigVerifyGadget<C, GC> +impl<const MSG_LEN: usize, C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> + BlindSigVerifyGadget<MSG_LEN, C, GC> where C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>,@@ -202,10 +230,10 @@ <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( + pub fn verify( parameters: &ParametersVar<C, GC>, poseidon_hash: &PoseidonGadget<ConstraintF<C>>, - m: &MsgVar<C, GC>, + m: &MsgVar<MSG_LEN, C, GC>, s: &SignatureVar<C, GC>, q: &PublicKeyVar<C, GC>, ) -> Result<Boolean<ConstraintF<C>>, SynthesisError> {@@ -230,9 +258,10 @@ }
} pub struct BlindSigBatchVerifyGadget< + const NUM_SIGS: usize, + const MSG_LEN: usize, C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>, - const NUM_SIGS: usize, > where for<'a> &'a GC: GroupOpsBounds<'a, C, GC>, {@@ -240,8 +269,12 @@ _params: Parameters<C>, // TODO review if needed, maybe delete
_gc: PhantomData<GC>, } -impl<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>, const NUM_SIGS: usize> - BlindSigBatchVerifyGadget<C, GC, NUM_SIGS> +impl< + const NUM_SIGS: usize, + const MSG_LEN: usize, + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, + > BlindSigBatchVerifyGadget<NUM_SIGS, MSG_LEN, C, GC> where C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>,@@ -254,10 +287,10 @@ <C as ProjectiveCurve>::BaseField: PrimeField,
FpVar<<C as ProjectiveCurve>::BaseField>: Mul<FpVar<Fp256<FqParameters>>>, FpVar<<C as ProjectiveCurve>::BaseField>: From<FpVar<Fp256<FqParameters>>>, { - fn batch_verify( + pub fn batch_verify( parameters: &ParametersVar<C, GC>, poseidon_hash: &PoseidonGadget<ConstraintF<C>>, - m: &MsgVar<C, GC>, + m: &MsgVar<MSG_LEN, C, GC>, sigs: &[SignatureVar<C, GC>], q: &PublicKeyVar<C, GC>, ) -> Result<Boolean<ConstraintF<C>>, SynthesisError> {@@ -287,8 +320,11 @@ }
// example of circuit using BlindSigVerifyGadget to verify a single blind signature #[derive(Clone)] -pub struct BlindSigVerifyCircuit<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> -where +pub struct BlindSigVerifyCircuit< + const MSG_LEN: usize, + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, +> where <C as ProjectiveCurve>::BaseField: PrimeField, { _group: PhantomData<*const GC>,@@ -296,11 +332,11 @@ pub params: Parameters<C>,
pub poseidon_hash_native: poseidon_native::Poseidon<ConstraintF<C>>, pub signature: Option<Signature<C>>, pub pub_key: Option<PublicKey<C>>, - pub message: Option<Msg<C>>, + pub message: Option<Msg<MSG_LEN, C>>, } -impl<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> ConstraintSynthesizer<ConstraintF<C>> - for BlindSigVerifyCircuit<C, GC> +impl<const MSG_LEN: usize, C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>> + ConstraintSynthesizer<ConstraintF<C>> for BlindSigVerifyCircuit<MSG_LEN, C, GC> where C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>,@@ -325,7 +361,7 @@ let pub_key =
PublicKeyVar::<C, GC>::new_input(ark_relations::ns!(cs, "public key"), || { self.pub_key.ok_or(SynthesisError::AssignmentMissing) })?; - let m = MsgVar::<C, GC>::new_input(ark_relations::ns!(cs, "message"), || { + let m = MsgVar::<MSG_LEN, C, GC>::new_input(ark_relations::ns!(cs, "message"), || { self.message.ok_or(SynthesisError::AssignmentMissing) })?; let signature =@@ -339,7 +375,7 @@ self.poseidon_hash_native,
) .unwrap(); - let v = BlindSigVerifyGadget::<C, GC>::verify( + let v = BlindSigVerifyGadget::<MSG_LEN, C, GC>::verify( ¶meters, &poseidon_hash, &m,@@ -353,9 +389,10 @@
// example of circuit using BlindSigVerifyGadget to verify a batch of blind signatures #[derive(Clone)] pub struct BlindSigBatchVerifyCircuit< + const NUM_SIGS: usize, + const MSG_LEN: usize, C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>, - const NUM_SIGS: usize, > where <C as ProjectiveCurve>::BaseField: PrimeField, {@@ -364,11 +401,15 @@ pub params: Parameters<C>,
pub poseidon_hash_native: poseidon_native::Poseidon<ConstraintF<C>>, pub signatures: Option<Vec<Signature<C>>>, pub pub_key: Option<PublicKey<C>>, - pub message: Option<Msg<C>>, + pub message: Option<Msg<MSG_LEN, C>>, } -impl<C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>, const NUM_SIGS: usize> - ConstraintSynthesizer<ConstraintF<C>> for BlindSigBatchVerifyCircuit<C, GC, NUM_SIGS> +impl< + const NUM_SIGS: usize, + const MSG_LEN: usize, + C: ProjectiveCurve, + GC: CurveVar<C, ConstraintF<C>>, + > ConstraintSynthesizer<ConstraintF<C>> for BlindSigBatchVerifyCircuit<NUM_SIGS, MSG_LEN, C, GC> where C: ProjectiveCurve, GC: CurveVar<C, ConstraintF<C>>,@@ -393,7 +434,7 @@ let pub_key =
PublicKeyVar::<C, GC>::new_input(ark_relations::ns!(cs, "public key"), || { self.pub_key.ok_or(SynthesisError::AssignmentMissing) })?; - let m = MsgVar::<C, GC>::new_input(ark_relations::ns!(cs, "message"), || { + let m = MsgVar::<MSG_LEN, C, GC>::new_input(ark_relations::ns!(cs, "message"), || { self.message.ok_or(SynthesisError::AssignmentMissing) })?;@@ -415,7 +456,7 @@ self.poseidon_hash_native,
) .unwrap(); - let v = BlindSigBatchVerifyGadget::<C, GC, NUM_SIGS>::batch_verify( + let v = BlindSigBatchVerifyGadget::<NUM_SIGS, MSG_LEN, C, GC>::batch_verify( ¶meters, &poseidon_hash, &m,@@ -447,7 +488,7 @@ poseidon_hash: &poseidon::Poseidon<Fq>,
) -> ( Parameters<BabyJubJub>, PublicKey<BabyJubJub>, - Msg<BabyJubJub>, + Msg<3, BabyJubJub>, Signature<BabyJubJub>, ) { let mut rng = ark_std::test_rng();@@ -457,7 +498,7 @@ let (k, signer_r) = S::new_request_params(¶ms, &mut rng);
let m = [Fq::from(1234), Fq::from(5689), Fq::from(3456)]; 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 s = S::unblind(s_blinded, &u); let verified = S::verify(¶ms, &poseidon_hash, &m, s.clone(), pk); assert!(verified); (params, pk, Msg(m), s)@@ -469,7 +510,7 @@ n: usize,
) -> ( Parameters<BabyJubJub>, PublicKey<BabyJubJub>, - Msg<BabyJubJub>, + Msg<3, BabyJubJub>, Vec<Signature<BabyJubJub>>, ) { let mut rng = ark_std::test_rng();@@ -481,7 +522,7 @@ for _ in 0..n {
let (k, signer_r) = S::new_request_params(¶ms, &mut rng); 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 s = S::unblind(s_blinded, &u); let verified = S::verify(¶ms, &poseidon_hash, &m, s.clone(), pk); assert!(verified); signatures.push(s);@@ -491,15 +532,15 @@ }
#[test] fn test_single_verify() { - // TODO N_INPUTS+1 (N_INPUTS msg_to_sign_length) let poseidon_params = poseidon_setup_params::<Fq>(Curve::Bn254, 5, 4); let poseidon_hash = poseidon::Poseidon::new(poseidon_params); + const MSG_LEN: usize = 3; // create signature using native-rust lib let (params, pk, m, s) = generate_single_sig_native_data(&poseidon_hash); // use the constraint system to verify the signature - type SG = BlindSigVerifyGadget<BabyJubJub, BabyJubJubVar>; + type SG = BlindSigVerifyGadget<MSG_LEN, BabyJubJub, BabyJubJubVar>; let cs = ConstraintSystem::<Fq>::new_ref(); let params_var =@@ -508,7 +549,8 @@ 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 = MsgVar::<BabyJubJub, BabyJubJubVar>::new_witness(cs.clone(), || Ok(m)).unwrap(); + let m_var = MsgVar::<MSG_LEN, BabyJubJub, BabyJubJubVar>::new_witness(cs.clone(), || Ok(m)) + .unwrap(); let poseidon_hash_var = PoseidonGadget::<Fq>::from_native(&mut cs.clone(), poseidon_hash).unwrap();@@ -528,12 +570,13 @@ #[test]
fn test_single_verify_constraint_system() { let poseidon_params = poseidon_setup_params::<Fq>(Curve::Bn254, 5, 4); let poseidon_hash = poseidon::Poseidon::new(poseidon_params); + const MSG_LEN: usize = 3; // create signature using native-rust lib let (params, pk, m, s) = generate_single_sig_native_data(&poseidon_hash); // use the constraint system to verify the signature - let circuit = BlindSigVerifyCircuit::<BabyJubJub, BabyJubJubVar> { + let circuit = BlindSigVerifyCircuit::<MSG_LEN, BabyJubJub, BabyJubJubVar> { params, poseidon_hash_native: poseidon_hash.clone(), signature: Some(s),@@ -552,13 +595,14 @@ #[test]
fn test_batch_verify_constraint_system() { let poseidon_params = poseidon_setup_params::<Fq>(Curve::Bn254, 5, 4); let poseidon_hash = poseidon::Poseidon::new(poseidon_params); + const MSG_LEN: usize = 3; // create signatures using native-rust lib const NUM_SIGS: usize = 5; let (params, pk, m, sigs) = generate_batch_sig_native_data(&poseidon_hash, NUM_SIGS); // use the constraint system to verify the batch of signatures - let circuit = BlindSigBatchVerifyCircuit::<BabyJubJub, BabyJubJubVar, NUM_SIGS> { + let circuit = BlindSigBatchVerifyCircuit::<NUM_SIGS, MSG_LEN, BabyJubJub, BabyJubJubVar> { params, poseidon_hash_native: poseidon_hash.clone(), signatures: Some(sigs),
@@ -34,7 +34,7 @@ s: C::ScalarField, // ScalarField == Fr
r: <C as ProjectiveCurve>::Affine, } -#[derive(Debug)] +#[derive(Clone, Default, Debug)] pub struct UserSecretData<C: ProjectiveCurve> { a: C::ScalarField, b: C::ScalarField,@@ -153,7 +153,7 @@
Ok((m_blinded, u)) } - pub fn unblind(s_blinded: C::ScalarField, u: UserSecretData<C>) -> Signature<C> { + pub fn unblind(s_blinded: C::ScalarField, u: &UserSecretData<C>) -> Signature<C> { // s = a s' + b let s = u.a * s_blinded + u.b; Signature { s, r: u.r }@@ -240,7 +240,7 @@ 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 s = S::unblind(s_blinded, &u); let verified = S::verify(¶ms, &poseidon_hash, &m, s, pk); assert!(verified);