From 8ef59ccfe347088026dee7576c823a8d27e708ea Mon Sep 17 00:00:00 2001 From: aniampio Date: Thu, 23 Nov 2023 18:36:45 +0000 Subject: [PATCH] Add verification for the coin signatures --- common/nym_offline_compact_ecash/src/error.rs | 3 + .../src/scheme/setup.rs | 104 +++++++++++++++++- 2 files changed, 104 insertions(+), 3 deletions(-) diff --git a/common/nym_offline_compact_ecash/src/error.rs b/common/nym_offline_compact_ecash/src/error.rs index 12228735a6..88b5dcbbf9 100644 --- a/common/nym_offline_compact_ecash/src/error.rs +++ b/common/nym_offline_compact_ecash/src/error.rs @@ -34,6 +34,9 @@ pub enum CompactEcashError { #[error("Expiration Date related error: {0}")] ExpirationDate(String), + #[error("Coin Indices related error: {0}")] + CoinIndices(String), + #[error( "Deserailization error, expected at least {} bytes, got {}", min, diff --git a/common/nym_offline_compact_ecash/src/scheme/setup.rs b/common/nym_offline_compact_ecash/src/scheme/setup.rs index e669f6fd89..330c2c4c25 100644 --- a/common/nym_offline_compact_ecash/src/scheme/setup.rs +++ b/common/nym_offline_compact_ecash/src/scheme/setup.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::ops::Index; use bls12_381::{G1Affine, G1Projective, G2Affine, G2Prepared, G2Projective, Scalar}; +use group::{Curve, GroupEncoding}; use ff::Field; use rand::thread_rng; @@ -10,6 +11,7 @@ use crate::utils::{hash_g1, Signature}; use crate::scheme::keygen::{SecretKeyAuth, VerificationKeyAuth}; use crate::constants; use rayon::prelude::*; +use crate::utils::{check_bilinear_pairing, generate_lagrangian_coefficients_at_origin}; pub struct GroupParameters { @@ -142,14 +144,13 @@ pub struct CoinIndexSignature{ pub type PartialCoinIndexSignature = CoinIndexSignature; -pub fn sign_coin_indices(params: Parameters, vk: &VerificationKeyAuth, sk_auth: SecretKeyAuth) -> Vec{ - +pub fn sign_coin_indices(params: &Parameters, vk: &VerificationKeyAuth, sk_auth: &SecretKeyAuth) -> Vec{ let m1: Scalar = Scalar::from_bytes(&constants::TYPE_IDX).unwrap(); let m2: Scalar = Scalar::from_bytes(&constants::TYPE_IDX).unwrap(); let mut partial_coins_signatures = Vec::with_capacity(params.L() as usize); for l in 0..params.L(){ - let m0: Scalar = Scalar::from(l); + let m0: Scalar = Scalar::from(l as u64); // Compute the hash h let mut concatenated_bytes = Vec::with_capacity(vk.to_bytes().len() + l.to_le_bytes().len()); concatenated_bytes.extend_from_slice(&vk.to_bytes()); @@ -171,6 +172,72 @@ pub fn sign_coin_indices(params: Parameters, vk: &VerificationKeyAuth, sk_auth: partial_coins_signatures } +pub fn verify_coin_indices_signatures( + params: &Parameters, + vk: &VerificationKeyAuth, + vk_auth: &VerificationKeyAuth, + signatures: &[CoinIndexSignature], +) -> Result<()>{ + let m1: Scalar = Scalar::from_bytes(&constants::TYPE_IDX).unwrap(); + let m2: Scalar = Scalar::from_bytes(&constants::TYPE_IDX).unwrap(); + for (l, sig) in signatures.iter().enumerate() { + let m0: Scalar = Scalar::from(l as u64); + // Compute the hash h + let mut concatenated_bytes = Vec::with_capacity(vk.to_bytes().len() + l.to_le_bytes().len()); + concatenated_bytes.extend_from_slice(&vk.to_bytes()); + concatenated_bytes.extend_from_slice(&l.to_le_bytes()); + let h = hash_g1(concatenated_bytes); + // Check if the hash is matching + if sig.h != h { + return Err(CompactEcashError::CoinIndices( + "Failed to verify the commitment hash".to_string(), + )); + } + let partially_signed_attributes = [m0, m1, m2] + .iter() + .zip(vk_auth.beta_g2.iter()) + .map(|(m, beta_i)| beta_i * Scalar::from(*m)) + .sum::(); + if !check_bilinear_pairing( + &sig.h.to_affine(), + &G2Prepared::from((vk_auth.alpha + partially_signed_attributes).to_affine()), + &sig.s.to_affine(), + params.grp().prepared_miller_g2(), + ) { + return Err(CompactEcashError::CoinIndices( + "Verification of the coin signature failed".to_string(), + )); + } + } + Ok(()) + +} + +pub fn aggregate_indices_signatures(params: Parameters, vk: &VerificationKeyAuth, signatures: &[(u64, VerificationKeyAuth, Vec)]){ + // Check if all indices are unique + // if signatures.iter().map(|(index, _, _)| index).unique().count() != signatures.len() { + // return Err(CompactEcashError::CoinIndices( + // "Not enough unique indices shares".to_string(), + // )); + // } + // Evaluate at 0 the Lagrange basis polynomials k_i + let coefficients = generate_lagrangian_coefficients_at_origin(&signatures.iter().map(|(index, _, _)| *index).collect::>()); + let m1: Scalar = Scalar::from_bytes(&constants::TYPE_IDX).unwrap(); + let m2: Scalar = Scalar::from_bytes(&constants::TYPE_IDX).unwrap(); + for l in 0..params.L(){ + let m0: Scalar = Scalar::from(l); + // Compute the hash h + let mut concatenated_bytes = Vec::with_capacity(vk.to_bytes().len() + l.to_le_bytes().len()); + concatenated_bytes.extend_from_slice(&vk.to_bytes()); + concatenated_bytes.extend_from_slice(&l.to_le_bytes()); + let h = hash_g1(concatenated_bytes); + for (i, vk_auth, sig) in signatures.iter(){ + + } + } + +} + pub fn setup(L: u64) -> Parameters { let grp = GroupParameters::new().unwrap(); let x = grp.random_scalar(); @@ -196,3 +263,34 @@ pub fn setup(L: u64) -> Parameters { signs, } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::scheme::keygen::{ttp_keygen}; + use crate::scheme::aggregation::aggregate_verification_keys; + + #[test] + fn test_sign_coins(){ + let L = 32; + let params = setup(L); + let authorities_keypairs = ttp_keygen(¶ms.grp(), 2, 3).unwrap(); + let indices: [u64; 3] = [1, 2, 3]; + + // Pick one authority to do the signing + let sk_i_auth = authorities_keypairs[0].secret_key(); + let vk_i_auth = authorities_keypairs[0].verification_key(); + + // list of verification keys of each authority + let verification_keys_auth: Vec = authorities_keypairs + .iter() + .map(|keypair| keypair.verification_key()) + .collect(); + // the global master verification key + let verification_key = aggregate_verification_keys(&verification_keys_auth, Some(&indices)).unwrap(); + + let partial_signatures = sign_coin_indices(¶ms, &verification_key, &sk_i_auth); + assert!(verify_coin_indices_signatures(¶ms, &verification_key, &vk_i_auth, &partial_signatures).is_ok()); + + } +} \ No newline at end of file