From 8a3a6448c974d09c645f3b74d4c9ff9d2dd27249 Mon Sep 17 00:00:00 2001 From: Marcos Nicolau <76252340+MarcosNicolau@users.noreply.github.com> Date: Fri, 13 Jun 2025 11:45:26 -0300 Subject: [PATCH 01/10] docs: aggregation mode (#1964) Co-authored-by: Julian Arce <52429267+JuArce@users.noreply.github.com> Co-authored-by: Mauro Toscano <12560266+MauroToscano@users.noreply.github.com> --- aggregation_mode/src/backend/mod.rs | 26 +++ .../agg_mode_components/1_deep_dive.md | 91 ++++++++ docs/3_guides/3.1_aggregation_mode.md | 208 ++++++++++++++++++ docs/SUMMARY.md | 2 + 4 files changed, 327 insertions(+) create mode 100644 docs/2_architecture/agg_mode_components/1_deep_dive.md create mode 100644 docs/3_guides/3.1_aggregation_mode.md diff --git a/aggregation_mode/src/backend/mod.rs b/aggregation_mode/src/backend/mod.rs index f9abf49d7a..42caf401b8 100644 --- a/aggregation_mode/src/backend/mod.rs +++ b/aggregation_mode/src/backend/mod.rs @@ -187,6 +187,32 @@ impl ProofAggregator { .map_err(AggregatedProofSubmissionError::ReceiptError) } + /// ### Blob capacity + /// + /// As dictated in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844), each blob can hold: + /// + /// - `FIELD_ELEMENTS_PER_BLOB = 4096` + /// - `BYTES_PER_FIELD_ELEMENT = 32` + /// + /// This gives a total theoretical capacity of: + /// + /// `FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT = 4096 * 32 = 131072 bytes` + /// + /// However, this full capacity isn't usable due to the encoding of KZG commitments to elliptic curve points. + /// Specifically: + /// + /// - Ethereum uses the BLS12-381 curve, whose scalar field modulus is slightly less than `2^256` + /// (closer to `2^255`). + /// - Therefore, 32-byte field elements can't represent all 256-bit values. + /// - To ensure values are within the field modulus, we **pad with a leading `0x00` byte**, + /// effectively capping values below the modulus. + /// - This reduces the usable payload to **31 bytes per field element**. + /// + /// So, the _actual usable capacity_ per blob is: + /// + /// `4096 * 31 = 126976 bytes` + /// + /// Meaning that we can send as much as 126976 / 32 = 3968 proofs per blob async fn construct_blob( &self, leaves: Vec<[u8; 32]>, diff --git a/docs/2_architecture/agg_mode_components/1_deep_dive.md b/docs/2_architecture/agg_mode_components/1_deep_dive.md new file mode 100644 index 0000000000..8ef241deae --- /dev/null +++ b/docs/2_architecture/agg_mode_components/1_deep_dive.md @@ -0,0 +1,91 @@ +# Aggregation Mode Deep Dive + +The Aggregation Mode runs **once every 24 hours** and performs the following steps: + +1. **Fetch Proofs from the Verification Layer** + Queries `NewBatchV3` events from the `AlignedLayerServiceManager` and downloads the batches from `S3`, starting from the last processed block of the previous run. + +2. **Filter Proofs** + Filters proofs by supported verifiers and proof types. + +3. **Aggregate Proofs in the zkVM** + Selected proofs are aggregated using a zkVM. + +4. **Construct the Blob** + A blob is built containing the [commitments](#proof-commitment) of the aggregated proofs. + +5. **Send Aggregated Proof** + The final aggregated proof and its blob are sent to the `AlignedProofAggregationService` contract for verification. + +> [Note] +> Currently if you want your proof to be verified in the `AggregationMode` you need to submit it via the `VerificationLayer`. In the future, users will be able to decide if they want to use any of the modes in particular or both of them + +## Aggregators and Supported Proof Types + +Two separate aggregators are run every 24 hours: + +- **Risc0**: Aggregates proofs of types `Composite` and `Succinct`. +- **SP1**: Aggregates proofs of type `Compressed`. + +## Proof Commitment + +The **proof commitment** is a hash that uniquely identifies a proof. It is defined as the keccak of the proof public inputs + program ID: + +- **For SP1**: + The commitment is computed as: `keccak(proof_public_inputs_bytes || vk_hash_bytes)` +- **For Risc0**: + The commitment is computed as: `keccack(receipt_public_inputs_bytes || image_id_bytes)` + +## Multilayer Aggregation + +To scale aggregation without exhausting zkVM memory, aggregation is split in two programs: + +1. **User Proof Aggregator** + Processes chunks of `n` user proofs. Each run creates an aggregated proof that commits to a Merkle root of the user proofs inputs. This step is repeated for as many chunks as needed. Usually each chunks contains `256` proofs but it can be lowered based on the machine specs. + +2. **Chunk Aggregator** + Aggregates all chunk-level proofs into a single final proof. It receives: + + - The chunked proofs + - The original [proofs commitments](#proof-commitment) included each chunk received + + During verification, it checks that each chunk’s committed Merkle root matches the reconstructed root to ensure input correctness. The final Merkle root, representing all user [proofs commitments](#proof-commitment), is then committed as a public input. + +## Verification + +Once aggregated, the proof is sent to Ethereum and verified via the `AlignedProofAggregationService` contract. Depending on the proving system, the contract invokes: + +- `verifySP1` for SP1 proofs +- `verifyRisc0` for Risc0 proofs + +Each function receives: + +- The public inputs +- The proof binary + +The program ID is hardcoded in the contract to ensure only trusted aggregation programs (`chunk_aggregator`) are accepted. + +If verification succeeds, the new proof is added to the `aggregatedProofs` map in contract storage. + +### Proof Inclusion Verification + +To verify a user’s proof on-chain, the following must be provided: + +- The proof bytes +- The proof public inputs +- The program ID +- A Merkle proof + +The Merkle root is computed and checked for existence in the contract using the `verifyProofInclusion` function of the `ProofAggregationServiceContract`, which: + +1. Computes the merkle root +2. Returns `true` or `false` depending if there exists an `aggregatedProof` with the computed root. + +## Data Availability + +When submitting the aggregated proof to Ethereum, we include a **blob** that contains the [commitments](#proof-commitment) of all the individual proofs that were aggregated. This blob serves two main purposes: + +- It makes the [proof commitments](#proof-commitment) publicly available for **18 days**. +- It allows users to: + - Inspect which proofs were aggregated + - Get a Merkle proof to verify that their proof is included in the aggregated proof diff --git a/docs/3_guides/3.1_aggregation_mode.md b/docs/3_guides/3.1_aggregation_mode.md new file mode 100644 index 0000000000..7421145600 --- /dev/null +++ b/docs/3_guides/3.1_aggregation_mode.md @@ -0,0 +1,208 @@ +## Aggregation Mode L2 integration example + +This guide demonstrates how to build a dummy L2 application that integrates with Aligned Aggregation Mode. 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 Verification Layer (a.k.a Fast Mode). +- On-chain state update via proof verification with Aligned Aggregation Mode. + +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 + +7. Load the proof binary: Retrieve the saved proof binary from disk. +8. 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. [Rust](https://www.rust-lang.org/tools/install): we have tested in v1.85.1 +2. [Foundry](https://book.getfoundry.sh/getting-started/installation) +3. [Docker](https://docs.docker.com/engine/): for SP1 prover + +Submodules of the repo should be imported by running on the root folder: + +```shell +make submodules +``` + +You can run the example on: + +- [Holesky](#setup-holeksy) +- [Localnet](#setup-localnet) + +## Setup Holeksy + +### 1. Create keystore + +You can use cast to create a local keystore. If you already have one you can skip this step. + +```bash +cast wallet new-mnemonic +``` + +Then you can import your created keystore using: + +```bash +cast wallet import --interactive +``` + +Then you need to obtain some funds to pay for gas and proof verification. +You can do this by using this [faucet](https://cloud.google.com/application/web3/faucet/ethereum/holesky) + +_This same wallet is used to send the proof via aligned, so you'll also need to fund it on aligned. Follow this [guide](https://docs.alignedlayer.com/guides/0_submitting_proofs#id-2.-send-funds-to-aligned)._ + +### 2. Deploy the contract + +- Generate the base `.env`: + +```shell +make gen_env_contract_holesky +``` + +- Get the program ID of the l2 program you are proving: + +```shell +make generate_program_id +``` + +- 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: + +```shell +make deploy_contract +``` + +_Save the output contract address._ + +### 3. Setup the L2 + +- Generate the base `.env` run: + +```shell +make gen_env_l2_holesky +``` + +- 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](#running-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 + +```shell +# This will start the local net +make ethereum_package_start +# Start the batcher +make batcher_start_ethereum_package +``` + +- Navigate back to the example directory: + +```shell +cd examples/l2 +``` + +- Generate the `.env` files for the contracts and L2: + +```shell +make gen_env_contract_devnet +make gen_env_l2_devnet +``` + +- Generate a pre funded wallet (or create one as specified [previously here](#1-create-keystore)): + +```shell +# This will generate the keystore and fund it on aligned +make gen_devnet_owner_wallet +``` + +- Generate the program ID of the program that is going to be proven: + +```shell +make generate_program_id +``` + +- Set the generated program ID on `contracts/.env`. + +- Deploy the contract + +```shell +make deploy_contract +``` + +- Set the output address of the contract in `.env` + +- [run the l2](#running-the-l2) + +## Running the L2 + +- Set up the initial State + +```shell +make init_state +``` + +- Perform the L2 account updates and prove them in the zkvm: + +```shell +make prove_state_transition +``` + +- Wait 24 hs for the proof to be aggregated, or if running locally, run the aggregator with either: + + ```make start_proof_aggregator_ethereum_package AGGREGATOR=sp1``` + + or with cuda: + `make start_proof_aggregator_gpu_ethereum_package AGGREGATOR=sp1` + +- Update state transition on chain: + +```shell +make update_state_on_chain +``` + +You should see a transaction receipt in the console and after the stateRoot updated on-chain. diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index ef49a049aa..5e03f17176 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -20,6 +20,7 @@ * [Aggregator](./2_architecture/components/5_aggregator.md) * [Explorer](./2_architecture/components/6_explorer.md) * [Aggregation mode](2_architecture/2_aggregation_mode.md) + * [Deep Dive](2_architecture/agg_mode_components/1_deep_dive.md) ## Guides @@ -27,6 +28,7 @@ * [Build your first Aligned Application](3_guides/2_build_your_first_aligned_application.md) * [Modify ZkQuiz Questions](3_guides/2.2_modify_zkquiz_questions.md) * [Validating public input](3_guides/3_validating_public_input.md) +* [Aggregation Mode](3_guides/3.1_aggregation_mode.md) * [SDK Intro](3_guides/1_SDK_how_to.md) * [SDK API Reference](3_guides/1.2_SDK_api_reference.md) * [Generating proofs for Aligned](3_guides/4_generating_proofs.md) From 9ae28030135cd1e7f99b32ed3fb959cfc3a4c6ae Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Tue, 17 Jun 2025 16:46:32 -0300 Subject: [PATCH 02/10] Change links for downloading aligned on the try aligned section --- docs/1_introduction/1_try_aligned.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/1_introduction/1_try_aligned.md b/docs/1_introduction/1_try_aligned.md index 717f8ad6f6..cca28b9324 100644 --- a/docs/1_introduction/1_try_aligned.md +++ b/docs/1_introduction/1_try_aligned.md @@ -14,7 +14,7 @@ We will download a previously generated SP1 proof, send it to Aligned for verifi 1. Download and install Aligned to send proofs in the testnet: ```bash -curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/main/batcher/aligned/install_aligned.sh | bash +curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/testnet/batcher/aligned/install_aligned.sh | bash ``` 2. Run the ```source``` command that should appear in the shell @@ -22,7 +22,7 @@ curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/main/batche 3. Download the example SP1 proof file together with the ELF file of the proved program using: ```bash -curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/main/batcher/aligned/get_proof_test_files.sh | bash +curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/testnet/batcher/aligned/get_proof_test_files.sh | bash ``` 4. Send the proof to be verified in Aligned with From d0b0560ecd802dd797105213653f634c6fc47e06 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Tue, 17 Jun 2025 16:52:06 -0300 Subject: [PATCH 03/10] Add reference to the Why Ethereum article on the respective FAQ question --- docs/1_introduction/3_faq.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/1_introduction/3_faq.md b/docs/1_introduction/3_faq.md index ef95245b47..8b03d0f383 100644 --- a/docs/1_introduction/3_faq.md +++ b/docs/1_introduction/3_faq.md @@ -31,6 +31,8 @@ The batcher cannot transfer user's funds to other accounts, only spend them to c Ethereum is the most decentralized and most significant source of liquidity in the crypto ecosystem. We believe it is the most ambitious and long-term project on the internet. Aligned is being built to help Ethereum achieve its highest potential, and we believe this is only possible through validity/zero-knowledge proofs. +For further reading on this subject, you can refer to [this aligned blog article](https://blog.alignedlayer.com/why-ethereum/), which explains why we chose Ethereum. + ### What is Aligned's throughput? Aligned runs the verifier’s code natively. Verification time depends on the proof system, program run, and public input. Generally, most verifiers can be run on the order of milliseconds on consumer-grade hardware. We can optimize the code for speed and leverage parallelization by running it natively. Our current testnet can verify more than 4000 proofs per second. From d9abacf33bfff1bc6ce88458d18826c037f53ffc Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Tue, 17 Jun 2025 16:57:02 -0300 Subject: [PATCH 04/10] Add link to the section that explains how to send proofs without a batcher in FAQ --- docs/1_introduction/3_faq.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/1_introduction/3_faq.md b/docs/1_introduction/3_faq.md index 8b03d0f383..37d49840b2 100644 --- a/docs/1_introduction/3_faq.md +++ b/docs/1_introduction/3_faq.md @@ -25,6 +25,8 @@ The batcher cannot transfer user's funds to other accounts, only spend them to c ### How do I send proofs without a batcher? +You can see the steps to do it in [this markdown file](https://github.com/yetanotherco/aligned_layer/blob/8a3a6448c974d09c645f3b74d4c9ff9d2dd27249/docs/3_guides/8_submitting_batch_without_batcher.md). + ### How do I run my own batcher? ### Why build Aligned on top of Ethereum? From a8d5f59135b28eed16c775d844315430749d21c3 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Tue, 17 Jun 2025 17:04:47 -0300 Subject: [PATCH 05/10] Add parameter to the createNewTask method of the ServiceManagerContract in docs --- docs/2_architecture/components/3_service_manager_contract.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/2_architecture/components/3_service_manager_contract.md b/docs/2_architecture/components/3_service_manager_contract.md index bc80239dd5..b016c99c5a 100644 --- a/docs/2_architecture/components/3_service_manager_contract.md +++ b/docs/2_architecture/components/3_service_manager_contract.md @@ -19,7 +19,8 @@ Besides the base [EigenLayer middleware contracts](https://github.com/Layr-Labs/ ```solidity function createNewTask( bytes32 batchMerkleRoot, - string calldata batchDataPointer + string calldata batchDataPointer, + uint256 respondToTaskFeeLimit ) external payable ``` @@ -27,6 +28,7 @@ This method is called to create a new batch verification task that will broadcas * `batchMerkleRoot` is a 256 bit hash corresponding to the Merkle Root of the proofs batch to be verified by operators. * `batchDataPointer` is a string representing a link to some specific data storage location. This is used by operators to download the entire batch of proofs. +* `respondToTaskFeeLimit` are the funds required for the operator to respond to the task #### Respond to task From 8aad04d0b55d1772a5e904d6c75cf37b44996b19 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Tue, 17 Jun 2025 17:05:09 -0300 Subject: [PATCH 06/10] Add parameter to the respondToTask method of the ServiceManagerContract in docs --- docs/2_architecture/components/3_service_manager_contract.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/2_architecture/components/3_service_manager_contract.md b/docs/2_architecture/components/3_service_manager_contract.md index b016c99c5a..ef4b74e77f 100644 --- a/docs/2_architecture/components/3_service_manager_contract.md +++ b/docs/2_architecture/components/3_service_manager_contract.md @@ -35,6 +35,7 @@ This method is called to create a new batch verification task that will broadcas ```solidity function respondToTask( bytes32 batchMerkleRoot, + address senderAddress, NonSignerStakesAndSignature memory nonSignerStakesAndSignature ) external ``` @@ -43,6 +44,7 @@ This method is used by the Aggregator once the quorum for a particular task has * `batchMerkleRoot` is a 256 bit hash representing the Merkle Root of the batch that has been verified and signed by operators. * `nonSignerStakesAndSignature` is a struct provided by EigenLayer middleware with information about operators' signatures, stakes and quorum for the given task. +* `senderAddress` is the address of the batcher that created the task being responded to. ### Verify batch inclusion From 69862f39b4e63991e7ec654ebf2275b336fb819a Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Tue, 17 Jun 2025 17:07:20 -0300 Subject: [PATCH 07/10] Add an equal for config file flag set in registration command --- docs/3_guides/6_setup_aligned.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/3_guides/6_setup_aligned.md b/docs/3_guides/6_setup_aligned.md index 35b617357f..89184b8ae5 100644 --- a/docs/3_guides/6_setup_aligned.md +++ b/docs/3_guides/6_setup_aligned.md @@ -105,7 +105,7 @@ Different configs for operators can be found in `config-files/config-operator`. If you wish to only register an operator you can run: ```bash -make operator_full_registration CONFIG_FILE +make operator_full_registration CONFIG_FILE= ``` and to start it once it has been registered: From 23bf95f21142b289375aa09df84e89d272860081 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Wed, 18 Jun 2025 10:54:23 -0300 Subject: [PATCH 08/10] Revert "docs: aggregation mode (#1964)" This reverts commit 8a3a6448c974d09c645f3b74d4c9ff9d2dd27249. --- aggregation_mode/src/backend/mod.rs | 26 --- .../agg_mode_components/1_deep_dive.md | 91 -------- docs/3_guides/3.1_aggregation_mode.md | 208 ------------------ docs/SUMMARY.md | 2 - 4 files changed, 327 deletions(-) delete mode 100644 docs/2_architecture/agg_mode_components/1_deep_dive.md delete mode 100644 docs/3_guides/3.1_aggregation_mode.md diff --git a/aggregation_mode/src/backend/mod.rs b/aggregation_mode/src/backend/mod.rs index 42caf401b8..f9abf49d7a 100644 --- a/aggregation_mode/src/backend/mod.rs +++ b/aggregation_mode/src/backend/mod.rs @@ -187,32 +187,6 @@ impl ProofAggregator { .map_err(AggregatedProofSubmissionError::ReceiptError) } - /// ### Blob capacity - /// - /// As dictated in [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844), each blob can hold: - /// - /// - `FIELD_ELEMENTS_PER_BLOB = 4096` - /// - `BYTES_PER_FIELD_ELEMENT = 32` - /// - /// This gives a total theoretical capacity of: - /// - /// `FIELD_ELEMENTS_PER_BLOB * BYTES_PER_FIELD_ELEMENT = 4096 * 32 = 131072 bytes` - /// - /// However, this full capacity isn't usable due to the encoding of KZG commitments to elliptic curve points. - /// Specifically: - /// - /// - Ethereum uses the BLS12-381 curve, whose scalar field modulus is slightly less than `2^256` - /// (closer to `2^255`). - /// - Therefore, 32-byte field elements can't represent all 256-bit values. - /// - To ensure values are within the field modulus, we **pad with a leading `0x00` byte**, - /// effectively capping values below the modulus. - /// - This reduces the usable payload to **31 bytes per field element**. - /// - /// So, the _actual usable capacity_ per blob is: - /// - /// `4096 * 31 = 126976 bytes` - /// - /// Meaning that we can send as much as 126976 / 32 = 3968 proofs per blob async fn construct_blob( &self, leaves: Vec<[u8; 32]>, diff --git a/docs/2_architecture/agg_mode_components/1_deep_dive.md b/docs/2_architecture/agg_mode_components/1_deep_dive.md deleted file mode 100644 index 8ef241deae..0000000000 --- a/docs/2_architecture/agg_mode_components/1_deep_dive.md +++ /dev/null @@ -1,91 +0,0 @@ -# Aggregation Mode Deep Dive - -The Aggregation Mode runs **once every 24 hours** and performs the following steps: - -1. **Fetch Proofs from the Verification Layer** - Queries `NewBatchV3` events from the `AlignedLayerServiceManager` and downloads the batches from `S3`, starting from the last processed block of the previous run. - -2. **Filter Proofs** - Filters proofs by supported verifiers and proof types. - -3. **Aggregate Proofs in the zkVM** - Selected proofs are aggregated using a zkVM. - -4. **Construct the Blob** - A blob is built containing the [commitments](#proof-commitment) of the aggregated proofs. - -5. **Send Aggregated Proof** - The final aggregated proof and its blob are sent to the `AlignedProofAggregationService` contract for verification. - -> [Note] -> Currently if you want your proof to be verified in the `AggregationMode` you need to submit it via the `VerificationLayer`. In the future, users will be able to decide if they want to use any of the modes in particular or both of them - -## Aggregators and Supported Proof Types - -Two separate aggregators are run every 24 hours: - -- **Risc0**: Aggregates proofs of types `Composite` and `Succinct`. -- **SP1**: Aggregates proofs of type `Compressed`. - -## Proof Commitment - -The **proof commitment** is a hash that uniquely identifies a proof. It is defined as the keccak of the proof public inputs + program ID: - -- **For SP1**: - The commitment is computed as: `keccak(proof_public_inputs_bytes || vk_hash_bytes)` -- **For Risc0**: - The commitment is computed as: `keccack(receipt_public_inputs_bytes || image_id_bytes)` - -## Multilayer Aggregation - -To scale aggregation without exhausting zkVM memory, aggregation is split in two programs: - -1. **User Proof Aggregator** - Processes chunks of `n` user proofs. Each run creates an aggregated proof that commits to a Merkle root of the user proofs inputs. This step is repeated for as many chunks as needed. Usually each chunks contains `256` proofs but it can be lowered based on the machine specs. - -2. **Chunk Aggregator** - Aggregates all chunk-level proofs into a single final proof. It receives: - - - The chunked proofs - - The original [proofs commitments](#proof-commitment) included each chunk received - - During verification, it checks that each chunk’s committed Merkle root matches the reconstructed root to ensure input correctness. The final Merkle root, representing all user [proofs commitments](#proof-commitment), is then committed as a public input. - -## Verification - -Once aggregated, the proof is sent to Ethereum and verified via the `AlignedProofAggregationService` contract. Depending on the proving system, the contract invokes: - -- `verifySP1` for SP1 proofs -- `verifyRisc0` for Risc0 proofs - -Each function receives: - -- The public inputs -- The proof binary - -The program ID is hardcoded in the contract to ensure only trusted aggregation programs (`chunk_aggregator`) are accepted. - -If verification succeeds, the new proof is added to the `aggregatedProofs` map in contract storage. - -### Proof Inclusion Verification - -To verify a user’s proof on-chain, the following must be provided: - -- The proof bytes -- The proof public inputs -- The program ID -- A Merkle proof - -The Merkle root is computed and checked for existence in the contract using the `verifyProofInclusion` function of the `ProofAggregationServiceContract`, which: - -1. Computes the merkle root -2. Returns `true` or `false` depending if there exists an `aggregatedProof` with the computed root. - -## Data Availability - -When submitting the aggregated proof to Ethereum, we include a **blob** that contains the [commitments](#proof-commitment) of all the individual proofs that were aggregated. This blob serves two main purposes: - -- It makes the [proof commitments](#proof-commitment) publicly available for **18 days**. -- It allows users to: - - Inspect which proofs were aggregated - - Get a Merkle proof to verify that their proof is included in the aggregated proof diff --git a/docs/3_guides/3.1_aggregation_mode.md b/docs/3_guides/3.1_aggregation_mode.md deleted file mode 100644 index 7421145600..0000000000 --- a/docs/3_guides/3.1_aggregation_mode.md +++ /dev/null @@ -1,208 +0,0 @@ -## Aggregation Mode L2 integration example - -This guide demonstrates how to build a dummy L2 application that integrates with Aligned Aggregation Mode. 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 Verification Layer (a.k.a Fast Mode). -- On-chain state update via proof verification with Aligned Aggregation Mode. - -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 - -7. Load the proof binary: Retrieve the saved proof binary from disk. -8. 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. [Rust](https://www.rust-lang.org/tools/install): we have tested in v1.85.1 -2. [Foundry](https://book.getfoundry.sh/getting-started/installation) -3. [Docker](https://docs.docker.com/engine/): for SP1 prover - -Submodules of the repo should be imported by running on the root folder: - -```shell -make submodules -``` - -You can run the example on: - -- [Holesky](#setup-holeksy) -- [Localnet](#setup-localnet) - -## Setup Holeksy - -### 1. Create keystore - -You can use cast to create a local keystore. If you already have one you can skip this step. - -```bash -cast wallet new-mnemonic -``` - -Then you can import your created keystore using: - -```bash -cast wallet import --interactive -``` - -Then you need to obtain some funds to pay for gas and proof verification. -You can do this by using this [faucet](https://cloud.google.com/application/web3/faucet/ethereum/holesky) - -_This same wallet is used to send the proof via aligned, so you'll also need to fund it on aligned. Follow this [guide](https://docs.alignedlayer.com/guides/0_submitting_proofs#id-2.-send-funds-to-aligned)._ - -### 2. Deploy the contract - -- Generate the base `.env`: - -```shell -make gen_env_contract_holesky -``` - -- Get the program ID of the l2 program you are proving: - -```shell -make generate_program_id -``` - -- 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: - -```shell -make deploy_contract -``` - -_Save the output contract address._ - -### 3. Setup the L2 - -- Generate the base `.env` run: - -```shell -make gen_env_l2_holesky -``` - -- 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](#running-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 - -```shell -# This will start the local net -make ethereum_package_start -# Start the batcher -make batcher_start_ethereum_package -``` - -- Navigate back to the example directory: - -```shell -cd examples/l2 -``` - -- Generate the `.env` files for the contracts and L2: - -```shell -make gen_env_contract_devnet -make gen_env_l2_devnet -``` - -- Generate a pre funded wallet (or create one as specified [previously here](#1-create-keystore)): - -```shell -# This will generate the keystore and fund it on aligned -make gen_devnet_owner_wallet -``` - -- Generate the program ID of the program that is going to be proven: - -```shell -make generate_program_id -``` - -- Set the generated program ID on `contracts/.env`. - -- Deploy the contract - -```shell -make deploy_contract -``` - -- Set the output address of the contract in `.env` - -- [run the l2](#running-the-l2) - -## Running the L2 - -- Set up the initial State - -```shell -make init_state -``` - -- Perform the L2 account updates and prove them in the zkvm: - -```shell -make prove_state_transition -``` - -- Wait 24 hs for the proof to be aggregated, or if running locally, run the aggregator with either: - - ```make start_proof_aggregator_ethereum_package AGGREGATOR=sp1``` - - or with cuda: - `make start_proof_aggregator_gpu_ethereum_package AGGREGATOR=sp1` - -- Update state transition on chain: - -```shell -make update_state_on_chain -``` - -You should see a transaction receipt in the console and after the stateRoot updated on-chain. diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 5e03f17176..ef49a049aa 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -20,7 +20,6 @@ * [Aggregator](./2_architecture/components/5_aggregator.md) * [Explorer](./2_architecture/components/6_explorer.md) * [Aggregation mode](2_architecture/2_aggregation_mode.md) - * [Deep Dive](2_architecture/agg_mode_components/1_deep_dive.md) ## Guides @@ -28,7 +27,6 @@ * [Build your first Aligned Application](3_guides/2_build_your_first_aligned_application.md) * [Modify ZkQuiz Questions](3_guides/2.2_modify_zkquiz_questions.md) * [Validating public input](3_guides/3_validating_public_input.md) -* [Aggregation Mode](3_guides/3.1_aggregation_mode.md) * [SDK Intro](3_guides/1_SDK_how_to.md) * [SDK API Reference](3_guides/1.2_SDK_api_reference.md) * [Generating proofs for Aligned](3_guides/4_generating_proofs.md) From 8c3b58eebdc615159c82e6397831b3a131f11082 Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Wed, 18 Jun 2025 14:05:23 -0300 Subject: [PATCH 09/10] Update the aligned install url to the staging version --- docs/1_introduction/1_try_aligned.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/1_introduction/1_try_aligned.md b/docs/1_introduction/1_try_aligned.md index 8e503e4e62..a9091d547f 100644 --- a/docs/1_introduction/1_try_aligned.md +++ b/docs/1_introduction/1_try_aligned.md @@ -14,7 +14,7 @@ We will download a previously generated SP1 proof, send it to Aligned for verifi 1. Download and install Aligned to send proofs in the testnet: ```bash -curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/testnet/batcher/aligned/install_aligned.sh | bash +curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/testnet/crates/cli/install_aligned.sh | bash ``` 2. Run the `source` command that should appear in the shell @@ -22,7 +22,7 @@ curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/testnet/bat 3. Download the example SP1 proof file together with the ELF file of the proved program using: ```bash -curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/testnet/batcher/aligned/get_proof_test_files.sh | bash +curl -L https://raw.githubusercontent.com/yetanotherco/aligned_layer/testnet/crates/cli/get_proof_test_files.sh | bash ``` 4. Send the proof to be verified in Aligned with From 88de5d1cd2814790d7d9064c0c9d7e84ead9fd2a Mon Sep 17 00:00:00 2001 From: maximopalopoli Date: Mon, 23 Jun 2025 17:46:21 -0300 Subject: [PATCH 10/10] Adapt the submit proofs without batcher link to be compatible with gitbook --- docs/1_introduction/3_faq.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/1_introduction/3_faq.md b/docs/1_introduction/3_faq.md index 37d49840b2..6d544d4885 100644 --- a/docs/1_introduction/3_faq.md +++ b/docs/1_introduction/3_faq.md @@ -25,7 +25,7 @@ The batcher cannot transfer user's funds to other accounts, only spend them to c ### How do I send proofs without a batcher? -You can see the steps to do it in [this markdown file](https://github.com/yetanotherco/aligned_layer/blob/8a3a6448c974d09c645f3b74d4c9ff9d2dd27249/docs/3_guides/8_submitting_batch_without_batcher.md). +You can see the steps to do it in [this guide](../3_guides/8_submitting_batch_without_batcher.md). ### How do I run my own batcher?