Quantum Protocol Specifications
Last updated
Last updated
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 quantum-sdk. 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 () along with their public inputs () 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 (). 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 () verified on-chain.
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 Specifications
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:
Aggregation:
SNARKification:
Consolidation:
This section goes into depth about each component and the inner workings of the Quantum Protocol.
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.
The circuitHash
also plays a critical role in later stages, such as during the User Inclusion Check.
Formula for Computing circuitHash
:
For SP1 Proofs,
For all other proving schemes,
This hashing mechanism ensures that each circuit is uniquely identifiable and securely tied to its associated verification logic.
Gnark Groth16/Plonk
SnarkJS Groth16
For SnarkJS Groth16, the user’s Verification Key is converted into *PreparedVerifyingKey,* and then serialised into bytes using Canonical Serialize.
Risc0 Compressed
For Risc0 Compressed Proofs, just the user’s risc0 Image Id is used.
SP1 Succinct
Plonky2
For Plonky2, the user sends VerifierOnlyCircuitData and CommonCircuitData during Circuit Registration as both of them are required to successfully verify a Plonky2 proofs.
Halo2 KZG/KZG-EVM
For Halo2 KZG/KZG-EVM, the user sends PlonkProtocol and s_g2 as both are required to successfully verify Halo2 KZG or KZG-EVM proofs.
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.
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
.
Gnark Groth16/Plonk , SnarkJS Groth16
Private Inputs (Reduction circuit private inputs):
Reduction Circuit Constraints:
Risc0 Compressed
Private Inputs (Reduction circuit private inputs):
Reduction Circuit Constraints:
Plonky2
Private Inputs (Reduction Circuit Private Inputs):
Public Inputs:
Constraints:
Halo2 KZG/EVM
Private Inputs:
Public Inputs:
Constraints:
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.
Private Inputs:
Constraints:
Private Inputs:
Constraints:
Steps for Inclusion Check:
Retrieve the inclusion proof :
The user queries the Quantum Node for an inclusion_proof
associated with their submitted proof.
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.
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:
iii. Reconstructing the Leaf:
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:
This ensures that the user’s proof was correctly included, verified, and aggregated within the protocol.
At this stage, each user-submitted proof () (excluding SP1 proofs) and its corresponding public inputs () 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 () along with new reduced public inputs ().
The sp1 proofs and the reduced proofs (), along with their public inputs (), 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 () and their corresponding aggregated public inputs ().
The aggregated proofs () and the corresponding public inputs () undergo a further transformation at this stage. The proofs with their associated public inputs () are recursively verified and converted into 2 Groth16 proofs () using the circuits provided here and here, respectively.
At the final stage, the Groth16 proofs () and their public inputs () are recursively verified inside a Gnark circuit. This produces the final proof () and its public inputs ().
: The circuit-specific data, which varies based on the proving scheme.
: The unique identifier for the reduction circuit used in the protocol.
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 .
For SP1 Succinct Proofs, is computed from SP1VerifyingKey using this function.
In this stage, the user submits the proof they want aggregated, along with the corresponding public inputs . In return, the user receives a unique proofId
. This proofId
is computed as follows:
This step produces a compressed proof (), 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:
: User circuit verification key
: Proof user wants to get aggregated corresponding to
: Public inputs corresponding to
Public Input ( : Reduction Circuit Public Input):
: User risc0 circuit Image Id
: User generated risc0 journal
Public Inputs ( : Reduction Circuit Public Input):
: User plonky2 circuit common_data
: User circuit verification_only
data
: Plonky2 proof user wants to get aggregated corresponding to
: User circuit public inputs
()
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
Public Input ():
Reduced Proofs:
Reduced Public Inputs:
User Proof Types:
User Proof Hashes:
User Public Input Hashes:
User Circuit Datas:
Public Input ():
User Proofs:
Public Inputs:
User Public Inputs:
User Circuit Datas:
This stage converts compressed proofs () to 2 groth16 proofs () using the circuits provided here and here. The only reason for this step is to reduce on-chain verification cost on Ethereum. The public input in this stage which is the is defined as:
At this stage, the Groth16 proofs () and their public inputs () are recursively verified inside a Gnark circuit. This produces the final proof () and its public inputs (). Additionally, this stage future-proofs the system by enabling seamless integration with additional VMs for reduction and aggregation, requiring minimal modifications.
Once the Snarkification step is complete, the Groth16 proof () is submitted to the QuantumVerifier contract on Ethereum for on-chain verification. The corresponding public input (), 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
() is stored in the Quantum contract's state as a record of successful aggregation and proof verification.
After the Super Root () is verified and stored on-chain, individual users can perform an Inclusion Check to verify that their proof () was correctly included in the aggregated proof.
The inclusion_proof
is a Merkle proof that demonstrates that the user’s proof () was correctly verified using the appropriate verifier circuit identified by , corresponding to the public inputs () for the circuit with circuit data . It also confirms that this verified proof was included in the Merkle tree whose root is the Super Root.
The circuit_hash
uniquely identifies the user’s circuit and is derived during the Circuit Registration phase as:
: The hash of the user’s individual proof.
: The public inputs corresponding to the proof.
: A Merkle proof that links the user’s proof to the Super Root stored on-chain.
Inside the protocol smart contract, the submitted data is used to reconstruct the Merkle leaf as:
If the inclusion_proof
is valid and the Merkle proof matches the Super Root, the user’s public inputs () are confirmed as part of the aggregated proof.