BLS aggregation, the math that makes it work, and the things you simply can’t do with ECDSA or Schnorr Imagine a consensus protocol where 500,000 validatorBLS aggregation, the math that makes it work, and the things you simply can’t do with ECDSA or Schnorr Imagine a consensus protocol where 500,000 validator

One Signature to Verify Them All

2026/06/29 15:50
10 min read
For feedback or concerns regarding this content, please contact us at crypto.news@mexc.com

BLS aggregation, the math that makes it work, and the things you simply can’t do with ECDSA or Schnorr

Imagine a consensus protocol where 500,000 validators each attest to the same block. With ECDSA, that’s 500,000 signatures to gossip, store, and verify — roughly 32 MB of signature data per slot, half a million verifications. The chain would drown in its own cryptography.

Ethereum’s beacon chain handles exactly this scenario, and the artifact that lands on-chain is a single 96-byte signature plus a bitfield of who participated. That collapse — from hundreds of thousands of signatures down to one — is the headline feature of BLS, and it’s the thing that ECDSA cannot do at all and Schnorr can only do with a coordination protocol bolted on.

This piece walks through how BLS signatures work, the algebra behind aggregation, the one attack you have to defend against, and the use cases that are genuinely unique to the scheme. The Rust at the end compiles and runs.

The one ingredient: a bilinear pairing

Everything BLS does rests on a pairing — a map that takes two curve points and produces an element of a third group, with one magical property.

Take three groups of the same prime order r: G₁, G₂, and Gₜ. A pairing is a function

e : G₁ × G₂ → Gₜ

that is bilinear, meaning scalars can be slid across it freely:

e([a]P, [b]Q) = e(P, Q)^(a·b)

That single identity is the whole trick. It lets you “see” a multiplication that happened in the exponent of two separate points, without ever learning the scalars themselves. ECDSA and Schnorr live on ordinary elliptic curves where no such map exists; BLS lives on pairing-friendly curves where it does. In practice that curve is BLS12–381: a 381-bit prime field, embedding degree 12, around 128-bit security. Points in G₁ compress to 48 bytes, points in G₂ to 96 bytes.

The scheme itself

BLS is almost embarrassingly small once you have the pairing. I’ll use the minimal-public-key layout (public keys in G₁, signatures in G₂), which is the one Ethereum and the blst library use. Let g₁ be a fixed generator of G₁, and let H be a hash that maps an arbitrary message onto a point in G₂.

Key generation. Pick a random scalar sk. The public key is a point:

pk = [sk] g₁ (a point in G₁, 48 bytes)

Signing. Hash the message to a curve point and multiply by the secret key:

σ = [sk] H(m) (a point in G₂, 96 bytes)

Note what’s missing: there is no nonce, no randomness, no per-signature k. For a given key and message there is exactly one valid signature. Hold onto that — it matters later.

Verification. Check one pairing equation:

e(g₁, σ) =? e(pk, H(m))

Why it holds is one line of bilinearity:

e(g₁, σ) = e(g₁, [sk] H(m)) = e(g₁, H(m))^sk
e(pk, H(m)) = e([sk] g₁, H(m)) = e(g₁, H(m))^sk ✓

The verifier never sees sk, yet the two sides only match if the signer knew it. That's the entire scheme.

Aggregation: the part you can’t get elsewhere

Here’s where the pairing earns its keep. Because a signature is just a point and points add, you can sum signatures. There are two cases worth separating, because they have different costs and different security footguns.

Case 1 — many signers, the same message

This is the validator scenario. Everyone signs the same block m. Add up all the signatures:

σ_agg = σ₁ + σ₂ + … + σₙ = [sk₁ + sk₂ + … + skₙ] H(m)

and add up all the public keys into one aggregate key:

apk = pk₁ + pk₂ + … + pkₙ

Verification is then a single pairing equation, no matter how many signers were involved:

e(g₁, σ_agg) =? e(apk, H(m))

A thousand signers, a million signers — verification is still two pairings after a handful of cheap point additions. The on-chain footprint is one 96-byte signature. No other signature scheme gives you constant-size, constant-verification-cost aggregation without the signers coordinating.

Case 2 — different signers, different messages

Now suppose each signer signs their own message — think a batch of distinct transactions. You can still aggregate:

σ_agg = σ₁ + σ₂ + … + σₙ where σᵢ = [skᵢ] H(mᵢ)

but verification now needs one pairing per distinct message:

e(g₁, σ_agg) =? e(pk₁, H(m₁)) · e(pk₂, H(m₂)) · … · e(pkₙ, H(mₙ))

That’s n + 1 pairings. The win here is bandwidth and storage, not verification CPU — you ship and store one signature instead of n. The same-message case (one bitfield, two pairings) is the one that's almost free.

The rogue-key attack — read this before you ship

The same-message aggregation apk = Σ pkᵢ has a famous hole. Suppose honest parties publish pk₁. A malicious party registering afterward can advertise

pk₂ = [sk₂] g₁ − pk₁

Now the aggregate key is apk = pk₁ + pk₂ = [sk₂] g₁, whose secret the attacker knows entirely. They can sign on behalf of the "group" alone and forge the honest party's participation. The honest party never signed anything.

There are three standard defenses, corresponding to the three IETF ciphersuites in draft-irtf-cfrg-bls-signature:

  1. Proof of Possession (PoP). Each participant must publish a signature over their own public key, proving they hold the matching secret. You can’t register a key you derived as a difference of others’ keys, because you don’t know its discrete log. This is what Ethereum uses, and it keeps same-message aggregation cheap.
  2. Message augmentation. Sign pk ‖ m instead of m, binding every signature to its signer's key. No PoP registry needed, but you lose the pure same-message fast path.
  3. Distinct messages (the “basic” scheme). Require that all messages in an aggregate are distinct, which structurally rules out the attack.

Pick one deliberately. The naive Σ pkᵢ with no defense is exploitable.

What BLS can do that ECDSA and Schnorr can’t

Aggregation alone isn’t the full story. Here is the part the title promised — capabilities that are unique or dramatically simpler with BLS.

1. Non-interactive aggregation. This is the real differentiator. ECDSA has no native aggregation whatsoever. Schnorr does aggregate (MuSig2), but the signers must run an interactive protocol first — exchanging nonce commitments before anyone signs. BLS signers never talk to each other. Each signs independently, publishes, and any third party can aggregate the published signatures afterward, even years later. This is precisely why Ethereum can fold together attestations from validators who have no channel between them. With Schnorr you’d need every validator online and coordinating in a multi-round dance every slot.

2. Unique, deterministic signatures → verifiable randomness. Because there’s no nonce, σ = [sk] H(m) is the signature — there is exactly one. ECDSA and Schnorr both inject a per-signature nonce, so a signer can produce many valid signatures for the same message and choose among them. Uniqueness turns a BLS signature into a Verifiable Random Function: the drand beacon (the "League of Entropy") signs each round number with a threshold key, and the unique resulting signature, hashed, is unbiasable public randomness. You cannot build this from ECDSA or Schnorr, because the signer could grind the nonce to skew the output. Determinism is a feature here, not a footnote.

3. Dead-simple threshold signatures. BLS is linear in the key — σ_agg = [Σ skᵢ] H(m) — so Shamir secret sharing composes with it directly. A t-of-n set of partial signatures Lagrange-interpolates into the single group signature, and the result is identical no matter which t signers showed up. That canonical output is exactly what makes the VRF use work. Threshold ECDSA exists, but it's a heavyweight MPC affair (GG18/GG20 and friends) with multiple interactive rounds; threshold BLS is interpolation.

4. Incremental aggregation in gossip networks. Aggregation is just point addition, so a node can keep folding new signatures into a running aggregate as they trickle in over the network — no need to collect them all first.

The honest tradeoffs

BLS is not free, and a balanced article says so.

  • Pairings are expensive. A single BLS verification (two pairings) is meaningfully slower than an ECDSA verify. The distinct-message aggregate verify is n+1 pairings, so it saves bytes, not CPU. Only the same-message fast-aggregate path is cheap regardless of n.
  • Signing needs hash-to-curve, which is fiddlier to implement correctly than ECDSA’s hash-to-scalar.
  • Bigger, gnarlier implementations and far less HSM / hardware support than secp256k1 or Ed25519.
  • Pairing-friendly curves took a security haircut. Improved number-field-sieve attacks are why the curve is BLS12–381 (≈128-bit) and not something smaller — the original BLS12–381 security estimates were revised downward.
  • Not quantum-resistant — like ECDSA and Schnorr, it rests on discrete log.

It runs

Here’s a complete, compiling example against the blst crate (the same library Ethereum consensus clients use). It exercises a single signature, same-message aggregation over 1,000 signers, distinct-message aggregation, and tamper rejection.

rust

use blst::min_pk::{AggregateSignature, PublicKey, SecretKey, Signature};
use blst::BLST_ERROR;
// Standard DST for Ethereum-style minimal-pubkey BLS.
const DST: &[u8] = b"BLS_SIG_BLS12381G2_XMD:SHA-256_SSWU_RO_NUL_";
fn keypair(seed: &[u8; 32]) -> (SecretKey, PublicKey) {
let sk = SecretKey::key_gen(seed, &[]).expect("key_gen");
let pk = sk.sk_to_pk();
(sk, pk)
}
fn main() {
// 1. One signer, one message.
let (sk, pk) = keypair(&[1u8; 32]);
let msg = b"settle block #42";
let sig = sk.sign(msg, DST, &[]);
assert_eq!(sig.verify(true, msg, DST, &[], &pk, true), BLST_ERROR::BLST_SUCCESS);
println!("signature: {} bytes, pubkey: {} bytes",
sig.compress().len(), pk.compress().len());
// 2. Same message, 1000 signers -> ONE signature (fast_aggregate_verify).
let n = 1000;
let mut sks = Vec::new();
let mut pks = Vec::new();
for i in 0..n {
let mut seed = [0u8; 32];
seed[..8].copy_from_slice(&(i as u64 + 7).to_le_bytes());
let (s, p) = keypair(&seed);
sks.push(s);
pks.push(p);
}
let block = b"finalize epoch 17";
let sigs: Vec<Signature> = sks.iter().map(|s| s.sign(block, DST, &[])).collect();
// Anyone can aggregate the published signatures - no coordination needed.
let sig_refs: Vec<&Signature> = sigs.iter().collect();
let agg = AggregateSignature::aggregate(&sig_refs, true).unwrap().to_signature();
let pk_refs: Vec<&PublicKey> = pks.iter().collect();
assert_eq!(agg.fast_aggregate_verify(true, block, DST, &pk_refs),
BLST_ERROR::BLST_SUCCESS);
println!("{} sigs on one message -> {} bytes", n, agg.compress().len());
// 3. Distinct messages, distinct signers (aggregate_verify).
let (sk_a, pk_a) = keypair(&[10u8; 32]);
let (sk_b, pk_b) = keypair(&[20u8; 32]);
let (sk_c, pk_c) = keypair(&[30u8; 32]);
let (m_a, m_b, m_c): (&[u8], &[u8], &[u8]) =
(b"alice->bob:5", b"bob->carol:3", b"carol->alice:1");
let s_a = sk_a.sign(m_a, DST, &[]);
let s_b = sk_b.sign(m_b, DST, &[]);
let s_c = sk_c.sign(m_c, DST, &[]);
let agg2 = AggregateSignature::aggregate(&[&s_a, &s_b, &s_c], true)
.unwrap().to_signature();
let msgs: [&[u8]; 3] = [m_a, m_b, m_c];
let pks2 = [&pk_a, &pk_b, &pk_c];
assert_eq!(agg2.aggregate_verify(true, &msgs, DST, &pks2, true),
BLST_ERROR::BLST_SUCCESS);
// 4. Tampering is caught.
let forged: [&[u8]; 3] = [m_a, b"bob->carol:3000", m_c];
assert_ne!(agg2.aggregate_verify(true, &forged, DST, &pks2, true),
BLST_ERROR::BLST_SUCCESS);
println!("all checks passed.");
}

Output:

signature: 96 bytes, pubkey: 48 bytes
1000 sigs on one message -> 96 bytes
all checks passed.

A thousand signatures, one 96-byte artifact, verified against a thousand public keys with two pairings. That’s the whole pitch.

The takeaway

ECDSA gives you signatures. Schnorr gives you signatures that aggregate if everyone coordinates first. BLS gives you signatures that aggregate after the fact, by anyone, with no coordination at all — and as a bonus, because they’re unique and deterministic, they double as a source of verifiable randomness and slot cleanly into threshold schemes. That combination is why it underpins Ethereum consensus, drand, Chia, and most modern threshold-cryptography stacks.

The cost is real: pairings are slow, the curves are heavy, and the rogue-key attack will bite you if you skip proof-of-possession. But for any system where you’re collecting independent attestations at scale, nothing else comes close.

Follow me on X.


One Signature to Verify Them All was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.

Market Opportunity
MATH Logo
MATH Price(MATH)
$0.02399
$0.02399$0.02399
+3.53%
USD
MATH (MATH) Live Price Chart

World Cup Combo: Aim for 200x

World Cup Combo: Aim for 200xWorld Cup Combo: Aim for 200x

Combine up to 20 World Cup matches in one order

Disclaimer: The articles reposted on this site are sourced from public platforms and are provided for informational purposes only. They do not necessarily reflect the views of MEXC. All rights remain with the original authors. If you believe any content infringes on third-party rights, please contact crypto.news@mexc.com for removal. MEXC makes no guarantees regarding the accuracy, completeness, or timeliness of the content and is not responsible for any actions taken based on the information provided. The content does not constitute financial, legal, or other professional advice, nor should it be considered a recommendation or endorsement by MEXC.