Data Availability
Citrea utilizes Bitcoin as its unified layer for data availability and settlement. The bitcoin-da implementation handles publishing rollup data to Bitcoin and retrieving that data for verification within the light client proof circuit:
By leveraging the transaction Merkle root in Bitcoin block headers and verifying the header-chain proof-of-work, Citrea generates ZK proofs that cryptographically confirm specific transactions exist on the blockchain. This allows the protocol to verify data inclusion mathematically, ensuring the rollup state is always derivable from Bitcoin itself.
Bitcoin as Settlement Layer
Beyond data availability, Bitcoin serves as Citrea's settlement layer. Unlike Ethereum rollups that settle via on-chain verifier contracts, Citrea achieves settlement through a cryptographic proof chain anchored to Bitcoin's proof-of-work; the proofs themselves are the settlement mechanism.
State Commitment Pipeline
Settlement on Citrea follows a three-stage pipeline, each stage publishing data to Bitcoin:
Sequencer Commitments: The sequencer periodically publishes commitments containing a Merkle root over sequential L2 block hashes and the batch's ending L2 block number (the start is implicitly the previous commitment's end + 1). Once finalized on Bitcoin, these commitments pin the canonical ordering of L2 blocks, the sequencer cannot reorder or omit transactions without contradicting data already settled on Bitcoin.
Batch Proofs: The batch prover generates a zkSNARK proving that executing all transactions in a committed batch, starting from the previous proven state root, produces the claimed new state root. This proof, along with compressed state diffs, is published to Bitcoin. The proof attests: "the state transition is valid". Proof payloads are Brotli-compressed before inscribed on-chain. Batch proofs under MAX_TX_BODY_SIZE (397KB) fit in a single transaction; larger proofs are chunked and later aggregated.
Light Client Proofs: The light client prover produces recursive proofs that chain together, each verifying the previous proof plus new batch proofs. The resulting proof encapsulates the entire rollup history: "starting from genesis and applying all batches yields state root X". This single proof is sufficient for external verifiers to confirm Citrea's state without processing the full history.
Settlement Without Smart Contracts
Bitcoin lacks the programmability to verify zkSNARKs directly on-chain. Citrea addresses this through two mechanisms:
Full node verification: Citrea full nodes fetch batch proofs from Bitcoin and verify them locally. Once verified, the batch reaches proven finality. The state transition is cryptographically guaranteed, secured by both the zkSNARK soundness and Bitcoin's proof-of-work protecting the data.
BitVM-based bridge verification: The Clementine bridge uses BitVM to optimistically verify light client proofs on Bitcoin. Operators can be challenged if they claim an incorrect state, with the light client proof serving as the dispute resolution mechanism. This enables trust-minimized BTC withdrawals without requiring Bitcoin soft forks.
Finality Guarantees
L2 transactions inherit Bitcoin's finality in stages (see Transaction Finality):
Soft-confirmed
Sequencer signature
Fast UX, but can still be reorged
Finalized
Sequencer commitment on Bitcoin
Transactions are considered finalized after 6 L1 confirmations
Proven
Batch proof on Bitcoin
Execution validity is cryptographically verified
Once proven, reverting an L2 transaction would require either breaking the zkSNARK (computationally infeasible) or executing a deep Bitcoin reorganization beyond the finality depthβmaking proven L2 transactions effectively as secure as L1 Bitcoin transactions.
Publishing Data on Bitcoin Using Inscriptions
Citrea publishes data using a Taproot commit-reveal scheme. The commit transaction locks funds to a script that can only be spent by revealing the inscription data. The reveal transaction then spends this output, embedding the data in the witness. This type of data was popularized and named "inscriptions" by the Ordinals protocol.
The reveal script has a header identifying the transaction type:
The body follows with an OP_FALSE OP_IF ... OP_ENDIF pattern that creates an unexecuted code branch, allowing data storage without affecting script execution. Each body chunk is limited to 520 bytes due to Bitcoin's script push size limit.
Witness data benefits from the SegWit discount, costing approximately 1/4 the fee of equivalent data stored in transaction outputs.
WTXID Prefix
The light client proof must verify that all relevant DA transactions in a Bitcoin block are included. Scanning and parsing every transaction in a block to check if it's a Citrea inscription adds significant overhead to the ZK circuitβthe circuit cost grows linearly with the number of transactions, regardless of whether they are Citrea-related.
Citrea uses a witness transaction ID (WTXID) prefix mechanism to reduce this overhead. The transaction publisher (sequencer, batch prover, or security council) adjusts a nonce in the reveal script until the resulting WTXID starts with a specific prefix (0x0202). The circuit then filters candidate transactions by checking only the first two bytes of each WTXID, parsing only those that match.
With a 2-byte prefix, a random transaction has a 1/65,536 chance of matching, resulting in approximately 0.0015% false positives per block. These are filtered out during transaction format parsing. The prefix mechanism is purely a performance optimization for the ZK circuitβit has no security value since anyone can craft a matching nonce. Security comes entirely from signature verification: all Citrea inscriptions must contain a valid signature from an authorized key (sequencer, batch prover, or security council).
Transaction Types
The bitcoin-da implementation supports multiple transaction types: Complete batch proofs (type 0x00), Aggregate batch proofs (0x01), Chunks (0x02), BatchProofMethodId updates (0x03), and Sequencer Commitments (0x04).
Batch Proofs
A batch proof that fits within 397KB is published as a single Complete transaction. This limit exists because Bitcoin Core's default mempool policy rejects transactions exceeding 400KB (MAX_STANDARD_TX_WEIGHT), and 397KB leaves room for script overhead while ensuring transactions propagate across the network. The inscription contains a signature, the batch prover's public key, and the compressed proof data split into 520-byte chunks:
When a batch proof exceeds 397KB, it's split across multiple Chunk transactions. Each chunk contains only the raw data (no signature or public key). An Aggregate transaction then ties these chunks together by containing pointers to each chunk's txid and wtxid, along with a signature from the batch prover covering the aggregate data. The light client proof verifies the aggregate transaction's signature and uses the pointers to locate and reconstruct the full proof from the referenced chunks.
BatchProofMethodId
The BatchProofMethodId transaction allows the security council to update the ZK verification key (method ID) used by the light client proof to verify batch proofs. This enables the light client proof to verify batch proofs generated with an updated proving system. It contains a new method ID, the L2 activation height, and 3-of-5 security council signatures.
Sequencer Commitment
The sequencer publishes commitments that include a Merkle root of L2 block hashes, a monotonic index, and the ending L2 block number. See SequencerCommitment for the full structure.
For implementation details and full transaction format specifications, see the bitcoin-da crate.
Verification in the Light Client Proof
The DA verifier runs inside the light client proof circuit and enforces both completeness and correctness of data.
Completeness ensures no relevant transactions are omitted. A transaction is "relevant" if its WTXID starts with the Citrea prefix (0x0202) and successfully parses as a valid Citrea inscription. The verifier iterates through all transaction WTXIDs in the block, filters by prefix, parses matching transactions, and rejects the proof if any valid Citrea transaction is missing from the provided data.
Correctness ensures included data is valid and untampered:
Witness data verification: The verifier computes the witness Merkle root from all WTXIDs in the block. The coinbase transaction contains a SegWit commitment in its output (prefixed
0x6a24aa21a9ed). The verifier confirmsSHA256d(witness_merkle_root || witness_nonce)matches this commitment.Coinbase inclusion: The coinbase transaction itself is verified against the header's Merkle root via a txid Merkle proof, establishing that the witness commitment comes from the actual block.
Sender authentication: Inscriptions include the sender's public key and a signature over
SHA256(blob_body). The verifier checks this ECDSA signature to confirm data originated from an authorized party (sequencer, batch prover, or security council).Decompression bounds: When reconstructing Brotli-compressed payloads, the circuit enforces protocol size limits on the decompressed output. Any payload that expands beyond allowed bounds of 100 MB (see MAX_DECOMPRESSED_BLOB_SIZE) causes proof failure, preventing decompression-bomb style attacks inside the circuit.
The verifier also validates the Bitcoin header chain itselfβchecking block hashes, height continuity, difficulty targets, proof of work, and timestamp validity. On mainnet, 6 block confirmations are required before data is considered final (see Transaction Finality). See NetworkConstants for network-specific parameters.
Recursive Proof Accumulation
The light client proof is recursive: each proof verifies the previous proof before processing the next L1 block. This creates a chain where verifying a single proof attests that, for the given Bitcoin chain up to that block, the L2 state produced by the circuit is correct and consistent with all on-chain commitments.
Chain Structure
Each light client proof takes as input:
The previous light client proof (None for the genesis proof)
A Bitcoin block header with inclusion and completeness proofs
A witness for accessing the circuit's JMT state
The circuit first verifies the previous proof using the zkVM's verification API, extracting the previous output. It then verifies the new block header follows the previous block under Bitcoin's consensus rulesβchecking proof-of-work, height continuity, difficulty targets, and timestamp validity.
Accumulated State
The circuit maintains a JellyFish Merkle Tree (JMT) that accumulates the following data across blocks:
Block hashes
Proves a specific L1 block was seen by the circuit
Sequencer commitments
Stores commitment data indexed by monotonic index
Verified state transitions
Maps commitment index to verified (initial_root, final_root, last_l2_height)
Proof chunks
Stores chunk bodies by wtxid for later aggregation
Batch proof method IDs
Tracks verification keys with activation heights
Transaction Processing
For each Bitcoin block, the circuit processes all relevant transactions extracted via the completeness proof:
Sequencer commitments: Stored in the JMT by their index. The circuit verifies the sender is the authorized sequencer.
Batch proofs (Complete or Aggregate): The circuit verifies the zkSNARK using the appropriate method ID from the JMT. It then validates the sequencer commitment relationβensuring the batch proof's referenced commitments exist in the JMT with matching hashes. Upon successful verification, each commitment in the batch's range is marked as a
VerifiedStateTransitionin the JMT.Proof chunks: Stored in the JMT by their wtxid. When an Aggregate transaction arrives, the circuit retrieves and concatenates the chunks to reconstruct the full proof.
Method ID updates: Stores new verification keys with their activation L2 height after validating 3-of-5 security council signatures.
State Root Advancement
After processing all transactions, the circuit attempts to advance the L2 state. It checks if the next sequencer commitment index has a verified state transition whose initial state root matches the current L2 state root. If so, it updates:
The L2 state root to the transition's final state root
The last L2 height
The last sequencer commitment index
This advancement continues for as many consecutive verified transitions as available, ensuring the L2 state only advances through cryptographically verified state transitions that form a continuous chain from genesis.
Output
The circuit output contains:
l2_state_root: The verified L2 state rootlcp_state_root: Root of the circuit's JMT, committing to all accumulated datalight_client_proof_method_id: The verification key of this proof, used to ensure the next proof verifies against the same circuit versionlatest_da_state: Bitcoin chain state (block hash, height, total work, difficulty parameters)last_l2_heightandlast_sequencer_commitment_index: Progress markers
By the time a proof is generated for block height h, every Citrea transaction from the initial Bitcoin block to h has been extracted, verified for sender authorization, and processed. The lcp_state_root cryptographically commits to this complete history. The Clementine bridge uses this proof to obtain the verified L2 state root, which it then uses to validate withdrawal claims via storage proofs.
References
Last updated
Was this helpful?