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.
This commit is contained in:
2022-11-04 16:17:32 +01:00
parent 91762eeccc
commit 60ba3f986f
2 changed files with 90 additions and 46 deletions

View File

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

View File

@@ -34,7 +34,7 @@ pub struct Signature<C: ProjectiveCurve> {
r: <C as ProjectiveCurve>::Affine, r: <C as ProjectiveCurve>::Affine,
} }
#[derive(Debug)] #[derive(Clone, Default, Debug)]
pub struct UserSecretData<C: ProjectiveCurve> { pub struct UserSecretData<C: ProjectiveCurve> {
a: C::ScalarField, a: C::ScalarField,
b: C::ScalarField, b: C::ScalarField,
@@ -153,7 +153,7 @@ where
Ok((m_blinded, u)) 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 // s = a s' + b
let s = u.a * s_blinded + u.b; let s = u.a * s_blinded + u.b;
Signature { s, r: u.r } Signature { s, r: u.r }
@@ -240,7 +240,7 @@ mod tests {
let s_blinded = S::blind_sign(sk, k, m_blinded); 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(&params, &poseidon_hash, &m, s, pk); let verified = S::verify(&params, &poseidon_hash, &m, s, pk);
assert!(verified); assert!(verified);