From 45e5f1219817f4bf7f2cf6528a8c72bfe9fb0d90 Mon Sep 17 00:00:00 2001 From: aniampio Date: Sat, 11 Nov 2023 11:16:25 +0000 Subject: [PATCH 1/8] Add function to verify partial blind signature --- common/nymcoconut/src/scheme/issuance.rs | 53 +++++++++++++++++++++++- 1 file changed, 52 insertions(+), 1 deletion(-) diff --git a/common/nymcoconut/src/scheme/issuance.rs b/common/nymcoconut/src/scheme/issuance.rs index 710fc41df9..a3df758eb5 100644 --- a/common/nymcoconut/src/scheme/issuance.rs +++ b/common/nymcoconut/src/scheme/issuance.rs @@ -4,7 +4,7 @@ use std::convert::TryFrom; use std::convert::TryInto; -use bls12_381::{G1Affine, G1Projective, Scalar}; +use bls12_381::{G1Affine, G1Projective, Scalar, pairing}; use group::{Curve, GroupEncoding}; use crate::error::{CoconutError, Result}; @@ -12,6 +12,7 @@ use crate::proofs::ProofCmCs; use crate::scheme::setup::Parameters; use crate::scheme::BlindedSignature; use crate::scheme::SecretKey; +use crate::scheme::keygen::VerificationKey; use crate::Attribute; /// Creates a Coconut Signature under a given secret key on a set of public attributes only. #[cfg(test)] @@ -318,6 +319,21 @@ pub fn blind_sign( Ok(BlindedSignature(h, sig)) } +pub fn verify_partial_blind_signature( + params: &Parameters, + blind_sign_request: &BlindSignRequest, + blind_sig: &BlindedSignature, + partial_verification_key: &VerificationKey) -> bool{ + + // check the correctness and validity of the partial signature + let pairing0 = pairing(&blind_sig.1.to_affine(), params.gen2()); + let pairing1 = pairing(&blind_sig.0.to_affine(), &partial_verification_key.alpha.to_affine()); + let pairing2 = pairing(&blind_sign_request.private_attributes_commitments.get(0).unwrap().to_affine(), &partial_verification_key.beta_g2.get(0).unwrap().to_affine()); + let pairing3 = pairing(&blind_sign_request.private_attributes_commitments.get(1).unwrap().to_affine(), &partial_verification_key.beta_g2.get(1).unwrap().to_affine()); + let composed_pairing = pairing1 + pairing2 + pairing3; + pairing0 == composed_pairing +} + #[cfg(test)] pub fn sign( params: &mut Parameters, @@ -354,6 +370,7 @@ pub fn sign( #[cfg(test)] mod tests { use super::*; + use crate::scheme::keygen::{keygen, SecretKey, VerificationKey}; #[test] fn blind_sign_request_bytes_roundtrip() { @@ -385,4 +402,38 @@ mod tests { lambda ); } + + #[test] + fn successful_verify_partial_blind_signature(){ + // 0 public and 2 private attribute + let params = Parameters::new(2).unwrap(); + let private_attributes = params.n_random_scalars(2); + + let (_commitments_openings, request) = + prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap(); + + let validator_keypair = keygen(¶ms); + let blind_sig = blind_sign(¶ms, &validator_keypair.secret_key(), &request, &[]).unwrap(); + + assert!(verify_partial_blind_signature(¶ms, &request, &blind_sig, &validator_keypair.verification_key())); + } + + #[test] + fn verify_partial_blind_signature_with_wrong_key(){ + // 0 public and 2 private attribute + let params = Parameters::new(2).unwrap(); + let private_attributes = params.n_random_scalars(2); + + let (_commitments_openings, request) = + prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap(); + + let validator_keypair = keygen(¶ms); + let validator2_keypair = keygen(¶ms); + let blind_sig = blind_sign(¶ms, &validator_keypair.secret_key(), &request, &[]).unwrap(); + + // this assertion should fail, as we try to verify with a wrong validator key + assert_eq!(verify_partial_blind_signature(¶ms, &request, &blind_sig, &validator2_keypair.verification_key()), + false); + } + } From 15abfb390f6d93a724e643930d99d3c7963c50ea Mon Sep 17 00:00:00 2001 From: aniampio Date: Sat, 11 Nov 2023 11:21:36 +0000 Subject: [PATCH 2/8] Make the function more generic --- common/nymcoconut/src/scheme/issuance.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/common/nymcoconut/src/scheme/issuance.rs b/common/nymcoconut/src/scheme/issuance.rs index a3df758eb5..39af39b419 100644 --- a/common/nymcoconut/src/scheme/issuance.rs +++ b/common/nymcoconut/src/scheme/issuance.rs @@ -324,13 +324,16 @@ pub fn verify_partial_blind_signature( blind_sign_request: &BlindSignRequest, blind_sig: &BlindedSignature, partial_verification_key: &VerificationKey) -> bool{ - - // check the correctness and validity of the partial signature + let pairing0 = pairing(&blind_sig.1.to_affine(), params.gen2()); - let pairing1 = pairing(&blind_sig.0.to_affine(), &partial_verification_key.alpha.to_affine()); - let pairing2 = pairing(&blind_sign_request.private_attributes_commitments.get(0).unwrap().to_affine(), &partial_verification_key.beta_g2.get(0).unwrap().to_affine()); - let pairing3 = pairing(&blind_sign_request.private_attributes_commitments.get(1).unwrap().to_affine(), &partial_verification_key.beta_g2.get(1).unwrap().to_affine()); - let composed_pairing = pairing1 + pairing2 + pairing3; + + let composed_pairing = blind_sign_request.private_attributes_commitments + .iter() + .zip(&partial_verification_key.beta_g2) + .fold(pairing(&blind_sig.0.to_affine(), &partial_verification_key.alpha.to_affine()), |acc, (commitment, beta_g2)| { + acc + pairing(&commitment.to_affine(), &beta_g2.to_affine()) + }); + pairing0 == composed_pairing } From 5e8767c5d61ec9ddba15f69863595c59b8ffeef0 Mon Sep 17 00:00:00 2001 From: aniampio Date: Sat, 11 Nov 2023 11:26:17 +0000 Subject: [PATCH 3/8] Update tests --- common/nymcoconut/src/scheme/issuance.rs | 52 ++++++++++++++++-------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/common/nymcoconut/src/scheme/issuance.rs b/common/nymcoconut/src/scheme/issuance.rs index 39af39b419..8c562dd1bc 100644 --- a/common/nymcoconut/src/scheme/issuance.rs +++ b/common/nymcoconut/src/scheme/issuance.rs @@ -4,15 +4,15 @@ use std::convert::TryFrom; use std::convert::TryInto; -use bls12_381::{G1Affine, G1Projective, Scalar, pairing}; +use bls12_381::{pairing, G1Affine, G1Projective, Scalar}; use group::{Curve, GroupEncoding}; use crate::error::{CoconutError, Result}; use crate::proofs::ProofCmCs; +use crate::scheme::keygen::VerificationKey; use crate::scheme::setup::Parameters; use crate::scheme::BlindedSignature; use crate::scheme::SecretKey; -use crate::scheme::keygen::VerificationKey; use crate::Attribute; /// Creates a Coconut Signature under a given secret key on a set of public attributes only. #[cfg(test)] @@ -323,16 +323,23 @@ pub fn verify_partial_blind_signature( params: &Parameters, blind_sign_request: &BlindSignRequest, blind_sig: &BlindedSignature, - partial_verification_key: &VerificationKey) -> bool{ - + partial_verification_key: &VerificationKey, +) -> bool { let pairing0 = pairing(&blind_sig.1.to_affine(), params.gen2()); - let composed_pairing = blind_sign_request.private_attributes_commitments + let composed_pairing = blind_sign_request + .private_attributes_commitments .iter() .zip(&partial_verification_key.beta_g2) - .fold(pairing(&blind_sig.0.to_affine(), &partial_verification_key.alpha.to_affine()), |acc, (commitment, beta_g2)| { - acc + pairing(&commitment.to_affine(), &beta_g2.to_affine()) - }); + .fold( + pairing( + &blind_sig.0.to_affine(), + &partial_verification_key.alpha.to_affine(), + ), + |acc, (commitment, beta_g2)| { + acc + pairing(&commitment.to_affine(), &beta_g2.to_affine()) + }, + ); pairing0 == composed_pairing } @@ -407,7 +414,7 @@ mod tests { } #[test] - fn successful_verify_partial_blind_signature(){ + fn successful_verify_partial_blind_signature() { // 0 public and 2 private attribute let params = Parameters::new(2).unwrap(); let private_attributes = params.n_random_scalars(2); @@ -416,13 +423,19 @@ mod tests { prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap(); let validator_keypair = keygen(¶ms); - let blind_sig = blind_sign(¶ms, &validator_keypair.secret_key(), &request, &[]).unwrap(); + let blind_sig = + blind_sign(¶ms, &validator_keypair.secret_key(), &request, &[]).unwrap(); - assert!(verify_partial_blind_signature(¶ms, &request, &blind_sig, &validator_keypair.verification_key())); + assert!(verify_partial_blind_signature( + ¶ms, + &request, + &blind_sig, + &validator_keypair.verification_key() + )); } #[test] - fn verify_partial_blind_signature_with_wrong_key(){ + fn verify_partial_blind_signature_with_wrong_key() { // 0 public and 2 private attribute let params = Parameters::new(2).unwrap(); let private_attributes = params.n_random_scalars(2); @@ -432,11 +445,18 @@ mod tests { let validator_keypair = keygen(¶ms); let validator2_keypair = keygen(¶ms); - let blind_sig = blind_sign(¶ms, &validator_keypair.secret_key(), &request, &[]).unwrap(); + let blind_sig = + blind_sign(¶ms, &validator_keypair.secret_key(), &request, &[]).unwrap(); // this assertion should fail, as we try to verify with a wrong validator key - assert_eq!(verify_partial_blind_signature(¶ms, &request, &blind_sig, &validator2_keypair.verification_key()), - false); + assert_eq!( + verify_partial_blind_signature( + ¶ms, + &request, + &blind_sig, + &validator2_keypair.verification_key() + ), + false + ); } - } From 16f51a00148f042ea2207404f62ea7bfd71e9045 Mon Sep 17 00:00:00 2001 From: aniampio Date: Mon, 13 Nov 2023 10:28:36 +0000 Subject: [PATCH 4/8] Add documentation to the verification function --- common/nymcoconut/src/scheme/issuance.rs | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/common/nymcoconut/src/scheme/issuance.rs b/common/nymcoconut/src/scheme/issuance.rs index 8c562dd1bc..2dd1b35e27 100644 --- a/common/nymcoconut/src/scheme/issuance.rs +++ b/common/nymcoconut/src/scheme/issuance.rs @@ -319,6 +319,27 @@ pub fn blind_sign( Ok(BlindedSignature(h, sig)) } +/// Verifies a partial blind signature using the provided parameters and validator's verification key. +/// +/// # Arguments +/// +/// * `params` - A reference to the cryptographic parameters. +/// * `blind_sign_request` - A reference to the blind signature request signed by the client. +/// * `blind_sig` - A reference to the issued partial blinded signature to be verified. +/// * `partial_verification_key` - A reference to the validator's partial verification key. +/// +/// # Returns +/// +/// A boolean indicating whether the partial blind signature is valid (`true`) or not (`false`). +/// +/// # Remarks +/// +/// This function verifies the correctness and validity of a partial blind signature using +/// the provided cryptographic parameters, blind signature request, blinded signature, +/// and partial verification key. +/// It calculates pairings based on the provided values and checks whether the partial blind signature +/// is consistent with the verification key and commitments in the blind signature request. +/// The function returns `true` if the partial blind signature is valid, and `false` otherwise. pub fn verify_partial_blind_signature( params: &Parameters, blind_sign_request: &BlindSignRequest, @@ -435,7 +456,7 @@ mod tests { } #[test] - fn verify_partial_blind_signature_with_wrong_key() { + fn fail_verify_partial_blind_signature_with_wrong_key() { // 0 public and 2 private attribute let params = Parameters::new(2).unwrap(); let private_attributes = params.n_random_scalars(2); From 1f5568b4a78f399e92a5134672cf8371a71986e8 Mon Sep 17 00:00:00 2001 From: aniampio Date: Mon, 13 Nov 2023 13:50:47 +0000 Subject: [PATCH 5/8] Extend the function to support also public attributes --- common/nymcoconut/src/scheme/issuance.rs | 69 +++++++++++++++++++++--- 1 file changed, 61 insertions(+), 8 deletions(-) diff --git a/common/nymcoconut/src/scheme/issuance.rs b/common/nymcoconut/src/scheme/issuance.rs index 2dd1b35e27..7276c3f1f9 100644 --- a/common/nymcoconut/src/scheme/issuance.rs +++ b/common/nymcoconut/src/scheme/issuance.rs @@ -325,6 +325,7 @@ pub fn blind_sign( /// /// * `params` - A reference to the cryptographic parameters. /// * `blind_sign_request` - A reference to the blind signature request signed by the client. +/// * `public_attributes` - A reference to the public attributes included in the client's request. /// * `blind_sig` - A reference to the issued partial blinded signature to be verified. /// * `partial_verification_key` - A reference to the validator's partial verification key. /// @@ -343,12 +344,15 @@ pub fn blind_sign( pub fn verify_partial_blind_signature( params: &Parameters, blind_sign_request: &BlindSignRequest, + public_attributes: &[Attribute], blind_sig: &BlindedSignature, partial_verification_key: &VerificationKey, ) -> bool { + let num_private_attributes = blind_sign_request.private_attributes_commitments.len(); + // e(c, g2) let pairing0 = pairing(&blind_sig.1.to_affine(), params.gen2()); - let composed_pairing = blind_sign_request + let private_pairings = blind_sign_request .private_attributes_commitments .iter() .zip(&partial_verification_key.beta_g2) @@ -362,6 +366,22 @@ pub fn verify_partial_blind_signature( }, ); + let beta_g2_to_zip: Vec<_> = partial_verification_key + .beta_g2 + .iter() + .skip(num_private_attributes) + .cloned() + .collect(); + let composed_pairing = public_attributes.iter().zip(beta_g2_to_zip).fold( + private_pairings, + |acc, (public_attr, beta_g2)| { + acc + pairing( + &(blind_sig.0 * public_attr).to_affine(), + &beta_g2.to_affine(), + ) + }, + ); + pairing0 == composed_pairing } @@ -436,8 +456,34 @@ mod tests { #[test] fn successful_verify_partial_blind_signature() { - // 0 public and 2 private attribute - let params = Parameters::new(2).unwrap(); + let params = Parameters::new(4).unwrap(); + let private_attributes = params.n_random_scalars(2); + let public_attributes = params.n_random_scalars(2); + + let (_commitments_openings, request) = + prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap(); + + let validator_keypair = keygen(¶ms); + let blind_sig = blind_sign( + ¶ms, + &validator_keypair.secret_key(), + &request, + &public_attributes, + ) + .unwrap(); + + assert!(verify_partial_blind_signature( + ¶ms, + &request, + &public_attributes, + &blind_sig, + &validator_keypair.verification_key() + )); + } + + #[test] + fn successful_verify_partial_blind_signature_no_public_attributes() { + let params = Parameters::new(4).unwrap(); let private_attributes = params.n_random_scalars(2); let (_commitments_openings, request) = @@ -450,6 +496,7 @@ mod tests { assert!(verify_partial_blind_signature( ¶ms, &request, + &[], &blind_sig, &validator_keypair.verification_key() )); @@ -457,23 +504,29 @@ mod tests { #[test] fn fail_verify_partial_blind_signature_with_wrong_key() { - // 0 public and 2 private attribute - let params = Parameters::new(2).unwrap(); + let params = Parameters::new(4).unwrap(); let private_attributes = params.n_random_scalars(2); + let public_attributes = params.n_random_scalars(2); let (_commitments_openings, request) = - prepare_blind_sign(¶ms, &private_attributes, &[]).unwrap(); + prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap(); let validator_keypair = keygen(¶ms); let validator2_keypair = keygen(¶ms); - let blind_sig = - blind_sign(¶ms, &validator_keypair.secret_key(), &request, &[]).unwrap(); + let blind_sig = blind_sign( + ¶ms, + &validator_keypair.secret_key(), + &request, + &public_attributes, + ) + .unwrap(); // this assertion should fail, as we try to verify with a wrong validator key assert_eq!( verify_partial_blind_signature( ¶ms, &request, + &public_attributes, &blind_sig, &validator2_keypair.verification_key() ), From d0b9583b79182b5bb9d3e5727c95e1340711673d Mon Sep 17 00:00:00 2001 From: aniampio Date: Mon, 13 Nov 2023 14:34:22 +0000 Subject: [PATCH 6/8] Add benchmark for verification of a single partial blind signature --- common/nymcoconut/benches/benchmarks.rs | 26 +++++++++++++++++++++++++ common/nymcoconut/src/lib.rs | 1 + 2 files changed, 27 insertions(+) diff --git a/common/nymcoconut/benches/benchmarks.rs b/common/nymcoconut/benches/benchmarks.rs index 74149c15c9..9fd379c0d7 100644 --- a/common/nymcoconut/benches/benchmarks.rs +++ b/common/nymcoconut/benches/benchmarks.rs @@ -9,6 +9,7 @@ use nym_coconut::{ aggregate_signature_shares, aggregate_verification_keys, blind_sign, elgamal_keygen, prepare_blind_sign, prove_bandwidth_credential, setup, ttp_keygen, verify_credential, Attribute, BlindedSignature, Parameters, Signature, SignatureShare, VerificationKey, + verify_partial_blind_signature, }; use rand::seq::SliceRandom; use std::ops::Neg; @@ -237,11 +238,36 @@ fn bench_coconut(c: &mut Criterion) { blinded_signatures.push(blinded_signature) } + let verification_keys: Vec = coconut_keypairs .iter() .map(|keypair| keypair.verification_key()) .collect(); + // verify a random partial blind signature + let rand_idx = 1; + let random_blind_signature = blinded_signatures.get(rand_idx).unwrap(); + let partial_verification_key = verification_keys.get(rand_idx).unwrap(); + + group.bench_function( + &format!( + "verify_partial_blind_signature_{}_private_attributes_{}_public_attributes", + case.num_private_attrs, + case.num_public_attrs + ), + |b| { + b.iter(|| { + verify_partial_blind_signature( + ¶ms, + &blind_sign_request, + &public_attributes, + &random_blind_signature, + &partial_verification_key + ) + }) + }, + ); + // Lets bench worse case, ie aggregating all let indices: Vec = (1..=case.num_authorities).collect(); // aggregate verification keys diff --git a/common/nymcoconut/src/lib.rs b/common/nymcoconut/src/lib.rs index a98b546fc1..821b1b3b29 100644 --- a/common/nymcoconut/src/lib.rs +++ b/common/nymcoconut/src/lib.rs @@ -14,6 +14,7 @@ pub use scheme::aggregation::aggregate_signature_shares; pub use scheme::aggregation::aggregate_verification_keys; pub use scheme::issuance::blind_sign; pub use scheme::issuance::prepare_blind_sign; +pub use scheme::issuance::verify_partial_blind_signature; pub use scheme::issuance::BlindSignRequest; pub use scheme::keygen::ttp_keygen; pub use scheme::keygen::KeyPair; From ae22a132a3f156da47b630b4594e8234036aa6b0 Mon Sep 17 00:00:00 2001 From: aniampio Date: Mon, 13 Nov 2023 14:35:01 +0000 Subject: [PATCH 7/8] Update benchmarks --- common/nymcoconut/benches/benchmarks.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/common/nymcoconut/benches/benchmarks.rs b/common/nymcoconut/benches/benchmarks.rs index 9fd379c0d7..77d043e566 100644 --- a/common/nymcoconut/benches/benchmarks.rs +++ b/common/nymcoconut/benches/benchmarks.rs @@ -8,8 +8,8 @@ use group::{Curve, Group}; use nym_coconut::{ aggregate_signature_shares, aggregate_verification_keys, blind_sign, elgamal_keygen, prepare_blind_sign, prove_bandwidth_credential, setup, ttp_keygen, verify_credential, - Attribute, BlindedSignature, Parameters, Signature, SignatureShare, VerificationKey, - verify_partial_blind_signature, + verify_partial_blind_signature, Attribute, BlindedSignature, Parameters, Signature, + SignatureShare, VerificationKey, }; use rand::seq::SliceRandom; use std::ops::Neg; @@ -238,7 +238,6 @@ fn bench_coconut(c: &mut Criterion) { blinded_signatures.push(blinded_signature) } - let verification_keys: Vec = coconut_keypairs .iter() .map(|keypair| keypair.verification_key()) @@ -252,8 +251,7 @@ fn bench_coconut(c: &mut Criterion) { group.bench_function( &format!( "verify_partial_blind_signature_{}_private_attributes_{}_public_attributes", - case.num_private_attrs, - case.num_public_attrs + case.num_private_attrs, case.num_public_attrs ), |b| { b.iter(|| { @@ -262,7 +260,7 @@ fn bench_coconut(c: &mut Criterion) { &blind_sign_request, &public_attributes, &random_blind_signature, - &partial_verification_key + &partial_verification_key, ) }) }, From b1ac5b4e866c28c06ac8c5c7ea5dfe1cad9572b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C4=99drzej=20Stuczy=C5=84ski?= Date: Thu, 23 Nov 2023 11:14:51 +0000 Subject: [PATCH 8/8] using multimiller loop for partial blinded signature verification --- common/nymcoconut/benches/benchmarks.rs | 10 +-- common/nymcoconut/src/scheme/issuance.rs | 104 ++++++++++++++--------- 2 files changed, 67 insertions(+), 47 deletions(-) diff --git a/common/nymcoconut/benches/benchmarks.rs b/common/nymcoconut/benches/benchmarks.rs index 77d043e566..6627b437e1 100644 --- a/common/nymcoconut/benches/benchmarks.rs +++ b/common/nymcoconut/benches/benchmarks.rs @@ -6,8 +6,8 @@ use criterion::{criterion_group, criterion_main, Criterion}; use ff::Field; use group::{Curve, Group}; use nym_coconut::{ - aggregate_signature_shares, aggregate_verification_keys, blind_sign, elgamal_keygen, - prepare_blind_sign, prove_bandwidth_credential, setup, ttp_keygen, verify_credential, + aggregate_signature_shares, aggregate_verification_keys, blind_sign, prepare_blind_sign, + prove_bandwidth_credential, setup, ttp_keygen, verify_credential, verify_partial_blind_signature, Attribute, BlindedSignature, Parameters, Signature, SignatureShare, VerificationKey, }; @@ -176,8 +176,6 @@ fn bench_coconut(c: &mut Criterion) { let binding_number = params.random_scalar(); let private_attributes = vec![serial_number, binding_number]; - let _elgamal_keypair = elgamal_keygen(¶ms); - // The prepare blind sign is performed by the user let (pedersen_commitments_openings, blind_sign_request) = prepare_blind_sign(¶ms, &private_attributes, &public_attributes).unwrap(); @@ -259,8 +257,8 @@ fn bench_coconut(c: &mut Criterion) { ¶ms, &blind_sign_request, &public_attributes, - &random_blind_signature, - &partial_verification_key, + random_blind_signature, + partial_verification_key, ) }) }, diff --git a/common/nymcoconut/src/scheme/issuance.rs b/common/nymcoconut/src/scheme/issuance.rs index 7276c3f1f9..98a63f4511 100644 --- a/common/nymcoconut/src/scheme/issuance.rs +++ b/common/nymcoconut/src/scheme/issuance.rs @@ -3,9 +3,10 @@ use std::convert::TryFrom; use std::convert::TryInto; +use std::ops::Neg; -use bls12_381::{pairing, G1Affine, G1Projective, Scalar}; -use group::{Curve, GroupEncoding}; +use bls12_381::{multi_miller_loop, G1Affine, G1Projective, G2Prepared, Scalar}; +use group::{Curve, Group, GroupEncoding}; use crate::error::{CoconutError, Result}; use crate::proofs::ProofCmCs; @@ -349,40 +350,64 @@ pub fn verify_partial_blind_signature( partial_verification_key: &VerificationKey, ) -> bool { let num_private_attributes = blind_sign_request.private_attributes_commitments.len(); - // e(c, g2) - let pairing0 = pairing(&blind_sig.1.to_affine(), params.gen2()); + if num_private_attributes + public_attributes.len() > partial_verification_key.beta_g2.len() { + return false; + } - let private_pairings = blind_sign_request + // TODO: we're losing some memory here due to extra allocation, + // but worst-case scenario (given SANE amount of attributes), it's just few kb at most + let c_neg = blind_sig.1.to_affine().neg(); + let g2_prep = params.prepared_miller_g2(); + + let mut terms = vec![ + // (c^{-1}, g2) + (c_neg, g2_prep.clone()), + // (s, alpha) + ( + blind_sig.0.to_affine(), + G2Prepared::from(partial_verification_key.alpha.to_affine()), + ), + ]; + + // for each private attribute, add (cm_i, beta_i) to the miller terms + for (private_attr_commit, beta_g2) in blind_sign_request .private_attributes_commitments .iter() .zip(&partial_verification_key.beta_g2) - .fold( - pairing( - &blind_sig.0.to_affine(), - &partial_verification_key.alpha.to_affine(), - ), - |acc, (commitment, beta_g2)| { - acc + pairing(&commitment.to_affine(), &beta_g2.to_affine()) - }, - ); + { + // (cm_i, beta_i) + terms.push(( + private_attr_commit.to_affine(), + G2Prepared::from(beta_g2.to_affine()), + )) + } - let beta_g2_to_zip: Vec<_> = partial_verification_key - .beta_g2 - .iter() - .skip(num_private_attributes) - .cloned() - .collect(); - let composed_pairing = public_attributes.iter().zip(beta_g2_to_zip).fold( - private_pairings, - |acc, (public_attr, beta_g2)| { - acc + pairing( - &(blind_sig.0 * public_attr).to_affine(), - &beta_g2.to_affine(), - ) - }, - ); + // for each public attribute, add (s^pub_j, beta_{priv + j}) to the miller terms + for (pub_attr, beta_g2) in public_attributes.iter().zip( + partial_verification_key + .beta_g2 + .iter() + .skip(num_private_attributes), + ) { + // (s^pub_j, beta_j) + terms.push(( + (blind_sig.0 * pub_attr).to_affine(), + G2Prepared::from(beta_g2.to_affine()), + )) + } - pairing0 == composed_pairing + // get the references to all the terms to get the arguments the miller loop expects + let terms_refs = terms.iter().map(|(g1, g2)| (g1, g2)).collect::>(); + + // since checking whether e(a, b) == e(c, d) + // is equivalent to checking e(a, b) • e(c, d)^{-1} == id + // and thus to e(a, b) • e(c^{-1}, d) == id + // + // compute e(c^1, g2) • e(s, alpha) • e(cm_0, beta_0) • e(cm_i, beta_i) • (s^pub_0, beta_{i+1}) (s^pub_j, beta_{i + j}) + multi_miller_loop(&terms_refs) + .final_exponentiation() + .is_identity() + .into() } #[cfg(test)] @@ -421,7 +446,7 @@ pub fn sign( #[cfg(test)] mod tests { use super::*; - use crate::scheme::keygen::{keygen, SecretKey, VerificationKey}; + use crate::scheme::keygen::keygen; #[test] fn blind_sign_request_bytes_roundtrip() { @@ -522,15 +547,12 @@ mod tests { .unwrap(); // this assertion should fail, as we try to verify with a wrong validator key - assert_eq!( - verify_partial_blind_signature( - ¶ms, - &request, - &public_attributes, - &blind_sig, - &validator2_keypair.verification_key() - ), - false - ); + assert!(!verify_partial_blind_signature( + ¶ms, + &request, + &public_attributes, + &blind_sig, + &validator2_keypair.verification_key() + ),); } }