In the following page, we detail all the steps required for a protocol to integrate with Quantum. We use the ZKP2P's VenmoOnRamp2 circuit as an example throughout the demo.

Step 1: Setup Nodejs repo

Firstly, install quantum-sdk in your project:

npm i quantum-sdk

Step 2: Circuit registration with Quantum

Now, assuming that the circuit's proving key, and verification key files have been generated following the steps detailed in Circom's documentation, the next step is to register the verification key file.

The circuit_hash received above is basically an identifier for this circuit, and here onward any interactions for this circuit will be done using this circuit_hash.

Step 2.1: Check if registration is completed

Next, we check if the circuit registration is complete.

import { Quantum } from"quantum-sdk";import { CircuitRegistrationStatus } from"quantum-sdk/dist/src/enum/circuit_registration_status";constRPC_ENDPOINT="xx.xxx.xx";constAUTH_KEY="xx-xxx";constquantum=newQuantum(RPC_ENDPOINT,AUTH_KEY);asyncfunctionmain() {let connection =awaitquantum.checkServerConnection();if (!connection) {throwError("Not connected with Quantum server"); }constcircuit_hash="xxxxxxxxxx"; // circuit hash that we received during registrationlet registered_response =awaitquantum.isCircuitRegistered(circuit_hash);let status =registered_response.isCircuitRegistered.circuitRegistrationStatus;if (status !=CircuitRegistrationStatus.Completed) {throwError("Circuit not registered yet"); }// Reduction circuit hash unique to user's circuitlet reduction_circuit_hash =registered_response.isCircuitRegistered.reductionCircuitHash;console.log(reduction_circuit_hash);}

The reduction_circuit_hash received above will be used later during public inputs verification.

Step 3: Proof submission to Quantum

Next, we will submit a proof to Quantum for aggregation. After the protocol has generated proof.json and public.json files through either Snarkjs or Rapidsnark, they can submit the proof to quantum as follows:

import { Quantum } from"quantum-sdk";import { ProofType } from"quantum-sdk/dist/src/enum/proof_type";constRPC_ENDPOINT="xx.xxx.xx";constAUTH_KEY="xx-xxx";constquantum=newQuantum(RPC_ENDPOINT,AUTH_KEY);asyncfunctionmain() {constproof_path="path/to/proof.json";constpublic_path="path/to/public.json";let connection =awaitquantum.checkServerConnection();if (!connection) {throwError("Not connected with Quantum server"); }constcircuit_hash="xxxxxxxxxx"; // circuit hash that we received during registrationlet proof_type =ProofType.GROTH16;letproof_hash= (awaitquantum.submitProof( proof_path, public_path, circuit_hash, proof_type ) ).proofHash.asString();console.log(proof_hash);}

The proof_hash received above will be used to check the status of the proof.

Step 3.1: Check if proof is verified

To check if a proof has been aggregated and submitted on chain:

import { Quantum } from"quantum-sdk";import { ProofStatus } from"quantum-sdk/dist/src/enum/proof_status";constRPC_ENDPOINT="xx.xxx.xx";constAUTH_KEY="xx-xxx";constquantum=newQuantum(RPC_ENDPOINT,AUTH_KEY);asyncfunctionmain() {let connection =awaitquantum.checkServerConnection();if (!connection) {throwError("Not connected with Quantum server"); }let proof_hash ="xxxxxxxxxx"; // proof hash that we received during proof submissionlet proof_status = (awaitquantum.getProofData(proof_hash)).proofData.status;if (proof_status !=ProofStatus.VERIFIED) {throwError("Not verified on chain yet"); }}

Step 4: Compute vkey_hash

When an aggregated proof is submitted on chain, all the individual proofs’ public inputs are hashed and stored in a map against vkey_hash , which can be computed as follows:

import { getVKeyHash } from"quantum-sdk/dist/src/quantum_helper";asyncfunctionmain() {constcircuit_hash="xxxxxxxxxx"; // circuit hash that we received during registrationconstreduction_circuit_hash="yyyyyyyyyy"; // Reduction circuit hash received during circuit registration checkconstvkey_hash=getVKeyHash(circuit_hash, reduction_circuit_hash);console.log(vkey_hash);}

Step 5: Verifying public inputs in contract

To verify public inputs on chain, the protocol needs to make slight changes to their contract, which are summarised below. We demonstrate by making changes to ZKP2P's VenmoSendProcessorV2 contract.

/* other imports */// Import ProtocolVerifier_{n} corresponding to your n number of public inputs// We support ProtocolVerifier_{1} to ProtocolVerifier_{15}; import accordinglyimport {ProtocolVerifier_2} from"quantum-sdk/contracts/lib/ProtocolVerifier.sol";contractVenmoSendProcessorV2isISendProcessor, BaseProcessorV2 {/* othercontract state */bytes32 vKeyHash; // the same vkey_hash that we constructed earlieraddressconstant QUANTUM; // address of quantum contractconstructor(/* other fields */,bytes32 vKeyHash_,address quantum_ ) /* other constructors */ { vKeyHash = vKeyHash_; QUANTUM = quantum_; }/* other functions */functionprocessProof(uint256[12] calldata_signals ) /* functionkeywordsandreturn type */ { ProtocolVerifier_12.verifyPubInputs(_signals, vKeyHash, QUANTUM);/* remaining function logic */ }}

With this, we have completed the integration of Quantum with this protocol. If you are still facing any problems in integrating Quantum with your protocol, please reach out to us.