Speed up the verification function and add benchmarks
This commit is contained in:
@@ -18,6 +18,7 @@ use nym_compact_ecash::{
|
||||
};
|
||||
use nym_compact_ecash::identify::{identify, IdentifyResult};
|
||||
use nym_compact_ecash::setup::setup;
|
||||
use nym_compact_ecash::scheme::expiration_date_signatures::{sign_expiration_date, verify_valid_dates_signatures};
|
||||
|
||||
#[allow(unused)]
|
||||
fn double_pairing(g11: &G1Affine, g21: &G2Affine, g12: &G1Affine, g22: &G2Affine) {
|
||||
@@ -181,31 +182,31 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
let (req, req_info) = withdrawal_request(grp, &user_keypair.secret_key()).unwrap();
|
||||
|
||||
// CLIENT BENCHMARK: prepare a single withdrawal request
|
||||
// group.bench_function(
|
||||
// &format!(
|
||||
// "[Client] withdrawal_request_{}_authorities_{}_L_{}_threshold",
|
||||
// case.num_authorities, case.L, case.threshold_p,
|
||||
// ),
|
||||
// |b| b.iter(|| withdrawal_request(grp, &user_keypair.secret_key()).unwrap()),
|
||||
// );
|
||||
group.bench_function(
|
||||
&format!(
|
||||
"[Client] withdrawal_request_{}_authorities_{}_L_{}_threshold",
|
||||
case.num_authorities, case.L, case.threshold_p,
|
||||
),
|
||||
|b| b.iter(|| withdrawal_request(grp, &user_keypair.secret_key()).unwrap()),
|
||||
);
|
||||
|
||||
// ISSUING AUTHRORITY BENCHMARK: Benchmark the issue_wallet function
|
||||
// called by an authority to issue a blind signature on a partial wallet
|
||||
let mut rng = rand::thread_rng();
|
||||
let keypair = authorities_keypairs.choose(&mut rng).unwrap();
|
||||
// group.bench_function(
|
||||
// &format!("[Issuing Authority] issue_partial_wallet_with_L_{}", case.L, ),
|
||||
// |b| {
|
||||
// b.iter(|| {
|
||||
// issue_wallet(
|
||||
// &grp,
|
||||
// keypair.secret_key(),
|
||||
// user_keypair.public_key(),
|
||||
// &req,
|
||||
// ).unwrap()
|
||||
// })
|
||||
// },
|
||||
// );
|
||||
group.bench_function(
|
||||
&format!("[Issuing Authority] issue_partial_wallet_with_L_{}", case.L, ),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
issue_wallet(
|
||||
&grp,
|
||||
keypair.secret_key(),
|
||||
user_keypair.public_key(),
|
||||
&req,
|
||||
).unwrap()
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let mut wallet_blinded_signatures = Vec::new();
|
||||
for auth_keypair in authorities_keypairs {
|
||||
@@ -221,10 +222,10 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
// CLIENT BENCHMARK: verify the issued partial wallet
|
||||
let w = wallet_blinded_signatures.get(0).clone().unwrap();
|
||||
let vk = verification_keys_auth.get(0).clone().unwrap();
|
||||
// group.bench_function(
|
||||
// &format!("[Client] issue_verify_a_partial_wallet_with_L_{}", case.L, ),
|
||||
// |b| b.iter(|| issue_verify(&grp, vk, &user_keypair.secret_key(), w, &req_info).unwrap()),
|
||||
// );
|
||||
group.bench_function(
|
||||
&format!("[Client] issue_verify_a_partial_wallet_with_L_{}", case.L, ),
|
||||
|b| b.iter(|| issue_verify(&grp, vk, &user_keypair.secret_key(), w, &req_info).unwrap()),
|
||||
);
|
||||
|
||||
let unblinded_wallet_shares: Vec<PartialWallet> = izip!(
|
||||
wallet_blinded_signatures.iter(),
|
||||
@@ -234,24 +235,24 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
.collect();
|
||||
|
||||
// CLIENT BENCHMARK: aggregating all partial wallets
|
||||
// group.bench_function(
|
||||
// &format!(
|
||||
// "[Client] aggregate_wallets_with_L_{}_threshold_{}",
|
||||
// case.L, case.threshold_p,
|
||||
// ),
|
||||
// |b| {
|
||||
// b.iter(|| {
|
||||
// aggregate_wallets(
|
||||
// &grp,
|
||||
// &verification_key,
|
||||
// &user_keypair.secret_key(),
|
||||
// &unblinded_wallet_shares,
|
||||
// &req_info,
|
||||
// )
|
||||
// .unwrap()
|
||||
// })
|
||||
// },
|
||||
// );
|
||||
group.bench_function(
|
||||
&format!(
|
||||
"[Client] aggregate_wallets_with_L_{}_threshold_{}",
|
||||
case.L, case.threshold_p,
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
aggregate_wallets(
|
||||
&grp,
|
||||
&verification_key,
|
||||
&user_keypair.secret_key(),
|
||||
&unblinded_wallet_shares,
|
||||
&req_info,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// Aggregate partial wallets
|
||||
let aggr_wallet = aggregate_wallets(
|
||||
@@ -264,28 +265,28 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
.unwrap();
|
||||
|
||||
// SPENDING PHASE
|
||||
let pay_info = PayInfo { info: [6u8; 32] };
|
||||
let pay_info = PayInfo { payinfo: [6u8; 88] };
|
||||
// CLIENT BENCHMARK: spend a single coin from the wallet
|
||||
// group.bench_function(
|
||||
// &format!(
|
||||
// "[Client] spend_a_single_coin_L_{}_threshold_{}",
|
||||
// case.L, case.threshold_p,
|
||||
// ),
|
||||
// |b| {
|
||||
// b.iter(|| {
|
||||
// aggr_wallet
|
||||
// .spend(
|
||||
// ¶ms,
|
||||
// &verification_key,
|
||||
// &user_keypair.secret_key(),
|
||||
// &pay_info,
|
||||
// true,
|
||||
// case.spend_vv,
|
||||
// )
|
||||
// .unwrap()
|
||||
// })
|
||||
// },
|
||||
// );
|
||||
group.bench_function(
|
||||
&format!(
|
||||
"[Client] spend_a_single_coin_L_{}_threshold_{}",
|
||||
case.L, case.threshold_p,
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
aggr_wallet
|
||||
.spend(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
&user_keypair.secret_key(),
|
||||
&pay_info,
|
||||
true,
|
||||
case.spend_vv,
|
||||
)
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
let (payment, upd_wallet) = aggr_wallet
|
||||
.spend(
|
||||
@@ -299,19 +300,19 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
.unwrap();
|
||||
|
||||
// MERCHANT BENCHMARK: verify whether the submitted payment is legit
|
||||
// group.bench_function(
|
||||
// &format!(
|
||||
// "[Merchant] spend_verify_of_a_single_payment_L_{}_threshold_{}",
|
||||
// case.L, case.threshold_p,
|
||||
// ),
|
||||
// |b| {
|
||||
// b.iter(|| {
|
||||
// payment
|
||||
// .spend_verify(¶ms, &verification_key, &pay_info)
|
||||
// .unwrap()
|
||||
// })
|
||||
// },
|
||||
// );
|
||||
group.bench_function(
|
||||
&format!(
|
||||
"[Merchant] spend_verify_of_a_single_payment_L_{}_threshold_{}",
|
||||
case.L, case.threshold_p,
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
payment
|
||||
.spend_verify(¶ms, &verification_key, &pay_info)
|
||||
.unwrap()
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// BENCHMARK IDENTIFICATION
|
||||
// Let's generate a double spending payment
|
||||
@@ -320,7 +321,7 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
let current_l = aggr_wallet.l.get();
|
||||
aggr_wallet.l.set(current_l - case.spend_vv);
|
||||
|
||||
let pay_info2 = PayInfo { info: [7u8; 32] };
|
||||
let pay_info2 = PayInfo { payinfo: [7u8; 88] };
|
||||
let (payment2, _) = aggr_wallet.spend(
|
||||
¶ms,
|
||||
&verification_key,
|
||||
@@ -356,5 +357,45 @@ fn bench_compact_ecash(c: &mut Criterion) {
|
||||
assert_eq!(identify_result, IdentifyResult::DoubleSpendingPublicKeys(user_keypair.public_key()));
|
||||
}
|
||||
|
||||
criterion_group!(benches, bench_compact_ecash);
|
||||
|
||||
fn bench_partial_sign_expiration_date(c: &mut Criterion){
|
||||
let mut group = c.benchmark_group("benchmark-expiration-date");
|
||||
let L = 32;
|
||||
let params = setup(L);
|
||||
let expiration_date = 1703183958;
|
||||
|
||||
let authorities_keys = ttp_keygen(¶ms.grp(), 2, 3).unwrap();
|
||||
let sk_i_auth = authorities_keys[0].secret_key();
|
||||
let vk_i_auth = authorities_keys[0].verification_key();
|
||||
let partial_exp_sig = sign_expiration_date(¶ms, &sk_i_auth, expiration_date);
|
||||
|
||||
// ISSUING AUTHORITY BENCHMARK: issue a set of (partial) signatures for a given expiration date
|
||||
group.bench_function(
|
||||
&format!(
|
||||
"[IssuingAuthority] sign_expiration_date",
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
sign_expiration_date(¶ms, &sk_i_auth, expiration_date)
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
// CLIENT: verify the correctness of the set of (partial) signatures for a given expiration date
|
||||
assert!(verify_valid_dates_signatures(¶ms, &vk_i_auth, &partial_exp_sig, expiration_date).is_ok());
|
||||
group.bench_function(
|
||||
&format!(
|
||||
"[Client] verify_valid_dates_signatures",
|
||||
),
|
||||
|b| {
|
||||
b.iter(|| {
|
||||
verify_valid_dates_signatures(¶ms, &vk_i_auth, &partial_exp_sig, expiration_date)
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
criterion_group!(benches, bench_partial_sign_expiration_date);
|
||||
criterion_main!(benches);
|
||||
|
||||
@@ -21,7 +21,7 @@ use crate::traits::Bytable;
|
||||
|
||||
mod error;
|
||||
mod proofs;
|
||||
mod scheme;
|
||||
pub mod scheme;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
mod traits;
|
||||
|
||||
@@ -92,36 +92,39 @@ pub fn verify_valid_dates_signatures(
|
||||
signatures: &[ExpirationDateSignature],
|
||||
expiration_date: u64,
|
||||
) -> Result<()>{
|
||||
for (l , sig) in signatures.iter().enumerate() {
|
||||
let m0: Scalar = Scalar::from(expiration_date);
|
||||
let m1: Scalar = Scalar::from(expiration_date - constants::VALIDITY_PERIOD + l as u64);
|
||||
let m2: Scalar = Scalar::from_bytes(&constants::TYPE_EXP).unwrap();
|
||||
// Compute the hash
|
||||
let h = hash_g1([m0.to_bytes(), m1.to_bytes(), m2.to_bytes()].concat());
|
||||
// Verify the signature correctness
|
||||
if sig.h != h {
|
||||
return Err(CompactEcashError::ExpirationDate(
|
||||
"Failed to verify the commitment hash".to_string(),
|
||||
));
|
||||
}
|
||||
let partially_signed_attributes = [m0, m1, m2]
|
||||
.iter()
|
||||
.zip(vkey.beta_g2.iter())
|
||||
.map(|(m, beta_i)| beta_i * Scalar::from(*m))
|
||||
.sum::<G2Projective>();
|
||||
signatures
|
||||
.par_iter()
|
||||
.enumerate()
|
||||
.try_for_each(|(l, sig)| {
|
||||
let m0: Scalar = Scalar::from(expiration_date);
|
||||
let m1: Scalar = Scalar::from(expiration_date - constants::VALIDITY_PERIOD + l as u64);
|
||||
let m2: Scalar = Scalar::from_bytes(&constants::TYPE_EXP).unwrap();
|
||||
// Compute the hash
|
||||
let h = hash_g1([m0.to_bytes(), m1.to_bytes(), m2.to_bytes()].concat());
|
||||
// Verify the signature correctness
|
||||
if sig.h != h {
|
||||
return Err(CompactEcashError::ExpirationDate(
|
||||
"Failed to verify the commitment hash".to_string(),
|
||||
));
|
||||
}
|
||||
let partially_signed_attributes = [m0, m1, m2]
|
||||
.iter()
|
||||
.zip(vkey.beta_g2.iter())
|
||||
.map(|(m, beta_i)| beta_i * Scalar::from(*m))
|
||||
.sum::<G2Projective>();
|
||||
|
||||
if !check_bilinear_pairing(
|
||||
&sig.h.to_affine(),
|
||||
&G2Prepared::from((vkey.alpha + partially_signed_attributes).to_affine()),
|
||||
&sig.s.to_affine(),
|
||||
params.grp().prepared_miller_g2(),
|
||||
) {
|
||||
return Err(CompactEcashError::ExpirationDate(
|
||||
"Verification of the date signature failed".to_string(),
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
if !check_bilinear_pairing(
|
||||
&sig.h.to_affine(),
|
||||
&G2Prepared::from((vkey.alpha + partially_signed_attributes).to_affine()),
|
||||
&sig.s.to_affine(),
|
||||
params.grp().prepared_miller_g2(),
|
||||
) {
|
||||
return Err(CompactEcashError::ExpirationDate(
|
||||
"Verification of the date signature failed".to_string(),
|
||||
));
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
/// Aggregates partial expiration date signatures into a list of aggregated expiration date signatures.
|
||||
@@ -131,9 +134,7 @@ pub fn verify_valid_dates_signatures(
|
||||
/// * `params` - The cryptographic parameters used in the signing process.
|
||||
/// * `vk_auth` - The global verification key.
|
||||
/// * `expiration_date` - The expiration date for which the signatures are being aggregated (as unix timestamp).
|
||||
/// * `indices` - A list of unique indices corresponding to the signing authorities.
|
||||
/// * `vkeys` - A list of verification keys associated with the signing authorities.
|
||||
/// * `signatures` - A list of partial expiration date signatures to be aggregated.
|
||||
/// * `signatures` - A list of tuples containing unique indices, verification keys, and partial expiration date signatures corresponding to the signing authorities.
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
@@ -142,16 +143,23 @@ pub fn verify_valid_dates_signatures(
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function returns an error if there is a mismatch in the lengths of `vkeys` and `signatures`,
|
||||
/// or if there are not enough unique indices. It also returns an error the verification of
|
||||
/// the partial or aggregated signatures fails.
|
||||
/// This function returns an error if there is a mismatch in the lengths of `signatures`. This occurs
|
||||
/// when the number of tuples in `signatures` is not equal to the expected number of signing authorities.
|
||||
/// Each tuple should contain a unique index, a verification key, and a list of partial signatures.
|
||||
///
|
||||
/// It also returns an error if there are not enough unique indices. This happens when the number
|
||||
/// of unique indices in the tuples is less than the total number of signing authorities.
|
||||
///
|
||||
/// Additionally, an error is returned if the verification of the partial or aggregated signatures fails.
|
||||
/// This can occur if the cryptographic verification process fails for any of the provided signatures.
|
||||
///
|
||||
pub fn aggregate_expiration_signatures(
|
||||
params: &Parameters,
|
||||
vk_auth: &VerificationKeyAuth,
|
||||
expiration_date: u64,
|
||||
signatures: &[(u64, VerificationKeyAuth, Vec<PartialExpirationDateSignature>)],
|
||||
) -> Result<Vec<ExpirationDateSignature>>{
|
||||
// Check if we have enough unique partial signatures to meet the required threshold
|
||||
// Check if all indices are unique
|
||||
if signatures.iter().map(|(index, _, _)| index).unique().count() != signatures.len() {
|
||||
return Err(CompactEcashError::ExpirationDate(
|
||||
"Not enough unique indices shares".to_string(),
|
||||
@@ -180,6 +188,7 @@ pub fn aggregate_expiration_signatures(
|
||||
verify_valid_dates_signatures(params, vkey, partial_signatures, expiration_date)
|
||||
})?;
|
||||
|
||||
|
||||
// Collect the partial signatures for the same valid date
|
||||
let collected_at_l: Vec<_> = signatures
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user