diff --git a/CHANGELOG.md b/CHANGELOG.md index b611239..d6b4646 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - Change the implementation for hashing a slice of bytes into a BlsScalar to `BlsScalar::hash_to_scalar` [#3] +- Add validity check for `PublicKey` and `Signature` in signature verification [#7] + +### Added + +- Add `is_valid` check for `PublicKey` [#7] +- Add `Error::InvalidPoint` variant for invalid `PublicKey` and `Signature` points [#7] ## [0.1.0] - 2024-01-08 @@ -18,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Add initial commit, this package continues the development of [dusk-bls12_381-sign](https://github.com/dusk-network/bls12_381-sign/) at version `0.6.0` under the new name: `bls12_381-bls` and without the go related code. +[#7]: https://github.com/dusk-network/bls12_381-bls/issues/7 [#3]: https://github.com/dusk-network/bls12_381-bls/issues/3 diff --git a/src/error.rs b/src/error.rs index 7a4f79d..73bf55d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,6 +15,8 @@ pub enum Error { BytesError(DuskBytesError), /// Cryptographic invalidity InvalidSignature, + /// Invalid Point + InvalidPoint, } impl From for Error { @@ -30,6 +32,9 @@ impl fmt::Display for Error { Self::InvalidSignature => { write!(f, "Invalid Signature") } + Self::InvalidPoint => { + write!(f, "Invalid Point") + } } } } diff --git a/src/keys/public.rs b/src/keys/public.rs index f7f6d84..36771af 100644 --- a/src/keys/public.rs +++ b/src/keys/public.rs @@ -52,6 +52,9 @@ impl PublicKey { /// Verify a [`Signature`] by comparing the results of the two pairing /// operations: e(sig, g_2) == e(Hâ‚’(m), pk). pub fn verify(&self, sig: &Signature, msg: &[u8]) -> Result<(), Error> { + if !self.is_valid() || !sig.is_valid() { + return Err(Error::InvalidPoint); + } let h0m = h0(msg); let p1 = dusk_bls12_381::pairing(&sig.0, &G2Affine::generator()); let p2 = dusk_bls12_381::pairing(&h0m, &self.0); diff --git a/src/signature.rs b/src/signature.rs index 8cb967d..93a4e23 100644 --- a/src/signature.rs +++ b/src/signature.rs @@ -30,6 +30,36 @@ impl Signature { }), ) } + + /// Returns true if the inner point is free of an $h$-torsion component, and + /// so it exists within the $q$-order subgroup $\mathbb{G}_2$. This + /// should always return true unless an "unchecked" API was used. + pub fn is_torsion_free(&self) -> bool { + self.0.is_torsion_free().into() + } + + /// Returns true if the inner point is on the curve. This should always + /// return true unless an "unchecked" API was used. + pub fn is_on_curve(&self) -> bool { + self.0.is_on_curve().into() + } + + /// Returns true if the inner point is the identity (the point at infinity). + pub fn is_identity(&self) -> bool { + self.0.is_identity().into() + } + + /// Returns true if the inner point is valid according to certain criteria. + /// + /// A [`Signature`] is considered valid if its inner point meets the + /// following conditions: + /// 1. It is free of an $h$-torsion component and exists within the + /// $q$-order subgroup $\mathbb{G}_2$. + /// 2. It is on the curve. + /// 3. It is not the identity. + pub fn is_valid(&self) -> bool { + self.is_torsion_free() && self.is_on_curve() && !self.is_identity() + } } impl Serializable<48> for Signature { diff --git a/tests/signature.rs b/tests/signature.rs index cba191d..20420f4 100644 --- a/tests/signature.rs +++ b/tests/signature.rs @@ -4,7 +4,8 @@ // // Copyright (c) DUSK NETWORK. All rights reserved. -use bls12_381_bls::{PublicKey, SecretKey, APK}; +use bls12_381_bls::{Error, PublicKey, SecretKey, APK}; +use dusk_bls12_381::BlsScalar; use rand::rngs::StdRng; use rand::{RngCore, SeedableRng}; @@ -178,6 +179,17 @@ fn sign_verify_aggregated_incorrect_apk() { assert!(apk.verify(&agg_sig, &msg).is_err()); } +#[test] +fn sign_verify_identity_fails() { + let rng = &mut StdRng::seed_from_u64(0xbeef); + let msg = random_message(rng); + let sk = SecretKey::from(BlsScalar::zero()); + let pk = PublicKey::from(&sk); + let sig = sk.sign_vulnerable(&msg); + + assert_eq!(pk.verify(&sig, &msg).unwrap_err(), Error::InvalidPoint); +} + fn random_message(rng: &mut StdRng) -> [u8; 100] { let mut msg = [0u8; 100];