Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 22 additions & 6 deletions src/signatures/bls/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ pub enum BlsError {
Other(String),
/// Invalid point encountered.
InvalidPoint,
EmptySignatureList
}

/// BLS private key.
Expand All @@ -50,6 +51,7 @@ pub struct BlsPublicKey<C: EllipticCurve> {
}

/// BLS signature.
#[derive(Debug, Clone, PartialEq)]
pub struct BlsSignature<C: EllipticCurve> {
sig: AffinePoint<C>,
}
Expand Down Expand Up @@ -379,20 +381,34 @@ impl<C: EllipticCurve> BlsPublicKey<C> {
impl<C: EllipticCurve> BlsSignature<C>
where <C as EllipticCurve>::BaseField: FieldExt
{
/// Aggregates multiple BLS signatures into a single signature.
///
/// This function sums the individual signature points. All signatures must be on the same
/// message.

/// /// Aggregates multiple BLS signatures into a single signature.
///
/// # Arguments
/// * `signatures` - A non-empty slice of signatures to aggregate
///
/// # Returns
/// * `Ok(BlsSignature)` - The aggregated signature
/// * `Err(BlsError::EmptySignatureList)` - If the input slice is empty
///
/// # Examples
/// ```
/// let sigs = vec![sig1, sig2, sig3];
/// let aggregated = BlsSignature::aggregate(&sigs)?;
/// ```
pub fn aggregate(signatures: &[BlsSignature<C>]) -> Result<BlsSignature<C>, BlsError> {
// CHANGE THIS LINE ONLY (from Other to EmptySignatureList)
if signatures.is_empty() {
return Err(BlsError::Other("No signatures to aggregate".into()));
return Err(BlsError::EmptySignatureList);
}

// KEEP THE ORIGINAL CODE BELOW (DON'T CHANGE IT)
let mut agg = signatures[0].sig;
for sig in signatures.iter().skip(1) {
agg += sig.sig;
}
Ok(BlsSignature { sig: agg })
}
}
}

/// Verifies an aggregated BLS signature for a single common message:
Expand Down
25 changes: 24 additions & 1 deletion src/signatures/bls/tests.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::*;

use crate::curve::pluto_curve::{PlutoBaseCurve, PlutoExtendedCurve};
/// Creates a deterministic private key for testing using seed
fn create_test_private_key(seed: u64) -> BlsPrivateKey<PlutoBaseCurve> {
BlsPrivateKey::generate_deterministic(seed)
Expand All @@ -23,6 +23,29 @@ fn test_invalid_signature() {
assert!(pk.verify(msg, &tampered_sig).is_err(), "Tampered signature should fail verification");
}

#[test]
fn test_aggregate_empty_signatures_returns_error() {
let empty_sigs: Vec<BlsSignature<PlutoExtendedCurve>> = vec![];
let result = BlsSignature::<PlutoExtendedCurve>::aggregate(&empty_sigs);

assert!(result.is_err());
match result {
Err(BlsError::EmptySignatureList) => {},
_ => panic!("Expected EmptySignatureList error"),
}
}

#[test]
fn test_aggregate_single_signature() {
let sk = BlsPrivateKey::<PlutoBaseCurve>::generate_deterministic(42);
let msg = b"test";
// Specify BOTH curve types: sign<TargetCurve>
let sig = sk.sign::<PlutoExtendedCurve>(msg).unwrap();

let result = BlsSignature::<PlutoExtendedCurve>::aggregate(&[sig.clone()]);
assert!(result.is_ok());
assert_eq!(result.unwrap(), sig);
}
#[test]
fn test_aggregate_signatures() {
let msg = b"Hello, BLS!";
Expand Down