Proof Aggregation Service

Proof Aggregation Service L2 integration example

This guide demonstrates how to build a dummy L2 application that integrates with Aligned's Proof Aggregation Service. The L2 does not post state diffs or any data to Ethereum, only commitments. The prover has to prove that:

  1. The state database used in the proof must match the commitment stored in the on-chain contract. This is validated by computing the commitment of the received data in the zkvm and then exposing it as a public input.

  2. The users performing the transfers have enough balance

After processing the transfers, the vm computes the commitment of the post state, which is exposed as a public input. The smart contract then updates the on-chain state root. If a user later wants to retrieve their state, the application must return it along with a Merkle proof, so they can verify it against the contract’s state root.

Notice a lot of checks that a real L2 should have are missing, since the focus are on the integration of Aligned.

The code can be viewed at examples/l2.

L2 workflow overview

This Layer 2 (L2) system operates in two main steps:

  • Off-chain execution and proof generation + verification with Aligned's Proof Verification Layer.

  • On-chain state update via proof verification with Aligned's Proof Aggregation Service.

In Step 1, we execute user transfers and generate a zkVM-based proof of the state transition, which is submitted to Aligned’s verification layer.

In Step 2, once the proof is aggregated (every 24 hours), it is verified on-chain to update the global state.

Step 1: Off-Chain Execution + Proof Generation

  1. Initialize State: Load or initialize the current system state.

  2. Load Transfers: Retrieve or receive the user transfer data for this batch.

  3. Execute in zkVM: Run the zkVM with the loaded transfers to compute the new state.

  4. Generate Proof: Produce a zk-proof for the executed state transition committing the commitment of the received + the commitment of the new state.

  5. Submit Proof to Aligned: Send the proof to Aligned Verification Layer

  6. Save the binary proof locally for later on-chain verification.

Step 2: Proof Verification + On-Chain State Update

  1. Load the proof binary: Retrieve the saved proof binary from disk.

  2. Update On-Chain State: Call the smart contract method updateStateTransition, which:

    • Internally calls verifyProofInclusion on AlignedProofAggregationService which:

      1. Computes the proof commitment from the proof public_inputs and program_id.

      2. Uses the Merkle proof to reconstruct and validate the Merkle root.

      3. Confirms whether there exists and aggregated proof with that root.

    • Validates that the initial_state_root proof public input matches the on-chain state.

    • If valid, updates the on-chain state root to the post_state_root.

Usage

Requirements

  1. Rustarrow-up-right: we have tested in v1.85.1

  2. Dockerarrow-up-right: for SP1 prover

Submodules of the repo should be imported by running on the root folder:

You can run the example on:

Setup Holeksy

1. Create keystore

You can use cast to create a local keystore. If you already have one you can skip this step.

Then you can import your created keystore using:

Then you need to obtain some funds to pay for gas and proof verification. You can do this by using this faucetarrow-up-right

This same wallet is used to send the proof via aligned, so you'll also need to fund it on aligned. Follow this guidearrow-up-right.

2. Deploy the contract

  • Generate the base .env:

  • Get the program ID of the l2 program you are proving:

  • Complete the following fields contracts/.env file:

    • PROGRAM_ID= (use the previously generated ID, you can re check with a cat ./crates/l2/programs_ids.json )

    • PRIVATE_KEY: the private key used for the deployment, it needs to have some funds to pay for the deployment.

    • OWNER_ADDRESS: you have to provide the address of the wallet created in step 1..

  • Deploy the contracts with:

Save the output contract address.

3. Setup the L2

  • Generate the base .env run:

  • Complete the missing fields on the .env:

    • PRIVATE_KEY_STORE_PATH: The path to the keystore created in 1..

    • PRIVATE_KEY_STORE_PASSWORD: The password of the keystore crated in step 1..

    • STATE_TRANSITION_CONTRACT_ADDRESS: The address of the contract deployed in step 2.

Finally run the l2.

Setup Localnet

You can also run this example on a local devnet. To get started, navigate to the root of the Aligned repository

  • Start Ethereum package and the Batcher

  • Navigate back to the example directory:

  • Generate the .env files for the contracts and L2:

  • Generate the program ID of the program that is going to be proven:

  • Set the generated program ID on contracts/.env.

  • Deploy the contract

  • Set the output address of the contract in .env

Running the L2

  • Set up the initial State

  • Perform the L2 account updates and prove them in the zkvm:

  • Wait 24 hs for the proof to be aggregated, or if running locally, run the aggregator with either:

    or with cuda: make start_proof_aggregator_gpu_ethereum_package AGGREGATOR=sp1

  • Update state transition on chain:

You should see a transaction receipt in the console and after the stateRoot updated on-chain.

Last updated