# Proofs

Citrea's proof system is the backbone of its security model. By generating zero-knowledge proofs of correct state transitions, Citrea ensures that anyone can verify the rollup's integrity without re-executing every transaction. This page provides a technical deep dive into the proof architecture, covering prover nodes, circuits, and the verification pipeline.

## Proof System Overview

***

Citrea employs a two-tier proving architecture:

* **Batch Proofs:** Prove the correct execution of sequencer commitments (L2 state transitions)
* **Light Client Proofs:** Aggregate batch proofs and verify Bitcoin consensus, forming a recursive proof chain

Both proof types are generated using the **RISC-0 zkVM**, which executes RISC-V programs and produces STARK proofs that are then wrapped in **Groth16 SNARKs** for succinct verification by full nodes and the Light Client Prover. Proofs are inscribed on Bitcoin for permanent availability. The design enables full nodes to verify proofs directly, while the Light Client Prover produces a single recursive proof that external verifiers (including the Clementine bridge) can check without processing the entire chain history.

<figure><img src="/files/IDOr2FNqQbW6eU6dfdA4" alt=""><figcaption><p>Proof System Architecture</p></figcaption></figure>

In addition to these two proof types, Citrea's bridge Clementine uses two more proof types:

* **Bridge Proofs:** Proves the honesty of the bridge operator by recursively verifying light client proofs and proving that withdrawals are paid out correctly.
* **Header chain proofs:** Prove the correctness of the Bitcoin header chain by verifying the difficulty adjustments, timestamps, and previous block hash linkage.

Header chain proofs are used by Watchtowers to challenge a bridge operator by proving the total work of the longest chain, later the challenged operator will need to prove it's honesty by providing a light client proof with more work than the Watchtower's proof. More details about the challenge process can be found in the [Clementine](/essentials/clementine-trust-minimized-bitcoin-bridge.md) documentation.

## Node Types

***

### Batch Prover

The Batch Prover is a dedicated node that monitors Bitcoin for finalized sequencer commitments and generates proofs of correct L2 execution. It maintains a replica of the rollup state and coordinates with the zkVM to produce succinct proofs.

**Core Responsibilities:**

* Syncs L1 (Bitcoin) blocks to track finalized sequencer commitments
* Syncs L2 blocks from the sequencer to maintain state
* Partitions commitments into provable batches
* Generates circuit inputs and coordinates proof generation
* Submits verified proofs to Bitcoin

<details>

<summary><strong>Batch Prover Architecture</strong></summary>

The Batch Prover consists of three interdependent modules:

**L1 Syncer:**

* Tracks finalized Bitcoin blocks via the DA service
* Extracts sequencer commitments from Bitcoin blocks
* Stores short header proofs for verifying `setBlockInfo` system transactions
* Records block height-to-hash mappings and commitment indices
* Signals the prover when new L1 blocks are processed

**L2 Syncer:**

* Fetches L2 blocks from the sequencer's RPC endpoint
* Applies blocks to the state transition function (STF)
* Maintains current state root and L2 block hash
* Validates state against sequencer claims

**Prover Core:**

* Receives signals from both syncers
* Manages proving session lifecycle
* Creates circuit inputs from commitment partitions
* Coordinates with parallel proving service
* Handles proof verification and submission

</details>

### Light Client Prover

The Light Client Prover (LCP) produces recursive proofs that encapsulate the entire rollup state. Each proof builds on the previous one, verifying both the batch proofs and Bitcoin's consensus rules. Verifying a single proof attests that, for the given Bitcoin chain up to that DA block, the L2 state produced by the circuit is correct, verified, and consistent with the on-chain commitments. For a detailed explanation, see the [light client circuit documentation](https://github.com/chainwayxyz/citrea/blob/nightly/docs/light-client-circuit.md).

**Core Responsibilities:**

* Processes each Bitcoin block containing Citrea data
* Verifies Bitcoin header chain (proof-of-work, difficulty adjustments)
* Validates and aggregates batch proofs
* Maintains a Jellyfish Merkle Tree (JMT) state for commitment tracking
* Produces recursive proofs for external verification

{% hint style="info" %}
The Light Client Prover's output feeds directly into Clementine. The bridge uses the LCP proof in BitVM to verify rollup state without trusting any single party.
{% endhint %}

## Circuits

***

Citrea and Clementine circuits run as RISC Zero guest programs and each cover a distinct part of the verification pipeline. Citrea proves L2 execution and light-client state, while Clementine provides the Header Chain, Work-Only, and Bridge circuits for Bitcoin header verification, compact work extraction, and bridge payout validation.

### Batch Proof Circuit

The Batch Proof Circuit verifies that a sequence of L2 blocks was executed correctly, producing a valid state transition from the previous proven state.

**Circuit Inputs:**

| Field                           | Description                                                                                      |
| ------------------------------- | ------------------------------------------------------------------------------------------------ |
| `initial_state_root`            | State root before batch execution                                                                |
| `final_state_root`              | State root after batch execution (host-side reference; not consumed by the V3 guest input split) |
| `sequencer_commitments`         | Commitments being proven                                                                         |
| `l2_blocks`                     | L2 blocks grouped by commitment (as `VecDeque<Vec<L2Block>>`)                                    |
| `state_transition_witnesses`    | State and offchain witnesses per block (as `VecDeque<Vec<(Witness, Witness)>>`)                  |
| `short_header_proofs`           | Bitcoin header proofs for verifying `SetBlockInfo` system transactions                           |
| `previous_sequencer_commitment` | Prior commitment (None if this is the first batch proof)                                         |
| `prev_hash_proof`               | Merkle proof for verifying the `prev_hash` of the first L2 block                                 |
| `cache_prune_l2_heights`        | L2 heights at which to prune witness cache (zkVM memory management)                              |
| `last_l1_hash_witness`          | Witness for reading the last L1 hash from the Bitcoin light client contract                      |

**Circuit Execution:**

1. Deserializes circuit input (split into two parts to manage zkVM memory)
2. Initializes the State Transition Function with storage runtime
3. Verifies L2 block chain continuity using `prev_hash_proof`
4. Replays L2 blocks against the initial state, applying transactions
5. Validates intermediate state roots at commitment boundaries
6. Accumulates state diffs across all processed blocks
7. Verifies short header proofs for system transactions (e.g., `setBlockInfo`)
8. Commits output (state roots, state diff, commitment range) to the journal

<details>

<summary><strong>Batch Proof Output Structure</strong></summary>

```
BatchProofCircuitOutputV3:
├── state_roots: Vec<[u8; 32]>                               // State roots: [initial, after_commit_1, ..., final]
│                                                            // Length = num_commitments + 1
├── final_l2_block_hash: [u8; 32]                            // Hash of last L2 block processed
├── state_diff: CumulativeStateDiff                          // Cumulative state changes across batch
├── last_l2_height: u64                                      // Final L2 block height
├── sequencer_commitment_hashes: Vec<[u8; 32]>               // SHA256 hashes of processed commitments
├── sequencer_commitment_index_range: (u32, u32)             // Range (start, end) inclusive
├── last_l1_hash_on_bitcoin_light_client_contract: [u8; 32]  // Latest Bitcoin hash known
├── previous_commitment_index: Option<u32>                   // Index of prior commitment (None if first)
└── previous_commitment_hash: Option<[u8; 32]>               // Hash of prior commitment (None if first)
```

</details>

### Light Client Circuit

The Light Client Circuit verifies Bitcoin consensus and aggregates batch proofs into a single recursive proof. It maintains persistent state via a Jellyfish Merkle Tree, enabling flexible proof chaining even when proofs arrive out of order.

**Circuit Inputs:**

| Field                          | Description                                                               |
| ------------------------------ | ------------------------------------------------------------------------- |
| `da_block_header`              | Bitcoin block header being processed                                      |
| `inclusion_proof`              | Merkle proof of transaction inclusion (wtxids, coinbase tx, merkle proof) |
| `completeness_proof`           | Raw transactions matching relevant wtxid prefixes                         |
| `previous_light_client_proof`  | Prior LCP proof bytes (None for the first proof)                          |
| `witness`                      | JMT state hints for verification                                          |
| `light_client_proof_method_id` | Current circuit version identifier (256 bits)                             |

**Circuit Execution:**

1. Verifies the previous light client proof (if exists) using the method ID and extracts its output
2. Validates the Bitcoin header chain against consensus rules (PoW, difficulty, timestamps, continuity)
3. Verifies transaction inclusion and completeness proofs against the block header
4. Inserts the current Bitcoin block hash into the JMT state
5. Processes relevant transactions from the block:
   * **Chunks**: Stored in JMT by wtxid for later aggregation
   * **Complete proofs**: Decompressed, verified against method ID, state transitions recorded
   * **Aggregates**: Chunks retrieved by wtxid, concatenated, decompressed, verified
   * **Sequencer commitments**: Stored in JMT by index (sender verified)
   * **Method ID upgrades**: 3-of-5 security council signatures verified, chain ID checked, new IDs recorded
6. Chains verified state transitions to advance L2 state root (processes in order by commitment index)
7. Computes and validates JMT state root transition
8. Outputs new LCP proof with updated L2 state, LCP state root, and DA state

<details>

<summary><strong>Light Client Output Structure</strong></summary>

```
LightClientCircuitOutput:
├── l2_state_root: [u8; 32]                 // Current L2 state
├── lcp_state_root: [u8; 32]                // JMT state root
├── light_client_proof_method_id: [u32; 8]  // Circuit version
├── latest_da_state: LatestDaState          // Bitcoin chain state
│   ├── block_hash: [u8; 32]
│   ├── block_height: u64
│   ├── total_work: [u8; 32]
│   ├── current_target_bits: u32
│   ├── epoch_start_time: u32
│   └── prev_11_timestamps: [u32; 11]
├── last_l2_height: u64                     // Highest proven L2 block
└── last_sequencer_commitment_index: u32    // Highest proven commitment
```

</details>

### Bitcoin Verification in the Light Client Circuit

The Light Client Circuit performs Bitcoin header-chain verification, ensuring that proofs are anchored to valid Bitcoin blocks:

**Proof-of-Work Validation:**

* Verifies block hash is below the current difficulty target
* Converts compact bits to full target representation
* Accumulates total work across the header chain

**Difficulty Adjustment:**

* Detects epoch boundaries (every 2016 blocks on mainnet)
* Calculates new target based on actual vs expected time (14 days expected)
* Enforces minimum and maximum target bounds

**Header Continuity:**

* Validates previous block hash linkage
* Ensures consecutive block heights
* Checks timestamp validity against median time past

**SegWit Commitment Verification:**

* Locates witness commitment in coinbase output (script starting with `0x6a24aa21a9ed`)
* Computes wtxid merkle root from all block transactions
* Validates commitment equals `sha256(sha256(wtxid_merkle_root || witness_reserved_value))`
* Ensures witness data integrity for inscribed proofs

### Header Chain Circuit

The Header Chain Circuit verifies Bitcoin block headers against Bitcoin consensus rules and commits an updated chain state. It supports recursive proof chaining: the first proof starts from a genesis `ChainState`, and subsequent proofs verify the previous Header Chain proof before applying more headers.

State is maintained in `ChainState`, which includes the current Bitcoin height, accumulated work, best block hash, difficulty state, previous 11 timestamps, and a Merkle Mountain Range (MMR) of verified block hashes. The MMR lets later circuits prove that a Bitcoin block hash belongs to the verified chain without replaying every header.

**Circuit Inputs:**

| Field           | Description                                                                                                            |
| --------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `method_id`     | Header Chain circuit version identifier. It must match any prior proof's method ID.                                    |
| `prev_proof`    | Either `GenesisBlock(ChainState)` for the first proof or `PrevProof(BlockHeaderCircuitOutput)` for recursive chaining. |
| `block_headers` | Contiguous Bitcoin headers, ordered from the next expected block after the current chain state.                        |

**Circuit Execution:**

1. Reads `HeaderChainCircuitInput` from the zkVM host.
2. Initializes state from either the genesis `ChainState` or a verified previous `BlockHeaderCircuitOutput`.
3. If a previous proof is provided, checks that its `method_id` matches the current input and recursively verifies it with `guest.verify`.
4. Initializes the active target from the current chain state and initializes a local accumulated-work value.
5. Iterates over every header in `block_headers`. For each header:
   * Advances the working block height by one.
   * Selects the target, expected `bits`, and work increment for that height and network.
   * Computes the Bitcoin block hash.
   * Checks chain continuity by requiring `prev_block_hash` to equal the current `best_block_hash`.
   * Validates the header `bits` field against the expected network difficulty.
   * Validates proof of work by checking the block hash against the selected target.
   * Enforces median-time-past by requiring the block timestamp to be greater than the median of the previous 11 timestamps.
   * Appends the verified block hash to the MMR.
   * Updates the working best block hash, accumulated work, timestamp ring buffer, epoch start time when applicable, and the previous-header timestamp used by Testnet4's minimum-difficulty rule.
   * After the last block of a non-regtest difficulty epoch, recomputes and stores the target bits to use for the next epoch.
6. After all provided headers have been processed, writes the final accumulated work back into `chain_state.total_work`.
7. Commits one `BlockHeaderCircuitOutput` for the whole batch.

<details>

<summary><strong>Header Chain Output Structure</strong></summary>

```
BlockHeaderCircuitOutput:
├── method_id: [u32; 8]
├── genesis_state_hash: [u8; 32]
└── chain_state: ChainState
    ├── block_height: u32
    ├── total_work: [u8; 32]
    ├── best_block_hash: [u8; 32]
    ├── current_target_bits: u32
    ├── epoch_start_time: u32
    ├── prev_11_timestamps: [u32; 11]
    └── block_hashes_mmr: MMRGuest
        ├── subroots: Vec<[u8; 32]>
        └── size: u32
```

</details>

### Work-Only Circuit

The Work-Only Circuit verifies a Header Chain proof and extracts only the data needed by watchtowers and the Bridge Circuit: accumulated Bitcoin work and the genesis state hash. It makes watchtower challenges compact by converting the Header Chain proof's 256-bit total work into a 128-bit value that can be included alongside a compressed Groth16 proof.

**Circuit Inputs:**

| Field                         | Description                                    |
| ----------------------------- | ---------------------------------------------- |
| `header_chain_circuit_output` | Public output of a Header Chain Circuit proof. |

**Circuit Execution:**

1. Reads `WorkOnlyCircuitInput` from the zkVM host.
2. Uses the Header Chain method ID baked into the circuit for the compile-time `BITCOIN_NETWORK`.
3. Checks that `header_chain_circuit_output.method_id` matches the expected Header Chain method ID.
4. Verifies the Header Chain proof with `env::verify`.
5. Reads `chain_state.total_work` from the verified Header Chain output and converts it from a 256-bit value to a 128-bit value by keeping the lower 128 bits.
6. Commits `WorkOnlyCircuitOutput` containing the 128-bit work value and the Header Chain `genesis_state_hash`.

<details>

<summary><strong>Work-Only Output Structure</strong></summary>

```
WorkOnlyCircuitOutput:
├── work_u128: [u8; 16]
└── genesis_state_hash: [u8; 32]
```

</details>

### Bridge Circuit

The Bridge Circuit verifies that an operator is entitled to reimburse a withdrawal from the bridge vault during the BitVM challenge flow. It combines the operator's Header Chain proof, watchtower challenge data, payout transaction SPV proof, and a Citrea Light Client proof. The light-client output provides the Citrea L2 state root, which is then used to verify Clementine bridge contract storage proofs for the withdrawal and deposit data.

The circuit's public output is a 32-byte journal hash. That hash commits to the payout block hash, the operator's latest verified Bitcoin block hash, which watchtowers sent valid challenges, and a deposit constant derived from deposit-specific bridge data.

**Circuit Inputs:**

| Field                                      | Description                                                                                                                                                                     |
| ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `kickoff_tx`                               | Kickoff transaction for the reimbursement flow; it contains the reimbursement connector and connector outputs used by challenge, Assert, and Disprove paths.                    |
| `all_tweaked_watchtower_pubkeys`           | Registered tweaked x-only public keys for watchtower challenge outputs.                                                                                                         |
| `watchtower_inputs`                        | Watchtower challenge transactions, prevouts, witnesses, input indexes, watchtower indexes, and optional annex digests.                                                          |
| `hcp`                                      | Operator's `BlockHeaderCircuitOutput` from the Header Chain Circuit.                                                                                                            |
| `payout_spv`                               | SPV proof for the payout transaction, including the payout transaction, block inclusion proof, block header, and MMR inclusion proof.                                           |
| `payout_input_index`                       | Input index in the payout transaction that should spend the user's verified withdrawal outpoint.                                                                                |
| `lcp`                                      | Citrea light-client proof journal bytes. The Bridge Circuit verifies the journal against the configured light-client image ID, then deserializes it as the light-client output. |
| `sp`                                       | Storage proof input for Clementine bridge contract data on Citrea: withdrawal UTXO txid, withdrawal vout, and deposit move txid.                                                |
| `watchtower_challenge_connector_start_idx` | Kickoff output index where watchtower challenge connector outputs begin.                                                                                                        |

**Circuit Execution:**

1. Reads `BridgeCircuitInput` from the zkVM host.
2. Checks that `hcp.method_id` matches the expected Header Chain method ID for the compile-time `BITCOIN_NETWORK`.
3. Verifies the operator's Header Chain proof with `guest.verify`.
4. Verifies each watchtower challenge input:
   * The challenge input must spend the kickoff output at `watchtower_challenge_connector_start_idx + watchtower_idx * 2`.
   * The spent kickoff output must be P2TR.
   * The output x-only key must match the registered watchtower key.
   * The Taproot key-path Schnorr signature must verify under BIP341 sighash rules.
5. Records a 160-bit bitmap of watchtowers that sent valid challenge transactions.
6. Parses each valid watchtower challenge commitment in one of two forms:
   * A first `OP_RETURN` output containing 128 bytes of compressed Groth16 proof plus 16 bytes of total work.
   * First and second P2TR outputs containing the first 64 proof bytes, followed by a third `OP_RETURN` output containing the remaining 64 proof bytes plus 16 bytes of total work.
7. Sorts valid watchtower commitments by claimed total work in descending order.
8. Verifies compressed Groth16 Work-Only proofs until the first valid proof is found. This produces `max_total_work`.
9. Compares the operator's Header Chain total work against `max_total_work`; the operator must have at least as much verified work as the strongest valid watchtower challenge.
10. Verifies the payout SPV proof:
    * Computes the payout transaction mid-state txid.
    * Reconstructs the Bitcoin Merkle root using the mid-state inclusion proof.
    * Checks the reconstructed Merkle root against the `merkle_root` field of `payout_spv.block_header`.
    * Checks the payout block hash against the Header Chain MMR inclusion proof.
11. Verifies the Citrea light-client journal against the network light-client image ID.
12. Deserializes the light-client output and checks its method ID against the configured image ID.
13. Requires the light-client latest DA block hash to equal the payout SPV block hash.
14. Verifies Clementine contract storage proofs against the light-client L2 state root:
    * withdrawal outpoint txid,
    * withdrawal vout,
    * deposit move txid.
15. Requires the payout transaction input at `payout_input_index` to spend the verified withdrawal outpoint and vout.
16. Reads the operator x-only public key from the first `OP_RETURN` output of the payout transaction.
17. Computes `deposit_constant` from the operator key, watchtower keys, watchtower connector start index, move txid, kickoff round outpoint, and Header Chain genesis state hash.
18. Truncates the payout block hash and latest Header Chain block hash to their final 20 bytes.
19. Computes the final journal hash:
    * `inner = blake3(payout_tx_blockhash || latest_blockhash || challenge_sending_watchtowers)`
    * `journal_hash = blake3(deposit_constant || inner)`
20. Commits the 32-byte journal hash.

<details>

<summary><strong>Bridge Circuit Committed Output</strong></summary>

```
Bridge Circuit journal:
└── journal_hash: [u8; 32]
```

</details>

### Circuit Relations

<figure><img src="/files/C5SPgn4lelvZcFpMM3fn" alt="Diagram showing the relationships between Citrea and Clementine circuits"><figcaption><p>Circuit Relations</p></figcaption></figure>

## ZKVM and Proof Generation

***

### RISC-0 zkVM

Citrea uses the **RISC-0 zkVM** as its primary proving backend. RISC-0 executes RISC-V programs and generates STARKs that are wrapped in Groth16 SNARKs for succinct verification by nodes.

**Guest Programs (ELF Binaries):**

* `batch-proof-bitcoin`: Batch proof circuit for Bitcoin DA
* `light-client-proof-bitcoin`: Light client circuit for Bitcoin DA
* `header-chain-guest`: Clementine Header Chain circuit
* `work-only-guest`: Clementine Work-Only circuit
* `bridge-circuit-guest`: Clementine Bridge Circuit

**Proving Modes:**

* `Skip`: Skip proving entirely
* `Execute`: Execute the zkVM without generating proofs (testing/development)
* `ProveWithSampling`: The prover runs the rollup verification logic in the zkVM and produces a zk proof
* `ProveWithSamplingWithFakeProofs(N)`: The prover runs the rollup verification logic in the zkVM and produces a zk/fake proof. If proof\_sampling\_number is 0, then we always produce real proofs Otherwise we prove with a probability of 1/proof\_sampling\_number

**Proof Pipeline:**

<figure><img src="/files/Ttcy6ysJ7QPQSRhgiHMG" alt=""><figcaption><p>Proof Pipeline</p></figcaption></figure>

### Code Commitments (Method IDs)

Each circuit version is identified by a **method ID** — a 256-bit hash derived from the compiled ELF binary. Method IDs serve as code commitments, ensuring proofs were generated with the expected circuit logic.

```
Method ID: [u32; 8] (256 bits)
Computed from: risc0_zkvm::compute_image_id(elf_binary)
```

**Method ID Security:**

* Initial method IDs hardcoded per network at genesis
* Upgrades require 3-of-5 security council signatures (ECDSA over EIP-191 prefixed, keccak256-hashed message)
* Activation L2 height must exceed previous method ID's activation height
* Chain ID embedded in upgrade body prevents cross-network replay attacks
* Method IDs stored as `Vec<(activation_l2_height, [u32; 8])>` to support versioned circuits

{% hint style="warning" %}
Method ID upgrades are protected by the security council multisig. This prevents unauthorized circuit changes while enabling protocol upgrades when needed.
{% endhint %}

## Commitment Partitioning

***

Before proving, the Batch Prover partitions pending commitments into provable chunks. This balances proof generation efficiency with Bitcoin transaction size constraints.

**Pre-Partition Filtering:**

Before partitioning, the prover filters commitments:

* **Unsynced filter:** Excludes commitments whose L2 blocks haven't been synced yet
* **Index gap filter:** Excludes commitments that lack a known previous commitment (ensures sequential proving)

**Partition Boundary Conditions:**

| Condition        | Description                                                                               |
| ---------------- | ----------------------------------------------------------------------------------------- |
| Spec Change      | Fork/specification change between commitments triggers a new partition                    |
| State Diff Size  | Compressed state diff exceeds `MAX_TX_BODY_SIZE` (397,000 bytes) triggers a new partition |
| Commitment Count | Exceeds `max_commitments_per_proof` limit triggers a new partition                        |
| One-by-One Mode  | Each commitment becomes its own partition (optional mode)                                 |

**Partitioning Flow:**

<figure><img src="/files/A3HulduTAfIXEOr58a9w" alt=""><figcaption><p>Partitioning Flow</p></figcaption></figure>

## Proof Formats on Bitcoin

***

Proofs are inscribed on Bitcoin using SegWit witness data. Due to Bitcoin's transaction size limits, large proofs are split into chunks and later aggregated.

### Transaction Types

| Type                  | Description                                                      |
| --------------------- | ---------------------------------------------------------------- |
| `Complete`            | Full proof fitting in a single transaction                       |
| `Aggregate`           | References chunk txids and wtxids for reconstruction             |
| `Chunk`               | Partial proof segment (stored by wtxid in LCP JMT state)         |
| `BatchProofMethodId`  | Circuit upgrade with 3-of-5 security council signatures          |
| `SequencerCommitment` | L2 block range commitment (merkle root, index, end block number) |

### Aggregation Mechanism

When a proof exceeds Citrea's `MAX_TX_BODY_SIZE` (397,000 bytes):

1. **Compression:** Proof is serialized and compressed
2. **Chunking:** Compressed data split into segments fitting within `MAX_TX_BODY_SIZE`
3. **Inscription:** Each chunk inscribed as `DataOnDa::Chunk` in a separate transaction
4. **Aggregation:** Parent transaction (`DataOnDa::Aggregate`) lists chunk wtxids for retrieval
5. **Reconstruction:** Light Client retrieves chunks by wtxid from JMT state, concatenates them
6. **Decompression:** Combined chunks decompressed to original proof
7. **Verification:** Proof verified against the batch proof method ID for the relevant L2 height

{% hint style="info" %}
The chunking mechanism keeps individual transactions under `MAX_TX_BODY_SIZE` (397,000 bytes) while enabling arbitrarily large proofs. Chunks are stored in the Light Client's JMT state indexed by wtxid until the aggregate transaction arrives.
{% endhint %}

## Verification Pipeline

***

### On-Chain Flow (Bitcoin)

<figure><img src="/files/qMO5snB9Aevu4ckSuiNk" alt=""><figcaption><p>On-Chain Verification Flow</p></figcaption></figure>

### Full Node Verification

Full nodes verify proofs as they arrive on Bitcoin:

1. **Fetch:** Retrieve proof transaction from Bitcoin block
2. **Decompress:** Extract and decompress proof blob
3. **Verify SNARK:** Check Groth16 proof against method ID
4. **Validate Output:** Confirm the L1 hash is known, commitment hashes match, and the pre-state root matches ledger state
5. **Update State:** Apply state diff and advance proven tip

### Light Client State Chaining

The Light Client uses state root chaining to connect batch proofs:

```rust
// State chaining logic (from light-client-prover/src/circuit/mod.rs)
while let Some(sequencer_commitment_info) =
    VerifiedStateTransitionForSequencerCommitmentIndexAccessor::<S>::get(
        last_sequencer_commitment_index + 1,
        &mut working_set,
    )
{
    if sequencer_commitment_info.initial_state_root == last_l2_state_root {
        // Chain this proof to advance L2 state
        last_l2_state_root = sequencer_commitment_info.final_state_root;
        last_l2_height = sequencer_commitment_info.last_l2_height;
        last_sequencer_commitment_index += 1;
    } else {
        // State root mismatch - should be unreachable if batch proofs are valid
        unreachable!("Commitment with the next index having an unexpected state root");
    }
}
```

**Key Properties:**

* Proofs can arrive out of order on Bitcoin
* Proof ranges may overlap. A later proof can cover already-verified commitments while extending with newer ones
* JMT stores verified state transitions indexed by commitment number
* State root continuity ensures chain integrity
* Chaining advances automatically when gaps are filled

## Settlement via Clementine

***

The Light Client Prover's output enables trust-minimized settlement through Clementine:

1. **LCP Proof Generation:** Light Client produces recursive proof of current state
2. **BitVM Verification:** Bridge operators can be challenged using LCP proof
3. **Dispute Resolution:** Invalid claims disproven via proof verification in BitVM
4. **Settlement:** Valid withdrawals proceed once verification completes

{% hint style="success" %}
The LCP combines Bitcoin consensus verification with batch proof aggregation into a single artifact. This enables Clementine to verify rollup state with Bitcoin-level security guarantees, without trusting the sequencer or any bridge operator.
{% endhint %}

## Security Considerations

***

### Proof Soundness

* **Computational Soundness:** Groth16 proofs are computationally sound under standard cryptographic assumptions
* **Code Commitment:** Method IDs bind proofs to specific circuit logic
* **Security Council:** 3-of-5 multisig protects method ID upgrades

### Liveness Guarantees

* **Proof Sampling:** `ProveWithSamplingWithFakeProofs` mode enables testing with occasional real proofs based on configurable probability
* **Recovery Mode:** Interrupted proving sessions tracked in ledger DB and recovered on restart
* **Parallel Proving:** Multiple proofs generated concurrently via the parallel prover service
* **Partition Flexibility:** Large commitment ranges automatically split to fit transaction limits

### Bitcoin Anchoring

* **Immutable Ordering:** After finality depth, sequencer commitments are treated as fixed; before that, L1 reorgs can reorder data
* **Data Availability:** State diffs inscribed alongside proofs enable state reconstruction
* **Fork Resistance:** Deep Bitcoin reorg required to reverse proven batches

## Summary

***

Citrea's proof system achieves trust-minimized verification through a carefully designed architecture:

| Component                                                                                               | Role                                                             |
| ------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------- |
| [Batch Prover](/essentials/architecture-and-transaction-lifecycle.md#batch-prover)                      | Proves L2 state transitions for sequencer commitments            |
| [Light Client Prover](/essentials/architecture-and-transaction-lifecycle.md#light-client-prover)        | Aggregates proofs and verifies Bitcoin header-chain rules        |
| [Batch Proof Circuit](https://github.com/chainwayxyz/citrea/blob/nightly/docs/batch-proof-circuit.md)   | Verifies correct execution of L2 blocks                          |
| [Light Client Circuit](https://github.com/chainwayxyz/citrea/blob/nightly/docs/light-client-circuit.md) | Recursive verification with Bitcoin header chain                 |
| [RISC-0 zkVM](https://www.risczero.com/)                                                                | Executes circuits and generates Groth16 proofs                   |
| [Bitcoin DA](https://github.com/chainwayxyz/citrea/blob/nightly/docs/da.md)                             | Data availability layer enabling ZK verification of rollup state |
| [Clementine](/essentials/clementine-trust-minimized-bitcoin-bridge.md)                                  | Consumes LCP proofs for trust-minimized settlement               |

The two-tier architecture separates concerns: Batch Proofs handle high-throughput L2 verification, while Light Client Proofs provide succinct recursive verification for external consumers. Together, they enable Citrea to inherit Bitcoin's security while maintaining EVM compatibility and scalability.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.citrea.xyz/advanced/proofs.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
