BLS, Schnorr, and EVM Precompiles

Beyond ECDSA over secp256k1, several other signature and cryptographic schemes appear in advanced smart-contract systems. Some are exposed as EVM precompiles; others are implemented in Solidity or Yul at significant gas cost; some are emerging as new precompiles in upcoming forks. Auditors should know what's available, what's commonly misused, and what to watch for.

The Existing Precompiles (Pre-Pectra)

The EVM has historically exposed a small fixed set of cryptographic precompiles:

AddressNamePurpose
0x01ecrecoversecp256k1 ECDSA recovery
0x02sha256SHA-256 hash
0x03ripemd160RIPEMD-160 hash (legacy)
0x04identityMemory copy
0x05modexpModular exponentiation (EIP-198)
0x06bn256AddBN254 / alt_bn128 point addition
0x07bn256ScalarMulBN254 scalar multiplication
0x08bn256PairingBN254 pairing check (used in ZK verifiers)
0x09blake2fBlake2 compression (EIP-152)

These power most on-chain cryptography. The BN254 precompiles in particular are the backbone of Groth16 ZK proof verification on Ethereum (used by Tornado Cash, zkSync Era verifier, Loopring, many privacy and rollup systems).

Post-Cancun and Post-Pectra Additions

Recent and upcoming forks add new precompiles relevant to modern audits:

  • EIP-2537: BLS12-381 precompiles (target Pectra). Eight new precompiles supporting addition, scalar multiplication, multi-scalar multiplication, pairing, and field-to-curve mappings on BLS12-381. Enables practical on-chain BLS aggregate signature verification at a fraction of the gas cost of pure-Solidity implementations.
  • EIP-7212: P-256 (secp256r1) verification precompile (Pectra). Enables direct verification of P-256 signatures, which is the curve used by WebAuthn / passkeys / TPM / mobile-device secure enclaves. Critical for account abstraction wallets that authenticate via biometrics.
  • EIP-2935: BLOCKHASH expansion / historical state roots (Pectra, related cryptography). Makes more historical state available for fraud-proof and bridge designs.

Auditors should know which precompiles a given chain supports — not every L2 supports the same set. Polygon zkEVM, zkSync Era, Linea, Scroll, Optimism, and Base may differ in their support timing for post-Pectra precompiles.

BLS Aggregate Signatures

BLS signatures (over BLS12-381) have the property that N signatures from N different signers on the same message can be aggregated into a single signature, verifiable in roughly the cost of one signature plus N public-key additions. This is what makes the beacon chain's attestation aggregation efficient.

For application contracts, BLS aggregation enables:

  • Validator-set signatures (light clients, bridges): one signature covers thousands of validators' attestations.
  • Multi-party authorization: a transaction signed by N parties at once, verified at the cost of ~1 signature.
  • Threshold schemes: M-of-N signing without per-signer reveal.

Audit Considerations for BLS

  • Rogue-key attacks. Naïve aggregation lets an attacker who controls one public key generate a key that, when added to others, cancels out their contributions. Defenses: proof-of-possession (PoP) requirements, distinct domain separation tags, or message-augmented aggregation (each signature signs (pubkey || message) rather than just message).
  • Subgroup checks. A BLS public key or signature outside the proper subgroup of the curve can produce invalid verifications. Precompiles handle this; pure-Solidity implementations often forget.
  • Domain separation. BLS signatures should use a domain separation tag (DST) that uniquely identifies the application. Without it, signatures from one BLS-using protocol can be replayed in another.
  • Message hashing. "Hash-to-curve" must follow the standardized hash-to-curve scheme (RFC 9380). Implementations that use ad-hoc hashing are usually broken.

A BLS verification routine in Solidity that doesn't use the EIP-2537 precompiles is expensive (~50-100k gas per signature historically), and home-rolled implementations are likely buggy. A modern audit should expect post-Pectra contracts to use the precompiles directly.

Schnorr Signatures

Schnorr signatures have similar mathematical properties to ECDSA but are easier to reason about and natively support multi-party signing (MuSig, MuSig2). They have no dedicated EVM precompile but can be verified using secp256k1 operations.

A clever trick: a Schnorr signature on secp256k1 can be verified using ecrecover (the secp256k1 ECDSA precompile) by feeding the precompile carefully constructed inputs. This is the basis of compact Schnorr verification on EVM. Contracts using this technique should be audited carefully — the construction is subtle and small errors are catastrophic.

Audit notes:

  • The construction relies on specific algebraic properties; a bug in setup defeats the signature scheme entirely.
  • Domain separation matters as much as for any other scheme.
  • MuSig2 (the modern multi-signature variant) requires a multi-round nonce-generation protocol off-chain; the on-chain verification is just standard Schnorr but the off-chain protocol's correctness is critical.

Schnorr remains uncommon in production Solidity but is appearing more often in research-grade designs (compact multisigs, threshold cryptography, advanced DAO governance).

ZK Proof Verification

While not "signatures" in the traditional sense, ZK proof verification frequently appears in audit scope:

  • Groth16 proofs verify via the BN254 pairing precompile. Verifiers are auto-generated by circom, snarkjs, gnark; they are usually correct but the trusted setup is application-specific and should be reviewed.
  • PLONK / Halo2 proofs are more flexible but more expensive to verify on-chain. The verifier contracts are larger and more bug-prone.
  • STARK proofs are typically too expensive to verify in EVM today; STARK-based systems use off-chain verification with on-chain commitments instead.

For any ZK system in audit:

  • Verify the verifier contract corresponds to the circuit you think it does. Mismatched verifying keys = a verifier that accepts the wrong proofs.
  • Verify that public inputs to the proof are properly checked on-chain (off-chain provers can lie about what they're proving if the public inputs aren't constrained by the contract).
  • Verify the trusted setup ceremony, if applicable — a corrupted setup means proofs can be forged.

ZK auditing is a specialized sub-discipline. A general auditor should know when to escalate to a ZK-specialist (every time the project has bespoke circuits) and when the standard checks suffice (when the project uses a well-vetted verifier for a standard primitive).

VRF (Verifiable Random Functions)

VRFs produce randomness that is both unpredictable and verifiable. Two common patterns:

  • Chainlink VRF (off-chain VRF with on-chain verification): Chainlink's oracle network generates the VRF output off-chain; the contract verifies the proof on-chain.
  • RANDAO / block.prevrandao: The beacon chain's onchain randomness, available via block.prevrandao. Cheaper but somewhat manipulable by the proposer (who can choose to not include their block and forfeit it for randomness manipulation).

Audit considerations:

  • block.prevrandao is partially manipulable. A proposer who would profit from a particular randomness outcome can compute it and decide whether to include the block. For low-value randomness this is fine; for high-value lotteries it's not.
  • VRF callback re-entrancy. Chainlink VRF responses come in a separate transaction (the callback). The contract's state may have changed between request and callback; state must be persisted correctly across the gap.
  • VRF request DOS. If the requester pays for the VRF, an attacker who can trigger requests can drain the requester's budget.

Native Cryptographic Operations to Avoid

A few patterns are reliably bad and should be flagged on sight:

  • Custom hash functions implemented in Solidity. Use keccak256 or sha256 precompiles; nothing custom.
  • "Encryption" implemented in Solidity without acknowledging that on-chain data is public regardless. There is no secure encryption-at-rest on a public blockchain.
  • Random-number generation from block properties (block.timestamp, blockhash, block.coinbase) when the value matters. All of these are at least somewhat manipulable.
  • Custom elliptic-curve arithmetic beyond what precompiles provide. Almost always buggy.

A Pragmatic Checklist

For any contract whose cryptography goes beyond ecrecover + EIP-712:

  • Identify exactly which precompiles or curve operations are used.
  • Confirm the target chain supports them at the deployment time.
  • Verify domain separation tags are present and unique to the application.
  • Verify subgroup checks (for BLS, pairing schemes) are performed.
  • Verify nonce / replay protection at the same level as for ECDSA.
  • If using a ZK verifier, confirm the verifying key matches the circuit; treat the circuit itself as an auditable artifact.
  • If using block.prevrandao for randomness, document the value of being able to manipulate it, and confirm the protocol design tolerates it.
  • If using off-chain VRF or oracles, confirm the request/response flow handles state changes safely.

Most of these need a specialist for full review. A general auditor should at least flag them for specialist attention rather than waving them through.