Skip to content

Back to the catalog

A hash-only rollup: OP Stack L2 accounts as Lamport-style hash chains, no ECDSA inside the L2
ethresear.charticle

A hash-only rollup: OP Stack L2 accounts as Lamport-style hash chains, no ECDSA inside the L2

Hash-only rollup: an OP Stack L2 (chain ID 42069000, live since 30 September 2026) where accounts are keccak-256 hash chains and transactions carry no signatures. Spending uses a commit-reveal step through two new transaction types in op-geth. The post describes a flaw the authors found: unauthenticated commits could be overwritten, which allowed preimage front-running. It was fixed with a first-commit-wins rule on 21 October 2026. It lists the remaining limits: L1 ECDSA, no fault proofs, a centralized sequencer, 160-bit addresses and wallet desync.

TL;DR Presents a signature-free post-quantum OP Stack L2 built on keccak hash chains, a fixed commit-overwrite front-running flaw, and open questions on remaining attacks.
Document

What it is

A design post from the founder of bb84, a payments app, for an OP Stack L2 (chain ID 42069000, live since 30 September 2026) with no signatures on L2 transactions. An account is the tip of a keccak-256 hash chain (N = 1000 by default). Spending reveals the next preimage. The post gives the account and transaction rules in enough detail to review them, and asks for criticism.

How it works

Address is trunc20(keccak256("OP_HASH_ADDR_v1" ‖ C)), where C = s_N. The predeploy NullifierTree (0x4200…0042) stores lastReveal, chainDepth and spent nullifiers per address. Two EIP-2718 types are added in op-geth: 0x7C HashCommitTx and 0x7F HashRevealTx. The state transition replaces ecrecover with five checks, run before gas purchase:

  1. from is registered and chainDepth[from] > 0.
  2. keccak256(preImage) == lastReveal[from].
  3. The nullifier equals keccak256("OP_NULLIFIER_v1" ‖ preImage ‖ nonce ‖ txDigest).
  4. The nullifier is unspent.
  5. A matching commitment, keccak256("OP_COMMIT_BIND_v1" ‖ nullifier ‖ preImage ‖ txDigest ‖ nonce), exists.

Authorization is consumed even if the EVM call reverts. After the Onyx hardfork, every ECDSA-typed transaction is rejected.

On the last chain step (chainDepth == 1), the reveal may carry newCommitment and newChainLength, which are bound by txDigest. If that step is missed, the address is dead.

The commit step exists because a revealed preimage is public and could be reused with a different to. The commit cannot be signed, so it is unauthenticated. The first version overwrote the pending commit. An attacker who read a preimage from a pending reveal could replace the victim's commit with one binding the same preimage to the attacker's txDigest. The authors found this themselves. The fix, active from 21 October 2026 00:00 UTC, has four parts:

  • One pending-commit slot per address; a new commit is rejected while an unexpired one exists.
  • The slot clears only on the matching reveal or on expiry (expireAfterBlocks, default 5).
  • The wallet broadcasts the reveal only after the commit receipt.
  • The txpool refuses commits the rule would reject, and the public RPC serves only eth_, net_ and web3_ methods without pending-transaction filters.

Preconditions / Affected

The design applies to this one chain and its bb84 wallet. Users hold only bridged USDC/EURC as StealthMintableERC20 (factory at 0x4200…0045), with no native-ETH spending. Commit and reveal are gas-free, limited to 10 transactions per minute per address. Withdrawals use a separate message passer (0x4200…0043) and a modified OptimismPortal.

Caveats

The post lists these limits:

  • Griefing: anyone can post a junk commit and block an address for up to 5 blocks. It cannot move funds, and the per-address rate limit bounds it.
  • Sequencer edge case: if an honest commit expires or is reorged out while its reveal is pending, the preimage is exposed and unbound. Only the operator's sequencer sees the pool today. The post says the protocol should not rely on that.
  • Unbuilt fix: a Guy Fawkes-style append-only commitment scheme would remove both problems. It needs a transaction format change and has not been built.
  • L1: still ECDSA. Deposits come from L1 EOAs and withdrawals pay out to L1 addresses.
  • No fault proofs: a permissioned proposer posts output roots through a custom dispute game that resolves immediately. By the L2BEAT framework it would not be Stage 0. Fast merchant withdrawals (2 hours instead of 7 days) also trust a registry operator.
  • Sequencer: centralized and run by the authors.
  • Addresses: 160-bit truncation leaves about 2^80 quantum second-preimage resistance on the address alone, against 2^128 for the chain.
  • Wallet desync: a wallet that loses its chain position can lock itself out until it resyncs. This happened in production.

The open questions are whether first-commit-wins is sound under reorgs, whether a second short hash chain could authenticate commits, whether this could be an AA validation mode, and whether Cannon/asterisc can prove the custom transaction types. A longer arXiv write-up is promised but not yet posted.

Organisations named here

  • asterisc
  • Cannon
  • EIP-2718
  • front-running
  • Guy Fawkes protocol
  • Lamport signatures
  • Onyx hardfork

Technologies named here

  • bb84
  • OP Stack and op-geth
  • Cannon and asterisc
  • op-program
  • Predeploys
  • L2BEAT
  • Bridged USDC/EURC as StealthMintableERC20 instances
  • 160-bit truncated addresses
  • Wallet state
  • Ethereum
  • ECDSA
  • EIP-7702
  • op-geth
  • OP Stack

Techniques named here

  • Front-running attack
  • Commit overwrite attack on the unauthenticated commit step
  • Commit griefing
  • Malicious sequencer edge case
  • Post-quantum reasoning
  • Grover's algorithm