diff --git a/README.md b/README.md new file mode 100644 index 00000000..34a27e8b --- /dev/null +++ b/README.md @@ -0,0 +1,277 @@ +# halo2-lib + +This repository aims to provide basic primitives for writing zero-knowledge proof circuits using the [Halo 2](https://zcash.github.io/halo2/) proving stack. + +## Getting Started + +For a brief introduction to zero-knowledge proofs (ZK), see this [doc](https://docs.axiom.xyz/zero-knowledge-proofs/introduction-to-zk). + +Halo 2 is written in Rust, so you need to [install](https://www.rust-lang.org/tools/install) Rust to use this library: + +```bash +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +``` + +Clone this repo and start off in the `halo2-lib` directory. + +```bash +git clone https://github.com/axiom-crypto/halo2-lib.git +cd halo2-lib +``` + +## halo2-base + +This crate provides an additional API for writing circuits in Halo 2 using our [simple vertical gate](https://docs.axiom.xyz/zero-knowledge-proofs/getting-started-with-halo2#halo2-lib). It also provides basic functions built using this API. The provided methods can be found in [`GateInstructions`](https://axiom-crypto.github.io/halo2-lib/halo2_base/gates/trait.GateInstructions.html) and [`RangeInstructions`](https://axiom-crypto.github.io/halo2-lib/halo2_base/gates/trait.RangeInstructions.html). The latter are operations that require using a lookup table for range checks. + +- Read the [Rust docs](https://axiom-crypto.github.io/halo2-lib/halo2_base/index.html) for this crate. +- To get started with Halo 2 and to learn how to build using the `halo2-base` API, see the [Getting Started](https://docs.axiom.xyz/zero-knowledge-proofs/getting-started-with-halo2) guide. + +To run some basic tests, run the following command: + +```bash +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: + +```bash +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). + +- [Rust docs](https://axiom-crypto.github.io/halo2-lib/halo2_ecc/index.html) + +### 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. + +- The "halo2-axiom" feature uses our [`halo2_proofs`](https://github.com/axiom-crypto/halo2) which is a fork of the [PSE one](https://github.com/privacy-scaling-explorations/halo2) which we have slightly optimized for proving speed. +- The "halo2-pse" feature uses the Privacy Scaling Explorations [`halo2_proofs`](https://github.com/privacy-scaling-explorations/halo2) which is the most stable and has the most reviewers. + +We guarantee that the proofs generated by the two forks are identical. + +#### Memory allocator + +The "jemallocator" feature uses the [jemallocator](https://crates.io/crates/jemallocator) crate for memory allocation. +You can turn it off to use the system allocator. Or use feature "mimalloc" to use the [mimalloc](https://crates.io/crates/mimalloc) crate. We have found the performance of these allocators heavily depends on what machine you are running on. + +### Modules + +- `bigint`: Provides support for optimized big integer arithmetic in ZK. +- `fields`: Provides common functions for prime field arithmetic, optimized for prime fields that are larger than the scalar field used in the proving system. + - `fp2`: Field operations over certain quadratic extension fields. + - `fp12`: Field operations over certain degree `12` extension fields (designed with BN254 and BLS12-381 in mind). +- `ecc`: Library of elliptic curve cryptographic primitives, currently for short Weierstrass curves over base fields compatible with `fields` module (in particular field extension are allowed). + - Elliptic curve addition and doubling. + - Scalar multiplication and multiscalar multiplication (MSM, multiexp). Implementations are ZK-optimized, using windowed methods and Pippenger's algorithm when appropriate. + - ECDSA signature verification. +- `secp256k1`: Specialization of the `ecc` module for the secp256k1 curve. + - `test_secp256k1_ecdsa` and `bench_secp256k1_ecdsa` show how to implement ECDSA signature verification for secp256k1. (More details below.) +- `bn254`: Specialization of the `ecc` module for the BN254 curve. + - `final_exp` and `pairing` modules together implement the optimal Ate pairing for BN254 in ZK. The implementation has been optimized for the specifics of BN curves, but can be easily adapted to BLS curves (coming soon!). + +### 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](https://docs.axiom.xyz/axiom-architecture/how-axiom-works/kzg-trusted-setup). + +Tests can be run in the same way as in the previous [section](#halo2-base). The available commands are: + +```bash +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](https://docs.axiom.xyz/zero-knowledge-proofs/getting-started-with-halo2#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): +| Test | Config File | +| --- | --- | +| `test_secp256k1_ecdsa` | `src/secp256k1/configs/ecdsa_circuit.config` | +| `test_ec_add` | `src/bn254/configs/ec_add_circuit.config` | +| `test_fixed_base_msm` | `src/bn254/configs/fixed_msm_circuit.config` | +| `test_msm` | `src/bn254/configs/msm_circuit.config` | +| `test_pairing` | `src/bn254/configs/pairing_circuit.config` | + +### Benchmarks + +We have tests that are actually benchmarks using the production Halo2 prover. +As mentioned [above](#Configurable-Circuits), 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: + +```bash +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: +| Benchmark | Config File | Results File | +| --- | --- | --- | +| `bench_secp256k1_ecdsa` | `src/secp256k1/configs/bench_ecdsa.config` | `src/secp256k1/results/ecdsa_bench.csv` | +| `bench_ec_add` | `src/bn254/configs/bench_ec_add.config` | `src/bn254/results/ec_add_bench.csv` | +| `bench_fixed_base_msm` | `src/bn254/configs/bench_fixed_msm.config` | `src/bn254/results/fixed_msm_bench.csv` | +| `bench_msm` | `src/bn254/configs/bench_msm.config` | `src/bn254/results/msm_bench.csv` | +| `bench_pairing` | `src/bn254/configs/bench_pairing.config` | `src/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: + +```bash +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](https://github.com/jemalloc/jemalloc/blob/dev/TUNING.md) with + +```bash +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](https://docs.axiom.xyz/zero-knowledge-proofs/getting-started-with-halo2#plonkish-arithmetization). + +| `k` | Num Advice | Num Lookup Advice | Num Fixed | Proof Time (M2 Max) | Proof Time (r6a.8xl) | Proof Time (r6g.8xl) | +| --- | ---------- | ----------------- | --------- | ------------------- | -------------------- | -------------------- | +| 11 | 291 | 53 | 4 | 3.5s | 7.3s | 7.2s | +| 12 | 139 | 24 | 2 | 2.6s | 3.3s | 5.3s | +| 13 | 68 | 12 | 1 | 2.2s | 2.6s | 4.7s | +| 14 | 34 | 6 | 1 | 2.1s | 2.4s | 4.5s | +| 15 | 17 | 3 | 1 | `1.98s` ⚡ | 2.28s | 4.5s | +| 16 | 8 | 2 | 1 | 2.3s | 2.5s | 5.2s | +| 17 | 4 | 1 | 1 | 2.7s | 2.9s | 6s | +| 18 | 2 | 1 | 1 | 4.4s | 4.7s | 9.5s | +| 19 | 1 | 1 | 1 | 7.6s | 7.6s | 16s | + +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](https://github.com/jemalloc/jemalloc/blob/dev/TUNING.md) with + +```bash +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](https://docs.axiom.xyz/zero-knowledge-proofs/getting-started-with-halo2#plonkish-arithmetization). + +| `k` | Num Advice | Num Lookup Advice | Num Fixed | Proof Time (M2 Max) | Proof Time (r6a.8xl) | Proof Time (r6g.8xl) | +| --- | ---------- | ----------------- | --------- | ------------------- | -------------------- | -------------------- | +| 14 | 211 | 27 | 1 | 11.8s | 16.9s | 24.8s | +| 15 | 105 | 14 | 1 | 10.4s | 12.7s | 23.6s | +| 16 | 50 | 6 | 1 | `9.5s` ⚡ | 10.96s | 21.6s | +| 17 | 25 | 3 | 1 | 9.7s | 11.2s | 22.7s | +| 18 | 13 | 2 | 1 | 11.9s | 13.5s | 27.3s | +| 19 | 6 | 1 | 1 | 14.8s | 15.3s | 30.6s | +| 20 | 3 | 1 | 1 | 23.7s | 23.8s | 48.1s | +| 21 | 2 | 1 | 1 | 40.3s | 40.8s | 82.5s | +| 22 | 1 | 1 | 1 | 69.1s | 66.9s | 135s | + +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 +``` + +| `k` | Num Advice | Num Lookup Advice | Num Fixed | Proof Time (M2 Max) | +| --- | ---------- | ----------------- | --------- | ------------------- | +| 17 | 84 | 11 | 1 | `27.8s` ⚡ | +| 18 | 42 | 6 | 1 | 29.95s | +| 19 | 20 | 3 | 1 | 32.6s | +| 20 | 11 | 2 | 1 | 41.3s | +| 21 | 6 | 1 | 1 | 51.9s | diff --git a/halo2-base/Cargo.toml b/halo2-base/Cargo.toml index cf9ededf..a12545b6 100644 --- a/halo2-base/Cargo.toml +++ b/halo2-base/Cargo.toml @@ -15,7 +15,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" # Use Axiom's custom halo2 monorepo for faster proving when feature = "halo2-axiom" is on -halo2_proofs_axiom = { git = "https://github.com/axiom-crypto/halo2.git", tag = "v2023_01_17", package = "halo2_proofs", optional = true } +halo2_proofs_axiom = { git = "https://github.com/axiom-crypto/halo2.git", branch = "axiom/dev", package = "halo2_proofs", optional = true } # Use PSE halo2 and halo2curves for compatibility when feature = "halo2-pse" is on halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_01_20", optional = true } diff --git a/halo2-base/src/gates/builder.rs b/halo2-base/src/gates/builder.rs index 9771aa15..d58c0d2f 100644 --- a/halo2-base/src/gates/builder.rs +++ b/halo2-base/src/gates/builder.rs @@ -168,7 +168,7 @@ impl GateThreadBuilder { let column = basic_gate.value; let value = if use_unknown { Value::unknown() } else { Value::known(advice) }; #[cfg(feature = "halo2-axiom")] - let cell = region.assign_advice(column, row_offset, value); + let cell = *region.assign_advice(column, row_offset, value).cell(); #[cfg(not(feature = "halo2-axiom"))] let cell = region.assign_advice(|| "", column, row_offset, || value).unwrap().cell(); @@ -188,7 +188,7 @@ impl GateThreadBuilder { #[cfg(feature = "halo2-axiom")] { let ncell = region.assign_advice(column, row_offset, value); - region.constrain_equal(&ncell, &cell); + region.constrain_equal(ncell.cell(), &cell); } #[cfg(not(feature = "halo2-axiom"))] { @@ -270,7 +270,7 @@ impl GateThreadBuilder { #[cfg(feature = "halo2-axiom")] { let bcell = region.assign_advice(column, lookup_offset, value); - region.constrain_equal(&acell, &bcell); + region.constrain_equal(&acell, bcell.cell()); } #[cfg(not(feature = "halo2-axiom"))] { @@ -315,21 +315,24 @@ pub fn assign_threads_in( let mut lookup_advice = lookup_advice.iter(); let mut lookup_column = lookup_advice.next(); for ctx in threads { - for advice in ctx.cells_to_lookup { - if lookup_offset >= config.max_rows { - lookup_offset = 0; - lookup_column = lookup_advice.next(); - } - let value = advice.value; - let lookup_column = *lookup_column.unwrap(); - #[cfg(feature = "halo2-axiom")] - region.assign_advice(lookup_column, lookup_offset, Value::known(value)); - #[cfg(not(feature = "halo2-axiom"))] - region - .assign_advice(|| "", lookup_column, lookup_offset, || Value::known(value)) - .unwrap(); + // if lookup_column is empty, that means there should be a single advice column and it has lookup enabled, so we don't need to copy to special lookup advice columns + if lookup_column.is_some() { + for advice in ctx.cells_to_lookup { + if lookup_offset >= config.max_rows { + lookup_offset = 0; + lookup_column = lookup_advice.next(); + } + let value = advice.value; + let lookup_column = *lookup_column.unwrap(); + #[cfg(feature = "halo2-axiom")] + region.assign_advice(lookup_column, lookup_offset, Value::known(value)); + #[cfg(not(feature = "halo2-axiom"))] + region + .assign_advice(|| "", lookup_column, lookup_offset, || Value::known(value)) + .unwrap(); - lookup_offset += 1; + lookup_offset += 1; + } } for advice in ctx.advice { #[cfg(feature = "halo2-axiom")] diff --git a/halo2-ecc/configs/bn254/bench_pairing.config b/halo2-ecc/configs/bn254/bench_pairing.config index 4e79bdd4..273d096c 100644 --- a/halo2-ecc/configs/bn254/bench_pairing.config +++ b/halo2-ecc/configs/bn254/bench_pairing.config @@ -1,9 +1,9 @@ -{"strategy":"Simple","degree":14,"num_advice":221,"num_lookup_advice":27,"num_fixed":1,"lookup_bits":13,"limb_bits":91,"num_limbs":3} -{"strategy":"Simple","degree":15,"num_advice":106,"num_lookup_advice":14,"num_fixed":1,"lookup_bits":14,"limb_bits":90,"num_limbs":3} -{"strategy":"Simple","degree":16,"num_advice":51,"num_lookup_advice":6,"num_fixed":1,"lookup_bits":15,"limb_bits":90,"num_limbs":3} +{"strategy":"Simple","degree":14,"num_advice":211,"num_lookup_advice":27,"num_fixed":1,"lookup_bits":13,"limb_bits":91,"num_limbs":3} +{"strategy":"Simple","degree":15,"num_advice":105,"num_lookup_advice":14,"num_fixed":1,"lookup_bits":14,"limb_bits":90,"num_limbs":3} +{"strategy":"Simple","degree":16,"num_advice":50,"num_lookup_advice":6,"num_fixed":1,"lookup_bits":15,"limb_bits":90,"num_limbs":3} {"strategy":"Simple","degree":17,"num_advice":25,"num_lookup_advice":3,"num_fixed":1,"lookup_bits":16,"limb_bits":88,"num_limbs":3} {"strategy":"Simple","degree":18,"num_advice":13,"num_lookup_advice":2,"num_fixed":1,"lookup_bits":17,"limb_bits":88,"num_limbs":3} {"strategy":"Simple","degree":19,"num_advice":6,"num_lookup_advice":1,"num_fixed":1,"lookup_bits":18,"limb_bits":90,"num_limbs":3} -{"strategy":"Simple","degree":20,"num_advice":4,"num_lookup_advice":1,"num_fixed":1,"lookup_bits":19,"limb_bits":88,"num_limbs":3} +{"strategy":"Simple","degree":20,"num_advice":3,"num_lookup_advice":1,"num_fixed":1,"lookup_bits":19,"limb_bits":88,"num_limbs":3} {"strategy":"Simple","degree":21,"num_advice":2,"num_lookup_advice":1,"num_fixed":1,"lookup_bits":20,"limb_bits":88,"num_limbs":3} {"strategy":"Simple","degree":22,"num_advice":1,"num_lookup_advice":1,"num_fixed":1,"lookup_bits":21,"limb_bits":88,"num_limbs":3} diff --git a/halo2-ecc/configs/secp256k1/bench_ecdsa.config b/halo2-ecc/configs/secp256k1/bench_ecdsa.config index 9d2fee7c..07591eae 100644 --- a/halo2-ecc/configs/secp256k1/bench_ecdsa.config +++ b/halo2-ecc/configs/secp256k1/bench_ecdsa.config @@ -1,9 +1,9 @@ {"strategy":"Simple","degree":19,"num_advice":1,"num_lookup_advice":1,"num_fixed":1,"lookup_bits":18,"limb_bits":88,"num_limbs":3} {"strategy":"Simple","degree":18,"num_advice":2,"num_lookup_advice":1,"num_fixed":1,"lookup_bits":17,"limb_bits":88,"num_limbs":3} {"strategy":"Simple","degree":17,"num_advice":4,"num_lookup_advice":1,"num_fixed":1,"lookup_bits":16,"limb_bits":88,"num_limbs":3} -{"strategy":"Simple","degree":16,"num_advice":9,"num_lookup_advice":2,"num_fixed":1,"lookup_bits":15,"limb_bits":90,"num_limbs":3} +{"strategy":"Simple","degree":16,"num_advice":8,"num_lookup_advice":2,"num_fixed":1,"lookup_bits":15,"limb_bits":90,"num_limbs":3} {"strategy":"Simple","degree":15,"num_advice":17,"num_lookup_advice":3,"num_fixed":1,"lookup_bits":14,"limb_bits":90,"num_limbs":3} -{"strategy":"Simple","degree":14,"num_advice":36,"num_lookup_advice":6,"num_fixed":1,"lookup_bits":13,"limb_bits":91,"num_limbs":3} -{"strategy":"Simple","degree":13,"num_advice":71,"num_lookup_advice":12,"num_fixed":1,"lookup_bits":12,"limb_bits":88,"num_limbs":3} -{"strategy":"Simple","degree":12,"num_advice":142,"num_lookup_advice":24,"num_fixed":2,"lookup_bits":11,"limb_bits":88,"num_limbs":3} -{"strategy":"Simple","degree":11,"num_advice":305,"num_lookup_advice":53,"num_fixed":4,"lookup_bits":10,"limb_bits":88,"num_limbs":3} \ No newline at end of file +{"strategy":"Simple","degree":14,"num_advice":34,"num_lookup_advice":6,"num_fixed":1,"lookup_bits":13,"limb_bits":91,"num_limbs":3} +{"strategy":"Simple","degree":13,"num_advice":68,"num_lookup_advice":12,"num_fixed":1,"lookup_bits":12,"limb_bits":88,"num_limbs":3} +{"strategy":"Simple","degree":12,"num_advice":139,"num_lookup_advice":24,"num_fixed":2,"lookup_bits":11,"limb_bits":88,"num_limbs":3} +{"strategy":"Simple","degree":11,"num_advice":291,"num_lookup_advice":53,"num_fixed":4,"lookup_bits":10,"limb_bits":88,"num_limbs":3} \ No newline at end of file diff --git a/halo2-ecc/src/bigint/big_is_zero.rs b/halo2-ecc/src/bigint/big_is_zero.rs index 5014d194..d6b03cd5 100644 --- a/halo2-ecc/src/bigint/big_is_zero.rs +++ b/halo2-ecc/src/bigint/big_is_zero.rs @@ -1,7 +1,5 @@ use super::{CRTInteger, OverflowInteger}; use halo2_base::{gates::GateInstructions, utils::ScalarField, AssignedValue, Context}; -use num_bigint::BigInt; -use num_traits::Zero; /// assume you know that the limbs of `a` are all in [0, 2^{a.max_limb_bits}) pub fn positive( @@ -40,7 +38,6 @@ pub fn crt( ctx: &mut Context, a: &CRTInteger, ) -> AssignedValue { - debug_assert_eq!(a.value, BigInt::zero()); let out_trunc = assign::(gate, ctx, &a.truncation); let out_native = gate.is_zero(ctx, a.native); gate.and(ctx, out_trunc, out_native) diff --git a/halo2-ecc/src/bigint/mod.rs b/halo2-ecc/src/bigint/mod.rs index a8c93bd2..f7f2886c 100644 --- a/halo2-ecc/src/bigint/mod.rs +++ b/halo2-ecc/src/bigint/mod.rs @@ -25,19 +25,17 @@ pub mod sub; pub mod sub_no_carry; #[derive(Clone, Debug, PartialEq)] +#[derive(Default)] pub enum BigIntStrategy { // use existing gates + #[default] Simple, // vertical custom gates of length 4 for dot product between an unknown vector and a constant vector, both of length 3 // we restrict to gate of length 4 since this uses the same set of evaluation points Rotation(0..=3) as our simple gate // CustomVerticalShort, } -impl Default for BigIntStrategy { - fn default() -> Self { - BigIntStrategy::Simple - } -} + #[derive(Clone, Debug)] pub struct OverflowInteger { diff --git a/halo2-ecc/src/bn254/tests/pairing.rs b/halo2-ecc/src/bn254/tests/pairing.rs index e8194f58..703736b7 100644 --- a/halo2-ecc/src/bn254/tests/pairing.rs +++ b/halo2-ecc/src/bn254/tests/pairing.rs @@ -111,7 +111,7 @@ fn bench_pairing() -> Result<(), Box> { let results_path = "results/bn254/pairing_bench.csv"; let mut fs_results = File::create(results_path).unwrap(); - writeln!(fs_results, "degree,num_advice,num_lookup,num_fixed,lookup_bits,limb_bits,num_limbs,vk_size,proof_time,proof_size,verify_time")?; + writeln!(fs_results, "degree,num_advice,num_lookup,num_fixed,lookup_bits,limb_bits,num_limbs,proof_time,proof_size,verify_time")?; let bench_params_reader = BufReader::new(bench_params_file); for line in bench_params_reader.lines() { diff --git a/halo2-ecc/src/ecc/fixed_base.rs b/halo2-ecc/src/ecc/fixed_base.rs index 440f6993..c69a4f31 100644 --- a/halo2-ecc/src/ecc/fixed_base.rs +++ b/halo2-ecc/src/ecc/fixed_base.rs @@ -123,8 +123,8 @@ where .flat_map(|scalar_chunk| chip.gate().num_to_bits(ctx, scalar_chunk, max_bits)) .collect::>(); - let cached_point_window_rev = cached_points.chunks(1usize << window_bits).into_iter().rev(); - let bit_window_rev = bits.chunks(window_bits).into_iter().rev(); + let cached_point_window_rev = cached_points.chunks(1usize << window_bits).rev(); + let bit_window_rev = bits.chunks(window_bits).rev(); let mut curr_point = None; // `is_started` is just a way to deal with if `curr_point` is actually identity let mut is_started = ctx.load_zero(); @@ -228,12 +228,11 @@ where let sm = cached_points .chunks(cached_points.len() / points.len()) - .into_iter() - .zip(bits.chunks(total_bits).into_iter()) + .zip(bits.chunks(total_bits)) .map(|(cached_points, bits)| { let cached_point_window_rev = - cached_points.chunks(1usize << window_bits).into_iter().rev(); - let bit_window_rev = bits.chunks(window_bits).into_iter().rev(); + cached_points.chunks(1usize << window_bits).rev(); + let bit_window_rev = bits.chunks(window_bits).rev(); let mut curr_point = None; // `is_started` is just a way to deal with if `curr_point` is actually identity let mut is_started = ctx.load_zero(); diff --git a/halo2-ecc/src/ecc/mod.rs b/halo2-ecc/src/ecc/mod.rs index 6b1c6655..1f83042d 100644 --- a/halo2-ecc/src/ecc/mod.rs +++ b/halo2-ecc/src/ecc/mod.rs @@ -526,8 +526,7 @@ where } for (cached_points, rounded_bits) in cached_points .chunks(cache_size) - .into_iter() - .zip(rounded_bits.chunks(rounded_bitlen).into_iter()) + .zip(rounded_bits.chunks(rounded_bitlen)) { let add_point = ec_select_from_bits::( chip, diff --git a/halo2-ecc/src/ecc/pippenger.rs b/halo2-ecc/src/ecc/pippenger.rs index 11ada696..fe481dde 100644 --- a/halo2-ecc/src/ecc/pippenger.rs +++ b/halo2-ecc/src/ecc/pippenger.rs @@ -91,7 +91,7 @@ where let mut bucket = Vec::with_capacity(1 << c); let mut rand_point = rand_base.clone(); - for (round, points_clump) in points.chunks(c).into_iter().enumerate() { + for (round, points_clump) in points.chunks(c).enumerate() { // compute all possible multi-products of elements in points[round * c .. round * (c+1)] // for later addition collision-prevension, we need a different random point per round diff --git a/halo2-ecc/src/lib.rs b/halo2-ecc/src/lib.rs index 55df690a..10da56bc 100644 --- a/halo2-ecc/src/lib.rs +++ b/halo2-ecc/src/lib.rs @@ -9,7 +9,7 @@ pub mod ecc; pub mod fields; pub mod bn254; -//pub mod secp256k1; +pub mod secp256k1; pub use halo2_base; pub(crate) use halo2_base::halo2_proofs; diff --git a/halo2-ecc/src/secp256k1/mod.rs b/halo2-ecc/src/secp256k1/mod.rs index c81e136f..ca4528e4 100644 --- a/halo2-ecc/src/secp256k1/mod.rs +++ b/halo2-ecc/src/secp256k1/mod.rs @@ -1,14 +1,12 @@ -use crate::halo2_proofs::halo2curves::secp256k1::Fp; +use crate::halo2_proofs::halo2curves::secp256k1::{Fp, Fq}; use crate::ecc; use crate::fields::fp; -#[allow(dead_code)] -type FpChip = fp::FpConfig; -#[allow(dead_code)] -type Secp256k1Chip = ecc::EccChip>; -#[allow(dead_code)] -const SECP_B: u64 = 7; +pub type FpChip<'range, F> = fp::FpChip<'range, F, Fp>; +pub type FqChip<'range, F> = fp::FpChip<'range, F, Fq>; +pub type Secp256k1Chip<'chip, F> = ecc::EccChip<'chip, F, FpChip<'chip, F>>; +pub const SECP_B: u64 = 7; #[cfg(test)] mod tests; diff --git a/halo2-ecc/src/secp256k1/tests/ecdsa.rs b/halo2-ecc/src/secp256k1/tests/ecdsa.rs index 3a91befb..739bffc7 100644 --- a/halo2-ecc/src/secp256k1/tests/ecdsa.rs +++ b/halo2-ecc/src/secp256k1/tests/ecdsa.rs @@ -1,32 +1,43 @@ #![allow(non_snake_case)] -use ark_std::{end_timer, start_timer}; -use halo2_base::{utils::PrimeField, SKIP_FIRST_PASS}; -use serde::{Deserialize, Serialize}; -use std::fs::File; -use std::marker::PhantomData; -use std::{env::var, io::Write}; - +use crate::fields::FpStrategy; use crate::halo2_proofs::{ arithmetic::CurveAffine, - circuit::*, dev::MockProver, halo2curves::bn256::{Bn256, Fr, G1Affine}, halo2curves::secp256k1::{Fp, Fq, Secp256k1Affine}, plonk::*, - poly::commitment::{Params, ParamsProver}, + poly::commitment::ParamsProver, transcript::{Blake2bRead, Blake2bWrite, Challenge255}, }; -use rand_core::OsRng; - -use crate::fields::fp::FpConfig; -use crate::secp256k1::FpChip; +use crate::halo2_proofs::{ + poly::kzg::{ + commitment::KZGCommitmentScheme, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + strategy::SingleStrategy, + }, + transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, +}; +use crate::secp256k1::{FpChip, FqChip}; use crate::{ ecc::{ecdsa::ecdsa_verify_no_pubkey_check, EccChip}, - fields::{fp::FpStrategy, FieldChip}, + fields::{FieldChip, PrimeField}, }; +use ark_std::{end_timer, start_timer}; +use halo2_base::gates::builder::{ + CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, +}; +use halo2_base::gates::RangeChip; +use halo2_base::utils::fs::gen_srs; use halo2_base::utils::{biguint_to_fe, fe_to_biguint, modulus}; +use halo2_base::Context; +use rand_core::OsRng; +use serde::{Deserialize, Serialize}; +use std::fs::File; +use std::io::BufReader; +use std::io::Write; +use std::{fs, io::BufRead}; -#[derive(Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] struct CircuitParams { strategy: FpStrategy, degree: u32, @@ -38,272 +49,121 @@ struct CircuitParams { num_limbs: usize, } -pub struct ECDSACircuit { - pub r: Option, - pub s: Option, - pub msghash: Option, - pub pk: Option, - pub G: Secp256k1Affine, - pub _marker: PhantomData, -} -impl Default for ECDSACircuit { - fn default() -> Self { - Self { - r: None, - s: None, - msghash: None, - pk: None, - G: Secp256k1Affine::generator(), - _marker: PhantomData, - } - } -} - -impl Circuit for ECDSACircuit { - type Config = FpChip; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self::default() - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let path = var("ECDSA_CONFIG") - .unwrap_or_else(|_| "./src/secp256k1/configs/ecdsa_circuit.config".to_string()); - let params: CircuitParams = serde_json::from_reader( - File::open(&path).unwrap_or_else(|_| panic!("{path:?} file should exist")), - ) - .unwrap(); - - FpChip::::configure( - meta, - params.strategy, - &[params.num_advice], - &[params.num_lookup_advice], - params.num_fixed, - params.lookup_bits, - params.limb_bits, - params.num_limbs, - modulus::(), - 0, - params.degree as usize, - ) - } - - fn synthesize( - &self, - fp_chip: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - fp_chip.range.load_lookup_table(&mut layouter)?; - - let limb_bits = fp_chip.limb_bits; - let num_limbs = fp_chip.num_limbs; - let num_fixed = fp_chip.range.gate.constants.len(); - let lookup_bits = fp_chip.range.lookup_bits; - let num_advice = fp_chip.range.gate.num_advice; - - let mut first_pass = SKIP_FIRST_PASS; - // ECDSA verify - layouter.assign_region( - || "ECDSA", - |region| { - if first_pass { - first_pass = false; - return Ok(()); - } - - let mut aux = fp_chip.new_context(region); - let ctx = &mut aux; - - let (r_assigned, s_assigned, m_assigned) = { - let fq_chip = FpConfig::::construct(fp_chip.range.clone(), limb_bits, num_limbs, modulus::()); - - let m_assigned = fq_chip.load_private( - ctx, - FpConfig::::fe_to_witness(&self.msghash.map_or(Value::unknown(), Value::known)), - ); - - let r_assigned = fq_chip - .load_private(ctx, FpConfig::::fe_to_witness(&self.r.map_or(Value::unknown(), Value::known))); - let s_assigned = fq_chip - .load_private(ctx, FpConfig::::fe_to_witness(&self.s.map_or(Value::unknown(), Value::known))); - (r_assigned, s_assigned, m_assigned) - }; - - let ecc_chip = EccChip::>::construct(fp_chip.clone()); - let pk_assigned = ecc_chip - .load_private(ctx, (self.pk.map_or(Value::unknown(), |pt| Value::known(pt.x)), self.pk.map_or(Value::unknown(), |pt| Value::known(pt.y)))); - // test ECDSA - let ecdsa = ecdsa_verify_no_pubkey_check::( - &ecc_chip.field_chip, - ctx, - &pk_assigned, - &r_assigned, - &s_assigned, - &m_assigned, - 4, - 4, - ); - - // IMPORTANT: this copies cells to the lookup advice column to perform range check lookups - // This is not optional. - fp_chip.finalize(ctx); - - #[cfg(feature = "display")] - if self.r.is_some() { - println!("ECDSA res {ecdsa:?}"); - - ctx.print_stats(&["Range"]); - } - Ok(()) - }) - } +fn ecdsa_test( + ctx: &mut Context, + params: CircuitParams, + r: Fq, + s: Fq, + msghash: Fq, + pk: Secp256k1Affine, +) { + std::env::set_var("LOOKUP_BITS", params.lookup_bits.to_string()); + let range = RangeChip::::default(params.lookup_bits); + let fp_chip = FpChip::::new(&range, params.limb_bits, params.num_limbs); + let fq_chip = FqChip::::new(&range, params.limb_bits, params.num_limbs); + + let [m, r, s] = + [msghash, r, s].map(|x| fq_chip.load_private(ctx, FqChip::::fe_to_witness(&x))); + + let ecc_chip = EccChip::>::new(&fp_chip); + let pk = ecc_chip.load_private(ctx, (pk.x, pk.y)); + // test ECDSA + let res = ecdsa_verify_no_pubkey_check::( + &fp_chip, ctx, &pk, &r, &s, &m, 4, 4, + ); + assert_eq!(res.value(), &F::one()); } -#[cfg(test)] -#[test] -fn test_secp256k1_ecdsa() { - let mut folder = std::path::PathBuf::new(); - folder.push("./src/secp256k1"); - folder.push("configs/ecdsa_circuit.config"); - let params_str = std::fs::read_to_string(folder.as_path()) - .expect("src/secp256k1/configs/ecdsa_circuit.config file should exist"); - let params: CircuitParams = serde_json::from_str(params_str.as_str()).unwrap(); - let K = params.degree; - - // generate random pub key and sign random message - let G = Secp256k1Affine::generator(); +fn random_ecdsa_circuit( + params: CircuitParams, + stage: CircuitBuilderStage, + break_points: Option, +) -> RangeCircuitBuilder { + let mut builder = match stage { + CircuitBuilderStage::Mock => GateThreadBuilder::mock(), + CircuitBuilderStage::Prover => GateThreadBuilder::prover(), + CircuitBuilderStage::Keygen => GateThreadBuilder::keygen(), + }; let sk = ::ScalarExt::random(OsRng); - let pubkey = Secp256k1Affine::from(G * sk); + let pubkey = Secp256k1Affine::from(Secp256k1Affine::generator() * sk); let msg_hash = ::ScalarExt::random(OsRng); let k = ::ScalarExt::random(OsRng); let k_inv = k.invert().unwrap(); - let r_point = Secp256k1Affine::from(G * k).coordinates().unwrap(); + let r_point = Secp256k1Affine::from(Secp256k1Affine::generator() * k).coordinates().unwrap(); let x = r_point.x(); let x_bigint = fe_to_biguint(x); let r = biguint_to_fe::(&(x_bigint % modulus::())); let s = k_inv * (msg_hash + (r * sk)); - let circuit = ECDSACircuit:: { - r: Some(r), - s: Some(s), - msghash: Some(msg_hash), - pk: Some(pubkey), - G, - _marker: PhantomData, - }; + let start0 = start_timer!(|| format!("Witness generation for circuit in {stage:?} stage")); + ecdsa_test(builder.main(0), params, r, s, msg_hash, pubkey); - let prover = MockProver::run(K, &circuit, vec![]).unwrap(); - //prover.assert_satisfied(); - assert_eq!(prover.verify(), Ok(())); + let circuit = match stage { + CircuitBuilderStage::Mock => { + builder.config(params.degree as usize, Some(20)); + RangeCircuitBuilder::mock(builder) + } + CircuitBuilderStage::Keygen => { + builder.config(params.degree as usize, Some(20)); + RangeCircuitBuilder::keygen(builder) + } + CircuitBuilderStage::Prover => RangeCircuitBuilder::prover(builder, break_points.unwrap()), + }; + end_timer!(start0); + circuit } -#[cfg(test)] #[test] -fn bench_secp256_ecdsa() -> Result<(), Box> { - /* - // Parameters for use with FpStrategy::CustomVerticalCRT - const DEGREE: [u32; 9] = [19, 18, 17, 16, 15, 14, 13, 12, 11]; - const NUM_ADVICE: [usize; 9] = [1, 2, 3, 6, 12, 25, 49, 98, 201]; - const NUM_LOOKUP: [usize; 9] = [0, 1, 1, 2, 3, 6, 12, 24, 53]; - const NUM_FIXED: [usize; 9] = [1, 1, 1, 1, 1, 1, 1, 2, 5]; - const LOOKUP_BITS: [usize; 9] = [18, 17, 16, 15, 14, 13, 12, 11, 10]; - const LIMB_BITS: [usize; 9] = [88, 88, 88, 88, 88, 88, 88, 88, 88]; - */ - - use halo2_base::utils::fs::gen_srs; - - use crate::halo2_proofs::{ - poly::kzg::{ - commitment::{KZGCommitmentScheme, ParamsKZG}, - multiopen::{ProverSHPLONK, VerifierSHPLONK}, - strategy::SingleStrategy, - }, - transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, - }; - use std::{env::set_var, fs, io::BufRead}; +fn test_secp256k1_ecdsa() { + let path = "configs/secp256k1/ecdsa_circuit.config"; + let params: CircuitParams = serde_json::from_reader( + File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")), + ) + .unwrap(); + + let circuit = random_ecdsa_circuit(params, CircuitBuilderStage::Mock, None); + MockProver::run(params.degree, &circuit, vec![]).unwrap().assert_satisfied(); +} +#[test] +fn bench_secp256k1_ecdsa() -> Result<(), Box> { let mut rng = OsRng; - - let mut folder = std::path::PathBuf::new(); - folder.push("./src/secp256k1"); - - folder.push("configs/bench_ecdsa.config"); - let bench_params_file = std::fs::File::open(folder.as_path()).unwrap(); - folder.pop(); - folder.pop(); - - folder.push("results/ecdsa_bench.csv"); - let mut fs_results = std::fs::File::create(folder.as_path()).unwrap(); - folder.pop(); - folder.pop(); - writeln!(fs_results, "degree,num_advice,num_lookup,num_fixed,lookup_bits,limb_bits,num_limbs,vk_size,proof_time,proof_size,verify_time")?; - folder.push("data"); - if !folder.is_dir() { - std::fs::create_dir(folder.as_path())?; - } - - let bench_params_reader = std::io::BufReader::new(bench_params_file); + let config_path = "configs/secp256k1/bench_ecdsa.config"; + let bench_params_file = + File::open(config_path).unwrap_or_else(|e| panic!("{config_path} does not exist: {e:?}")); + fs::create_dir_all("results/secp256k1").unwrap(); + fs::create_dir_all("data").unwrap(); + let results_path = "results/secp256k1/ecdsa_bench.csv"; + let mut fs_results = File::create(results_path).unwrap(); + writeln!(fs_results, "degree,num_advice,num_lookup,num_fixed,lookup_bits,limb_bits,num_limbs,proof_time,proof_size,verify_time")?; + + let bench_params_reader = BufReader::new(bench_params_file); for line in bench_params_reader.lines() { let bench_params: CircuitParams = serde_json::from_str(line.unwrap().as_str()).unwrap(); - println!( - "---------------------- degree = {} ------------------------------", - bench_params.degree - ); + let k = bench_params.degree; + println!("---------------------- degree = {k} ------------------------------",); - { - folder.pop(); - folder.push("configs/ecdsa_circuit.tmp.config"); - set_var("ECDSA_CONFIG", &folder); - let mut f = std::fs::File::create(folder.as_path())?; - write!(f, "{}", serde_json::to_string(&bench_params).unwrap())?; - folder.pop(); - folder.pop(); - folder.push("data"); - } - let params_time = start_timer!(|| "Time elapsed in circuit & params construction"); - let params = gen_srs(bench_params.degree); - let circuit = ECDSACircuit::::default(); - end_timer!(params_time); + let params = gen_srs(k); + println!("{bench_params:?}"); - let vk_time = start_timer!(|| "Time elapsed in generating vkey"); + let circuit = random_ecdsa_circuit(bench_params, CircuitBuilderStage::Keygen, None); + + let vk_time = start_timer!(|| "Generating vkey"); let vk = keygen_vk(¶ms, &circuit)?; end_timer!(vk_time); - let pk_time = start_timer!(|| "Time elapsed in generating pkey"); + let pk_time = start_timer!(|| "Generating pkey"); let pk = keygen_pk(¶ms, vk, &circuit)?; end_timer!(pk_time); - // generate random pub key and sign random message - let G = Secp256k1Affine::generator(); - let sk = ::ScalarExt::random(OsRng); - let pubkey = Secp256k1Affine::from(G * sk); - let msg_hash = ::ScalarExt::random(OsRng); - - let k = ::ScalarExt::random(OsRng); - let k_inv = k.invert().unwrap(); - - let r_point = Secp256k1Affine::from(G * k).coordinates().unwrap(); - let x = r_point.x(); - let x_bigint = fe_to_biguint(x); - let r = biguint_to_fe::(&x_bigint); - let s = k_inv * (msg_hash + (r * sk)); - - let proof_circuit = ECDSACircuit:: { - r: Some(r), - s: Some(s), - msghash: Some(msg_hash), - pk: Some(pubkey), - G, - _marker: PhantomData, - }; - let mut rng = OsRng; - + let break_points = circuit.0.break_points.take(); + drop(circuit); // create a proof let proof_time = start_timer!(|| "Proving time"); + let circuit = + random_ecdsa_circuit(bench_params, CircuitBuilderStage::Prover, Some(break_points)); let mut transcript = Blake2bWrite::<_, _, Challenge255<_>>::init(vec![]); create_proof::< KZGCommitmentScheme, @@ -311,14 +171,14 @@ fn bench_secp256_ecdsa() -> Result<(), Box> { Challenge255, _, Blake2bWrite, G1Affine, Challenge255>, - ECDSACircuit, - >(¶ms, &pk, &[proof_circuit], &[&[]], &mut rng, &mut transcript)?; + _, + >(¶ms, &pk, &[circuit], &[&[]], &mut rng, &mut transcript)?; let proof = transcript.finalize(); end_timer!(proof_time); let proof_size = { - folder.push(format!( - "ecdsa_circuit_proof_{}_{}_{}_{}_{}_{}_{}.data", + let path = format!( + "data/ecdsa_circuit_proof_{}_{}_{}_{}_{}_{}_{}.data", bench_params.degree, bench_params.num_advice, bench_params.num_lookup_advice, @@ -326,27 +186,27 @@ fn bench_secp256_ecdsa() -> Result<(), Box> { bench_params.lookup_bits, bench_params.limb_bits, bench_params.num_limbs - )); - let mut fd = std::fs::File::create(folder.as_path()).unwrap(); - folder.pop(); - fd.write_all(&proof).unwrap(); - fd.metadata().unwrap().len() + ); + let mut fd = File::create(&path)?; + fd.write_all(&proof)?; + let size = fd.metadata().unwrap().len(); + fs::remove_file(path)?; + size }; let verify_time = start_timer!(|| "Verify time"); let verifier_params = params.verifier_params(); let strategy = SingleStrategy::new(¶ms); let mut transcript = Blake2bRead::<_, _, Challenge255<_>>::init(&proof[..]); - assert!(verify_proof::< + verify_proof::< KZGCommitmentScheme, VerifierSHPLONK<'_, Bn256>, Challenge255, Blake2bRead<&[u8], G1Affine, Challenge255>, SingleStrategy<'_, Bn256>, >(verifier_params, pk.get_vk(), strategy, &[&[]], &mut transcript) - .is_ok()); + .unwrap(); end_timer!(verify_time); - fs::remove_file(var("ECDSA_CONFIG").unwrap())?; writeln!( fs_results, diff --git a/hashes/zkevm-keccak/src/keccak_packed_multi.rs b/hashes/zkevm-keccak/src/keccak_packed_multi.rs index d474f962..3edc2e1a 100644 --- a/hashes/zkevm-keccak/src/keccak_packed_multi.rs +++ b/hashes/zkevm-keccak/src/keccak_packed_multi.rs @@ -395,7 +395,7 @@ pub fn assign_advice_custom<'v, F: Field>( ) -> KeccakAssignedValue<'v, F> { #[cfg(feature = "halo2-axiom")] { - region.assign_advice(column, offset, value).unwrap() + region.assign_advice(column, offset, value) } #[cfg(feature = "halo2-pse")] {