Electron Labs
  • Quantum: Proof Aggregation for Ethereum
    • Introduction
    • Proof Lifecycle and Architecture
    • Quantum Protocol Specifications
    • Integration
    • Developer tutorial for integrating Quantum
    • Gas Cost Analysis
    • Developer Chat
Powered by GitBook
On this page
  • User Journey Overview
  • Aggregation Backend Overview
  • Specifications
  • 1. Circuit Registration
  • 2. Proof Submission
  • 3. Reduction
  • 4. Aggregation
  • 5. Snarkification
  • 6. Consolidation
  • 7. On-chain Superproof Verification
  • 8. User Inclusion Check
  1. Quantum: Proof Aggregation for Ethereum

Quantum Protocol Specifications

PreviousProof Lifecycle and ArchitectureNextIntegration

Last updated 3 months ago

User Journey Overview

This section outlines the complete user journey with the Quantum Protocol, basically highlighting all the user interactions with Quantum.

Users begin by registering the quantum circuits they wish to generate and aggregate proofs for. This is accomplished seamlessly using the . During the Circuit Registration phase, users submit circuit-specific data (e.g., verification keys) to the Quantum Node. In return, they receive a unique identifier called the circuitHash, which will be used in subsequent interactions with the protocol.

Once a circuit is registered, users can submit their proof (π\piπ) along with their public inputs (pispispis) to the Quantum Node. Upon submission, the user receives a proofHash, a unique identifier for their proof. The proofHash allows users to track the status of their proof during the aggregation process.

Within a designated time window, the Quantum Node aggregates all user-submitted proofs into an Aggregated Proof (πagg\pi_{agg}πagg​). The aggregation is encoded in a binary Merkle tree, whose root, known as the Super Root, is submitted and then verified on the QuantumVerifier contract deployed on Ethereum. Post this users can verify that their individual proof is included in the aggregated proof. This process, referred to as the Inclusion Check, involves obtaining an inclusion_proof from the Quantum Node. The inclusion_proof is a Merkle proof that allows the user to independently verify that their proof was verified and included as part of the aggregated proof (πagg\pi_{agg}πagg​) verified on-chain.

Aggregation Backend Overview

This section provides a high-level overview of the aggregation backend architecture. Details regarding constraints, public inputs, and their linkages across different stages are covered in the

The aggregation backend operates in four distinct stages: Reduction, Aggregation, SNARKification, and Consolidation. Each stage leverages a different prover: Risc0 zkVM for the reduction, Risc0 zkVM and Sp1 zkVM for the aggregation, Circom for SNARKification, and Gnark for Consolidation. The following flow diagram explains the whole process concisely:

Reduction:

At this stage, each user-submitted proof (π\piπ) (excluding SP1 proofs) and its corresponding public inputs (pispispis) are individually verified within a Risc0 zkVM circuit. This circuit implements the verification algorithm for the proving scheme and some hashing. The result of this process is a compressed proof (πreduced\pi_{reduced}πreduced​) along with new reduced public inputs (pisreducedpis_{reduced}pisreduced​).

Aggregation:

The sp1 proofs and the reduced proofs (πreduced\pi_{reduced}πreduced​), along with their public inputs (pisreducedpis_{reduced}pisreduced​), are recursively verified and encoded into two Merkle trees - using Sp1 zkVM for the former, and Risc0 zkVM for the latter. This produces the 2 aggregated proofs (πagg1,πagg2\pi_{agg1}, \pi_{agg2}πagg1​,πagg2​) and their corresponding aggregated public inputs (pisagg1,pisagg2pis_{agg1},pis_{agg2}pisagg1​,pisagg2​).

SNARKification:

Consolidation:

At the final stage, the Groth16 proofs (πsnark1,πsnark2\pi_{snark1},\pi_{snark2}πsnark1​,πsnark2​) and their public inputs (pissnark1,pissnark2pis_{snark1},pis_{snark2}pissnark1​,pissnark2​) are recursively verified inside a Gnark circuit. This produces the final proof (πfinal\pi_{final}πfinal​) and its public inputs (pisfinalpis_{final}pisfinal​).

Specifications

This section goes into depth about each component and the inner workings of the Quantum Protocol.

1. Circuit Registration

In this stage, the user submits circuit-specific data, which primarily includes the information necessary to verify proofs generated for the circuit. Depending on the proving scheme, either all or a subset of this data is used in formation of circuitVKey. For all the proving schemes, excluding SP1, this data is combined and hashed with the Risc0 Image ID associated with the verifier (reduction) circuit for the selected proving scheme. The resulting hash, known as the circuitHash, is returned to the user as a unique identifier for their circuit.

Formula for Computing circuitHash:

For SP1 Proofs,

circuitHash=user_circuit_datacircuitHash=user\_circuit\_datacircuitHash=user_circuit_data

For all other proving schemes,

circuitHash=Keccak(user_circuit_data∣∣risc0_image_id)circuitHash=Keccak(user\_circuit\_data ∣∣ risc0\_image\_id)circuitHash=Keccak(user_circuit_data∣∣risc0_image_id)
  • user_circuit_datauser\_circuit\_datauser_circuit_data: The circuit-specific data, which varies based on the proving scheme.

  • risc0_image_idrisc0\_image\_idrisc0_image_id: The unique identifier for the reduction circuit used in the protocol.

This hashing mechanism ensures that each circuit is uniquely identifiable and securely tied to its associated verification logic.

  • Gnark Groth16/Plonk

    For Gnark Groth16/Plonk, the user's Verification Key is serialized into bytes using the Borsh serialization format. The serialized bytes are then hashed using the Keccak Hash algorithm to compute user_circuit_datauser\_circuit\_datauser_circuit_data.

    user_circuit_data=Keccak(user_vkey_bytes)user\_circuit\_data = Keccak(user\_vkey\_bytes)user_circuit_data=Keccak(user_vkey_bytes)
  • SnarkJS Groth16

    user_circuit_data=Keccak(prepared_vkey_bytes)user\_circuit\_data = Keccak(prepared\_vkey\_bytes)user_circuit_data=Keccak(prepared_vkey_bytes)
  • Risc0 Compressed

    For Risc0 Compressed Proofs, just the user’s risc0 Image Id is used.

    user_circuit_data=Keccak(user_circuit_image_id_bytes)user\_circuit\_data = Keccak(user\_circuit\_image\_id\_bytes)user_circuit_data=Keccak(user_circuit_image_id_bytes)
  • SP1 Succinct

    user_circuit_data=keccak(sp1_verifying_key)user\_circuit\_data = keccak(sp1\_verifying\_key)user_circuit_data=keccak(sp1_verifying_key)
  • Plonky2

    user_circuit_data=keccak(vkeyu ∣∣ common_datau)user\_circuit\_data = keccak(vkey_{u} \ || \ common\_data_{u})user_circuit_data=keccak(vkeyu​ ∣∣ common_datau​)
  • Halo2 KZG/KZG-EVM

    user_circuit_data=keccak(protocol_datau ∣∣ s_g2u)user\_circuit\_data = keccak(protocol\_data_{u} \ || \ s\_g2_{u})user_circuit_data=keccak(protocol_datau​ ∣∣ s_g2u​)

2. Proof Submission

In this stage, the user submits the proof πu\pi_{u}πu​ they want aggregated, along with the corresponding public inputs pisupis_{u}pisu​. In return, the user receives a unique proofId. This proofId is computed as follows:

proofId=Keccak(circuitHash ∣∣ Keccak(πu) ∣∣ Keccak(pisu))proofId = Keccak(circuitHash \ || \ Keccak(\pi_{u}) \ || \ Keccak(pis_{u}))proofId=Keccak(circuitHash ∣∣ Keccak(πu​) ∣∣ Keccak(pisu​))

The proofHash allows users to track the status of their proof during the aggregation process and also serves as the leaf node in the binary Merkle tree that corresponds to the Super Root.

3. Reduction

The reduction stage validates the user's proof within a Risc0 circuit for all the proving schemes excluding SP1. The Risc0 circuit executes the verifier logic specific to each proving scheme, where each proving scheme is associated with a distinct reduction circuit, identified by a unique Risc0 Image ID.

This step produces a compressed proof (πred\pi_{red}πred​), unifying proofs from different proving schemes into a standardized format. The reduction circuit accepts all the necessary data for verifying a proof as private input, while the public input for the reduction circuit is typically as follows:

pisred==( keccak(user_circuit_data ∣∣ keccak(πu) ∣∣ keccak(pisu)))pis_{red} == ( \ keccak(user\_circuit\_data \ || \ keccak(\pi_{u}) \ || \ keccak(pis_{u})) )pisred​==( keccak(user_circuit_data ∣∣ keccak(πu​) ∣∣ keccak(pisu​)))
  • Gnark Groth16/Plonk , SnarkJS Groth16

    Private Inputs (Reduction circuit private inputs):

    1. vkeyuvkey_{u}vkeyu​ : User circuit verification key

    2. πu\pi_{u}πu​ : Proof user wants to get aggregated corresponding to vkeyuvkey_{u}vkeyu​

    3. pisupis_{u}pisu​: Public inputs corresponding to πu\pi_{u}πu​

    Public Input ( pisredpis_{red}pisred​ : Reduction Circuit Public Input):

    1. pisredpis_{red}pisred​ ( keccak(keccak(vkeyu) ∣∣ keccak(πu) ∣∣ keccak(pisu)))( \ keccak(keccak(vkey_{u} ) \ || \ keccak(\pi_{u}) \ || \ keccak(pis_{u})))( keccak(keccak(vkeyu​) ∣∣ keccak(πu​) ∣∣ keccak(pisu​)))

    Reduction Circuit Constraints:

    1. snark_verify(vkeyu,πu,pisu)==Truesnark\_verify(vkey_{u}, \pi_{u}, pis_{u}) == Truesnark_verify(vkeyu​,πu​,pisu​)==True

    2. pisred==( keccak(keccak(vkeyu) ∣∣ keccak(πu) ∣∣ keccak(pisu)))pis_{red} == ( \ keccak(keccak(vkey_{u}) \ || \ keccak(\pi_{u}) \ || \ keccak(pis_{u})) )pisred​==( keccak(keccak(vkeyu​) ∣∣ keccak(πu​) ∣∣ keccak(pisu​)))

  • Risc0 Compressed

    Private Inputs (Reduction circuit private inputs):

    1. image_iduimage\_id_{u}image_idu​ : User risc0 circuit Image Id

    2. journalujournal_{u}journalu​ : User generated risc0 journal

    Public Inputs ( pisredpis_{red}pisred​ : Reduction Circuit Public Input):

    1. pisredpis_{red}pisred​(keccak(image_idu ∣∣ keccak(journalu)))(keccak(image\_id_{u} \ || \ keccak(journal_{u}) ))(keccak(image_idu​ ∣∣ keccak(journalu​)))

    Reduction Circuit Constraints:

    1. risc0_verify_compressed(image_idu,journalu)==Truerisc0\_verify\_compressed(image\_id_{u}, journal_{u}) == Truerisc0_verify_compressed(image_idu​,journalu​)==True

    2. pisred==(keccak(image_idu ∣∣ keccak(journalu)))pis_{red} ==(keccak(image\_id_{u} \ || \ keccak(journal_{u})))pisred​==(keccak(image_idu​ ∣∣ keccak(journalu​)))

  • Plonky2

    Private Inputs (Reduction Circuit Private Inputs):

    1. common_dataucommon\_data_{u}common_datau​: User plonky2 circuit common_data

    2. vkeyuvkey_{u}vkeyu​: User circuit verification_only data

    3. πu\pi_{u}πu​: Plonky2 proof user wants to get aggregated corresponding to vkeyuvkey_{u}vkeyu​

    4. pisupis_{u}pisu​ : User circuit public inputs

    Public Inputs:

    1. pisredpis_{red}pisred​(keccak(keccak(vkeyu ∣∣ common_datau) ∣∣ keccak(πu) ∣∣ keccak(pisu))keccak(keccak(vkey_{u} \ || \ common\_data_{u}) \ || \ keccak(\pi_{u}) \ || \ keccak(pis_{u}))keccak(keccak(vkeyu​ ∣∣ common_datau​) ∣∣ keccak(πu​) ∣∣ keccak(pisu​)))

    Constraints:

    1. plonky2_verify_proof(common_datau,vkeyu,pisu,πu)plonky2\_verify\_proof(common\_data_{u}, vkey_{u}, pis_{u}, \pi_{u})plonky2_verify_proof(common_datau​,vkeyu​,pisu​,πu​)

    2. pisred==keccak(keccak(vkeyu ∣∣ common_datau) ∣∣ keccak(πu) ∣∣ keccak(pisu))pis_{red} == keccak(keccak(vkey_{u} \ || \ common\_data_{u}) \ || \ keccak(\pi_{u}) \ || \ keccak(pis_{u}))pisred​==keccak(keccak(vkeyu​ ∣∣ common_datau​) ∣∣ keccak(πu​) ∣∣ keccak(pisu​))

  • Halo2 KZG/EVM

    Private Inputs:

    1. protocol_datauprotocol\_data_{u}protocol_datau​

    2. s_g2us\_g2_{u}s_g2u​

    3. pisupis_{u}pisu​

    4. πu\pi_{u}πu​

    Public Inputs:

    1. pisredpis_{red}pisred​(keccak(protocol_datau ∣∣ s_g2u) ∣∣ keccak(πu) ∣∣ keccak(pisu))(keccak(protocol\_data_{u} \ || \ s\_g2_{u}) \ || \ keccak(\pi_{u}) \ || \ keccak(pis_{u}))(keccak(protocol_datau​ ∣∣ s_g2u​) ∣∣ keccak(πu​) ∣∣ keccak(pisu​))

    Constraints:

    1. halo2_verify(protocol_datau,pisu,s_g2u,πu)halo2\_verify(protocol\_data_{u}, pis_{u}, s\_g2_{u}, \pi_{u})halo2_verify(protocol_datau​,pisu​,s_g2u​,πu​)

    2. pisred==(keccak(protocol_datau ∣∣ s_g2u) ∣∣ keccak(πu) ∣∣ keccak(pisu))pis_{red} == (keccak(protocol\_data_{u} \ || \ s\_g2_{u}) \ || \ keccak(\pi_{u}) \ || \ keccak(pis_{u}))pisred​==(keccak(protocol_datau​ ∣∣ s_g2u​) ∣∣ keccak(πu​) ∣∣ keccak(pisu​))

4. Aggregation

In the aggregation stage, all the reduced proofs and public input pairs are recursively verified inside a single risc0 circuit and all the SP1 proofs are recursively verified inside a single sp1 circuit. These circuits encode all the user's proof in binary Merkle trees, producing 2 compressed proofs (πagg1,πagg2)(\pi_{agg1},\pi_{agg2})(πagg1​,πagg2​)

Within a Risc0 circuit, each individual proof is verified against its Reduction circuit’s Risc0 Image Id . These Image Id’s are hardcoded in the aggregation circuit corresponding to their proof_types.

Risc0

Public Input (pisagg1pis_{agg1}pisagg1​): risc0_rootrisc0\_rootrisc0_root

Private Inputs:

  1. Reduced Proofs: (πredi)i=0i=batch_size(\pi_{red_{i}})_{i=0}^{i=batch\_size}(πredi​​)i=0i=batch_size​

  2. Reduced Public Inputs: (pisredi)i=0i=batch_size(pis_{red_{i}})_{i=0}^{i=batch\_size}(pisredi​​)i=0i=batch_size​

  3. User Proof Types: (proof_typei)i=0i=batch_size(proof\_type_{i})_{i=0}^{i=batch\_size}(proof_typei​)i=0i=batch_size​

  4. User Proof Hashes: (π_hashi)i=0i=batch_size(\pi\_hash_{i})_{i=0}^{i=batch\_size}(π_hashi​)i=0i=batch_size​

  5. User Public Input Hashes: (pis_hashi)i=0i=batch_size(pis\_hash_{i})_{i=0}^{i=batch\_size}(pis_hashi​)i=0i=batch_size​

  6. User Circuit Datas: (ckt_data)i=0i=batch_size(ckt\_data)_{i=0}^{i=batch\_size}(ckt_data)i=0i=batch_size​

Constraints:

  1. (verify_risc0_proof(πredi,pisredi,redn_image_idi)==True)i=0i=batch_size(verify\_risc0\_proof(\pi_{red_{i}}, pis_{red_{i}}, redn\_image\_id_{i}) == True)_{i=0}^{i=batch\_size}(verify_risc0_proof(πredi​​,pisredi​​,redn_image_idi​)==True)i=0i=batch_size​

  2. (pisredi==keccak(ckt_datai ∣∣ π_hashi ∣∣ pis_hashi))i=0i=batch_size(pis_{red_{i}} == keccak(ckt\_data_{i} \ || \ \pi\_hash_{i} \ || \ pis\_hash_{i} ))_{i=0}^{i=batch\_size}(pisredi​​==keccak(ckt_datai​ ∣∣ π_hashi​ ∣∣ pis_hashi​))i=0i=batch_size​

  3. risc0_root==construct_tree(leaves);leaves=[keccak(keccak(ckt_datai ∣∣ redn_image_idi) ∣∣ π_hashi ∣∣ pis_hashi)]i=0i=batch_sizerisc0\_root == construct\_tree(leaves); \\leaves=[keccak(keccak(ckt\_data_{i} \ || \ redn\_image\_id_{i}) \ || \ \pi\_hash_{i} \ || \ pis\_hash_{i})]_{i=0}^{i=batch\_size}risc0_root==construct_tree(leaves);leaves=[keccak(keccak(ckt_datai​ ∣∣ redn_image_idi​) ∣∣ π_hashi​ ∣∣ pis_hashi​)]i=0i=batch_size​

SP1

Public Input (pisagg2pis_{agg2}pisagg2​): sp1_rootsp1\_rootsp1_root

Private Inputs:

  1. User Proofs: (πui)i=0i=batch_size(\pi_{u_{i}})_{i=0}^{i=batch\_size}(πui​​)i=0i=batch_size​

  2. Public Inputs: (pisui)i=0i=batch_size(pis_{u_{i}})_{i=0}^{i=batch\_size}(pisui​​)i=0i=batch_size​

  3. User Public Inputs: (pisi)i=0i=batch_size(pis_{i})_{i=0}^{i=batch\_size}(pisi​)i=0i=batch_size​

  4. User Circuit Datas: (ckt_data)i=0i=batch_size(ckt\_data)_{i=0}^{i=batch\_size}(ckt_data)i=0i=batch_size​

Constraints:

  1. (verify_sp1_proof(ckt_datai,πui,pisui)==True)i=0i=batch_size(verify\_sp1\_proof(ckt\_data_{i},\pi_{u_{i}}, pis_{u_{i}}) == True)_{i=0}^{i=batch\_size}(verify_sp1_proof(ckt_datai​,πui​​,pisui​​)==True)i=0i=batch_size​

  2. sp1_root==construct_tree(leaves);leaves=[keccak(ckt_datai ∣∣ pis_hashi)]i=0i=batch_sizesp1\_root == construct\_tree(leaves); \\leaves=[keccak(ckt\_data_{i} \ || \ pis\_hash_{i})]_{i=0}^{i=batch\_size}sp1_root==construct_tree(leaves);leaves=[keccak(ckt_datai​ ∣∣ pis_hashi​)]i=0i=batch_size​

5. Snarkification

super_root==keccak(risc0_root ∣∣ sp1_root)super\_root == keccak(risc0\_root\ || \ sp1\_root)super_root==keccak(risc0_root ∣∣ sp1_root)

6. Consolidation

At this stage, the Groth16 proofs (πsnark1,πsnark2\pi_{snark1},\pi_{snark2}πsnark1​,πsnark2​) and their public inputs (pissnark1,pissnark2pis_{snark1},pis_{snark2}pissnark1​,pissnark2​) are recursively verified inside a Gnark circuit. This produces the final proof (πfinal\pi_{final}πfinal​) and its public inputs (pisfinalpis_{final}pisfinal​). Additionally, this stage future-proofs the system by enabling seamless integration with additional VMs for reduction and aggregation, requiring minimal modifications.

7. On-chain Superproof Verification

Once the Snarkification step is complete, the Groth16 proof (πfinal\pi_{final}πfinal​) is submitted to the QuantumVerifier contract on Ethereum for on-chain verification. The corresponding public input (pisfinalpis_{final}pisfinal​), which is the Super Root, is also passed to the contract.

The QuantumVerifier contract validates the proof against the public input using the Groth16 verifier logic. If the verification is successful, the Super Root (pisfinalpis_{final}pisfinal​) is stored in the Quantum contract's state as a record of successful aggregation and proof verification.

8. User Inclusion Check

After the Super Root (pisfinalpis_{final}pisfinal​) is verified and stored on-chain, individual users can perform an Inclusion Check to verify that their proof (πu\pi_uπu​) was correctly included in the aggregated proof.

Steps for Inclusion Check:

  1. Retrieve the inclusion proof :

    • The user queries the Quantum Node for an inclusion_proof associated with their submitted proof.

    • The inclusion_proof is a Merkle proof that demonstrates that the user’s proof (πu\pi_{u}πu​) was correctly verified using the appropriate verifier circuit identified by redn_image_idproving_schemeredn\_image\_id_{proving\_scheme}redn_image_idproving_scheme​, corresponding to the public inputs (pisupis_{u}pisu​) for the circuit with circuit data ckt_datauckt\_data_{u}ckt_datau​. It also confirms that this verified proof was included in the Merkle tree whose root is the Super Root.

  2. Validate their public inputs on-chain using the Inclusion Proof :

    i. Pre-storing the circuit_hash:

    • The user first registers their circuit with the protocol and stores the circuit_hash in their protocol-specific smart contract.

    • The circuit_hash uniquely identifies the user’s circuit and is derived during the Circuit Registration phase as: circuitHash=Keccak(user_circuit_data∣∣risc0_image_id)circuitHash=Keccak(user\_circuit\_data ∣∣ risc0\_image\_id)circuitHash=Keccak(user_circuit_data∣∣risc0_image_id)

    • This serves as the foundation for reconstructing and verifying the inclusion proof.

    ii. Sending Proof Details to the Contract:

    • The user submits the following to their protocol smart contract:

      • Keccak(πu)Keccak(\pi_{u})Keccak(πu​): The hash of the user’s individual proof.

      • pisupis_{u}pisu​: The public inputs corresponding to the proof.

      • inclusion_proofinclusion\_proofinclusion_proof: A Merkle proof that links the user’s proof to the Super Root stored on-chain.

    iii. Reconstructing the Leaf:

    • Inside the protocol smart contract, the submitted data is used to reconstruct the Merkle leaf as: leaf=Keccak(circuitHash∣∣Keccak(πu)∣∣Keccak(pisu))leaf=Keccak(circuitHash ∣∣ Keccak(π_u) ∣∣ Keccak(pis_u))leaf=Keccak(circuitHash∣∣Keccak(πu​)∣∣Keccak(pisu​))

    • This leaf represents the hashed representation of the user’s proof and its associated public inputs, tied to the specific circuit.

    iv. Verifying the Inclusion Proof:

    • The reconstructed leaf is verified against the Merkle tree using the submitted inclusion_proof.

    • The smart contract calls the Quantum Verifier contract to cross-check the inclusion_proof against the Super Root stored on-chain during the On-Chain Superproof Verification step.

    v. Validation Outcome:

    • If the inclusion_proof is valid and the Merkle proof matches the Super Root, the user’s public inputs (pisupis_{u}pisu​) are confirmed as part of the aggregated proof.

    • This ensures that the user’s proof was correctly included, verified, and aggregated within the protocol.

The aggregated proofs (πagg1,πagg2\pi_{agg1},\pi_{agg2}πagg1​,πagg2​) and the corresponding public inputs (pisagg1,pisagg2pis_{agg1},pis_{agg2}pisagg1​,pisagg2​) undergo a further transformation at this stage. The proofs with their associated public inputs (pissnark1,pissnark2pis_{snark1},pis_{snark2}pissnark1​,pissnark2​) are recursively verified and converted into 2 Groth16 proofs (πsnark1,πsnark2\pi_{snark1},\pi_{snark2}πsnark1​,πsnark2​) using the circuits provided and , respectively.

The circuitHash also plays a critical role in later stages, such as during the .

For SnarkJS Groth16, the user’s Verification Key is converted into ,* and then serialised into bytes using .

For SP1 Succinct Proofs, user_circuit_datauser\_circuit\_datauser_circuit_data is computed from using this .

For Plonky2, the user sends and during Circuit Registration as both of them are required to successfully verify a Plonky2 proofs.

For Halo2 KZG/KZG-EVM, the user sends and as both are required to successfully verify Halo2 KZG or KZG-EVM proofs.

This stage converts compressed proofs (πagg1,πagg2\pi_{agg1},\pi_{agg2}πagg1​,πagg2​) to 2 groth16 proofs (πsnark1,πsnark2\pi_{snark1},\pi_{snark2}πsnark1​,πsnark2​) using the circuits provided and . The only reason for this step is to reduce on-chain verification cost on Ethereum. The public input in this stage which is the super_rootsuper\_rootsuper_root is defined as:

here
here
User Inclusion Check
*PreparedVerifyingKey
Canonical Serialize
SP1VerifyingKey
function
VerifierOnlyCircuitData
CommonCircuitData
PlonkProtocol
s_g2
here
here
Circuit Registration
quantum-sdk
Proof Submission
Inclusion Check
Specifications