Skip to content

[Bug] AggregatedAttestation::aggregate() produces invalid bitmap #92

@qj0r9j0vc2

Description

@qj0r9j0vc2

Problem

The AggregatedAttestation::aggregate() method creates a validator bitmap initialized to all zeros and never populates it. This results in attestations that will fail verification.

Location

crates/data-chain/src/attestation.rs:92-112

Code Analysis

pub fn aggregate(attestations: &[Attestation], validator_count: usize) -> Option<Self> {
    if attestations.is_empty() {
        return None;
    }

    let first = &attestations[0];
    let car_hash = first.car_hash;
    // ...

    // Build validator bitmap and collect signatures
    // Note: Without index mapping, we cannot populate the bitmap correctly
    // Use aggregate_with_indices() for proper bitmap population
    let validators = bitvec![u8, Lsb0; 0; validator_count];  // ALL ZEROS!
    let mut sigs: Vec<&BlsSignature> = Vec::with_capacity(attestations.len());

    for att in attestations {
        // Note: bitmap is never set!
        sigs.push(&att.signature);
    }

    // Aggregate signatures
    let aggregated_signature = BlsAggregateSignature::aggregate(&sigs).ok()?;

    Some(Self {
        car_hash,
        car_position,
        car_proposer,
        validators,  // Still all zeros
        aggregated_signature,
    })
}

The comment acknowledges the bug ("Without index mapping, we cannot populate the bitmap correctly") but the method still exists and could be called.

Impact

If aggregate() is called instead of aggregate_with_indices():

  1. count() returns 0: The attestation appears to have no attesters
  2. verify() fails: The verification function collects public keys based on the bitmap, which is empty
  3. Threshold checks fail: agg_att.count() < threshold will always be true

Where It Could Be Called

Any code path that has attestations but doesn't have validator indices readily available might call aggregate() instead of aggregate_with_indices().

Suggested Fix

Option 1: Remove the method entirely

// Delete aggregate() - only aggregate_with_indices() and aggregate_with_self() should exist

Option 2: Make it return an error

#[deprecated(note = "Use aggregate_with_indices() which correctly populates the validator bitmap")]
pub fn aggregate(_attestations: &[Attestation], _validator_count: usize) -> Option<Self> {
    None // Always return None to prevent misuse
}

Option 3: Mark it compile-time deprecated

#[deprecated(since = "0.1.0", note = "Use aggregate_with_indices() for correct bitmap population")]
pub fn aggregate(...) -> Option<Self> {
    unimplemented!("Use aggregate_with_indices() instead")
}

Severity

Medium - Code path exists that produces invalid attestations. The comment suggests awareness, but the method could still be accidentally used.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions