diff --git a/Cargo.lock b/Cargo.lock index 8de83de65b..1fe90814a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4868,6 +4868,7 @@ dependencies = [ "rayon", "serde", "sha2 0.9.9", + "subtle 2.5.0", "thiserror", "zeroize", ] diff --git a/Cargo.toml b/Cargo.toml index f7fdcd1716..d72cb74007 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -350,6 +350,7 @@ prometheus = { version = "0.13.0" } bls12_381 = { git = "https://github.com/jstuczyn/bls12_381", default-features = false, branch = "temp/experimental-serdect" } group = { version = "0.13.0", default-features = false } ff = { version = "0.13.0", default-features = false } +subtle = "2.5.0" # cosmwasm-related cosmwasm-schema = "=1.4.3" diff --git a/common/nym_offline_compact_ecash/Cargo.toml b/common/nym_offline_compact_ecash/Cargo.toml index e9d2acbda5..8e3e774ba0 100644 --- a/common/nym_offline_compact_ecash/Cargo.toml +++ b/common/nym_offline_compact_ecash/Cargo.toml @@ -25,6 +25,7 @@ rayon = { workspace = true, optional = true } zeroize = { workspace = true, features = ["zeroize_derive"] } ff = { workspace = true } group = { workspace = true } +subtle = { workspace = true } nym-pemstore = { path = "../pemstore" } nym-network-defaults = { path = "../network-defaults", default-features = false } diff --git a/common/nym_offline_compact_ecash/src/common_types.rs b/common/nym_offline_compact_ecash/src/common_types.rs index 6aaf81f673..14f9b1cb66 100644 --- a/common/nym_offline_compact_ecash/src/common_types.rs +++ b/common/nym_offline_compact_ecash/src/common_types.rs @@ -6,6 +6,7 @@ use crate::error::Result; use crate::helpers::{g1_tuple_to_bytes, recover_g1_tuple}; use bls12_381::{G1Projective, Scalar}; use serde::{Deserialize, Serialize}; +use subtle::Choice; pub type SignerIndex = u64; @@ -58,6 +59,11 @@ impl Signature { let (h, s) = recover_g1_tuple::(bytes)?; Ok(Signature { h, s }) } + + /// Checks whether any of the group elements of the signature is an identity element located at infinity + pub fn is_at_infinity(&self) -> Choice { + self.s.is_identity() | self.h.is_identity() + } } #[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)] diff --git a/common/nym_offline_compact_ecash/src/scheme/aggregation.rs b/common/nym_offline_compact_ecash/src/scheme/aggregation.rs index 994e64c2e2..9018cde7ea 100644 --- a/common/nym_offline_compact_ecash/src/scheme/aggregation.rs +++ b/common/nym_offline_compact_ecash/src/scheme/aggregation.rs @@ -50,6 +50,17 @@ where impl Aggregatable for PartialSignature { fn aggregate(sigs: &[PartialSignature], indices: Option<&[u64]>) -> Result { + // Ensure that we have valid signatures + if sigs.is_empty() { + return Err(CompactEcashError::AggregationEmptySet); + } + + // Check each individual signature for point at infinity + for sig in sigs { + if bool::from(sig.is_at_infinity()) { + return Err(CompactEcashError::IdentitySignature); + } + } let h = sigs .first() .ok_or(CompactEcashError::AggregationEmptySet)? @@ -109,7 +120,8 @@ pub fn aggregate_signatures( Err(err) => return Err(err), }; - if bool::from(signature.h.is_identity()) { + // Ensure the aggregated signature is not an infinity point + if bool::from(signature.is_at_infinity()) { return Err(CompactEcashError::IdentitySignature); } diff --git a/nym-wallet/Cargo.lock b/nym-wallet/Cargo.lock index 445c5f297a..6f20f00931 100644 --- a/nym-wallet/Cargo.lock +++ b/nym-wallet/Cargo.lock @@ -3156,6 +3156,7 @@ dependencies = [ "rand 0.8.5", "serde", "sha2 0.9.9", + "subtle 2.5.0", "thiserror", "zeroize", ]