Home

Awesome

halo2-lib

This repository aims to provide basic primitives for writing zero-knowledge proof circuits using the Halo 2 proving stack. To discuss or collaborate, join our community on Telegram.

Getting Started

For a brief introduction to zero-knowledge proofs (ZK), see this doc.

Halo 2 is written in Rust, so you need to install Rust to use this library:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Clone this repo and start off in the halo2-lib directory.

git clone https://github.com/axiom-crypto/halo2-lib.git
cd halo2-lib

Projects built with halo2-lib

halo2-base

This crate provides an additional API for writing circuits in Halo 2 using our simple vertical gate. It also provides basic functions built using this API. The provided methods can be found in GateInstructions and RangeInstructions. The latter are operations that require using a lookup table for range checks.

To run some basic tests, run the following command:

cargo test -- --nocapture test_gates
cargo test -- --nocapture test_range

(Rust tests by default do not display stdout, so we use --nocapture to enable streaming stdout.) These tests use the MockProver to check circuits are properly constrained, however it does not mimic a true production proving setup.

For benchmarks of native field multiplication and inner product where a production proving setup is run, run the following command:

cargo bench --bench mul
cargo bench --bench inner_product

These benchmarks use the criterion crate to run create_proof 10 times for statistical analysis. Note the benchmark circuits perform more than a one multiplication / inner product per circuit.

halo2-ecc

This crate uses halo2-base to provide a library of elliptic curve cryptographic primitives. In particular, we support elliptic curves over base fields that are larger than the scalar field used in the proving system (e.g., F_r for bn254 when using Halo 2 with a KZG backend).

Features

We recommend ignoring this section and using the default features if you are new to Rust. The default features are: "jemallocator", "halo2-axiom", "display". You can turn off "display" for a very small performance increase, where certain statistics about the circuit are not computed and printed.

Exactly one of "halo2-axiom" or "halo2-pse" feature should be turned on at all times.

We guarantee that the proofs generated by the two forks are identical.

Memory allocator

The "jemallocator" feature uses the jemallocator crate for memory allocation. You can turn it off to use the system allocator. Or use feature "mimalloc" to use the mimalloc crate. We have found the performance of these allocators heavily depends on what machine you are running on.

Modules

Tests with MockProver

Do not run cargo test without any filters. Some of the tests are actually benchmarks, and will take a long time to run.

Setup

All tests should be run in the halo2-lib/halo2-ecc directory. Some tests read files from specific directories, so they will not work if you are in the halo2-lib root directory.

For benchmarks below, you can symlink a params folder within halo2-ecc directory with previously generated universal trusted setup files. Otherwise, the benchmarks will generate a new random setup and save them in the params directory. Warning: These trusted setups are generated using a known random seed, so they are not secure. They should NOT be used in production. For more a production suitable trusted setup, see KZG Trusted Setup.

Tests can be run in the same way as in the previous section. The available commands are:

cargo test -- --nocapture test_fp
cargo test -- --nocapture test_fp12
cargo test -- --nocapture test_ecc
cargo test -- --nocapture test_secp256k1_ecdsa
cargo test -- --nocapture test_ec_add # for BN254
cargo test -- --nocapture test_fixed_base_msm # for BN254
cargo test -- --nocapture test_msm # for BN254
cargo test -- --nocapture test_pairing # for BN254

Configurable Circuits

A special features of circuits written using halo2-base is that any such circuit can be configured to have a different number of rows vs. columns, while keeping the total number of cells roughly the same. Different configurations make sense for different circumstances. For example, more rows vs. columns always leads to a cheaper gas cost for on-chain verification, but often at the cost of slower proving speed. For a rough mental model, see Cost Modeling.

In some of the tests above, the circuit configuration is read from a file. You can change the configuration by changing the numbers in the file. If some numbers are too small, the test will panic because there are not enough cells to construct the circuit. If you put numbers that are too large, the test will display suggestions for what the optimal numbers should be. In a future version we will have the circuits auto-configure themselves.

The benchmark config files below also give a list of possible configurations you can put in a test config files.

The test config file locations are (relative to halo2-ecc directory):

TestConfig File
test_secp256k1_ecdsasrc/secp256k1/configs/ecdsa_circuit.config
test_ec_addsrc/bn254/configs/ec_add_circuit.config
test_fixed_base_msmsrc/bn254/configs/fixed_msm_circuit.config
test_msmsrc/bn254/configs/msm_circuit.config
test_pairingsrc/bn254/configs/pairing_circuit.config

Benchmarks

We have tests that are actually benchmarks using the production Halo2 prover. As mentioned above, there are different configurations for each circuit that lead to very different proving times. The following benchmarks will take a list of possible configurations and benchmark each one. The results are saved in a file in the results directory. We currently supply the configuration lists, which should provide optimal configurations for a given circuit degree k (however you can check versus the stdout suggestions to see if they really are optimal!).

We run the benchmarks in --release mode for maximum speed.

Commands

The available benchmark commands are:

cargo test --release -- --nocapture bench_secp256k1_ecdsa
cargo test --release -- --nocapture bench_ec_add
cargo test --release -- --nocapture bench_fixed_base_msm
cargo test --release -- --nocapture bench_msm
cargo test --release -- --nocapture bench_pairing

The locations of the config and result files (relative to halo2-ecc directory) are:

BenchmarkConfig FileResults File
bench_secp256k1_ecdsasrc/secp256k1/configs/bench_ecdsa.configsrc/secp256k1/results/ecdsa_bench.csv
bench_ec_addsrc/bn254/configs/bench_ec_add.configsrc/bn254/results/ec_add_bench.csv
bench_fixed_base_msmsrc/bn254/configs/bench_fixed_msm.configsrc/bn254/results/fixed_msm_bench.csv
bench_msmsrc/bn254/configs/bench_msm.configsrc/bn254/results/msm_bench.csv
bench_pairingsrc/bn254/configs/bench_pairing.configsrc/bn254/results/pairing_bench.csv

To speed up benching time you can remove certain lines from the .config file for configurations you don't want to bench.

Criterion Benchmarks

To run more accurate benchmarks using the criterion crate, you can run the following commands:

cargo bench --bench msm
cargo bench --bench fixed_base_msm
cargo bench --bench fp_mul

This run the same proof generation over 10 runs and collect the average. Each circuit has a fixed configuration chosen for optimal speed. These benchmarks are mostly for use in performance optimization.

Secp256k1 ECDSA

We provide benchmarks for ECDSA signature verification for the Secp256k1 curve on several different machines. All machines only use CPUs.

On AWS EC2 instances r6a.8xl (AMD, x86) and r6g.8xl (Graviton, arm64), both with 32 CPU cores, 256 GB RAM, the bench is run using

cargo test --release --no-default-features --features "halo2-axiom, jemallocator" -- --nocapture bench_secp256k1_ecdsa

To optimize memory allocation to prioritize CPU utilization, we tune jemallocator with

export JEMALLOC_SYS_WITH_MALLOC_CONF="background_thread:true,metadata_thp:always,dirty_decay_ms:100000,muzzy_decay_ms:100000,narenas:1,abort_conf:true"

(in practice this did not make a big difference).

On a M2 Max Macbook Pro (12 CPU cores, 96 GB RAM) we ran the bench using

cargo test --release --no-default-features --features "halo2-axiom, mimalloc" -- --nocapture bench_secp256k1_ecdsa

(the performance of "mimalloc" vs "jemallocator" was similar).

The other columns provide information about the PLONKish arithmetization.

kNum AdviceNum Lookup AdviceNum FixedProof Time (M2 Max)Proof Time (r6a.8xl)Proof Time (r6g.8xl)
112915343.5s7.3s7.2s
121392422.6s3.3s5.3s
13681212.2s2.6s4.7s
1434612.1s2.4s4.5s
1517311.98s2.28s4.5s
168212.3s2.5s5.2s
174112.7s2.9s6s
182114.4s4.7s9.5s
191117.6s7.6s16s

The r6a has a higher clock speed than the r6g.

BN254 Pairing

We provide benchmarks of the optimal Ate pairing for BN254 on several different machines. All machines only use CPUs.

On AWS EC2 instances r6a.8xl (AMD, x86) and r6g.8xl (Graviton, arm64), both with 32 CPU cores, 256 GB RAM, the bench is run using

cargo test --release --no-default-features --features "halo2-axiom, jemallocator" -- --nocapture bench_pairing

To optimize memory allocation to prioritize CPU utilization, we tune jemallocator with

export JEMALLOC_SYS_WITH_MALLOC_CONF="background_thread:true,metadata_thp:always,dirty_decay_ms:100000,muzzy_decay_ms:100000,narenas:1,abort_conf:true"

(in practice this did not make a big difference).

On a M2 Max Macbook Pro (12 CPU cores, 96 GB RAM) we ran the bench using

cargo test --release --no-default-features --features "halo2-axiom, mimalloc" -- --nocapture bench_pairing

(the performance of "mimalloc" vs "jemallocator" was similar).

The other columns provide information about the PLONKish arithmetization.

kNum AdviceNum Lookup AdviceNum FixedProof Time (M2 Max)Proof Time (r6a.8xl)Proof Time (r6g.8xl)
1421127111.8s16.9s24.8s
1510514110.4s12.7s23.6s
1650619.5s10.96s21.6s
1725319.7s11.2s22.7s
18132111.9s13.5s27.3s
1961114.8s15.3s30.6s
2031123.7s23.8s48.1s
2121140.3s40.8s82.5s
2211169.1s66.9s135s

The r6a has a higher clock speed than the r6g. We hypothesize that the Apple Silicon integrated memory leads to the faster performance on the M2 Max.

BN254 MSM

We provide benchmarks of multi-scalar multiplication (MSM, multi-exp) with a batch size of 100 for BN254.

On a M2 Max Macbook Pro (12 CPU cores, 96 GB RAM) we ran the bench using

cargo test --release --no-default-features --features "halo2-axiom, mimalloc" -- --nocapture bench_msm
kNum AdviceNum Lookup AdviceNum FixedProof Time (M2 Max)
178411127.8s
18426129.95s
19203132.6s
20112141.3s
2161151.9s