diff --git a/common/nym_offline_divisible_ecash/src/proofs/proof_spend.rs b/common/nym_offline_divisible_ecash/src/proofs/proof_spend.rs index be66f0ccea..9d35b8e39c 100644 --- a/common/nym_offline_divisible_ecash/src/proofs/proof_spend.rs +++ b/common/nym_offline_divisible_ecash/src/proofs/proof_spend.rs @@ -364,6 +364,7 @@ mod tests { let rho2 = v.neg() * r_theta1; let rho3 = r_rr * r_tt; + let pg_varsigpr1_delta = pairing(&varsig_prime1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine()); let pg_psi0_delta = pairing(&psi_g1.to_affine(), ¶ms_a.get_ith_delta((vv - 1) as usize).to_affine()); let pg_varsigpr2_gen2 = pairing(&varsig_prime2.to_affine(), grp.gen2()); diff --git a/common/nym_offline_divisible_ecash/src/scheme/setup.rs b/common/nym_offline_divisible_ecash/src/scheme/setup.rs index c09e1d6bb2..36151e1b5d 100644 --- a/common/nym_offline_divisible_ecash/src/scheme/setup.rs +++ b/common/nym_offline_divisible_ecash/src/scheme/setup.rs @@ -113,7 +113,7 @@ impl Parameters { let sps_signatures: Vec = sigmas_u .iter() .zip(thetas_u.iter()) - .map(|(sigma, theta)| sps_keypair.sps_sk.sign(grp.clone(), Some(&vec![*sigma, *theta]), None)) + .map(|(sigma, theta)| sps_keypair.sps_sk.sign(&grp, Some(&vec![*sigma, *theta]), None)) .collect(); diff --git a/common/nym_offline_divisible_ecash/src/scheme/structure_preserving_signature.rs b/common/nym_offline_divisible_ecash/src/scheme/structure_preserving_signature.rs index 4ceb0f129e..e36bd1e6e6 100644 --- a/common/nym_offline_divisible_ecash/src/scheme/structure_preserving_signature.rs +++ b/common/nym_offline_divisible_ecash/src/scheme/structure_preserving_signature.rs @@ -1,4 +1,5 @@ use std::convert::TryFrom; +use std::fmt::Debug; use std::ops::Neg; use bls12_381::{G1Projective, G2Projective, Gt, pairing, Scalar}; @@ -33,7 +34,7 @@ impl SPSSecretKey { self.y } - pub fn sign(&self, grp: GroupParameters, messages_a: Option<&[G1Projective]>, messages_b: Option<&[G2Projective]>) -> SPSSignature { + pub fn sign(&self, grp: &GroupParameters, messages_a: Option<&[G1Projective]>, messages_b: Option<&[G2Projective]>) -> SPSSignature { let r = grp.random_scalar(); let rr = grp.gen1() * r; let ss: G1Projective = match messages_a { @@ -73,28 +74,71 @@ impl SPSVerificationKey { let pg_rr_yy = pairing(&signature.rr.to_affine(), &self.yy.to_affine()); let pg_ss_g2 = pairing(&signature.ss.to_affine(), grp.gen2()); let pg_g1_zz = pairing(grp.gen1(), &self.zz.to_affine()); - let prod_pg_ma_ww: Vec = messages_a.iter() + let pg_ma_ww: Vec = messages_a.iter() .zip(self.wws.iter()) - .map(|(m, ww)| pairing(&m.to_affine(), &ww.to_affine())) + .map(|(ma, ww)| pairing(&ma.to_affine(), &ww.to_affine())) .collect(); - let mut pg_m_ww = Gt::identity(); - for elem in prod_pg_ma_ww.iter() { - pg_m_ww = pg_m_ww + elem; + let mut prod_pg_ma_ww = Gt::identity(); + for elem in pg_ma_ww.iter() { + prod_pg_ma_ww = prod_pg_ma_ww + elem; } - // let pg_m_ww = prod_pg_ma_ww.fold(Gt::identity() | acc, elem | acc + elem); - // assert_eq!(pg_rr_yy + pg_ss_g2 + pg_m_ww, pg_g1_zz); + // let prod_pg_ma_ww = pg_ma_ww.iter().fold(Gt::identity() | acc, elem | acc + elem); - let pg_rr_tt = pairing(&signature.rr.to_affine(), &signature.tt.to_affine()); - let pg_g1_g2 = pairing(grp.gen1(), grp.gen2()); - // assert_eq!(pg_rr_tt, pg_g1_g2); + assert_eq!(pg_rr_yy + pg_ss_g2 + prod_pg_ma_ww, pg_g1_zz); - if pg_rr_yy + pg_ss_g2 + pg_m_ww == pg_g1_zz && pg_rr_tt == pg_g1_g2 { - return true; - } else { - return false; - } + let result = match messages_b { + Some(msgs_b) => { + let pg_rr_tt = pairing(&signature.rr.to_affine(), &signature.tt.to_affine()); + let pg_g1_g2 = pairing(grp.gen1(), grp.gen2()); + let pg_uu_mb: Vec = self.uus.iter() + .zip(msgs_b.iter()) + .map(|(uu, mb)| pairing(&uu.to_affine(), &mb.to_affine())) + .collect(); + + let mut prod_pg_uu_mb = Gt::identity(); + for elem in pg_uu_mb.iter() { + prod_pg_uu_mb = prod_pg_uu_mb + elem; + } + // let prod_pg_uu_mb = pg_uu_mb.iter().fold(Gt::identity() | acc, elem | acc + elem); + if pg_rr_tt + prod_pg_uu_mb == pg_g1_g2 { + true + } else { + false + } + } + + None => { + let pg_sign_rr_yy = pairing(&signature.rr.to_affine(), &self.yy.to_affine()); + let pg_sign_ss_gen2 = pairing(&signature.ss.to_affine(), &grp.gen2()); + let pg_ma_wws: Vec = messages_a.iter() + .zip(self.wws.iter()) + .map(|(ma, ww)| pairing(&ma.to_affine(), &ww.to_affine())) + .collect(); + + let mut prod_pg_ma_wws = Gt::identity(); + for elem in pg_ma_wws.iter() { + prod_pg_ma_wws = prod_pg_ma_wws + elem; + } + + let pg_gen1_zz = pairing(&grp.gen1(), &self.zz.to_affine()); + + let pg_rr_tt = pairing(&signature.rr.to_affine(), &signature.tt.to_affine()); + let pg_gen1_gen2 = pairing(&grp.gen1(), &grp.gen2()); + + assert_eq!(pg_sign_rr_yy + pg_sign_ss_gen2 + prod_pg_ma_wws, pg_gen1_zz); + assert_eq!(pg_rr_tt, pg_gen1_gen2); + + if pg_sign_rr_yy + pg_sign_ss_gen2 + prod_pg_ma_wws == pg_gen1_zz && pg_rr_tt == pg_gen1_gen2 { + true + } else { + false + } + } + }; + + return result; } pub fn get_ith_ww(&self, idx: usize) -> &G2Projective { return self.wws.get(idx).unwrap(); } @@ -144,3 +188,34 @@ pub struct SPSSignature { pub ss: G1Projective, pub tt: G2Projective, } + + +#[cfg(test)] +mod tests { + use rand::thread_rng; + + use crate::scheme::setup::GroupParameters; + use crate::scheme::structure_preserving_signature::SPSKeyPair; + use crate::utils::{hash_g1, hash_g2}; + + #[test] + fn sign_and_verify_for_two_msg_in_G1_and_two_msgs_in_G2() { + let rng = thread_rng(); + let grp = GroupParameters::new().unwrap(); + let sps_keypair = SPSKeyPair::new(grp.clone(), 2, 2); + let msgs_a = vec![hash_g1("messageA1"), hash_g1("messageA2")]; + let msgs_b = vec![hash_g2("messageB1"), hash_g2("messageB2")]; + let signature = sps_keypair.sps_sk.sign(&grp, Some(&msgs_a), Some(&msgs_b)); + assert!(sps_keypair.sps_vk.verify(&grp, signature, &msgs_a, Some(&msgs_b))); + } + + #[test] + fn sign_and_verify_for_two_msg_in_G1_and_no_msgs_in_G2() { + let rng = thread_rng(); + let grp = GroupParameters::new().unwrap(); + let sps_keypair = SPSKeyPair::new(grp.clone(), 2, 2); + let msgs_a = vec![hash_g1("messageA1"), hash_g1("messageA2")]; + let signature = sps_keypair.sps_sk.sign(&grp, Some(&msgs_a), None); + assert!(sps_keypair.sps_vk.verify(&grp, signature, &msgs_a, None)); + } +} \ No newline at end of file