Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
duyuefeng0708
GitHub Repository: duyuefeng0708/Cryptography-From-First-Principle
Path: blob/main/frontier/07-pairings/connect/bls-ethereum-consensus.ipynb
483 views
unlisted
Kernel: SageMath 10.0

Connect: BLS Signatures in Ethereum 2.0 Consensus

Module 07 | Real-World Connections

Trace how BLS signatures from Module 07 power Ethereum's proof-of-stake consensus.

Introduction

Ethereum's proof-of-stake consensus (the Beacon Chain) requires hundreds of thousands of validators to sign attestations, votes on which blocks are valid. Without aggregation, each slot would require transmitting and verifying ~tens of thousands of individual signatures.

BLS signatures on the BLS12-381 curve solve this:

  • Aggregation: thousands of signatures on the same attestation compress into a single 48-byte curve point.

  • Efficient verification: one pairing check verifies the entire aggregate.

  • No nonce: BLS signing is deterministic, eliminating the catastrophic nonce-reuse vulnerability of ECDSA.

This notebook traces the connection from the math in Module 07 to the engineering in Ethereum.

BLS12-381: The Pairing-Friendly Curve

Ethereum uses the BLS12-381 curve, a Barreto-Lynn-Scott curve with:

ParameterValue
Field prime pp381 bits (4.0×10114\approx 4.0 \times 10^{114})
Subgroup order rr255 bits (7.3×1076\approx 7.3 \times 10^{76})
Embedding degree kk12
G1G_1Points on E(Fp)E(\mathbb{F}_p): y2=x3+4y^2 = x^3 + 4
G2G_2Points on E(Fp2)E'(\mathbb{F}_{p^2}): a twist of EE
GTG_TSubgroup of Fp12\mathbb{F}_{p^{12}}^*
Security level128 bits

The "12" in BLS12-381 is the embedding degree. The "381" is the bit-length of pp. These were chosen so that the ECDLP in G1G_1 and the DLP in Fp12\mathbb{F}_{p^{12}}^* both provide 128-bit security, the same balance we explored in the pairing inversion notebook.

# === Toy BLS setup (simulating the Ethereum BLS workflow) === # We use our small supersingular curve to demonstrate the protocol. # Real Ethereum uses BLS12-381 with 381-bit primes. p = 467 E = EllipticCurve(GF(p), [1, 0]) # y^2 = x^3 + x, supersingular card = E.cardinality() n = 13 # prime subgroup order k = 2 # embedding degree cofactor = card // n F2.<a> = GF(p^k) E_ext = E.change_ring(F2) # G1 generator while True: g1 = cofactor * E.random_point() if g1 != E(0) and n * g1 == E(0): break g1_ext = E_ext(g1) # G2 generator cofactor_ext = E_ext.cardinality() // n while True: g2 = cofactor_ext * E_ext.random_point() if g2 != E_ext(0) and n * g2 == E_ext(0): if g1_ext.weil_pairing(g2, n) != 1: break print(f"Toy BLS setup (simulating Ethereum's BLS12-381 workflow)") print(f"Curve: y^2 = x^3 + x over GF({p})") print(f"Subgroup order: n = {n}") print(f"Embedding degree: k = {k}") print(f"G1 generator: {g1}") print(f"G2 generator: {g2}") print(f"\nIn Ethereum: BLS12-381 with 381-bit p, 255-bit n, k=12")

Validator Signing: Attestations

In each slot (12 seconds), a committee of validators is selected to attest to the current state of the chain. Each attestation contains:

  • Source checkpoint (justified epoch)

  • Target checkpoint (epoch being voted on)

  • Head block root

Each validator signs this attestation data using BLS:

σi=skiH(attestation_data)\sigma_i = sk_i \cdot H(\text{attestation\_data})

where HH is a hash-to-curve function mapping the attestation to a point in G1G_1.

# === Simulate Ethereum validators signing attestations === def hash_to_curve(message, E, n, cofactor): """Simplified hash-to-curve for teaching.""" h = hash(message) % (10^6) for x_try in range(h, h + 1000): x = GF(p)(x_try) y_sq = x^3 + x if y_sq.is_square(): y = y_sq.sqrt() P = E(x, y) Q = cofactor * P if Q != E(0): return Q return cofactor * E.random_point() # Register 10 validators (like a small Ethereum committee) num_validators = 10 validators = [] print(f"Registering {num_validators} validators...") for i in range(num_validators): sk = randint(1, n - 1) pk = sk * g2 validators.append({'id': i, 'sk': sk, 'pk': pk}) print(f" Validator {i}: pk = {pk}") print(f"\n{num_validators} validators registered (Ethereum has ~900,000+)")
# === Each validator signs the same attestation === # The attestation data (same message for all validators in a committee) attestation = "epoch=100,source=99,target=100,head=0xabcdef" h_att = hash_to_curve(attestation, E, n, cofactor) print(f"Attestation: '{attestation}'") print(f"H(attestation) = {h_att}") print() # Each validator signs signatures = [] for v in validators: sigma_i = v['sk'] * h_att signatures.append(sigma_i) print(f"{num_validators} individual signatures produced.") print(f"Without aggregation: {num_validators} curve points to transmit and verify.") print(f"With 900,000 validators: 900,000 * 48 bytes = ~43 MB per slot!")

Aggregation: Thousands to One

The magic of BLS: for same-message signing, aggregation is just point addition.

σagg=σ1+σ2++σn\sigma_{\text{agg}} = \sigma_1 + \sigma_2 + \cdots + \sigma_npkagg=pk1+pk2++pknpk_{\text{agg}} = pk_1 + pk_2 + \cdots + pk_n

Verification requires only 2 pairings regardless of the number of signers:

e(σagg,g2)=e(H(m),pkagg)e(\sigma_{\text{agg}}, g_2) = e(H(m), pk_{\text{agg}})

This reduces bandwidth from O(n)O(n) to O(1)O(1) per slot.

# === Aggregate all 10 validator signatures === # Aggregate signatures: just add the points sigma_agg = signatures[0] for sig in signatures[1:]: sigma_agg = sigma_agg + sig # Aggregate public keys pk_agg = validators[0]['pk'] for v in validators[1:]: pk_agg = pk_agg + v['pk'] print(f"Individual signatures: {num_validators} curve points") print(f"Aggregate signature: 1 curve point = {sigma_agg}") print(f"Aggregate public key: 1 curve point = {pk_agg}") print() # Verify with 2 pairings sigma_agg_ext = E_ext(sigma_agg) h_att_ext = E_ext(h_att) lhs = sigma_agg_ext.weil_pairing(g2, n) rhs = h_att_ext.weil_pairing(pk_agg, n) print(f"=== Aggregate Verification (2 pairings) ===") print(f"e(sigma_agg, g2) = {lhs}") print(f"e(H(att), pk_agg) = {rhs}") print(f"Valid? {lhs == rhs}") print() print(f"Verification cost: 2 pairings (same whether 10 or 900,000 validators!)")
# === Bandwidth comparison === # BLS12-381 sizes sig_size_bytes = 48 # compressed G1 point pk_size_bytes = 96 # compressed G2 point validators_eth = 900000 # approximate current Ethereum validator count committee_size = 128 # validators per committee in a slot committees_per_slot = 64 total_per_slot = committee_size * committees_per_slot # ~8192 attestations # Without aggregation no_agg_bytes = total_per_slot * sig_size_bytes # With aggregation (one aggregate per committee) agg_bytes = committees_per_slot * sig_size_bytes # 64 aggregate sigs print("=== Ethereum Beacon Chain Bandwidth (per slot, 12 seconds) ===") print(f"Validators attesting per slot: ~{total_per_slot}") print(f"Committees per slot: {committees_per_slot}") print() print(f"WITHOUT BLS aggregation:") print(f" {total_per_slot} individual sigs * {sig_size_bytes} bytes = {no_agg_bytes:,} bytes ({no_agg_bytes/1024:.1f} KB)") print(f" Plus {total_per_slot} verification operations") print() print(f"WITH BLS aggregation:") print(f" {committees_per_slot} aggregate sigs * {sig_size_bytes} bytes = {agg_bytes:,} bytes ({agg_bytes/1024:.1f} KB)") print(f" Only {committees_per_slot * 2} pairing operations for verification") print() print(f"Bandwidth reduction: {no_agg_bytes / agg_bytes:.0f}x") print(f"Verification reduction: {total_per_slot / (committees_per_slot * 2):.0f}x")

Why BLS over ECDSA?

Ethereum 1.0 used ECDSA on secp256k1 (the Bitcoin curve). The switch to BLS12-381 for the Beacon Chain was driven by aggregation:

FeatureECDSA (secp256k1)BLS (BLS12-381)
Signature size64 bytes48 bytes
AggregationNot possibleNative
Nonce requiredYes (critical!)No
Verification of nn sigsnn verifications2 pairings
Bandwidth for nn sigsO(n)O(n)O(1)O(1)
Single-sig verify speedFasterSlower (pairings)

For consensus with hundreds of thousands of validators, aggregation is not optional, it is the only way to keep the protocol feasible.

Concept Map: Module 07 to Ethereum

Module 07 ConceptEthereum Application
Bilinear pairing e:G1×G2GTe: G_1 \times G_2 \to G_TCore of BLS verification: e(σ,g2)=e(H(m),pk)e(\sigma, g_2) = e(H(m), pk)
Pairing-friendly curve (embedding degree kk)BLS12-381: k=12k = 12 balances curve and target security
BLS sign: σ=skH(m)\sigma = sk \cdot H(m)Validator signs attestation data
BLS verify: pairing equationBeacon chain verifies attestations
Signature aggregation: σi\sum \sigma_iCommittee sigs compress to one point
Same-message optimization: 2 pairingsAll validators in a committee attest to same data
Rogue key attack / PoP defenseValidators submit PoP at deposit (EIP-2333)
Hash-to-curvehash_to_G1 per the IETF hash-to-curve standard

Every concept from the explore notebooks has a direct engineering counterpart in Ethereum.

Summary

ConceptKey idea
BLS12-381Pairing-friendly curve with 128-bit security, chosen to balance ECDLP and target-field DLP
Validator signingEach validator signs attestations as σ=skH(attestation)\sigma = sk \cdot H(\text{attestation})
AggregationThousands of signatures compress into one curve point via simple addition
Two-pairing verificationOne aggregate is verified with 2 pairings, regardless of committee size
Proof of possessionValidators submit a PoP at registration to prevent the rogue key attack

Without pairings and BLS aggregation, proof-of-stake consensus at Ethereum's scale would be impractical. The abstract algebra of bilinear maps directly enables a real-world system processing billions of dollars in transactions.


Back to Module 07: Bilinear Pairings