/halo2-solidity-verifier

A set of tooling related to halo2 circuits verification inside Solidity contracts

Primary LanguageRustMIT LicenseMIT

Halo2 Solidity Verifier

⚠️ This repo has NOT been audited and is NOT intended for a production environment yet.

Solidity verifier generator for halo2 proof with KZG polynomial commitment scheme on BN254.

For audited solidity verifier generator and proof aggregation toolkits, please refer to snark-verifier.

Usage

Generate fully reusable verifier and verifying artifact separately as 2 solidity contracts

let generator = SolidityGenerator::new(&params, &vk, Bdfg21, num_instances);
let (verifier_solidity, vk_solidity) = generator.render_separately().unwrap();

Check examples/separately.rs for more details.

Generate verifier and verifying key in a single solidity contract

let generator = SolidityGenerator::new(&params, &vk, Bdfg21, num_instances);
let verifier_solidity = generator.render().unwrap();

Encode proof into calldata to invoke verifyProof

let calldata = encode_calldata(vk_address, &proof, &instances);

Note that function selector is already included.

Limitations & Caveats

  • It only allows circuit with exact 1 instance column and no rotated query to this instance column.
  • Currently even the configure is same, the selector compression might lead to different configuration when selector assignments are different. To avoid this, please use keygen_vk_custom with compress_selectors: false to do key generation without selector compression.
  • Now it only supports BDFG21 batch open scheme (aka SHPLONK), GWC19 is not yet implemented.

Compatibility

The Keccak256Transcript behaves exactly same as the EvmTranscript in snark-verifier.

Design Rationale for Conjoined Verifier

The current solidity verifier generator within snark-verifier faces a couple of issues:

  • The generator receives only unoptimized, low-level operations, such as add or mul. As a result, it currently unrolls all assembly codes, making it susceptible to exceeding the contract size limit, even with a moderately sized circuit.
  • The existing solution involves complex abstractions and APIs for consumers.

This repository is a ground-up rebuild, addressing these concerns while maintaining a focus on code size and readability. Remarkably, the gas cost is comparable, if not slightly lower, than the one generated by snark-verifier.

Design Rationale for Reusable Verifier

The previous render_separately solidity verifier, although granted some degree of reusability, was still dependent on a given circuit's configuation despite being independent of the verifying key. We wanted to reengineer the separate verifier to be completely independent of the circuit configuration, allowing for a single verifier to be used across multiple circuits.

In the process we created two new types of contracts--Halo2VerifierReusable and Halo2VerifierArtifact-- that replaced the previous Halo2Verifier and Halo2VerifierKey contracts generated by the render_seperately compilation respectively.

The Halo2VerifierArtifact extends the original Halo2VerifierKey by encoding all of the circuit configuration data that was hardcoded in the original separate Halo2Verifier into memory. The Halo2VerifierReusable then loads this configuration data dynamicaly from the Halo2VerifierArtifact at runtime, decodes it and executes the verification computation in a functionally identical manner to the conjoined version.

For large circuits, this reduces deployment costs by 77 percent enabling the deployment of circuits that were previously infeasible due to the contract size limit, requiring an aggregation to get below the limit.

Acknowledgement

The template is heavily inspired by Aztec's BaseUltraVerifier.sol.

Lookup Modularity

Note that we have extended the verifier to include the ability to verify mvlookup / logup lookups. This is hidden behind the mvlookup feature flag.