Skip to content
Security
Skill

/bls-aggregation-audit

L1 trigger - audits BLS signature aggregation: subgroup check, rogue-key attack defense, aggregation order, signing-domain separation.

From plugin
plamen
276160 skills12 agents4 commands
Install
$ npx -y skills add PlamenTSV/plamen --skill bls-aggregation-audit --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/bls-aggregation-audit

Context preview

The summary Claude sees to decide when to auto-load this skill.

L1 trigger - audits BLS signature aggregation: subgroup check, rogue-key attack defense, aggregation order, signing-domain separation.

SKILL.md

bls-aggregation-audit.SKILL.md
name: "bls-aggregation-audit"
description: "L1 trigger - audits BLS signature aggregation: subgroup check, rogue-key attack defense, aggregation order, signing-domain separation."

Injectable Skill: BLS Aggregation Audit

> **L1 trigger**: `L1_PATTERN=true` AND (`bls/` OR `blst` OR `milagro` OR `pairing` OR `aggregate_signature` OR `proof_of_possession` detected in recon subsystem map) > **Inject Into**: `depth-consensus-invariant` or `depth-external` > **Language**: Go, Rust, occasionally C > **Finding prefix**: `[BLS-N]` > **Status**: v0.1 draft, Round 4 exemplars pending

Orchestrator Decomposition Guide

  • Sections 1, 2: depth-consensus-invariant (protocol-level BLS use)
  • Section 3: depth-external (library interface, FFI)
  • Section 4: depth-edge-case (boundary inputs)

When This Skill Activates

Recon identifies BLS12-381 signature use, typically in: Ethereum beacon chain, Filecoin, Celo, Chia, Aptos, or any aggregated-signature consensus. BLS is subtle: textbook descriptions assume defenses (subgroup check, rogue-key defense) that implementations often forget.

1. Library Fingerprinting

Identify the BLS library:

| Library | Language | Canonical use | |---|---|---| | `blst` | C with Go/Rust bindings | Lighthouse, Prysm, Teku | | `milagro-crypto` | C | Older clients | | `arkworks` | Rust | Aptos, some academic | | `celo-bls-zexe` | Rust | Celo | | `py_ecc` | Python | Reference implementations | | hand-rolled pairing | Various | Red flag — usually wrong |

A hand-rolled pairing implementation is a near-certain bug source. Flag it for intensive review.

2. Subgroup Check

BLS signatures live in a subgroup of an elliptic curve group. An attacker can provide a curve point that is valid on the curve but outside the subgroup, leading to signature verification forgeries.

**Check**:

  • Is every **received** signature / public key checked for subgroup membership before use?
  • In `blst`, the function is `blst_p1_in_g1` / `blst_p2_in_g2`
  • In `arkworks`, there are `is_in_correct_subgroup_assuming_on_curve` helpers
  • Protocol-level: when a signature is received from a peer, is subgroup-checked BEFORE aggregation with trusted signatures?
  • Aggregation without subgroup check: combining a valid sig with a subgroup-invalid sig can corrupt the aggregate

Tag: `[BLS-SUBGROUP:{loc}:{checked}]`

**Known exemplar class**: the `blst` library had a historical subgroup-check advisory; check upgrade logs.

3. Rogue-Key Attack (Proof of Possession)

Rogue-key attack: attacker registers a public key that is the difference of a target's key and the attacker's, then signs a message that verifies as signed by both.

**Defenses**:

  • **Proof of Possession (PoP)**: requires each public key to come with a self-signature of the key. Ethereum beacon chain uses this.
  • **Hash-to-point including signer**: if the message hash includes the signer's public key, rogue-key is defeated

**Check**:

  • For every public key registration / deposit path, is PoP verified?
  • Is PoP using a distinct domain separator from normal signatures? (Required — otherwise PoP can be forged from a normal sig.)

Tag: `[BLS-ROGUE-KEY:{defense}:{status}]`

4. Signing Domain Separation

BLS signatures must include a **domain tag** in the hash-to-point step. This prevents a signature from one protocol being replayed in another.

**Check**:

  • List all message types signed (attestation, proposal, slashing, sync committee, PoP, ...)
  • Each must have a distinct domain tag
  • Domain tags must be **hardcoded constants**, not computed from user input
  • Domain tags must be consistent across client implementations

Tag: `[BLS-DOMAIN:{message-type}:{tag}]`

5. Aggregation Correctness

5a. Aggregation algebra

  • Sum of signatures = signature of sum (for BLS). Implementation must use curve addition correctly.
  • Aggregation of zero signatures is the identity element. Is this handled? Some libraries crash.
  • Aggregation of signatures on different messages requires a different verification formula (individual verification, not batch).

5b. Order independence

Signature aggregation must be commutative. If the verification result depends on insertion order, that's a bug (and a non-determinism source).

5c. Duplicate handling

If the same signature is aggregated twice, the result doubles. Is this intended? In beacon chain, double-counting an attestation is a slashing condition.

**Check**: Does the aggregation code deduplicate? Does it track which validators have already contributed?

Tag: `[BLS-AGG:{issue}]`

6. Hash-to-Curve

The hash-to-curve step (RFC 9380) has multiple valid implementations with subtle differences. Inconsistency across clients is a consensus bug.

**Check**:

  • Which hash-to-curve variant is used? SSWU? Icart?
  • Is the DST (domain separation tag) exactly as specified in the protocol?
  • Is cofactor clearing applied?

7. FFI Safety

Most BLS libraries are C (blst). Calling C from Go or Rust via FFI is a common bug source:

**Check**:

  • Every `unsafe` block around blst calls: is the pointer valid? Length correct?
  • Are buffers properly sized for blst's output?
  • Are errors from blst propagated, or silently ignored?
  • Is the calling convention correct? (blst's go bindings vs raw cgo)

Tag: `[BLS-FFI:{issue}]`

8. Boundary conditions

| State | Test | Expected | Observed | |---|---|---|---| | Zero signature | identity-like bytes | spec-defined rejection | | | Zero public key | identity-like bytes | rejected | | | Subgroup-invalid sig | on-curve but wrong subgroup | rejected | | | Empty aggregation | aggregate of zero sigs | identity or error | | | Duplicate in aggregate | same sig twice | spec-defined | | | Max validator aggregation | aggregate of all validators | no integer overflow in count | | | Domain tag swap | attestation sig used as proposal sig | rejected | |

9. Output schema

  • **Layer**: crypto
  • **Bug class**: subgroup / rogue-key / domain-sep / aggregation / hash-to-curve / ffi-safety
  • **
Read more
Ships withplamen

Autonomous Web3 security auditor for Claude Code and OpenAI Codex CLI. Orchestrates 18-100 AI agents across 40+ phases to produce audit reports with verified PoC exploits — for smart contracts and L1 node-client infrastructure.

Get the whole plugin