From 916b29fe89cb0dafebdf040777b1384587208ab5 Mon Sep 17 00:00:00 2001 From: Han Date: Mon, 24 Oct 2022 03:39:01 -0700 Subject: [PATCH 01/73] Rollback to pse halo2 and halo2wrong for first release (#5) * feat: move `Accumulator` to `accumulator.rs` * feat: update due to halo2 * feat: upgrade to use branch `feature/generic-instructions` of `halo2wrong` * refactor: rollback to `{halo2,halo2_wrong}` without challenge API and cleanup dependencies * chore: rename statement to instance and auxliary to witness * chore: use `finalize` instead of `code` * feat: add `Code::deployment` and `EvmLoader::deployment_code`; add example `evm-verifier-codegen` * fix: typo * feat: reduce generated evm verifier size; rename to `evm-verifier` and add another example `evm-verifier-with-accumulator` * fix: due to `halo2wrong` * feat: reorganize mods and traits * fix: allow empty `values` in `sum_*` and move them under `ScalarLoader` * ci: use `--all-features` for `cargo test` * fix: use same strategy for aggregation testing * fix: simplify trait `PlonkVerifier` again * fix: move system specified transcript under mod `system` * feat: add `quotient_poly` info in `Protocol` * feat: implement linearization for circom integration * feat: re-export loader's dependency for consumer * refactor: for circom's integration * tmp: pin `revm` to rev * fix: remove parentheses * fix: upgrade for multi-phase halo2 * feat: improve error reporting * chore: rename crate to snake case * feat: add `Domain` as an input of `PolynomialCommitmentScheme::read_proof` * refactor: for further integration * feat: generalize to suppoer also ipa and add builder fns to `system::halo2::Config` * feat: add `KzgDecider` for simple evm verifier * refactor: split `AccumulationScheme` and `AccumulatorEncoding` * refactor: split `PolynomialCommitmentScheme` and `MultiOpenScheme` * fix: not need sealed actually * fix: `chunk_size` should be `LIMBS` when recovering accumulator * feat: add `Expression::DistributePowers` to avoid stack overflow * fix: update and pin foundry * fix: move testing circuits under `system/halo2` * fix: allow accumulate single accumulator * feat: remove all patch and make less depending `halo2wrong` --- .github/workflows/ci.yaml | 2 +- .gitignore | 2 +- Cargo.toml | 69 +- examples/evm-verifier-with-accumulator.rs | 619 ++++++++++++ examples/evm-verifier.rs | 260 +++++ rust-toolchain | 2 +- src/cost.rs | 44 + src/lib.rs | 33 +- src/loader.rs | 195 ++-- src/loader/evm.rs | 68 +- src/loader/evm/accumulation.rs | 98 -- src/loader/evm/code.rs | 115 ++- src/loader/evm/loader.rs | 503 ++++++---- src/loader/evm/test.rs | 18 +- src/loader/evm/test/tui.rs | 2 +- src/loader/evm/transcript.rs | 229 ----- src/loader/evm/util.rs | 92 ++ src/loader/halo2.rs | 33 +- src/loader/halo2/accumulation.rs | 93 -- src/loader/halo2/loader.rs | 715 ++++++------- src/loader/halo2/shim.rs | 403 ++++++++ src/loader/halo2/test.rs | 66 ++ src/loader/halo2/transcript.rs | 363 ------- src/loader/native.rs | 87 +- src/loader/native/accumulation.rs | 111 -- src/loader/native/loader.rs | 61 -- src/pcs.rs | 138 +++ src/pcs/kzg.rs | 45 + src/pcs/kzg/accumulation.rs | 196 ++++ src/pcs/kzg/accumulator.rs | 208 ++++ src/pcs/kzg/decider.rs | 162 +++ src/pcs/kzg/multiopen.rs | 5 + src/pcs/kzg/multiopen/bdfg21.rs | 381 +++++++ src/pcs/kzg/multiopen/gwc19.rs | 167 +++ src/protocol.rs | 54 - src/protocol/halo2/test.rs | 176 ---- src/protocol/halo2/test/circuit/maingate.rs | 385 ------- src/protocol/halo2/test/circuit/plookup.rs | 947 ------------------ src/protocol/halo2/test/kzg.rs | 232 ----- src/protocol/halo2/test/kzg/evm.rs | 168 ---- src/protocol/halo2/test/kzg/halo2.rs | 380 ------- src/protocol/halo2/util.rs | 81 -- src/protocol/halo2/util/evm.rs | 142 --- src/protocol/halo2/util/halo2.rs | 212 ---- src/scheme.rs | 1 - src/scheme/kzg.rs | 35 - src/scheme/kzg/accumulation.rs | 171 ---- src/scheme/kzg/accumulation/plonk.rs | 373 ------- src/scheme/kzg/accumulation/shplonk.rs | 593 ----------- src/scheme/kzg/cost.rs | 29 - src/scheme/kzg/msm.rs | 149 --- src/system.rs | 2 + src/{protocol => system}/halo2.rs | 285 ++++-- src/system/halo2/test.rs | 221 ++++ .../halo2/test/circuit.rs | 1 - src/system/halo2/test/circuit/maingate.rs | 111 ++ .../halo2/test/circuit/standard.rs | 56 +- src/system/halo2/test/kzg.rs | 120 +++ src/system/halo2/test/kzg/evm.rs | 138 +++ src/system/halo2/test/kzg/halo2.rs | 372 +++++++ .../halo2/test/kzg/native.rs | 61 +- src/system/halo2/transcript.rs | 82 ++ src/system/halo2/transcript/evm.rs | 400 ++++++++ src/system/halo2/transcript/halo2.rs | 439 ++++++++ src/util.rs | 39 +- src/util/arithmetic.rs | 140 +-- src/util/hash.rs | 6 + src/util/hash/poseidon.rs | 178 ++++ src/util/msm.rs | 203 ++++ src/util/{expression.rs => protocol.rs} | 197 ++-- src/util/transcript.rs | 16 +- src/verifier.rs | 51 + src/verifier/plonk.rs | 464 +++++++++ 73 files changed, 7063 insertions(+), 6232 deletions(-) create mode 100644 examples/evm-verifier-with-accumulator.rs create mode 100644 examples/evm-verifier.rs create mode 100644 src/cost.rs delete mode 100644 src/loader/evm/accumulation.rs delete mode 100644 src/loader/evm/transcript.rs create mode 100644 src/loader/evm/util.rs delete mode 100644 src/loader/halo2/accumulation.rs create mode 100644 src/loader/halo2/shim.rs create mode 100644 src/loader/halo2/test.rs delete mode 100644 src/loader/halo2/transcript.rs delete mode 100644 src/loader/native/accumulation.rs delete mode 100644 src/loader/native/loader.rs create mode 100644 src/pcs.rs create mode 100644 src/pcs/kzg.rs create mode 100644 src/pcs/kzg/accumulation.rs create mode 100644 src/pcs/kzg/accumulator.rs create mode 100644 src/pcs/kzg/decider.rs create mode 100644 src/pcs/kzg/multiopen.rs create mode 100644 src/pcs/kzg/multiopen/bdfg21.rs create mode 100644 src/pcs/kzg/multiopen/gwc19.rs delete mode 100644 src/protocol.rs delete mode 100644 src/protocol/halo2/test.rs delete mode 100644 src/protocol/halo2/test/circuit/maingate.rs delete mode 100644 src/protocol/halo2/test/circuit/plookup.rs delete mode 100644 src/protocol/halo2/test/kzg.rs delete mode 100644 src/protocol/halo2/test/kzg/evm.rs delete mode 100644 src/protocol/halo2/test/kzg/halo2.rs delete mode 100644 src/protocol/halo2/util.rs delete mode 100644 src/protocol/halo2/util/evm.rs delete mode 100644 src/protocol/halo2/util/halo2.rs delete mode 100644 src/scheme.rs delete mode 100644 src/scheme/kzg.rs delete mode 100644 src/scheme/kzg/accumulation.rs delete mode 100644 src/scheme/kzg/accumulation/plonk.rs delete mode 100644 src/scheme/kzg/accumulation/shplonk.rs delete mode 100644 src/scheme/kzg/cost.rs delete mode 100644 src/scheme/kzg/msm.rs create mode 100644 src/system.rs rename src/{protocol => system}/halo2.rs (76%) create mode 100644 src/system/halo2/test.rs rename src/{protocol => system}/halo2/test/circuit.rs (67%) create mode 100644 src/system/halo2/test/circuit/maingate.rs rename src/{protocol => system}/halo2/test/circuit/standard.rs (69%) create mode 100644 src/system/halo2/test/kzg.rs create mode 100644 src/system/halo2/test/kzg/evm.rs create mode 100644 src/system/halo2/test/kzg/halo2.rs rename src/{protocol => system}/halo2/test/kzg/native.rs (50%) create mode 100644 src/system/halo2/transcript.rs create mode 100644 src/system/halo2/transcript/evm.rs create mode 100644 src/system/halo2/transcript/halo2.rs create mode 100644 src/util/hash.rs create mode 100644 src/util/hash/poseidon.rs create mode 100644 src/util/msm.rs rename src/util/{expression.rs => protocol.rs} (65%) create mode 100644 src/verifier.rs create mode 100644 src/verifier/plonk.rs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 83bfc0bb..a50958d0 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,7 +24,7 @@ jobs: cache-on-failure: true - name: Run test - run: cargo test --all --features test -- --nocapture + run: cargo test --all --all-features -- --nocapture lint: diff --git a/.gitignore b/.gitignore index ebb68914..0175c775 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,6 @@ .DS_Store /target -fixture +testdata Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index e6ac1d49..de037c4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,57 +1,54 @@ [package] -name = "plonk-verifier" +name = "plonk_verifier" version = "0.1.0" edition = "2021" [dependencies] -ff = "0.12.0" -group = "0.12.0" itertools = "0.10.3" lazy_static = "1.4.0" -num-bigint = "0.4" -num-traits = "0.2" +num-bigint = "0.4.3" +num-integer = "0.1.45" +num-traits = "0.2.15" rand = "0.8" rand_chacha = "0.3.1" -halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.2.1", package = "halo2curves" } - -# halo2 -blake2b_simd = { version = "1.0.0", optional = true } -halo2_proofs = { version = "0.2.0", optional = true } -halo2_wrong = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", package = "halo2wrong", optional = true } -halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", package = "ecc", optional = true } -halo2_wrong_maingate = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", package = "maingate", optional = true } -halo2_wrong_transcript = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", package = "transcript", optional = true } -poseidon = { git = "https://github.com/privacy-scaling-explorations/poseidon", branch = "padding", optional = true } - -# evm +halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.0", package = "halo2curves" } + +# system_halo2 +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2022_10_22", optional = true } + +# loader_evm ethereum_types = { package = "ethereum-types", version = "0.13.1", default-features = false, features = ["std"], optional = true } -foundry_evm = { git = "https://github.com/foundry-rs/foundry", package = "foundry-evm", rev = "93ee742d", optional = true } -crossterm = { version = "0.22.1", optional = true } -tui = { version = "0.16.0", default-features = false, features = ["crossterm"], optional = true } sha3 = { version = "0.10.1", optional = true } +# loader_halo2 +halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc", optional = true } +poseidon = { git = "https://github.com/privacy-scaling-explorations/poseidon", tag = "v2022_10_22", optional = true } + [dev-dependencies] paste = "1.0.7" +# system_halo2 +halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc" } + +# loader_evm +foundry_evm = { git = "https://github.com/foundry-rs/foundry", package = "foundry-evm", rev = "6b1ee60e" } +crossterm = { version = "0.22.1" } +tui = { version = "0.16.0", default-features = false, features = ["crossterm"] } + [features] -default = ["halo2", "evm"] -test = ["halo2", "evm"] +default = ["loader_evm", "loader_halo2", "system_halo2"] -halo2 = ["dep:blake2b_simd", "dep:halo2_proofs", "dep:halo2_wrong", "dep:halo2_wrong_ecc", "dep:halo2_wrong_maingate", "dep:halo2_wrong_transcript", "dep:poseidon"] -evm = ["dep:foundry_evm", "dep:crossterm", "dep:tui", "dep:ethereum_types", "dep:sha3"] -sanity-check = [] +loader_evm = ["dep:ethereum_types", "dep:sha3"] +loader_halo2 = ["dep:halo2_proofs", "dep:halo2_wrong_ecc", "dep:poseidon"] -[patch.crates-io] -halo2_proofs = { git = "https://github.com/han0110/halo2", branch = "experiment", package = "halo2_proofs" } +system_halo2 = ["dep:halo2_proofs"] -[patch."https://github.com/privacy-scaling-explorations/halo2"] -halo2_proofs = { git = "https://github.com/han0110/halo2", branch = "experiment", package = "halo2_proofs" } +sanity_check = [] -[patch."https://github.com/privacy-scaling-explorations/halo2curves"] -halo2_curves = { git = "https://github.com//privacy-scaling-explorations/halo2curves", tag = "0.2.1", package = "halo2curves" } +[[example]] +name = "evm-verifier" +required-features = ["loader_evm", "system_halo2"] -[patch."https://github.com/privacy-scaling-explorations/halo2wrong"] -halo2_wrong = { git = "https://github.com/han0110/halo2wrong", branch = "feature/range-chip-with-tagged-table", package = "halo2wrong" } -halo2_wrong_ecc = { git = "https://github.com/han0110/halo2wrong", branch = "feature/range-chip-with-tagged-table", package = "ecc" } -halo2_wrong_maingate = { git = "https://github.com/han0110/halo2wrong", branch = "feature/range-chip-with-tagged-table", package = "maingate" } -halo2_wrong_transcript = { git = "https://github.com/han0110/halo2wrong", branch = "feature/range-chip-with-tagged-table", package = "transcript" } +[[example]] +name = "evm-verifier-with-accumulator" +required-features = ["loader_halo2", "loader_evm", "system_halo2"] diff --git a/examples/evm-verifier-with-accumulator.rs b/examples/evm-verifier-with-accumulator.rs new file mode 100644 index 00000000..69def21e --- /dev/null +++ b/examples/evm-verifier-with-accumulator.rs @@ -0,0 +1,619 @@ +use ethereum_types::Address; +use foundry_evm::executor::{fork::MultiFork, Backend, ExecutorBuilder}; +use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; +use halo2_proofs::{ + dev::MockProver, + plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, ProvingKey, VerifyingKey}, + poly::{ + commitment::{Params, ParamsProver}, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::{ProverGWC, VerifierGWC}, + strategy::AccumulatorStrategy, + }, + VerificationStrategy, + }, + transcript::{EncodedChallenge, TranscriptReadBuffer, TranscriptWriterBuffer}, +}; +use itertools::Itertools; +use plonk_verifier::{ + loader::{ + evm::{encode_calldata, EvmLoader}, + native::NativeLoader, + }, + pcs::kzg::{Gwc19, Kzg, KzgAs, LimbsEncoding}, + system::halo2::{compile, transcript::evm::EvmTranscript, Config}, + verifier::{self, PlonkVerifier}, +}; +use rand::rngs::OsRng; +use std::{io::Cursor, rc::Rc}; + +const LIMBS: usize = 4; +const BITS: usize = 68; + +type Pcs = Kzg; +type As = KzgAs; +type Plonk = verifier::Plonk>; + +mod application { + use halo2_curves::bn256::Fr; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance}, + poly::Rotation, + }; + use rand::RngCore; + + #[derive(Clone, Copy)] + pub struct StandardPlonkConfig { + a: Column, + b: Column, + c: Column, + q_a: Column, + q_b: Column, + q_c: Column, + q_ab: Column, + constant: Column, + #[allow(dead_code)] + instance: Column, + } + + impl StandardPlonkConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { + let [a, b, c] = [(); 3].map(|_| meta.advice_column()); + let [q_a, q_b, q_c, q_ab, constant] = [(); 5].map(|_| meta.fixed_column()); + let instance = meta.instance_column(); + + [a, b, c].map(|column| meta.enable_equality(column)); + + meta.create_gate( + "q_a·a + q_b·b + q_c·c + q_ab·a·b + constant + instance = 0", + |meta| { + let [a, b, c] = + [a, b, c].map(|column| meta.query_advice(column, Rotation::cur())); + let [q_a, q_b, q_c, q_ab, constant] = [q_a, q_b, q_c, q_ab, constant] + .map(|column| meta.query_fixed(column, Rotation::cur())); + let instance = meta.query_instance(instance, Rotation::cur()); + Some( + q_a * a.clone() + + q_b * b.clone() + + q_c * c + + q_ab * a * b + + constant + + instance, + ) + }, + ); + + StandardPlonkConfig { + a, + b, + c, + q_a, + q_b, + q_c, + q_ab, + constant, + instance, + } + } + } + + #[derive(Clone, Default)] + pub struct StandardPlonk(Fr); + + impl StandardPlonk { + pub fn rand(mut rng: R) -> Self { + Self(Fr::from(rng.next_u32() as u64)) + } + + pub fn num_instance() -> Vec { + vec![1] + } + + pub fn instances(&self) -> Vec> { + vec![vec![self.0]] + } + } + + impl Circuit for StandardPlonk { + type Config = StandardPlonkConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + meta.set_minimum_degree(4); + StandardPlonkConfig::configure(meta) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + layouter.assign_region( + || "", + |mut region| { + region.assign_advice(|| "", config.a, 0, || Value::known(self.0))?; + region.assign_fixed(|| "", config.q_a, 0, || Value::known(-Fr::one()))?; + + region.assign_advice(|| "", config.a, 1, || Value::known(-Fr::from(5)))?; + for (idx, column) in (1..).zip([ + config.q_a, + config.q_b, + config.q_c, + config.q_ab, + config.constant, + ]) { + region.assign_fixed(|| "", column, 1, || Value::known(Fr::from(idx)))?; + } + + let a = region.assign_advice(|| "", config.a, 2, || Value::known(Fr::one()))?; + a.copy_advice(|| "", &mut region, config.b, 3)?; + a.copy_advice(|| "", &mut region, config.c, 4)?; + + Ok(()) + }, + ) + } + } +} + +mod aggregation { + use super::{As, Plonk, BITS, LIMBS}; + use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; + use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + plonk::{self, Circuit, ConstraintSystem}, + poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG}, + }; + use halo2_wrong_ecc::{ + integer::rns::Rns, + maingate::{ + MainGate, MainGateConfig, MainGateInstructions, RangeChip, RangeConfig, + RangeInstructions, RegionCtx, + }, + EccConfig, + }; + use itertools::Itertools; + use plonk_verifier::{ + loader::{self, native::NativeLoader}, + pcs::{ + kzg::{KzgAccumulator, KzgSuccinctVerifyingKey}, + AccumulationScheme, AccumulationSchemeProver, + }, + system, + util::arithmetic::{fe_to_limbs, FieldExt}, + verifier::PlonkVerifier, + Protocol, + }; + use rand::rngs::OsRng; + use std::{iter, rc::Rc}; + + const T: usize = 5; + const RATE: usize = 4; + const R_F: usize = 8; + const R_P: usize = 60; + + type Svk = KzgSuccinctVerifyingKey; + type BaseFieldEccChip = halo2_wrong_ecc::BaseFieldEccChip; + type Halo2Loader<'a> = loader::halo2::Halo2Loader<'a, G1Affine, BaseFieldEccChip>; + pub type PoseidonTranscript = + system::halo2::transcript::halo2::PoseidonTranscript; + + pub struct Snark { + protocol: Protocol, + instances: Vec>, + proof: Vec, + } + + impl Snark { + pub fn new(protocol: Protocol, instances: Vec>, proof: Vec) -> Self { + Self { + protocol, + instances, + proof, + } + } + } + + impl From for SnarkWitness { + fn from(snark: Snark) -> Self { + Self { + protocol: snark.protocol, + instances: snark + .instances + .into_iter() + .map(|instances| instances.into_iter().map(Value::known).collect_vec()) + .collect(), + proof: Value::known(snark.proof), + } + } + } + + #[derive(Clone)] + pub struct SnarkWitness { + protocol: Protocol, + instances: Vec>>, + proof: Value>, + } + + impl SnarkWitness { + fn without_witnesses(&self) -> Self { + SnarkWitness { + protocol: self.protocol.clone(), + instances: self + .instances + .iter() + .map(|instances| vec![Value::unknown(); instances.len()]) + .collect(), + proof: Value::unknown(), + } + } + + fn proof(&self) -> Value<&[u8]> { + self.proof.as_ref().map(Vec::as_slice) + } + } + + pub fn aggregate<'a>( + svk: &Svk, + loader: &Rc>, + snarks: &[SnarkWitness], + as_proof: Value<&'_ [u8]>, + ) -> KzgAccumulator>> { + let assign_instances = |instances: &[Vec>]| { + instances + .iter() + .map(|instances| { + instances + .iter() + .map(|instance| loader.assign_scalar(*instance)) + .collect_vec() + }) + .collect_vec() + }; + + let accumulators = snarks + .iter() + .flat_map(|snark| { + let instances = assign_instances(&snark.instances); + let mut transcript = + PoseidonTranscript::, _>::new(loader, snark.proof()); + let proof = + Plonk::read_proof(svk, &snark.protocol, &instances, &mut transcript).unwrap(); + Plonk::succinct_verify(svk, &snark.protocol, &instances, &proof).unwrap() + }) + .collect_vec(); + + let acccumulator = { + let mut transcript = PoseidonTranscript::, _>::new(loader, as_proof); + let proof = + As::read_proof(&Default::default(), &accumulators, &mut transcript).unwrap(); + As::verify(&Default::default(), &accumulators, &proof).unwrap() + }; + + acccumulator + } + + #[derive(Clone)] + pub struct AggregationConfig { + main_gate_config: MainGateConfig, + range_config: RangeConfig, + } + + impl AggregationConfig { + pub fn configure( + meta: &mut ConstraintSystem, + composition_bits: Vec, + overflow_bits: Vec, + ) -> Self { + let main_gate_config = MainGate::::configure(meta); + let range_config = + RangeChip::::configure(meta, &main_gate_config, composition_bits, overflow_bits); + AggregationConfig { + main_gate_config, + range_config, + } + } + + pub fn main_gate(&self) -> MainGate { + MainGate::new(self.main_gate_config.clone()) + } + + pub fn range_chip(&self) -> RangeChip { + RangeChip::new(self.range_config.clone()) + } + + pub fn ecc_chip(&self) -> BaseFieldEccChip { + BaseFieldEccChip::new(EccConfig::new( + self.range_config.clone(), + self.main_gate_config.clone(), + )) + } + } + + #[derive(Clone)] + pub struct AggregationCircuit { + svk: Svk, + snarks: Vec, + instances: Vec, + as_proof: Value>, + } + + impl AggregationCircuit { + pub fn new(params: &ParamsKZG, snarks: impl IntoIterator) -> Self { + let svk = params.get_g()[0].into(); + let snarks = snarks.into_iter().collect_vec(); + + let accumulators = snarks + .iter() + .flat_map(|snark| { + let mut transcript = + PoseidonTranscript::::new(snark.proof.as_slice()); + let proof = + Plonk::read_proof(&svk, &snark.protocol, &snark.instances, &mut transcript) + .unwrap(); + Plonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof).unwrap() + }) + .collect_vec(); + + let (accumulator, as_proof) = { + let mut transcript = PoseidonTranscript::::new(Vec::new()); + let accumulator = + As::create_proof(&Default::default(), &accumulators, &mut transcript, OsRng) + .unwrap(); + (accumulator, transcript.finalize()) + }; + + let KzgAccumulator { lhs, rhs } = accumulator; + let instances = [lhs.x, lhs.y, rhs.x, rhs.y] + .map(fe_to_limbs::<_, _, LIMBS, BITS>) + .concat(); + + Self { + svk, + snarks: snarks.into_iter().map_into().collect(), + instances, + as_proof: Value::known(as_proof), + } + } + + pub fn accumulator_indices() -> Vec<(usize, usize)> { + (0..4 * LIMBS).map(|idx| (0, idx)).collect() + } + + pub fn num_instance() -> Vec { + vec![4 * LIMBS] + } + + pub fn instances(&self) -> Vec> { + vec![self.instances.clone()] + } + + pub fn as_proof(&self) -> Value<&[u8]> { + self.as_proof.as_ref().map(Vec::as_slice) + } + } + + impl Circuit for AggregationCircuit { + type Config = AggregationConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self { + svk: self.svk, + snarks: self + .snarks + .iter() + .map(SnarkWitness::without_witnesses) + .collect(), + instances: Vec::new(), + as_proof: Value::unknown(), + } + } + + fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { + AggregationConfig::configure( + meta, + vec![BITS / LIMBS], + Rns::::construct().overflow_lengths(), + ) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), plonk::Error> { + let main_gate = config.main_gate(); + let range_chip = config.range_chip(); + + range_chip.load_table(&mut layouter)?; + + let (lhs, rhs) = layouter.assign_region( + || "", + |region| { + let ctx = RegionCtx::new(region, 0); + + let ecc_chip = config.ecc_chip(); + let loader = Halo2Loader::new(ecc_chip, ctx); + let KzgAccumulator { lhs, rhs } = + aggregate(&self.svk, &loader, &self.snarks, self.as_proof()); + + Ok((lhs.assigned(), rhs.assigned())) + }, + )?; + + for (limb, row) in iter::empty() + .chain(lhs.x().limbs()) + .chain(lhs.y().limbs()) + .chain(rhs.x().limbs()) + .chain(rhs.y().limbs()) + .zip(0..) + { + main_gate.expose_public(layouter.namespace(|| ""), limb.into(), row)?; + } + + Ok(()) + } + } +} + +fn gen_srs(k: u32) -> ParamsKZG { + ParamsKZG::::setup(k, OsRng) +} + +fn gen_pk>(params: &ParamsKZG, circuit: &C) -> ProvingKey { + let vk = keygen_vk(params, circuit).unwrap(); + keygen_pk(params, vk, circuit).unwrap() +} + +fn gen_proof< + C: Circuit, + E: EncodedChallenge, + TR: TranscriptReadBuffer>, G1Affine, E>, + TW: TranscriptWriterBuffer, G1Affine, E>, +>( + params: &ParamsKZG, + pk: &ProvingKey, + circuit: C, + instances: Vec>, +) -> Vec { + MockProver::run(params.k(), &circuit, instances.clone()) + .unwrap() + .assert_satisfied(); + + let instances = instances + .iter() + .map(|instances| instances.as_slice()) + .collect_vec(); + let proof = { + let mut transcript = TW::init(Vec::new()); + create_proof::, ProverGWC<_>, _, _, TW, _>( + params, + pk, + &[circuit], + &[instances.as_slice()], + OsRng, + &mut transcript, + ) + .unwrap(); + transcript.finalize() + }; + + let accept = { + let mut transcript = TR::init(Cursor::new(proof.clone())); + VerificationStrategy::<_, VerifierGWC<_>>::finalize( + verify_proof::<_, VerifierGWC<_>, _, TR, _>( + params.verifier_params(), + pk.get_vk(), + AccumulatorStrategy::new(params.verifier_params()), + &[instances.as_slice()], + &mut transcript, + ) + .unwrap(), + ) + }; + assert!(accept); + + proof +} + +fn gen_application_snark(params: &ParamsKZG) -> aggregation::Snark { + let circuit = application::StandardPlonk::rand(OsRng); + + let pk = gen_pk(params, &circuit); + let protocol = compile( + params, + pk.get_vk(), + Config::kzg().with_num_instance(application::StandardPlonk::num_instance()), + ); + + let proof = gen_proof::< + _, + _, + aggregation::PoseidonTranscript, + aggregation::PoseidonTranscript, + >(params, &pk, circuit.clone(), circuit.instances()); + aggregation::Snark::new(protocol, circuit.instances(), proof) +} + +fn gen_aggregation_evm_verifier( + params: &ParamsKZG, + vk: &VerifyingKey, + num_instance: Vec, + accumulator_indices: Vec<(usize, usize)>, +) -> Vec { + let svk = params.get_g()[0].into(); + let dk = (params.g2(), params.s_g2()).into(); + let protocol = compile( + params, + vk, + Config::kzg() + .with_num_instance(num_instance.clone()) + .with_accumulator_indices(accumulator_indices), + ); + + let loader = EvmLoader::new::(); + let mut transcript = EvmTranscript::<_, Rc, _, _>::new(loader.clone()); + + let instances = transcript.load_instances(num_instance); + let proof = Plonk::read_proof(&svk, &protocol, &instances, &mut transcript).unwrap(); + Plonk::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); + + loader.deployment_code() +} + +fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { + let calldata = encode_calldata(&instances, &proof); + let success = { + let mut evm = ExecutorBuilder::default() + .with_gas_limit(u64::MAX.into()) + .build(Backend::new(MultiFork::new().0, None)); + + let caller = Address::from_low_u64_be(0xfe); + let verifier = evm + .deploy(caller, deployment_code.into(), 0.into(), None) + .unwrap() + .address; + let result = evm + .call_raw(caller, verifier, calldata.into(), 0.into()) + .unwrap(); + + dbg!(result.gas_used); + + !result.reverted + }; + assert!(success); +} + +fn main() { + let params = gen_srs(22); + let params_app = { + let mut params = params.clone(); + params.downsize(8); + params + }; + + let snarks = [(); 3].map(|_| gen_application_snark(¶ms_app)); + let agg_circuit = aggregation::AggregationCircuit::new(¶ms, snarks); + let pk = gen_pk(¶ms, &agg_circuit); + let deployment_code = gen_aggregation_evm_verifier( + ¶ms, + pk.get_vk(), + aggregation::AggregationCircuit::num_instance(), + aggregation::AggregationCircuit::accumulator_indices(), + ); + + let proof = gen_proof::<_, _, EvmTranscript, EvmTranscript>( + ¶ms, + &pk, + agg_circuit.clone(), + agg_circuit.instances(), + ); + evm_verify(deployment_code, agg_circuit.instances(), proof); +} diff --git a/examples/evm-verifier.rs b/examples/evm-verifier.rs new file mode 100644 index 00000000..b51a9a30 --- /dev/null +++ b/examples/evm-verifier.rs @@ -0,0 +1,260 @@ +use ethereum_types::Address; +use foundry_evm::executor::{fork::MultiFork, Backend, ExecutorBuilder}; +use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; +use halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + dev::MockProver, + plonk::{ + create_proof, keygen_pk, keygen_vk, verify_proof, Advice, Circuit, Column, + ConstraintSystem, Error, Fixed, Instance, ProvingKey, VerifyingKey, + }, + poly::{ + commitment::{Params, ParamsProver}, + kzg::{ + commitment::{KZGCommitmentScheme, ParamsKZG}, + multiopen::{ProverGWC, VerifierGWC}, + strategy::AccumulatorStrategy, + }, + Rotation, VerificationStrategy, + }, + transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, +}; +use itertools::Itertools; +use plonk_verifier::{ + loader::evm::{encode_calldata, EvmLoader}, + pcs::kzg::{Gwc19, Kzg}, + system::halo2::{compile, transcript::evm::EvmTranscript, Config}, + verifier::{self, PlonkVerifier}, +}; +use rand::{rngs::OsRng, RngCore}; +use std::rc::Rc; + +type Plonk = verifier::Plonk>; + +#[derive(Clone, Copy)] +struct StandardPlonkConfig { + a: Column, + b: Column, + c: Column, + q_a: Column, + q_b: Column, + q_c: Column, + q_ab: Column, + constant: Column, + #[allow(dead_code)] + instance: Column, +} + +impl StandardPlonkConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { + let [a, b, c] = [(); 3].map(|_| meta.advice_column()); + let [q_a, q_b, q_c, q_ab, constant] = [(); 5].map(|_| meta.fixed_column()); + let instance = meta.instance_column(); + + [a, b, c].map(|column| meta.enable_equality(column)); + + meta.create_gate( + "q_a·a + q_b·b + q_c·c + q_ab·a·b + constant + instance = 0", + |meta| { + let [a, b, c] = [a, b, c].map(|column| meta.query_advice(column, Rotation::cur())); + let [q_a, q_b, q_c, q_ab, constant] = [q_a, q_b, q_c, q_ab, constant] + .map(|column| meta.query_fixed(column, Rotation::cur())); + let instance = meta.query_instance(instance, Rotation::cur()); + Some( + q_a * a.clone() + + q_b * b.clone() + + q_c * c + + q_ab * a * b + + constant + + instance, + ) + }, + ); + + StandardPlonkConfig { + a, + b, + c, + q_a, + q_b, + q_c, + q_ab, + constant, + instance, + } + } +} + +#[derive(Clone, Default)] +struct StandardPlonk(Fr); + +impl StandardPlonk { + fn rand(mut rng: R) -> Self { + Self(Fr::from(rng.next_u32() as u64)) + } + + fn num_instance() -> Vec { + vec![1] + } + + fn instances(&self) -> Vec> { + vec![vec![self.0]] + } +} + +impl Circuit for StandardPlonk { + type Config = StandardPlonkConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + meta.set_minimum_degree(4); + StandardPlonkConfig::configure(meta) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + layouter.assign_region( + || "", + |mut region| { + region.assign_advice(|| "", config.a, 0, || Value::known(self.0))?; + region.assign_fixed(|| "", config.q_a, 0, || Value::known(-Fr::one()))?; + + region.assign_advice(|| "", config.a, 1, || Value::known(-Fr::from(5)))?; + for (idx, column) in (1..).zip([ + config.q_a, + config.q_b, + config.q_c, + config.q_ab, + config.constant, + ]) { + region.assign_fixed(|| "", column, 1, || Value::known(Fr::from(idx)))?; + } + + let a = region.assign_advice(|| "", config.a, 2, || Value::known(Fr::one()))?; + a.copy_advice(|| "", &mut region, config.b, 3)?; + a.copy_advice(|| "", &mut region, config.c, 4)?; + + Ok(()) + }, + ) + } +} + +fn gen_srs(k: u32) -> ParamsKZG { + ParamsKZG::::setup(k, OsRng) +} + +fn gen_pk>(params: &ParamsKZG, circuit: &C) -> ProvingKey { + let vk = keygen_vk(params, circuit).unwrap(); + keygen_pk(params, vk, circuit).unwrap() +} + +fn gen_proof>( + params: &ParamsKZG, + pk: &ProvingKey, + circuit: C, + instances: Vec>, +) -> Vec { + MockProver::run(params.k(), &circuit, instances.clone()) + .unwrap() + .assert_satisfied(); + + let instances = instances + .iter() + .map(|instances| instances.as_slice()) + .collect_vec(); + let proof = { + let mut transcript = TranscriptWriterBuffer::<_, G1Affine, _>::init(Vec::new()); + create_proof::, ProverGWC<_>, _, _, EvmTranscript<_, _, _, _>, _>( + params, + pk, + &[circuit], + &[instances.as_slice()], + OsRng, + &mut transcript, + ) + .unwrap(); + transcript.finalize() + }; + + let accept = { + let mut transcript = TranscriptReadBuffer::<_, G1Affine, _>::init(proof.as_slice()); + VerificationStrategy::<_, VerifierGWC<_>>::finalize( + verify_proof::<_, VerifierGWC<_>, _, EvmTranscript<_, _, _, _>, _>( + params.verifier_params(), + pk.get_vk(), + AccumulatorStrategy::new(params.verifier_params()), + &[instances.as_slice()], + &mut transcript, + ) + .unwrap(), + ) + }; + assert!(accept); + + proof +} + +fn gen_evm_verifier( + params: &ParamsKZG, + vk: &VerifyingKey, + num_instance: Vec, +) -> Vec { + let svk = params.get_g()[0].into(); + let dk = (params.g2(), params.s_g2()).into(); + let protocol = compile( + params, + vk, + Config::kzg().with_num_instance(num_instance.clone()), + ); + + let loader = EvmLoader::new::(); + let mut transcript = EvmTranscript::<_, Rc, _, _>::new(loader.clone()); + + let instances = transcript.load_instances(num_instance); + let proof = Plonk::read_proof(&svk, &protocol, &instances, &mut transcript).unwrap(); + Plonk::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); + + loader.deployment_code() +} + +fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { + let calldata = encode_calldata(&instances, &proof); + let success = { + let mut evm = ExecutorBuilder::default() + .with_gas_limit(u64::MAX.into()) + .build(Backend::new(MultiFork::new().0, None)); + + let caller = Address::from_low_u64_be(0xfe); + let verifier = evm + .deploy(caller, deployment_code.into(), 0.into(), None) + .unwrap() + .address; + let result = evm + .call_raw(caller, verifier, calldata.into(), 0.into()) + .unwrap(); + + dbg!(result.gas_used); + + !result.reverted + }; + assert!(success); +} + +fn main() { + let params = gen_srs(8); + + let circuit = StandardPlonk::rand(OsRng); + let pk = gen_pk(¶ms, &circuit); + let deployment_code = gen_evm_verifier(¶ms, pk.get_vk(), StandardPlonk::num_instance()); + + let proof = gen_proof(¶ms, &pk, circuit.clone(), circuit.instances()); + evm_verify(deployment_code, circuit.instances(), proof); +} diff --git a/rust-toolchain b/rust-toolchain index db84486f..7cc6ef41 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2022-06-01 \ No newline at end of file +1.63.0 \ No newline at end of file diff --git a/src/cost.rs b/src/cost.rs new file mode 100644 index 00000000..b085aed8 --- /dev/null +++ b/src/cost.rs @@ -0,0 +1,44 @@ +use std::ops::Add; + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Cost { + pub num_instance: usize, + pub num_commitment: usize, + pub num_evaluation: usize, + pub num_msm: usize, +} + +impl Cost { + pub fn new( + num_instance: usize, + num_commitment: usize, + num_evaluation: usize, + num_msm: usize, + ) -> Self { + Self { + num_instance, + num_commitment, + num_evaluation, + num_msm, + } + } +} + +impl Add for Cost { + type Output = Cost; + + fn add(self, rhs: Cost) -> Self::Output { + Cost::new( + self.num_instance + rhs.num_instance, + self.num_commitment + rhs.num_commitment, + self.num_evaluation + rhs.num_evaluation, + self.num_msm + rhs.num_msm, + ) + } +} + +pub trait CostEstimation { + type Input; + + fn estimate_cost(input: &Self::Input) -> Cost; +} diff --git a/src/lib.rs b/src/lib.rs index b193cc5c..4e8da5fb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,19 +1,38 @@ -#![feature(int_log)] -#![feature(int_roundings)] -#![feature(assert_matches)] #![allow(clippy::type_complexity)] #![allow(clippy::too_many_arguments)] #![allow(clippy::upper_case_acronyms)] +pub mod cost; pub mod loader; -pub mod protocol; -pub mod scheme; +pub mod pcs; +pub mod system; pub mod util; +pub mod verifier; #[derive(Clone, Debug)] pub enum Error { InvalidInstances, - MissingQuery(util::Query), - MissingChallenge(usize), + InvalidLinearization, + InvalidQuery(util::protocol::Query), + InvalidChallenge(usize), + AssertionFailure(String), Transcript(std::io::ErrorKind, String), } + +#[derive(Clone, Debug)] +pub struct Protocol { + // Common description + pub domain: util::arithmetic::Domain, + pub preprocessed: Vec, + pub num_instance: Vec, + pub num_witness: Vec, + pub num_challenge: Vec, + pub evaluations: Vec, + pub queries: Vec, + pub quotient: util::protocol::QuotientPolynomial, + // Minor customization + pub transcript_initial_state: Option, + pub instance_committing_key: Option>, + pub linearization: Option, + pub accumulator_indices: Vec>, +} diff --git a/src/loader.rs b/src/loader.rs index ebca0ec9..8c39bae0 100644 --- a/src/loader.rs +++ b/src/loader.rs @@ -1,15 +1,21 @@ -use crate::util::{Curve, FieldOps, GroupOps, Itertools, PrimeField}; +use crate::{ + util::{ + arithmetic::{CurveAffine, FieldOps, PrimeField}, + Itertools, + }, + Error, +}; use std::{fmt::Debug, iter}; pub mod native; -#[cfg(feature = "evm")] +#[cfg(feature = "loader_evm")] pub mod evm; -#[cfg(feature = "halo2")] +#[cfg(feature = "loader_halo2")] pub mod halo2; -pub trait LoadedEcPoint: Clone + Debug + GroupOps + PartialEq { +pub trait LoadedEcPoint: Clone + Debug + PartialEq { type Loader: Loader; fn loader(&self) -> &Self::Loader; @@ -24,67 +30,11 @@ pub trait LoadedEcPoint: Clone + Debug + GroupOps + PartialEq { ) -> Self; } -pub trait LoadedScalar: Clone + Debug + FieldOps { +pub trait LoadedScalar: Clone + Debug + PartialEq + FieldOps { type Loader: ScalarLoader; fn loader(&self) -> &Self::Loader; - fn sum_with_coeff_and_constant(values: &[(F, Self)], constant: &F) -> Self { - assert!(!values.is_empty()); - - let loader = values.first().unwrap().1.loader(); - iter::empty() - .chain(if *constant == F::zero() { - None - } else { - Some(loader.load_const(constant)) - }) - .chain( - values - .iter() - .map(|(coeff, value)| loader.load_const(coeff) * value), - ) - .reduce(|acc, term| acc + term) - .unwrap() - } - - fn sum_products_with_coeff_and_constant(values: &[(F, Self, Self)], constant: &F) -> Self { - assert!(!values.is_empty()); - - let loader = values.first().unwrap().1.loader(); - iter::empty() - .chain(if *constant == F::zero() { - None - } else { - Some(loader.load_const(constant)) - }) - .chain( - values - .iter() - .map(|(coeff, lhs, rhs)| loader.load_const(coeff) * lhs * rhs), - ) - .reduce(|acc, term| acc + term) - .unwrap() - } - - fn sum_with_coeff(values: &[(F, Self)]) -> Self { - Self::sum_with_coeff_and_constant(values, &F::zero()) - } - - fn sum_with_const(values: &[Self], constant: &F) -> Self { - Self::sum_with_coeff_and_constant( - &values - .iter() - .map(|value| (F::one(), value.clone())) - .collect_vec(), - constant, - ) - } - - fn sum(values: &[Self]) -> Self { - Self::sum_with_const(values, &F::zero()) - } - fn square(&self) -> Self { self.clone() * self } @@ -133,7 +83,7 @@ pub trait LoadedScalar: Clone + Debug + FieldOps { } } -pub trait EcPointLoader { +pub trait EcPointLoader { type LoadedEcPoint: LoadedEcPoint; fn ec_point_load_const(&self, value: &C) -> Self::LoadedEcPoint; @@ -145,6 +95,13 @@ pub trait EcPointLoader { fn ec_point_load_one(&self) -> Self::LoadedEcPoint { self.ec_point_load_const(&C::generator()) } + + fn ec_point_assert_eq( + &self, + annotation: &str, + lhs: &Self::LoadedEcPoint, + rhs: &Self::LoadedEcPoint, + ) -> Result<(), Error>; } pub trait ScalarLoader { @@ -159,9 +116,121 @@ pub trait ScalarLoader { fn load_one(&self) -> Self::LoadedScalar { self.load_const(&F::one()) } + + fn assert_eq( + &self, + annotation: &str, + lhs: &Self::LoadedScalar, + rhs: &Self::LoadedScalar, + ) -> Result<(), Error>; + + fn sum_with_coeff_and_const( + &self, + values: &[(F, &Self::LoadedScalar)], + constant: F, + ) -> Self::LoadedScalar { + if values.is_empty() { + return self.load_const(&constant); + } + + let loader = values.first().unwrap().1.loader(); + iter::empty() + .chain(if constant == F::zero() { + None + } else { + Some(loader.load_const(&constant)) + }) + .chain(values.iter().map(|&(coeff, value)| { + if coeff == F::one() { + value.clone() + } else { + loader.load_const(&coeff) * value + } + })) + .reduce(|acc, term| acc + term) + .unwrap() + } + + fn sum_products_with_coeff_and_const( + &self, + values: &[(F, &Self::LoadedScalar, &Self::LoadedScalar)], + constant: F, + ) -> Self::LoadedScalar { + if values.is_empty() { + return self.load_const(&constant); + } + + let loader = values.first().unwrap().1.loader(); + iter::empty() + .chain(if constant == F::zero() { + None + } else { + Some(loader.load_const(&constant)) + }) + .chain(values.iter().map(|&(coeff, lhs, rhs)| { + if coeff == F::one() { + lhs.clone() * rhs + } else { + loader.load_const(&coeff) * lhs * rhs + } + })) + .reduce(|acc, term| acc + term) + .unwrap() + } + + fn sum_with_coeff(&self, values: &[(F, &Self::LoadedScalar)]) -> Self::LoadedScalar { + self.sum_with_coeff_and_const(values, F::zero()) + } + + fn sum_with_const(&self, values: &[&Self::LoadedScalar], constant: F) -> Self::LoadedScalar { + self.sum_with_coeff_and_const( + &values.iter().map(|&value| (F::one(), value)).collect_vec(), + constant, + ) + } + + fn sum(&self, values: &[&Self::LoadedScalar]) -> Self::LoadedScalar { + self.sum_with_const(values, F::zero()) + } + + fn sum_products_with_coeff( + &self, + values: &[(F, &Self::LoadedScalar, &Self::LoadedScalar)], + ) -> Self::LoadedScalar { + self.sum_products_with_coeff_and_const(values, F::zero()) + } + + fn sum_products_with_const( + &self, + values: &[(&Self::LoadedScalar, &Self::LoadedScalar)], + constant: F, + ) -> Self::LoadedScalar { + self.sum_products_with_coeff_and_const( + &values + .iter() + .map(|&(lhs, rhs)| (F::one(), lhs, rhs)) + .collect_vec(), + constant, + ) + } + + fn sum_products( + &self, + values: &[(&Self::LoadedScalar, &Self::LoadedScalar)], + ) -> Self::LoadedScalar { + self.sum_products_with_const(values, F::zero()) + } + + fn product(&self, values: &[&Self::LoadedScalar]) -> Self::LoadedScalar { + values + .iter() + .fold(self.load_one(), |acc, value| acc * *value) + } } -pub trait Loader: EcPointLoader + ScalarLoader + Clone { +pub trait Loader: + EcPointLoader + ScalarLoader + Clone + Debug +{ fn start_cost_metering(&self, _: &str) {} fn end_cost_metering(&self) {} diff --git a/src/loader/evm.rs b/src/loader/evm.rs index e0754532..7a07670c 100644 --- a/src/loader/evm.rs +++ b/src/loader/evm.rs @@ -1,70 +1,14 @@ -use crate::{ - scheme::kzg::Cost, - util::{Itertools, PrimeField}, -}; -use ethereum_types::U256; -use std::iter; - -mod accumulation; mod code; -mod loader; -mod transcript; +pub(crate) mod loader; +mod util; #[cfg(test)] mod test; -pub use loader::EvmLoader; -pub use transcript::EvmTranscript; +pub use loader::{EcPoint, EvmLoader, Scalar}; +pub use util::{encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, MemoryChunk}; + +pub use ethereum_types::U256; #[cfg(test)] pub use test::execute; - -// Assert F::Repr in little-endian -pub fn field_to_u256(f: &F) -> U256 -where - F: PrimeField, -{ - U256::from_little_endian(f.to_repr().as_ref()) -} - -pub fn u256_to_field(value: U256) -> F -where - F: PrimeField, -{ - let value = value % (field_to_u256(&-F::one()) + 1u64); - let mut repr = F::Repr::default(); - value.to_little_endian(repr.as_mut()); - F::from_repr(repr).unwrap() -} - -pub fn modulus() -> U256 -where - F: PrimeField, -{ - U256::from_little_endian((-F::one()).to_repr().as_ref()) + 1 -} - -pub fn encode_calldata(instances: Vec>, proof: Vec) -> Vec -where - F: PrimeField, -{ - iter::empty() - .chain( - instances - .into_iter() - .flatten() - .flat_map(|value| value.to_repr().as_ref().iter().rev().cloned().collect_vec()), - ) - .chain(proof) - .collect() -} - -pub fn estimate_gas(cost: Cost) -> usize { - let proof_size = cost.num_commitment * 64 + (cost.num_evaluation + cost.num_statement) * 32; - - let intrinsic_cost = 21000; - let calldata_cost = (proof_size as f64 * 15.25).ceil() as usize; - let ec_operation_cost = 113100 + (cost.num_msm - 2) * 6350; - - intrinsic_cost + calldata_cost + ec_operation_cost -} diff --git a/src/loader/evm/accumulation.rs b/src/loader/evm/accumulation.rs deleted file mode 100644 index cfe4be6f..00000000 --- a/src/loader/evm/accumulation.rs +++ /dev/null @@ -1,98 +0,0 @@ -use crate::{ - loader::evm::loader::{EvmLoader, Scalar}, - protocol::Protocol, - scheme::kzg::{AccumulationStrategy, Accumulator, SameCurveAccumulation, MSM}, - util::{Curve, Itertools, PrimeCurveAffine, PrimeField, Transcript, UncompressedEncoding}, - Error, -}; -use ethereum_types::U256; -use halo2_curves::{ - bn256::{G1Affine, G2Affine, G1}, - CurveAffine, -}; -use std::{ops::Neg, rc::Rc}; - -impl SameCurveAccumulation, LIMBS, BITS> { - pub fn code(self, g1: G1Affine, g2: G2Affine, s_g2: G2Affine) -> Vec { - let (lhs, rhs) = self.accumulator.unwrap().evaluate(g1.to_curve()); - let loader = lhs.loader(); - - let [g2, minus_s_g2] = [g2, s_g2.neg()].map(|ec_point| { - let coordinates = ec_point.coordinates().unwrap(); - let x = coordinates.x().to_repr(); - let y = coordinates.y().to_repr(); - ( - U256::from_little_endian(&x.as_ref()[32..]), - U256::from_little_endian(&x.as_ref()[..32]), - U256::from_little_endian(&y.as_ref()[32..]), - U256::from_little_endian(&y.as_ref()[..32]), - ) - }); - loader.pairing(&lhs, g2, &rhs, minus_s_g2); - - loader.code() - } -} - -impl - AccumulationStrategy, T, P> - for SameCurveAccumulation, LIMBS, BITS> -where - C::Scalar: PrimeField, - C: UncompressedEncoding, - T: Transcript>, -{ - type Output = (); - - fn extract_accumulator( - &self, - protocol: &Protocol, - loader: &Rc, - transcript: &mut T, - statements: &[Vec], - ) -> Option>> { - let accumulator_indices = protocol.accumulator_indices.as_ref()?; - - let num_statements = statements - .iter() - .map(|statements| statements.len()) - .collect_vec(); - - let challenges = transcript.squeeze_n_challenges(accumulator_indices.len()); - let accumulators = accumulator_indices - .iter() - .map(|indices| { - assert_eq!(indices.len(), 4 * LIMBS); - assert!(indices - .iter() - .enumerate() - .all(|(idx, index)| indices[0] == (index.0, index.1 - idx))); - let offset = - (num_statements[..indices[0].0].iter().sum::() + indices[0].1) * 0x20; - let lhs = loader.calldataload_ec_point_from_limbs::(offset); - let rhs = loader.calldataload_ec_point_from_limbs::(offset + 0x100); - Accumulator::new(MSM::base(lhs), MSM::base(rhs)) - }) - .collect_vec(); - - Some(Accumulator::random_linear_combine( - challenges.into_iter().zip(accumulators), - )) - } - - fn process( - &mut self, - _: &Rc, - transcript: &mut T, - _: P, - accumulator: Accumulator>, - ) -> Result { - self.accumulator = Some(match self.accumulator.take() { - Some(curr_accumulator) => { - accumulator + curr_accumulator * &transcript.squeeze_challenge() - } - None => accumulator, - }); - Ok(()) - } -} diff --git a/src/loader/evm/code.rs b/src/loader/evm/code.rs index 38069401..80dd5c71 100644 --- a/src/loader/evm/code.rs +++ b/src/loader/evm/code.rs @@ -1,6 +1,6 @@ use crate::util::Itertools; use ethereum_types::U256; -use foundry_evm::{revm::opcode::*, HashMap}; +use std::{collections::HashMap, iter}; pub enum Precompiled { BigModExp = 0x05, @@ -36,6 +36,37 @@ impl Code { code } + pub fn deployment(code: Vec) -> Vec { + let code_len = code.len(); + assert_ne!(code_len, 0); + + iter::empty() + .chain([ + PUSH1 + 1, + (code_len >> 8) as u8, + (code_len & 0xff) as u8, + PUSH1, + 14, + PUSH1, + 0, + CODECOPY, + ]) + .chain([ + PUSH1 + 1, + (code_len >> 8) as u8, + (code_len & 0xff) as u8, + PUSH1, + 0, + RETURN, + ]) + .chain(code) + .collect() + } + + pub fn stack_len(&self) -> usize { + self.stack_len + } + pub fn len(&self) -> usize { self.code.len() } @@ -180,3 +211,85 @@ impl_opcodes!( revert -> (REVERT, -2) selfdestruct -> (SELFDESTRUCT, -1) ); + +const STOP: u8 = 0x00; +const ADD: u8 = 0x01; +const MUL: u8 = 0x02; +const SUB: u8 = 0x03; +const DIV: u8 = 0x04; +const SDIV: u8 = 0x05; +const MOD: u8 = 0x06; +const SMOD: u8 = 0x07; +const ADDMOD: u8 = 0x08; +const MULMOD: u8 = 0x09; +const EXP: u8 = 0x0A; +const SIGNEXTEND: u8 = 0x0B; +const LT: u8 = 0x10; +const GT: u8 = 0x11; +const SLT: u8 = 0x12; +const SGT: u8 = 0x13; +const EQ: u8 = 0x14; +const ISZERO: u8 = 0x15; +const AND: u8 = 0x16; +const OR: u8 = 0x17; +const XOR: u8 = 0x18; +const NOT: u8 = 0x19; +const BYTE: u8 = 0x1A; +const SHL: u8 = 0x1B; +const SHR: u8 = 0x1C; +const SAR: u8 = 0x1D; +const SHA3: u8 = 0x20; +const ADDRESS: u8 = 0x30; +const BALANCE: u8 = 0x31; +const ORIGIN: u8 = 0x32; +const CALLER: u8 = 0x33; +const CALLVALUE: u8 = 0x34; +const CALLDATALOAD: u8 = 0x35; +const CALLDATASIZE: u8 = 0x36; +const CALLDATACOPY: u8 = 0x37; +const CODESIZE: u8 = 0x38; +const CODECOPY: u8 = 0x39; +const GASPRICE: u8 = 0x3A; +const EXTCODESIZE: u8 = 0x3B; +const EXTCODECOPY: u8 = 0x3C; +const RETURNDATASIZE: u8 = 0x3D; +const RETURNDATACOPY: u8 = 0x3E; +const EXTCODEHASH: u8 = 0x3F; +const BLOCKHASH: u8 = 0x40; +const COINBASE: u8 = 0x41; +const TIMESTAMP: u8 = 0x42; +const NUMBER: u8 = 0x43; +const DIFFICULTY: u8 = 0x44; +const GASLIMIT: u8 = 0x45; +const CHAINID: u8 = 0x46; +const SELFBALANCE: u8 = 0x47; +const BASEFEE: u8 = 0x48; +const POP: u8 = 0x50; +const MLOAD: u8 = 0x51; +const MSTORE: u8 = 0x52; +const MSTORE8: u8 = 0x53; +const SLOAD: u8 = 0x54; +const SSTORE: u8 = 0x55; +const JUMP: u8 = 0x56; +const JUMPI: u8 = 0x57; +const PC: u8 = 0x58; +const MSIZE: u8 = 0x59; +const GAS: u8 = 0x5A; +const JUMPDEST: u8 = 0x5B; +const PUSH1: u8 = 0x60; +const DUP1: u8 = 0x80; +const SWAP1: u8 = 0x90; +const LOG0: u8 = 0xA0; +const LOG1: u8 = 0xA1; +const LOG2: u8 = 0xA2; +const LOG3: u8 = 0xA3; +const LOG4: u8 = 0xA4; +const CREATE: u8 = 0xF0; +const CALL: u8 = 0xF1; +const CALLCODE: u8 = 0xF2; +const RETURN: u8 = 0xF3; +const DELEGATECALL: u8 = 0xF4; +const CREATE2: u8 = 0xF5; +const STATICCALL: u8 = 0xFA; +const REVERT: u8 = 0xFD; +const SELFDESTRUCT: u8 = 0xFF; diff --git a/src/loader/evm/loader.rs b/src/loader/evm/loader.rs index 258ffdd0..06ab7fd8 100644 --- a/src/loader/evm/loader.rs +++ b/src/loader/evm/loader.rs @@ -1,24 +1,49 @@ use crate::{ loader::evm::{ code::{Code, Precompiled}, - modulus, + fe_to_u256, modulus, }, - loader::{EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader}, - util::{Curve, FieldOps, Itertools, PrimeField, UncompressedEncoding}, + loader::{evm::u256_to_fe, EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader}, + util::{ + arithmetic::{CurveAffine, FieldOps, PrimeField}, + Itertools, + }, + Error, }; use ethereum_types::{U256, U512}; use std::{ cell::RefCell, + collections::HashMap, fmt::{self, Debug}, iter, - ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, + ops::{Add, AddAssign, DerefMut, Mul, MulAssign, Neg, Sub, SubAssign}, rc::Rc, }; -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] pub enum Value { Constant(T), Memory(usize), + Negated(Box>), + Sum(Box>, Box>), + Product(Box>, Box>), +} + +impl PartialEq for Value { + fn eq(&self, other: &Self) -> bool { + self.identifier() == other.identifier() + } +} + +impl Value { + fn identifier(&self) -> String { + match &self { + Value::Constant(_) | Value::Memory(_) => format!("{:?}", self), + Value::Negated(value) => format!("-({:?})", value), + Value::Sum(lhs, rhs) => format!("({:?} + {:?})", lhs, rhs), + Value::Product(lhs, rhs) => format!("({:?} * {:?})", lhs, rhs), + } + } } #[derive(Clone, Debug)] @@ -27,6 +52,7 @@ pub struct EvmLoader { scalar_modulus: U256, code: RefCell, ptr: RefCell, + cache: RefCell>, #[cfg(test)] gas_metering_ids: RefCell>, } @@ -46,13 +72,18 @@ impl EvmLoader { base_modulus, scalar_modulus, code: RefCell::new(code), - ptr: RefCell::new(0), + ptr: Default::default(), + cache: Default::default(), #[cfg(test)] gas_metering_ids: RefCell::new(Vec::new()), }) } - pub fn code(self: &Rc) -> Vec { + pub fn deployment_code(self: &Rc) -> Vec { + Code::deployment(self.runtime_code()) + } + + pub fn runtime_code(self: &Rc) -> Vec { let mut code = self.code.borrow().clone(); let dst = code.len() + 9; code.push(dst) @@ -72,7 +103,41 @@ impl EvmLoader { ptr } - fn scalar(self: &Rc, value: Value) -> Scalar { + pub(crate) fn scalar_modulus(&self) -> U256 { + self.scalar_modulus + } + + pub(crate) fn ptr(&self) -> usize { + *self.ptr.borrow() + } + + pub(crate) fn code_mut(&self) -> impl DerefMut + '_ { + self.code.borrow_mut() + } + + pub(crate) fn scalar(self: &Rc, value: Value) -> Scalar { + let value = if matches!( + value, + Value::Constant(_) | Value::Memory(_) | Value::Negated(_) + ) { + value + } else { + let identifier = value.identifier(); + let some_ptr = self.cache.borrow().get(&identifier).cloned(); + let ptr = if let Some(ptr) = some_ptr { + ptr + } else { + self.push(&Scalar { + loader: self.clone(), + value, + }); + let ptr = self.allocate(0x20); + self.code.borrow_mut().push(ptr).mstore(); + self.cache.borrow_mut().insert(identifier, ptr); + ptr + }; + Value::Memory(ptr) + }; Scalar { loader: self.clone(), value, @@ -87,13 +152,29 @@ impl EvmLoader { } fn push(self: &Rc, scalar: &Scalar) { - match scalar.value { + match scalar.value.clone() { Value::Constant(constant) => { self.code.borrow_mut().push(constant); } Value::Memory(ptr) => { self.code.borrow_mut().push(ptr).mload(); } + Value::Negated(value) => { + self.push(&self.scalar(*value)); + self.code.borrow_mut().push(self.scalar_modulus).sub(); + } + Value::Sum(lhs, rhs) => { + self.code.borrow_mut().push(self.scalar_modulus); + self.push(&self.scalar(*lhs)); + self.push(&self.scalar(*rhs)); + self.code.borrow_mut().addmod(); + } + Value::Product(lhs, rhs) => { + self.code.borrow_mut().push(self.scalar_modulus); + self.push(&self.scalar(*lhs)); + self.push(&self.scalar(*rhs)); + self.code.borrow_mut().mulmod(); + } } } @@ -139,46 +220,36 @@ impl EvmLoader { self.ec_point(Value::Memory(ptr)) } - pub fn calldataload_ec_point_from_limbs( + pub fn ec_point_from_limbs( self: &Rc, - offset: usize, + x_limbs: [Scalar; LIMBS], + y_limbs: [Scalar; LIMBS], ) -> EcPoint { let ptr = self.allocate(0x40); - for (ptr, offset) in [(ptr, offset), (ptr + 0x20, offset + LIMBS * 0x20)] { - for idx in 0..LIMBS { - if idx == 0 { - self.code - .borrow_mut() - // [..., success] - .push(offset) - // [..., success, x_limb_0_ptr] - .calldataload(); - // [..., success, x_limb_0] - } else { + for (ptr, limbs) in [(ptr, x_limbs), (ptr + 0x20, y_limbs)] { + for (idx, limb) in limbs.into_iter().enumerate() { + self.push(&limb); + // [..., success, acc] + if idx > 0 { self.code .borrow_mut() - // [..., success, x_acc] - .push(offset + idx * 0x20) - // [..., success, x_acc, x_limb_i_ptr] - .calldataload() - // [..., success, x_acc, x_limb_i] .push(idx * BITS) - // [..., success, x_acc, x_limb_i, shift] + // [..., success, acc, limb_i, shift] .shl() - // [..., success, x_acc, x_limb_i << shift] + // [..., success, acc, limb_i << shift] .add(); - // [..., success, x_acc] + // [..., success, acc] } } self.code .borrow_mut() - // [..., success, x] + // [..., success, coordinate] .dup(0) - // [..., success, x, x] + // [..., success, coordinate, coordinate] .push(ptr) - // [..., success, x, x, x_ptr] + // [..., success, coordinate, coordinate, ptr] .mstore(); - // [..., success, x] + // [..., success, coordinate] } // [..., success, x, y] self.validate_ec_point(); @@ -258,60 +329,21 @@ impl EvmLoader { .and(); } - pub fn squeeze_challenge(self: &Rc, ptr: usize, len: usize) -> (usize, Scalar) { - assert!(len > 0 && len % 0x20 == 0); - - let (ptr, len) = if len == 0x20 { - let ptr = if ptr + len != *self.ptr.borrow() { - (ptr..ptr + len) - .step_by(0x20) - .map(|ptr| self.dup_scalar(&self.scalar(Value::Memory(ptr)))) - .collect_vec() - .first() - .unwrap() - .ptr() - } else { - ptr - }; - self.code.borrow_mut().push(1).push(ptr + 0x20).mstore8(); - (ptr, len + 1) - } else { - (ptr, len) - }; - - let challenge_ptr = self.allocate(0x20); + pub fn keccak256(self: &Rc, ptr: usize, len: usize) -> usize { let hash_ptr = self.allocate(0x20); - self.code .borrow_mut() - .push(self.scalar_modulus) .push(len) .push(ptr) .keccak256() - .dup(0) .push(hash_ptr) - .mstore() - .r#mod() - .push(challenge_ptr) .mstore(); - - (hash_ptr, self.scalar(Value::Memory(challenge_ptr))) + hash_ptr } pub fn copy_scalar(self: &Rc, scalar: &Scalar, ptr: usize) { - match scalar.value { - Value::Constant(constant) => { - self.code.borrow_mut().push(constant).push(ptr).mstore(); - } - Value::Memory(src_ptr) => { - self.code - .borrow_mut() - .push(src_ptr) - .mload() - .push(ptr) - .mstore(); - } - } + self.push(scalar); + self.code.borrow_mut().push(ptr).mstore(); } pub fn dup_scalar(self: &Rc, scalar: &Scalar) -> Scalar { @@ -320,7 +352,7 @@ impl EvmLoader { self.scalar(Value::Memory(ptr)) } - fn dup_ec_point(self: &Rc, value: &EcPoint) -> EcPoint { + pub fn dup_ec_point(self: &Rc, value: &EcPoint) -> EcPoint { let ptr = self.allocate(0x40); match value.value { Value::Constant((x, y)) => { @@ -345,6 +377,9 @@ impl EvmLoader { .push(ptr + 0x20) .mstore(); } + Value::Negated(_) | Value::Sum(_, _) | Value::Product(_, _) => { + unreachable!() + } } self.ec_point(Value::Memory(ptr)) } @@ -390,14 +425,6 @@ impl EvmLoader { self.ec_point(Value::Memory(rd_ptr)) } - fn ec_point_sub(self: &Rc, _: &EcPoint, _: &EcPoint) -> EcPoint { - unreachable!() - } - - fn ec_point_neg(self: &Rc, _: &EcPoint) -> EcPoint { - unreachable!() - } - fn ec_point_scalar_mul(self: &Rc, ec_point: &EcPoint, scalar: &Scalar) -> EcPoint { let rd_ptr = self.dup_ec_point(ec_point).ptr(); self.dup_scalar(scalar); @@ -449,19 +476,15 @@ impl EvmLoader { } fn add(self: &Rc, lhs: &Scalar, rhs: &Scalar) -> Scalar { - if let (Value::Constant(lhs), Value::Constant(rhs)) = (lhs.value, rhs.value) { + if let (Value::Constant(lhs), Value::Constant(rhs)) = (&lhs.value, &rhs.value) { let out = (U512::from(lhs) + U512::from(rhs)) % U512::from(self.scalar_modulus); return self.scalar(Value::Constant(out.try_into().unwrap())); } - let ptr = self.allocate(0x20); - - self.code.borrow_mut().push(self.scalar_modulus); - self.push(rhs); - self.push(lhs); - self.code.borrow_mut().addmod().push(ptr).mstore(); - - self.scalar(Value::Memory(ptr)) + self.scalar(Value::Sum( + Box::new(lhs.value.clone()), + Box::new(rhs.value.clone()), + )) } fn sub(self: &Rc, lhs: &Scalar, rhs: &Scalar) -> Scalar { @@ -469,31 +492,22 @@ impl EvmLoader { return self.add(lhs, &self.neg(rhs)); } - let ptr = self.allocate(0x20); - - self.code.borrow_mut().push(self.scalar_modulus); - self.push(rhs); - self.code.borrow_mut().push(self.scalar_modulus).sub(); - self.push(lhs); - self.code.borrow_mut().addmod().push(ptr).mstore(); - - self.scalar(Value::Memory(ptr)) + self.scalar(Value::Sum( + Box::new(lhs.value.clone()), + Box::new(Value::Negated(Box::new(rhs.value.clone()))), + )) } fn mul(self: &Rc, lhs: &Scalar, rhs: &Scalar) -> Scalar { - if let (Value::Constant(lhs), Value::Constant(rhs)) = (lhs.value, rhs.value) { + if let (Value::Constant(lhs), Value::Constant(rhs)) = (&lhs.value, &rhs.value) { let out = (U512::from(lhs) * U512::from(rhs)) % U512::from(self.scalar_modulus); return self.scalar(Value::Constant(out.try_into().unwrap())); } - let ptr = self.allocate(0x20); - - self.code.borrow_mut().push(self.scalar_modulus); - self.push(rhs); - self.push(lhs); - self.code.borrow_mut().mulmod().push(ptr).mstore(); - - self.scalar(Value::Memory(ptr)) + self.scalar(Value::Product( + Box::new(lhs.value.clone()), + Box::new(rhs.value.clone()), + )) } fn neg(self: &Rc, scalar: &Scalar) -> Scalar { @@ -501,17 +515,7 @@ impl EvmLoader { return self.scalar(Value::Constant(self.scalar_modulus - constant)); } - let ptr = self.allocate(0x20); - - self.push(scalar); - self.code - .borrow_mut() - .push(self.scalar_modulus) - .sub() - .push(ptr) - .mstore(); - - self.scalar(Value::Memory(ptr)) + self.scalar(Value::Negated(Box::new(scalar.value.clone()))) } } @@ -552,19 +556,15 @@ pub struct EcPoint { } impl EcPoint { - pub(super) fn loader(&self) -> &Rc { + pub(crate) fn loader(&self) -> &Rc { &self.loader } - pub fn value(&self) -> Value<(U256, U256)> { - self.value - } - - pub fn is_const(&self) -> bool { - matches!(self.value, Value::Constant(_)) + pub(crate) fn value(&self) -> Value<(U256, U256)> { + self.value.clone() } - pub fn ptr(&self) -> usize { + pub(crate) fn ptr(&self) -> usize { match self.value { Value::Memory(ptr) => ptr, _ => unreachable!(), @@ -580,70 +580,6 @@ impl Debug for EcPoint { } } -impl Add for EcPoint { - type Output = Self; - - fn add(self, rhs: Self) -> Self { - self.loader.ec_point_add(&self, &rhs) - } -} - -impl Sub for EcPoint { - type Output = Self; - - fn sub(self, rhs: Self) -> Self { - self.loader.ec_point_sub(&self, &rhs) - } -} - -impl Neg for EcPoint { - type Output = Self; - - fn neg(self) -> Self { - self.loader.ec_point_neg(&self) - } -} - -impl<'a> Add<&'a Self> for EcPoint { - type Output = Self; - - fn add(self, rhs: &'a Self) -> Self { - self.loader.ec_point_add(&self, rhs) - } -} - -impl<'a> Sub<&'a Self> for EcPoint { - type Output = Self; - - fn sub(self, rhs: &'a Self) -> Self { - self.loader.ec_point_sub(&self, rhs) - } -} - -impl AddAssign for EcPoint { - fn add_assign(&mut self, rhs: Self) { - *self = self.loader.ec_point_add(self, &rhs); - } -} - -impl SubAssign for EcPoint { - fn sub_assign(&mut self, rhs: Self) { - *self = self.loader.ec_point_sub(self, &rhs); - } -} - -impl<'a> AddAssign<&'a Self> for EcPoint { - fn add_assign(&mut self, rhs: &'a Self) { - *self = self.loader.ec_point_add(self, rhs); - } -} - -impl<'a> SubAssign<&'a Self> for EcPoint { - fn sub_assign(&mut self, rhs: &'a Self) { - *self = self.loader.ec_point_sub(self, rhs); - } -} - impl PartialEq for EcPoint { fn eq(&self, other: &Self) -> bool { self.value == other.value @@ -652,8 +588,8 @@ impl PartialEq for EcPoint { impl LoadedEcPoint for EcPoint where - C: Curve + UncompressedEncoding, - C::Scalar: PrimeField, + C: CurveAffine, + C::ScalarExt: PrimeField, { type Loader = Rc; @@ -668,7 +604,7 @@ where Value::Constant(constant) if constant == U256::one() => ec_point, _ => ec_point.loader.ec_point_scalar_mul(&ec_point, &scalar), }) - .reduce(|acc, ec_point| acc + ec_point) + .reduce(|acc, ec_point| acc.loader.ec_point_add(&acc, &ec_point)) .unwrap() } } @@ -680,18 +616,27 @@ pub struct Scalar { } impl Scalar { - pub fn value(&self) -> Value { - self.value + pub(crate) fn loader(&self) -> &Rc { + &self.loader } - pub fn is_const(&self) -> bool { + pub(crate) fn value(&self) -> Value { + self.value.clone() + } + + pub(crate) fn is_const(&self) -> bool { matches!(self.value, Value::Constant(_)) } - pub fn ptr(&self) -> usize { + pub(crate) fn ptr(&self) -> usize { match self.value { Value::Memory(ptr) => ptr, - _ => unreachable!(), + _ => *self + .loader + .cache + .borrow() + .get(&self.value.identifier()) + .unwrap(), } } } @@ -879,34 +824,164 @@ impl> LoadedScalar for Scalar { impl EcPointLoader for Rc where - C: Curve + UncompressedEncoding, + C: CurveAffine, C::Scalar: PrimeField, { type LoadedEcPoint = EcPoint; fn ec_point_load_const(&self, value: &C) -> EcPoint { - let bytes = value.to_uncompressed(); - let (x, y) = ( - U256::from_little_endian(&bytes[..32]), - U256::from_little_endian(&bytes[32..]), - ); + let coordinates = value.coordinates().unwrap(); + let [x, y] = [coordinates.x(), coordinates.y()] + .map(|coordinate| U256::from_little_endian(coordinate.to_repr().as_ref())); self.ec_point(Value::Constant((x, y))) } + + fn ec_point_assert_eq(&self, _: &str, _: &EcPoint, _: &EcPoint) -> Result<(), Error> { + unimplemented!() + } } impl> ScalarLoader for Rc { type LoadedScalar = Scalar; fn load_const(&self, value: &F) -> Scalar { - self.scalar(Value::Constant(U256::from_little_endian( - value.to_repr().as_slice(), - ))) + self.scalar(Value::Constant(fe_to_u256(*value))) + } + + fn assert_eq(&self, _: &str, _: &Scalar, _: &Scalar) -> Result<(), Error> { + unimplemented!() + } + + fn sum_with_coeff_and_const(&self, values: &[(F, &Scalar)], constant: F) -> Scalar { + if values.is_empty() { + return self.load_const(&constant); + } + + let push_addend = |(coeff, value): &(F, &Scalar)| { + assert_ne!(*coeff, F::zero()); + match (*coeff == F::one(), &value.value) { + (true, _) => { + self.push(value); + } + (false, Value::Constant(value)) => { + self.push(&self.scalar(Value::Constant(fe_to_u256( + *coeff * u256_to_fe::(*value), + )))); + } + (false, _) => { + self.code.borrow_mut().push(self.scalar_modulus); + self.push(&self.scalar(Value::Constant(fe_to_u256(*coeff)))); + self.push(value); + self.code.borrow_mut().mulmod(); + } + } + }; + + let mut values = values.iter(); + if constant == F::zero() { + push_addend(values.next().unwrap()); + } else { + self.push(&self.scalar(Value::Constant(fe_to_u256(constant)))); + } + + let chunk_size = 16 - self.code.borrow().stack_len(); + for values in &values.chunks(chunk_size) { + let values = values.into_iter().collect_vec(); + + self.code.borrow_mut().push(self.scalar_modulus); + for _ in 1..chunk_size.min(values.len()) { + self.code.borrow_mut().dup(0); + } + self.code.borrow_mut().swap(chunk_size.min(values.len())); + + for value in values { + push_addend(value); + self.code.borrow_mut().addmod(); + } + } + + let ptr = self.allocate(0x20); + self.code.borrow_mut().push(ptr).mstore(); + + self.scalar(Value::Memory(ptr)) + } + + fn sum_products_with_coeff_and_const( + &self, + values: &[(F, &Scalar, &Scalar)], + constant: F, + ) -> Scalar { + if values.is_empty() { + return self.load_const(&constant); + } + + let push_addend = |(coeff, lhs, rhs): &(F, &Scalar, &Scalar)| { + assert_ne!(*coeff, F::zero()); + match (*coeff == F::one(), &lhs.value, &rhs.value) { + (_, Value::Constant(lhs), Value::Constant(rhs)) => { + self.push(&self.scalar(Value::Constant(fe_to_u256( + *coeff * u256_to_fe::(*lhs) * u256_to_fe::(*rhs), + )))); + } + (_, value @ Value::Memory(_), Value::Constant(constant)) + | (_, Value::Constant(constant), value @ Value::Memory(_)) => { + self.code.borrow_mut().push(self.scalar_modulus); + self.push(&self.scalar(Value::Constant(fe_to_u256( + *coeff * u256_to_fe::(*constant), + )))); + self.push(&self.scalar(value.clone())); + self.code.borrow_mut().mulmod(); + } + (true, _, _) => { + self.code.borrow_mut().push(self.scalar_modulus); + self.push(lhs); + self.push(rhs); + self.code.borrow_mut().mulmod(); + } + (false, _, _) => { + self.code.borrow_mut().push(self.scalar_modulus).dup(0); + self.push(&self.scalar(Value::Constant(fe_to_u256(*coeff)))); + self.push(lhs); + self.code.borrow_mut().mulmod(); + self.push(rhs); + self.code.borrow_mut().mulmod(); + } + } + }; + + let mut values = values.iter(); + if constant == F::zero() { + push_addend(values.next().unwrap()); + } else { + self.push(&self.scalar(Value::Constant(fe_to_u256(constant)))); + } + + let chunk_size = 16 - self.code.borrow().stack_len(); + for values in &values.chunks(chunk_size) { + let values = values.into_iter().collect_vec(); + + self.code.borrow_mut().push(self.scalar_modulus); + for _ in 1..chunk_size.min(values.len()) { + self.code.borrow_mut().dup(0); + } + self.code.borrow_mut().swap(chunk_size.min(values.len())); + + for value in values { + push_addend(value); + self.code.borrow_mut().addmod(); + } + } + + let ptr = self.allocate(0x20); + self.code.borrow_mut().push(ptr).mstore(); + + self.scalar(Value::Memory(ptr)) } } impl Loader for Rc where - C: Curve + UncompressedEncoding, + C: CurveAffine, C::Scalar: PrimeField, { #[cfg(test)] diff --git a/src/loader/evm/test.rs b/src/loader/evm/test.rs index d4ae4984..e204c1b8 100644 --- a/src/loader/evm/test.rs +++ b/src/loader/evm/test.rs @@ -9,12 +9,6 @@ use std::env::var_os; mod tui; -fn small_address(lsb: u8) -> Address { - let mut address = Address::zero(); - *address.0.last_mut().unwrap() = lsb; - address -} - fn debug() -> bool { matches!( var_os("DEBUG"), @@ -23,9 +17,15 @@ fn debug() -> bool { } pub fn execute(code: Vec, calldata: Vec) -> (bool, u64, Vec) { + assert!( + code.len() <= 0x6000, + "Contract size {} exceeds the limit 24576", + code.len() + ); + let debug = debug(); - let caller = small_address(0xfe); - let callee = small_address(0xff); + let caller = Address::from_low_u64_be(0xfe); + let callee = Address::from_low_u64_be(0xff); let mut evm = ExecutorBuilder::default() .with_gas_limit(u64::MAX.into()) @@ -52,5 +52,5 @@ pub fn execute(code: Vec, calldata: Vec) -> (bool, u64, Vec) { Tui::new(result.debug.unwrap().flatten(0), 0).start(); } - (!result.reverted, result.gas, costs) + (!result.reverted, result.gas_used, costs) } diff --git a/src/loader/evm/test/tui.rs b/src/loader/evm/test/tui.rs index 72866d19..fcaef36c 100644 --- a/src/loader/evm/test/tui.rs +++ b/src/loader/evm/test/tui.rs @@ -60,7 +60,7 @@ impl Tui { .expect("unable to execute disable mouse capture"); println!("{e}"); })); - let tick_rate = Duration::from_millis(200); + let tick_rate = Duration::from_millis(60); let (tx, rx) = mpsc::channel(); thread::spawn(move || { diff --git a/src/loader/evm/transcript.rs b/src/loader/evm/transcript.rs deleted file mode 100644 index a5ff68d2..00000000 --- a/src/loader/evm/transcript.rs +++ /dev/null @@ -1,229 +0,0 @@ -use crate::{ - loader::{ - evm::{ - loader::{EcPoint, EvmLoader, Scalar, Value}, - u256_to_field, - }, - native::NativeLoader, - Loader, - }, - util::{Curve, Group, Itertools, PrimeField, Transcript, TranscriptRead, UncompressedEncoding}, - Error, -}; -use ethereum_types::U256; -use sha3::{Digest, Keccak256}; -use std::{ - io::{self, Read, Write}, - marker::PhantomData, - rc::Rc, -}; - -pub struct MemoryChunk { - ptr: usize, - len: usize, -} - -impl MemoryChunk { - fn new(ptr: usize) -> Self { - Self { ptr, len: 0x20 } - } - - fn reset(&mut self, ptr: usize) { - self.ptr = ptr; - self.len = 0x20; - } - - fn include(&self, ptr: usize, size: usize) -> bool { - let range = self.ptr..=self.ptr + self.len; - range.contains(&ptr) && range.contains(&(ptr + size)) - } - - fn extend(&mut self, ptr: usize, size: usize) { - if !self.include(ptr, size) { - assert_eq!(self.ptr + self.len, ptr); - self.len += size; - } - } -} - -pub struct EvmTranscript, S, B> { - loader: L, - stream: S, - buf: B, - _marker: PhantomData, -} - -impl EvmTranscript, usize, MemoryChunk> -where - C: Curve + UncompressedEncoding, - C::Scalar: PrimeField, -{ - pub fn new(loader: Rc) -> Self { - let ptr = loader.allocate(0x20); - assert_eq!(ptr, 0); - Self { - loader, - stream: 0, - buf: MemoryChunk::new(ptr), - _marker: PhantomData, - } - } -} - -impl Transcript> for EvmTranscript, usize, MemoryChunk> -where - C: Curve + UncompressedEncoding, - C::Scalar: PrimeField, -{ - fn squeeze_challenge(&mut self) -> Scalar { - let (ptr, scalar) = self.loader.squeeze_challenge(self.buf.ptr, self.buf.len); - self.buf.reset(ptr); - scalar - } - - fn common_ec_point(&mut self, ec_point: &EcPoint) -> Result<(), Error> { - if let Value::Memory(ptr) = ec_point.value() { - self.buf.extend(ptr, 0x40); - } else { - unreachable!() - } - Ok(()) - } - - fn common_scalar(&mut self, scalar: &Scalar) -> Result<(), Error> { - match scalar.value() { - Value::Constant(_) if self.buf.ptr == 0 => { - self.loader.copy_scalar(scalar, self.buf.ptr); - } - Value::Memory(ptr) => { - self.buf.extend(ptr, 0x20); - } - _ => unreachable!(), - } - Ok(()) - } -} - -impl TranscriptRead> for EvmTranscript, usize, MemoryChunk> -where - C: Curve + UncompressedEncoding, - C::Scalar: PrimeField, -{ - fn read_scalar(&mut self) -> Result { - let scalar = self.loader.calldataload_scalar(self.stream); - self.stream += 0x20; - self.common_scalar(&scalar)?; - Ok(scalar) - } - - fn read_ec_point(&mut self) -> Result { - let ec_point = self.loader.calldataload_ec_point(self.stream); - self.stream += 0x40; - self.common_ec_point(&ec_point)?; - Ok(ec_point) - } -} - -impl EvmTranscript> -where - C: Curve, -{ - pub fn new(stream: S) -> Self { - Self { - loader: NativeLoader, - stream, - buf: Vec::new(), - _marker: PhantomData, - } - } -} - -impl Transcript for EvmTranscript> -where - C: Curve + UncompressedEncoding, - C::Scalar: PrimeField, -{ - fn squeeze_challenge(&mut self) -> C::Scalar { - let data = self - .buf - .iter() - .cloned() - .chain(if self.buf.len() == 0x20 { - Some(1) - } else { - None - }) - .collect_vec(); - let hash: [u8; 32] = Keccak256::digest(data).into(); - self.buf = hash.to_vec(); - u256_to_field(U256::from_big_endian(hash.as_slice())) - } - - fn common_ec_point(&mut self, ec_point: &C) -> Result<(), Error> { - let uncopressed = ec_point.to_uncompressed(); - self.buf.extend(uncopressed[..32].iter().rev().cloned()); - self.buf.extend(uncopressed[32..].iter().rev().cloned()); - - Ok(()) - } - - fn common_scalar(&mut self, scalar: &C::Scalar) -> Result<(), Error> { - self.buf.extend(scalar.to_repr().as_ref().iter().rev()); - - Ok(()) - } -} - -impl TranscriptRead for EvmTranscript> -where - C: Curve + UncompressedEncoding, - C::Scalar: PrimeField, - S: Read, -{ - fn read_scalar(&mut self) -> Result { - let mut data = [0; 32]; - self.stream - .read_exact(data.as_mut()) - .map_err(|err| Error::Transcript(err.kind(), err.to_string()))?; - data.reverse(); - let scalar = ::Scalar::from_repr_vartime(data).ok_or_else(|| { - Error::Transcript( - io::ErrorKind::Other, - "Invalid scalar encoding in proof".to_string(), - ) - })?; - self.common_scalar(&scalar)?; - Ok(scalar) - } - - fn read_ec_point(&mut self) -> Result { - let mut data = [0; 64]; - self.stream - .read_exact(data.as_mut()) - .map_err(|err| Error::Transcript(err.kind(), err.to_string()))?; - data.as_mut_slice()[..32].reverse(); - data.as_mut_slice()[32..].reverse(); - let ec_point = C::from_uncompressed(data).ok_or_else(|| { - Error::Transcript( - io::ErrorKind::Other, - "Invalid elliptic curve point encoding in proof".to_string(), - ) - })?; - self.common_ec_point(&ec_point)?; - Ok(ec_point) - } -} - -impl EvmTranscript> -where - C: Curve, - S: Write, -{ - pub fn stream_mut(&mut self) -> &mut S { - &mut self.stream - } - - pub fn finalize(self) -> S { - self.stream - } -} diff --git a/src/loader/evm/util.rs b/src/loader/evm/util.rs new file mode 100644 index 00000000..0d9698bd --- /dev/null +++ b/src/loader/evm/util.rs @@ -0,0 +1,92 @@ +use crate::{ + cost::Cost, + util::{arithmetic::PrimeField, Itertools}, +}; +use ethereum_types::U256; +use std::iter; + +pub struct MemoryChunk { + ptr: usize, + len: usize, +} + +impl MemoryChunk { + pub fn new(ptr: usize) -> Self { + Self { ptr, len: 0 } + } + + pub fn ptr(&self) -> usize { + self.ptr + } + + pub fn len(&self) -> usize { + self.len + } + + pub fn is_empty(&self) -> bool { + self.len == 0 + } + + pub fn end(&self) -> usize { + self.ptr + self.len + } + + pub fn reset(&mut self, ptr: usize) { + self.ptr = ptr; + self.len = 0; + } + + pub fn extend(&mut self, size: usize) { + self.len += size; + } +} + +// Assume fields implements traits in crate `ff` always have little-endian representation. +pub fn fe_to_u256(f: F) -> U256 +where + F: PrimeField, +{ + U256::from_little_endian(f.to_repr().as_ref()) +} + +pub fn u256_to_fe(value: U256) -> F +where + F: PrimeField, +{ + let value = value % modulus::(); + let mut repr = F::Repr::default(); + value.to_little_endian(repr.as_mut()); + F::from_repr(repr).unwrap() +} + +pub fn modulus() -> U256 +where + F: PrimeField, +{ + U256::from_little_endian((-F::one()).to_repr().as_ref()) + 1 +} + +pub fn encode_calldata(instances: &[Vec], proof: &[u8]) -> Vec +where + F: PrimeField, +{ + iter::empty() + .chain( + instances + .iter() + .flatten() + .flat_map(|value| value.to_repr().as_ref().iter().rev().cloned().collect_vec()), + ) + .chain(proof.iter().cloned()) + .collect() +} + +pub fn estimate_gas(cost: Cost) -> usize { + let proof_size = cost.num_commitment * 64 + (cost.num_evaluation + cost.num_instance) * 32; + + let intrinsic_cost = 21000; + let calldata_cost = (proof_size as f64 * 15.25).ceil() as usize; + let ec_operation_cost = 113100 + (cost.num_msm - 2) * 6350; + + intrinsic_cost + calldata_cost + ec_operation_cost +} diff --git a/src/loader/halo2.rs b/src/loader/halo2.rs index 3d227a8a..9eae74e3 100644 --- a/src/loader/halo2.rs +++ b/src/loader/halo2.rs @@ -1,6 +1,29 @@ -mod accumulation; -mod loader; -mod transcript; +pub(crate) mod loader; +mod shim; -pub use loader::Halo2Loader; -pub use transcript::PoseidonTranscript; +#[cfg(test)] +pub(crate) mod test; + +pub use loader::{EcPoint, Halo2Loader, Scalar}; +pub use shim::{Context, EccInstructions, IntegerInstructions}; +pub use util::Valuetools; + +pub use halo2_wrong_ecc; + +mod util { + use halo2_proofs::circuit::Value; + + pub trait Valuetools: Iterator> { + fn fold_zipped(self, init: B, mut f: F) -> Value + where + Self: Sized, + F: FnMut(B, V) -> B, + { + self.into_iter().fold(Value::known(init), |acc, value| { + acc.zip(value).map(|(acc, value)| f(acc, value)) + }) + } + } + + impl>> Valuetools for I {} +} diff --git a/src/loader/halo2/accumulation.rs b/src/loader/halo2/accumulation.rs deleted file mode 100644 index cc78ab83..00000000 --- a/src/loader/halo2/accumulation.rs +++ /dev/null @@ -1,93 +0,0 @@ -use crate::{ - loader::{ - halo2::loader::{Halo2Loader, Scalar}, - LoadedEcPoint, - }, - protocol::Protocol, - scheme::kzg::{AccumulationStrategy, Accumulator, SameCurveAccumulation, MSM}, - util::{Itertools, Transcript}, - Error, -}; -use halo2_curves::CurveAffine; -use halo2_wrong_ecc::AssignedPoint; -use std::rc::Rc; - -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> - SameCurveAccumulation>, LIMBS, BITS> -{ - pub fn finalize( - self, - g1: C, - ) -> ( - AssignedPoint, - AssignedPoint, - ) { - let (lhs, rhs) = self.accumulator.unwrap().evaluate(g1.to_curve()); - let loader = lhs.loader(); - ( - loader.ec_point_nomalize(&lhs.assigned()), - loader.ec_point_nomalize(&rhs.assigned()), - ) - } -} - -impl<'a, 'b, C, T, P, const LIMBS: usize, const BITS: usize> - AccumulationStrategy>, T, P> - for SameCurveAccumulation>, LIMBS, BITS> -where - C: CurveAffine, - T: Transcript>>, -{ - type Output = (); - - fn extract_accumulator( - &self, - protocol: &Protocol, - loader: &Rc>, - transcript: &mut T, - statements: &[Vec>], - ) -> Option>>> { - let accumulator_indices = protocol.accumulator_indices.as_ref()?; - - let challenges = transcript.squeeze_n_challenges(accumulator_indices.len()); - let accumulators = accumulator_indices - .iter() - .map(|indices| { - assert_eq!(indices.len(), 4 * LIMBS); - let assinged = indices - .iter() - .map(|index| statements[index.0][index.1].assigned()) - .collect_vec(); - let lhs = loader.assign_ec_point_from_limbs( - assinged[..LIMBS].to_vec().try_into().unwrap(), - assinged[LIMBS..2 * LIMBS].to_vec().try_into().unwrap(), - ); - let rhs = loader.assign_ec_point_from_limbs( - assinged[2 * LIMBS..3 * LIMBS].to_vec().try_into().unwrap(), - assinged[3 * LIMBS..].to_vec().try_into().unwrap(), - ); - Accumulator::new(MSM::base(lhs), MSM::base(rhs)) - }) - .collect_vec(); - - Some(Accumulator::random_linear_combine( - challenges.into_iter().zip(accumulators), - )) - } - - fn process( - &mut self, - _: &Rc>, - transcript: &mut T, - _: P, - accumulator: Accumulator>>, - ) -> Result { - self.accumulator = Some(match self.accumulator.take() { - Some(curr_accumulator) => { - accumulator + curr_accumulator * &transcript.squeeze_challenge() - } - None => accumulator, - }); - Ok(()) - } -} diff --git a/src/loader/halo2/loader.rs b/src/loader/halo2/loader.rs index e811debb..0d288ce7 100644 --- a/src/loader/halo2/loader.rs +++ b/src/loader/halo2/loader.rs @@ -1,184 +1,133 @@ use crate::{ - loader::{EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader}, - util::{Curve, Field, FieldOps, Group, Itertools}, -}; -use halo2_curves::CurveAffine; -use halo2_proofs::circuit; -use halo2_wrong_ecc::{ - integer::{ - rns::{Integer, Rns}, - IntegerInstructions, Range, + loader::{ + halo2::shim::{EccInstructions, IntegerInstructions}, + EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader, }, - maingate::{ - AssignedValue, CombinationOptionCommon, MainGate, MainGateInstructions, RegionCtx, Term, + util::{ + arithmetic::{CurveAffine, Field, FieldOps}, + Itertools, }, - AssignedPoint, BaseFieldEccChip, EccConfig, }; -use rand::rngs::OsRng; +use halo2_proofs::circuit; use std::{ - cell::RefCell, + cell::{Ref, RefCell, RefMut}, + collections::btree_map::{BTreeMap, Entry}, fmt::{self, Debug}, iter, - ops::{Add, AddAssign, Deref, DerefMut, Mul, MulAssign, Neg, Sub, SubAssign}, + marker::PhantomData, + ops::{Add, AddAssign, Deref, Mul, MulAssign, Neg, Sub, SubAssign}, rc::Rc, }; -const WINDOW_SIZE: usize = 3; - -#[derive(Clone, Debug)] -pub enum Value { - Constant(T), - Assigned(L), -} - -pub struct Halo2Loader<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> { - rns: Rc>, - ecc_chip: RefCell>, - main_gate: MainGate, - ctx: RefCell>, +#[derive(Debug)] +pub struct Halo2Loader<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { + ecc_chip: RefCell, + ctx: RefCell, + num_scalar: RefCell, num_ec_point: RefCell, + const_ec_point: RefCell>>, + _marker: PhantomData, #[cfg(test)] row_meterings: RefCell>, } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> - Halo2Loader<'a, 'b, C, LIMBS, BITS> -{ - pub fn new(ecc_config: EccConfig, ctx: RegionCtx<'a, 'b, C::Scalar>) -> Rc { - let ecc_chip = BaseFieldEccChip::new(ecc_config); - let main_gate = ecc_chip.main_gate(); +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, EccChip> { + pub fn new(ecc_chip: EccChip, ctx: EccChip::Context) -> Rc { Rc::new(Self { - rns: Rc::new(Rns::construct()), ecc_chip: RefCell::new(ecc_chip), - main_gate, ctx: RefCell::new(ctx), - num_ec_point: RefCell::new(0), + num_scalar: RefCell::default(), + num_ec_point: RefCell::default(), + const_ec_point: RefCell::default(), #[cfg(test)] - row_meterings: RefCell::new(Vec::new()), + row_meterings: RefCell::default(), + _marker: PhantomData, }) } - pub fn rns(&self) -> Rc> { - self.rns.clone() + pub fn into_ctx(self) -> EccChip::Context { + self.ctx.into_inner() } - pub fn ecc_chip(&self) -> impl Deref> + '_ { + pub fn ecc_chip(&self) -> Ref<'_, EccChip> { self.ecc_chip.borrow() } - pub(super) fn ctx_mut(&self) -> impl DerefMut> + '_ { + pub fn scalar_chip(&self) -> Ref<'_, EccChip::ScalarChip> { + Ref::map(self.ecc_chip(), |ecc_chip| ecc_chip.scalar_chip()) + } + + pub fn ctx(&self) -> Ref<'_, EccChip::Context> { + self.ctx.borrow() + } + + pub(crate) fn ctx_mut(&self) -> RefMut<'_, EccChip::Context> { self.ctx.borrow_mut() } - pub fn assign_const_scalar( - self: &Rc, - scalar: C::Scalar, - ) -> Scalar<'a, 'b, C, LIMBS, BITS> { + pub fn assign_const_scalar(self: &Rc, constant: C::Scalar) -> Scalar<'a, C, EccChip> { let assigned = self - .main_gate - .assign_constant(&mut self.ctx_mut(), scalar) + .scalar_chip() + .assign_constant(&mut self.ctx_mut(), constant) .unwrap(); self.scalar(Value::Assigned(assigned)) } pub fn assign_scalar( self: &Rc, - scalar: circuit::Value, - ) -> Scalar<'a, 'b, C, LIMBS, BITS> { + scalar: circuit::Value, + ) -> Scalar<'a, C, EccChip> { let assigned = self - .main_gate - .assign_value(&mut self.ctx_mut(), scalar) + .scalar_chip() + .assign_integer(&mut self.ctx_mut(), scalar) .unwrap(); self.scalar(Value::Assigned(assigned)) } - pub fn scalar( + pub(crate) fn scalar( self: &Rc, - value: Value>, - ) -> Scalar<'a, 'b, C, LIMBS, BITS> { + value: Value, + ) -> Scalar<'a, C, EccChip> { + let index = *self.num_scalar.borrow(); + *self.num_scalar.borrow_mut() += 1; Scalar { loader: self.clone(), + index, value, } } - pub fn assign_const_ec_point(self: &Rc, ec_point: C) -> EcPoint<'a, 'b, C, LIMBS, BITS> { - let assigned = self - .ecc_chip - .borrow() - .assign_constant(&mut self.ctx_mut(), ec_point) - .unwrap(); - self.ec_point(assigned) + pub fn assign_const_ec_point(self: &Rc, constant: C) -> EcPoint<'a, C, EccChip> { + let coordinates = constant.coordinates().unwrap(); + match self + .const_ec_point + .borrow_mut() + .entry((*coordinates.x(), *coordinates.y())) + { + Entry::Occupied(entry) => entry.get().clone(), + Entry::Vacant(entry) => { + let assigned = self + .ecc_chip() + .assign_point(&mut self.ctx_mut(), circuit::Value::known(constant)) + .unwrap(); + let ec_point = self.ec_point(assigned); + entry.insert(ec_point).clone() + } + } } pub fn assign_ec_point( self: &Rc, ec_point: circuit::Value, - ) -> EcPoint<'a, 'b, C, LIMBS, BITS> { + ) -> EcPoint<'a, C, EccChip> { let assigned = self - .ecc_chip - .borrow() + .ecc_chip() .assign_point(&mut self.ctx_mut(), ec_point) .unwrap(); self.ec_point(assigned) } - pub fn assign_ec_point_from_limbs( - self: &Rc, - x_limbs: [AssignedValue; LIMBS], - y_limbs: [AssignedValue; LIMBS], - ) -> EcPoint<'a, 'b, C, LIMBS, BITS> { - let [x, y] = [&x_limbs, &y_limbs] - .map(|limbs| { - limbs.iter().enumerate().fold( - circuit::Value::known([C::Scalar::zero(); LIMBS]), - |acc, (idx, limb)| { - acc.zip(limb.value()).map(|(mut acc, limb)| { - acc[idx] = *limb; - acc - }) - }, - ) - }) - .map(|limbs| { - self.ecc_chip - .borrow() - .integer_chip() - .assign_integer( - &mut self.ctx_mut(), - limbs - .map(|limbs| Integer::from_limbs(&limbs, self.rns.clone())) - .into(), - Range::Remainder, - ) - .unwrap() - }); - - let ec_point = AssignedPoint::new(x, y); - self.ecc_chip() - .assert_is_on_curve(&mut self.ctx_mut(), &ec_point) - .unwrap(); - - for (src, dst) in x_limbs.iter().chain(y_limbs.iter()).zip( - ec_point - .get_x() - .limbs() - .iter() - .chain(ec_point.get_y().limbs().iter()), - ) { - self.ctx - .borrow_mut() - .constrain_equal(src.cell(), dst.as_ref().cell()) - .unwrap(); - } - - self.ec_point(ec_point) - } - - pub fn ec_point( - self: &Rc, - assigned: AssignedPoint, - ) -> EcPoint<'a, 'b, C, LIMBS, BITS> { + fn ec_point(self: &Rc, assigned: EccChip::AssignedEcPoint) -> EcPoint<'a, C, EccChip> { let index = *self.num_ec_point.borrow(); *self.num_ec_point.borrow_mut() += 1; EcPoint { @@ -188,71 +137,66 @@ impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> } } - pub fn ec_point_nomalize( - self: &Rc, - assigned: &AssignedPoint, - ) -> AssignedPoint { - self.ecc_chip() - .normalize(&mut self.ctx_mut(), assigned) - .unwrap() - } - fn add( self: &Rc, - lhs: &Scalar<'a, 'b, C, LIMBS, BITS>, - rhs: &Scalar<'a, 'b, C, LIMBS, BITS>, - ) -> Scalar<'a, 'b, C, LIMBS, BITS> { + lhs: &Scalar<'a, C, EccChip>, + rhs: &Scalar<'a, C, EccChip>, + ) -> Scalar<'a, C, EccChip> { let output = match (&lhs.value, &rhs.value) { (Value::Constant(lhs), Value::Constant(rhs)) => Value::Constant(*lhs + rhs), (Value::Assigned(assigned), Value::Constant(constant)) - | (Value::Constant(constant), Value::Assigned(assigned)) => { - MainGateInstructions::add_constant( - &self.main_gate, + | (Value::Constant(constant), Value::Assigned(assigned)) => self + .scalar_chip() + .sum_with_coeff_and_const( &mut self.ctx_mut(), - assigned, + &[(C::Scalar::one(), assigned.clone())], *constant, ) .map(Value::Assigned) - .unwrap() - } - (Value::Assigned(lhs), Value::Assigned(rhs)) => { - MainGateInstructions::add(&self.main_gate, &mut self.ctx_mut(), lhs, rhs) - .map(Value::Assigned) - .unwrap() - } + .unwrap(), + (Value::Assigned(lhs), Value::Assigned(rhs)) => self + .scalar_chip() + .sum_with_coeff_and_const( + &mut self.ctx_mut(), + &[ + (C::Scalar::one(), lhs.clone()), + (C::Scalar::one(), rhs.clone()), + ], + C::Scalar::zero(), + ) + .map(Value::Assigned) + .unwrap(), }; self.scalar(output) } fn sub( self: &Rc, - lhs: &Scalar<'a, 'b, C, LIMBS, BITS>, - rhs: &Scalar<'a, 'b, C, LIMBS, BITS>, - ) -> Scalar<'a, 'b, C, LIMBS, BITS> { + lhs: &Scalar<'a, C, EccChip>, + rhs: &Scalar<'a, C, EccChip>, + ) -> Scalar<'a, C, EccChip> { let output = match (&lhs.value, &rhs.value) { (Value::Constant(lhs), Value::Constant(rhs)) => Value::Constant(*lhs - rhs), - (Value::Constant(constant), Value::Assigned(assigned)) => { - MainGateInstructions::neg_with_constant( - &self.main_gate, + (Value::Constant(constant), Value::Assigned(assigned)) => self + .scalar_chip() + .sum_with_coeff_and_const( &mut self.ctx_mut(), - assigned, + &[(-C::Scalar::one(), assigned.clone())], *constant, ) .map(Value::Assigned) - .unwrap() - } - (Value::Assigned(assigned), Value::Constant(constant)) => { - MainGateInstructions::add_constant( - &self.main_gate, + .unwrap(), + (Value::Assigned(assigned), Value::Constant(constant)) => self + .scalar_chip() + .sum_with_coeff_and_const( &mut self.ctx_mut(), - assigned, - constant.neg(), + &[(C::Scalar::one(), assigned.clone())], + -*constant, ) .map(Value::Assigned) - .unwrap() - } + .unwrap(), (Value::Assigned(lhs), Value::Assigned(rhs)) => { - MainGateInstructions::sub(&self.main_gate, &mut self.ctx_mut(), lhs, rhs) + IntegerInstructions::sub(self.scalar_chip().deref(), &mut self.ctx_mut(), lhs, rhs) .map(Value::Assigned) .unwrap() } @@ -262,89 +206,78 @@ impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> fn mul( self: &Rc, - lhs: &Scalar<'a, 'b, C, LIMBS, BITS>, - rhs: &Scalar<'a, 'b, C, LIMBS, BITS>, - ) -> Scalar<'a, 'b, C, LIMBS, BITS> { + lhs: &Scalar<'a, C, EccChip>, + rhs: &Scalar<'a, C, EccChip>, + ) -> Scalar<'a, C, EccChip> { let output = match (&lhs.value, &rhs.value) { (Value::Constant(lhs), Value::Constant(rhs)) => Value::Constant(*lhs * rhs), (Value::Assigned(assigned), Value::Constant(constant)) - | (Value::Constant(constant), Value::Assigned(assigned)) => { - MainGateInstructions::apply( - &self.main_gate, + | (Value::Constant(constant), Value::Assigned(assigned)) => self + .scalar_chip() + .sum_with_coeff_and_const( &mut self.ctx_mut(), - [ - Term::Assigned(assigned, *constant), - Term::unassigned_to_sub( - assigned.value().map(|assigned| *assigned * constant), - ), - ], + &[(*constant, assigned.clone())], C::Scalar::zero(), - CombinationOptionCommon::OneLinerAdd.into(), ) - .map(|mut assigned| Value::Assigned(assigned.swap_remove(1))) - .unwrap() - } - (Value::Assigned(lhs), Value::Assigned(rhs)) => { - MainGateInstructions::mul(&self.main_gate, &mut self.ctx_mut(), lhs, rhs) - .map(Value::Assigned) - .unwrap() - } + .map(Value::Assigned) + .unwrap(), + (Value::Assigned(lhs), Value::Assigned(rhs)) => self + .scalar_chip() + .sum_products_with_coeff_and_const( + &mut self.ctx_mut(), + &[(C::Scalar::one(), lhs.clone(), rhs.clone())], + C::Scalar::zero(), + ) + .map(Value::Assigned) + .unwrap(), }; self.scalar(output) } - fn neg( - self: &Rc, - scalar: &Scalar<'a, 'b, C, LIMBS, BITS>, - ) -> Scalar<'a, 'b, C, LIMBS, BITS> { + fn neg(self: &Rc, scalar: &Scalar<'a, C, EccChip>) -> Scalar<'a, C, EccChip> { let output = match &scalar.value { Value::Constant(constant) => Value::Constant(constant.neg()), - Value::Assigned(assigned) => MainGateInstructions::neg_with_constant( - &self.main_gate, - &mut self.ctx_mut(), - assigned, - C::Scalar::zero(), - ) - .map(Value::Assigned) - .unwrap(), + Value::Assigned(assigned) => { + IntegerInstructions::neg(self.scalar_chip().deref(), &mut self.ctx_mut(), assigned) + .map(Value::Assigned) + .unwrap() + } }; self.scalar(output) } - fn invert( - self: &Rc, - scalar: &Scalar<'a, 'b, C, LIMBS, BITS>, - ) -> Scalar<'a, 'b, C, LIMBS, BITS> { + fn invert(self: &Rc, scalar: &Scalar<'a, C, EccChip>) -> Scalar<'a, C, EccChip> { let output = match &scalar.value { Value::Constant(constant) => Value::Constant(Field::invert(constant).unwrap()), - Value::Assigned(assigned) => { - let (inv, non_invertable) = - MainGateInstructions::invert(&self.main_gate, &mut self.ctx_mut(), assigned) - .unwrap(); - self.main_gate - .assert_zero(&mut self.ctx_mut(), &non_invertable) - .unwrap(); - Value::Assigned(inv) - } + Value::Assigned(assigned) => Value::Assigned( + IntegerInstructions::invert( + self.scalar_chip().deref(), + &mut self.ctx_mut(), + assigned, + ) + .unwrap(), + ), }; self.scalar(output) } } #[cfg(test)] -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> - Halo2Loader<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, EccChip> { fn start_row_metering(self: &Rc, identifier: &str) { + use crate::loader::halo2::shim::Context; + self.row_meterings .borrow_mut() - .push((identifier.to_string(), *self.ctx.borrow().offset)) + .push((identifier.to_string(), self.ctx().offset())) } fn end_row_metering(self: &Rc) { + use crate::loader::halo2::shim::Context; + let mut row_meterings = self.row_meterings.borrow_mut(); let (_, row) = row_meterings.last_mut().unwrap(); - *row = *self.ctx.borrow().offset - *row; + *row = self.ctx().offset() - *row; } pub fn print_row_metering(self: &Rc) { @@ -354,14 +287,25 @@ impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> } } +#[derive(Clone, Debug)] +pub enum Value { + Constant(T), + Assigned(L), +} + #[derive(Clone)] -pub struct Scalar<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> { - loader: Rc>, - value: Value>, +pub struct Scalar<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { + loader: Rc>, + index: usize, + value: Value, } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Scalar<'a, 'b, C, LIMBS, BITS> { - pub fn assigned(&self) -> AssignedValue { +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Scalar<'a, C, EccChip> { + pub fn loader(&self) -> &Rc> { + &self.loader + } + + pub(crate) fn assigned(&self) -> EccChip::AssignedScalar { match &self.value { Value::Constant(constant) => self.loader.assign_const_scalar(*constant).assigned(), Value::Assigned(assigned) => assigned.clone(), @@ -369,19 +313,23 @@ impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Scalar<'a, ' } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> LoadedScalar - for Scalar<'a, 'b, C, LIMBS, BITS> +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> PartialEq for Scalar<'a, C, EccChip> { + fn eq(&self, other: &Self) -> bool { + self.index == other.index + } +} + +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> LoadedScalar + for Scalar<'a, C, EccChip> { - type Loader = Rc>; + type Loader = Rc>; fn loader(&self) -> &Self::Loader { &self.loader } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Debug - for Scalar<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Debug for Scalar<'a, C, EccChip> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Scalar") .field("value", &self.value) @@ -389,166 +337,146 @@ impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Debug } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> FieldOps - for Scalar<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> FieldOps for Scalar<'a, C, EccChip> { fn invert(&self) -> Option { - Some((&self.loader).invert(self)) + Some(self.loader.invert(self)) } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Add - for Scalar<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Add for Scalar<'a, C, EccChip> { type Output = Self; fn add(self, rhs: Self) -> Self::Output { - (&self.loader).add(&self, &rhs) + Halo2Loader::add(&self.loader, &self, &rhs) } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Sub - for Scalar<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Sub for Scalar<'a, C, EccChip> { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { - (&self.loader).sub(&self, &rhs) + Halo2Loader::sub(&self.loader, &self, &rhs) } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Mul - for Scalar<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Mul for Scalar<'a, C, EccChip> { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { - (&self.loader).mul(&self, &rhs) + Halo2Loader::mul(&self.loader, &self, &rhs) } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Neg - for Scalar<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Neg for Scalar<'a, C, EccChip> { type Output = Self; fn neg(self) -> Self::Output { - (&self.loader).neg(&self) + Halo2Loader::neg(&self.loader, &self) } } -impl<'a, 'b, 'c, C: CurveAffine, const LIMBS: usize, const BITS: usize> Add<&'c Self> - for Scalar<'a, 'b, C, LIMBS, BITS> +impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> Add<&'b Self> + for Scalar<'a, C, EccChip> { type Output = Self; - fn add(self, rhs: &'c Self) -> Self::Output { - (&self.loader).add(&self, rhs) + fn add(self, rhs: &'b Self) -> Self::Output { + Halo2Loader::add(&self.loader, &self, rhs) } } -impl<'a, 'b, 'c, C: CurveAffine, const LIMBS: usize, const BITS: usize> Sub<&'c Self> - for Scalar<'a, 'b, C, LIMBS, BITS> +impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> Sub<&'b Self> + for Scalar<'a, C, EccChip> { type Output = Self; - fn sub(self, rhs: &'c Self) -> Self::Output { - (&self.loader).sub(&self, rhs) + fn sub(self, rhs: &'b Self) -> Self::Output { + Halo2Loader::sub(&self.loader, &self, rhs) } } -impl<'a, 'b, 'c, C: CurveAffine, const LIMBS: usize, const BITS: usize> Mul<&'c Self> - for Scalar<'a, 'b, C, LIMBS, BITS> +impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> Mul<&'b Self> + for Scalar<'a, C, EccChip> { type Output = Self; - fn mul(self, rhs: &'c Self) -> Self::Output { - (&self.loader).mul(&self, rhs) + fn mul(self, rhs: &'b Self) -> Self::Output { + Halo2Loader::mul(&self.loader, &self, rhs) } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> AddAssign - for Scalar<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> AddAssign for Scalar<'a, C, EccChip> { fn add_assign(&mut self, rhs: Self) { - *self = (&self.loader).add(self, &rhs) + *self = Halo2Loader::add(&self.loader, self, &rhs) } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> SubAssign - for Scalar<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> SubAssign for Scalar<'a, C, EccChip> { fn sub_assign(&mut self, rhs: Self) { - *self = (&self.loader).sub(self, &rhs) + *self = Halo2Loader::sub(&self.loader, self, &rhs) } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> MulAssign - for Scalar<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> MulAssign for Scalar<'a, C, EccChip> { fn mul_assign(&mut self, rhs: Self) { - *self = (&self.loader).mul(self, &rhs) + *self = Halo2Loader::mul(&self.loader, self, &rhs) } } -impl<'a, 'b, 'c, C: CurveAffine, const LIMBS: usize, const BITS: usize> AddAssign<&'c Self> - for Scalar<'a, 'b, C, LIMBS, BITS> +impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> AddAssign<&'b Self> + for Scalar<'a, C, EccChip> { - fn add_assign(&mut self, rhs: &'c Self) { - *self = (&self.loader).add(self, rhs) + fn add_assign(&mut self, rhs: &'b Self) { + *self = Halo2Loader::add(&self.loader, self, rhs) } } -impl<'a, 'b, 'c, C: CurveAffine, const LIMBS: usize, const BITS: usize> SubAssign<&'c Self> - for Scalar<'a, 'b, C, LIMBS, BITS> +impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> SubAssign<&'b Self> + for Scalar<'a, C, EccChip> { - fn sub_assign(&mut self, rhs: &'c Self) { - *self = (&self.loader).sub(self, rhs) + fn sub_assign(&mut self, rhs: &'b Self) { + *self = Halo2Loader::sub(&self.loader, self, rhs) } } -impl<'a, 'b, 'c, C: CurveAffine, const LIMBS: usize, const BITS: usize> MulAssign<&'c Self> - for Scalar<'a, 'b, C, LIMBS, BITS> +impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> MulAssign<&'b Self> + for Scalar<'a, C, EccChip> { - fn mul_assign(&mut self, rhs: &'c Self) { - *self = (&self.loader).mul(self, rhs) + fn mul_assign(&mut self, rhs: &'b Self) { + *self = Halo2Loader::mul(&self.loader, self, rhs) } } #[derive(Clone)] -pub struct EcPoint<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> { - loader: Rc>, +pub struct EcPoint<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { + loader: Rc>, index: usize, - assigned: AssignedPoint, + assigned: EccChip::AssignedEcPoint, } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> - EcPoint<'a, 'b, C, LIMBS, BITS> -{ - pub fn assigned(&self) -> AssignedPoint { +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPoint<'a, C, EccChip> { + pub fn assigned(&self) -> EccChip::AssignedEcPoint { self.assigned.clone() } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> PartialEq - for EcPoint<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> PartialEq for EcPoint<'a, C, EccChip> { fn eq(&self, other: &Self) -> bool { self.index == other.index } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> LoadedEcPoint - for EcPoint<'a, 'b, C, LIMBS, BITS> +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> LoadedEcPoint + for EcPoint<'a, C, EccChip> { - type Loader = Rc>; + type Loader = Rc>; fn loader(&self) -> &Self::Loader { &self.loader } fn multi_scalar_multiplication( - pairs: impl IntoIterator, Self)>, + pairs: impl IntoIterator, Self)>, ) -> Self { let pairs = pairs.into_iter().collect_vec(); let loader = &pairs[0].0.loader; @@ -570,42 +498,37 @@ impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> LoadedEcPoin .chain(if scaled.is_empty() { None } else { - let aux_generator = ::CurveExt::random(OsRng).to_affine(); - loader - .ecc_chip - .borrow_mut() - .assign_aux_generator( - &mut loader.ctx.borrow_mut(), - circuit::Value::known(aux_generator), - ) - .unwrap(); - loader - .ecc_chip - .borrow_mut() - .assign_aux(&mut loader.ctx.borrow_mut(), WINDOW_SIZE, scaled.len()) - .unwrap(); Some( loader .ecc_chip - .borrow() - .mul_batch_1d_horizontal(&mut loader.ctx.borrow_mut(), scaled, WINDOW_SIZE) + .borrow_mut() + .multi_scalar_multiplication(&mut loader.ctx_mut(), scaled) .unwrap(), ) }) .chain(non_scaled) .reduce(|acc, ec_point| { - (loader.ecc_chip().deref()) - .add(&mut loader.ctx.borrow_mut(), &acc, &ec_point) + EccInstructions::add( + loader.ecc_chip().deref(), + &mut loader.ctx_mut(), + &acc, + &ec_point, + ) + .unwrap() + }) + .map(|output| { + loader + .ecc_chip() + .normalize(&mut loader.ctx_mut(), &output) .unwrap() }) .unwrap(); + loader.ec_point(output) } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Debug - for EcPoint<'a, 'b, C, LIMBS, BITS> -{ +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Debug for EcPoint<'a, C, EccChip> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EcPoint") .field("index", &self.index) @@ -614,110 +537,82 @@ impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Debug } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Add - for EcPoint<'a, 'b, C, LIMBS, BITS> +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> ScalarLoader + for Rc> { - type Output = Self; - - fn add(self, _: Self) -> Self::Output { - todo!() - } -} - -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Sub - for EcPoint<'a, 'b, C, LIMBS, BITS> -{ - type Output = Self; - - fn sub(self, _: Self) -> Self::Output { - todo!() - } -} + type LoadedScalar = Scalar<'a, C, EccChip>; -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Neg - for EcPoint<'a, 'b, C, LIMBS, BITS> -{ - type Output = Self; - - fn neg(self) -> Self::Output { - todo!() - } -} - -impl<'a, 'b, 'c, C: CurveAffine, const LIMBS: usize, const BITS: usize> Add<&'c Self> - for EcPoint<'a, 'b, C, LIMBS, BITS> -{ - type Output = Self; - - fn add(self, rhs: &'c Self) -> Self::Output { - self + rhs.clone() - } -} - -impl<'a, 'b, 'c, C: CurveAffine, const LIMBS: usize, const BITS: usize> Sub<&'c Self> - for EcPoint<'a, 'b, C, LIMBS, BITS> -{ - type Output = Self; - - fn sub(self, rhs: &'c Self) -> Self::Output { - self - rhs.clone() - } -} - -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> AddAssign - for EcPoint<'a, 'b, C, LIMBS, BITS> -{ - fn add_assign(&mut self, rhs: Self) { - *self = self.clone() + rhs - } -} - -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> SubAssign - for EcPoint<'a, 'b, C, LIMBS, BITS> -{ - fn sub_assign(&mut self, rhs: Self) { - *self = self.clone() - rhs - } -} - -impl<'a, 'b, 'c, C: CurveAffine, const LIMBS: usize, const BITS: usize> AddAssign<&'c Self> - for EcPoint<'a, 'b, C, LIMBS, BITS> -{ - fn add_assign(&mut self, rhs: &'c Self) { - *self = self.clone() + rhs - } -} - -impl<'a, 'b, 'c, C: CurveAffine, const LIMBS: usize, const BITS: usize> SubAssign<&'c Self> - for EcPoint<'a, 'b, C, LIMBS, BITS> -{ - fn sub_assign(&mut self, rhs: &'c Self) { - *self = self.clone() - rhs - } -} - -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> ScalarLoader - for Rc> -{ - type LoadedScalar = Scalar<'a, 'b, C, LIMBS, BITS>; - - fn load_const(&self, value: &C::Scalar) -> Scalar<'a, 'b, C, LIMBS, BITS> { + fn load_const(&self, value: &C::Scalar) -> Scalar<'a, C, EccChip> { self.scalar(Value::Constant(*value)) } -} -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> EcPointLoader - for Rc> -{ - type LoadedEcPoint = EcPoint<'a, 'b, C, LIMBS, BITS>; - - fn ec_point_load_const(&self, ec_point: &C::CurveExt) -> EcPoint<'a, 'b, C, LIMBS, BITS> { - self.assign_const_ec_point(ec_point.to_affine()) + fn assert_eq( + &self, + annotation: &str, + lhs: &Scalar<'a, C, EccChip>, + rhs: &Scalar<'a, C, EccChip>, + ) -> Result<(), crate::Error> { + self.scalar_chip() + .assert_equal(&mut self.ctx_mut(), &lhs.assigned(), &rhs.assigned()) + .map_err(|_| crate::Error::AssertionFailure(annotation.to_string())) + } + + fn sum_with_coeff_and_const( + &self, + values: &[(C::Scalar, &Scalar<'a, C, EccChip>)], + constant: C::Scalar, + ) -> Scalar<'a, C, EccChip> { + let values = values + .iter() + .map(|(coeff, value)| (*coeff, value.assigned())) + .collect_vec(); + self.scalar(Value::Assigned( + self.scalar_chip() + .sum_with_coeff_and_const(&mut self.ctx_mut(), &values, constant) + .unwrap(), + )) + } + + fn sum_products_with_coeff_and_const( + &self, + values: &[(C::Scalar, &Scalar<'a, C, EccChip>, &Scalar<'a, C, EccChip>)], + constant: C::Scalar, + ) -> Scalar<'a, C, EccChip> { + let values = values + .iter() + .map(|(coeff, lhs, rhs)| (*coeff, lhs.assigned(), rhs.assigned())) + .collect_vec(); + self.scalar(Value::Assigned( + self.scalar_chip() + .sum_products_with_coeff_and_const(&mut self.ctx_mut(), &values, constant) + .unwrap(), + )) + } +} + +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPointLoader + for Rc> +{ + type LoadedEcPoint = EcPoint<'a, C, EccChip>; + + fn ec_point_load_const(&self, ec_point: &C) -> EcPoint<'a, C, EccChip> { + self.assign_const_ec_point(*ec_point) + } + + fn ec_point_assert_eq( + &self, + annotation: &str, + lhs: &EcPoint<'a, C, EccChip>, + rhs: &EcPoint<'a, C, EccChip>, + ) -> Result<(), crate::Error> { + self.ecc_chip() + .assert_equal(&mut self.ctx_mut(), &lhs.assigned(), &rhs.assigned()) + .map_err(|_| crate::Error::AssertionFailure(annotation.to_string())) } } -impl<'a, 'b, C: CurveAffine, const LIMBS: usize, const BITS: usize> Loader - for Rc> +impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Loader + for Rc> { #[cfg(test)] fn start_cost_metering(&self, identifier: &str) { diff --git a/src/loader/halo2/shim.rs b/src/loader/halo2/shim.rs new file mode 100644 index 00000000..67f06cc9 --- /dev/null +++ b/src/loader/halo2/shim.rs @@ -0,0 +1,403 @@ +use crate::util::arithmetic::{CurveAffine, FieldExt}; +use halo2_proofs::{ + circuit::{Cell, Value}, + plonk::Error, +}; +use std::fmt::Debug; + +pub trait Context: Debug { + fn constrain_equal(&mut self, lhs: Cell, rhs: Cell) -> Result<(), Error>; + + fn offset(&self) -> usize; +} + +pub trait IntegerInstructions<'a, F: FieldExt>: Clone + Debug { + type Context: Context; + type Integer: Clone + Debug; + type AssignedInteger: Clone + Debug; + + fn integer(&self, fe: F) -> Self::Integer; + + fn assign_integer( + &self, + ctx: &mut Self::Context, + integer: Value, + ) -> Result; + + fn assign_constant( + &self, + ctx: &mut Self::Context, + integer: F, + ) -> Result; + + fn sum_with_coeff_and_const( + &self, + ctx: &mut Self::Context, + values: &[(F::Scalar, Self::AssignedInteger)], + constant: F::Scalar, + ) -> Result; + + fn sum_products_with_coeff_and_const( + &self, + ctx: &mut Self::Context, + values: &[(F::Scalar, Self::AssignedInteger, Self::AssignedInteger)], + constant: F::Scalar, + ) -> Result; + + fn sub( + &self, + ctx: &mut Self::Context, + a: &Self::AssignedInteger, + b: &Self::AssignedInteger, + ) -> Result; + + fn neg( + &self, + ctx: &mut Self::Context, + a: &Self::AssignedInteger, + ) -> Result; + + fn invert( + &self, + ctx: &mut Self::Context, + a: &Self::AssignedInteger, + ) -> Result; + + fn assert_equal( + &self, + ctx: &mut Self::Context, + a: &Self::AssignedInteger, + b: &Self::AssignedInteger, + ) -> Result<(), Error>; +} + +pub trait EccInstructions<'a, C: CurveAffine>: Clone + Debug { + type Context: Context; + type ScalarChip: IntegerInstructions< + 'a, + C::Scalar, + Context = Self::Context, + Integer = Self::Scalar, + AssignedInteger = Self::AssignedScalar, + >; + type AssignedEcPoint: Clone + Debug; + type Scalar: Clone + Debug; + type AssignedScalar: Clone + Debug; + + fn scalar_chip(&self) -> &Self::ScalarChip; + + fn assign_constant( + &self, + ctx: &mut Self::Context, + point: C, + ) -> Result; + + fn assign_point( + &self, + ctx: &mut Self::Context, + point: Value, + ) -> Result; + + fn add( + &self, + ctx: &mut Self::Context, + p0: &Self::AssignedEcPoint, + p1: &Self::AssignedEcPoint, + ) -> Result; + + fn multi_scalar_multiplication( + &mut self, + ctx: &mut Self::Context, + pairs: Vec<(Self::AssignedEcPoint, Self::AssignedScalar)>, + ) -> Result; + + fn normalize( + &self, + ctx: &mut Self::Context, + point: &Self::AssignedEcPoint, + ) -> Result; + + fn assert_equal( + &self, + ctx: &mut Self::Context, + a: &Self::AssignedEcPoint, + b: &Self::AssignedEcPoint, + ) -> Result<(), Error>; +} + +mod halo2_wrong { + use crate::{ + loader::halo2::{Context, EccInstructions, IntegerInstructions}, + util::{ + arithmetic::{CurveAffine, FieldExt, Group}, + Itertools, + }, + }; + use halo2_proofs::{ + circuit::{AssignedCell, Cell, Value}, + plonk::Error, + }; + use halo2_wrong_ecc::{ + integer::rns::Common, + maingate::{ + CombinationOption, CombinationOptionCommon, MainGate, MainGateInstructions, RegionCtx, + Term, + }, + AssignedPoint, BaseFieldEccChip, + }; + use rand::rngs::OsRng; + + impl<'a, F: FieldExt> Context for RegionCtx<'a, F> { + fn constrain_equal(&mut self, lhs: Cell, rhs: Cell) -> Result<(), Error> { + self.constrain_equal(lhs, rhs) + } + + fn offset(&self) -> usize { + self.offset() + } + } + + impl<'a, F: FieldExt> IntegerInstructions<'a, F> for MainGate { + type Context = RegionCtx<'a, F>; + type Integer = F; + type AssignedInteger = AssignedCell; + + fn integer(&self, scalar: F) -> Self::Integer { + scalar + } + + fn assign_integer( + &self, + ctx: &mut Self::Context, + integer: Value, + ) -> Result { + self.assign_value(ctx, integer) + } + + fn assign_constant( + &self, + ctx: &mut Self::Context, + integer: F, + ) -> Result { + MainGateInstructions::assign_constant(self, ctx, integer) + } + + fn sum_with_coeff_and_const( + &self, + ctx: &mut Self::Context, + values: &[(F, Self::AssignedInteger)], + constant: F, + ) -> Result { + self.compose( + ctx, + &values + .iter() + .map(|(coeff, assigned)| Term::Assigned(assigned, *coeff)) + .collect_vec(), + constant, + ) + } + + fn sum_products_with_coeff_and_const( + &self, + ctx: &mut Self::Context, + values: &[(F, Self::AssignedInteger, Self::AssignedInteger)], + constant: F, + ) -> Result { + match values.len() { + 0 => MainGateInstructions::assign_constant(self, ctx, constant), + 1 => { + let (scalar, lhs, rhs) = &values[0]; + let output = lhs + .value() + .zip(rhs.value()) + .map(|(lhs, rhs)| *scalar * lhs * rhs + constant); + + Ok(self + .apply( + ctx, + [ + Term::Zero, + Term::Zero, + Term::assigned_to_mul(lhs), + Term::assigned_to_mul(rhs), + Term::unassigned_to_sub(output), + ], + constant, + CombinationOption::OneLinerDoubleMul(*scalar), + )? + .swap_remove(4)) + } + _ => { + let (scalar, lhs, rhs) = &values[0]; + self.apply( + ctx, + [Term::assigned_to_mul(lhs), Term::assigned_to_mul(rhs)], + constant, + CombinationOptionCommon::CombineToNextScaleMul(-F::one(), *scalar).into(), + )?; + let acc = + Value::known(*scalar) * lhs.value() * rhs.value() + Value::known(constant); + let output = values.iter().skip(1).fold( + Ok::<_, Error>(acc), + |acc, (scalar, lhs, rhs)| { + acc.and_then(|acc| { + self.apply( + ctx, + [ + Term::assigned_to_mul(lhs), + Term::assigned_to_mul(rhs), + Term::Zero, + Term::Zero, + Term::Unassigned(acc, F::one()), + ], + F::zero(), + CombinationOptionCommon::CombineToNextScaleMul( + -F::one(), + *scalar, + ) + .into(), + )?; + Ok(acc + Value::known(*scalar) * lhs.value() * rhs.value()) + }) + }, + )?; + self.apply( + ctx, + [ + Term::Zero, + Term::Zero, + Term::Zero, + Term::Zero, + Term::Unassigned(output, F::zero()), + ], + F::zero(), + CombinationOptionCommon::OneLinerAdd.into(), + ) + .map(|mut outputs| outputs.swap_remove(4)) + } + } + } + + fn sub( + &self, + ctx: &mut Self::Context, + a: &Self::AssignedInteger, + b: &Self::AssignedInteger, + ) -> Result { + MainGateInstructions::sub(self, ctx, a, b) + } + + fn neg( + &self, + ctx: &mut Self::Context, + a: &Self::AssignedInteger, + ) -> Result { + MainGateInstructions::neg_with_constant(self, ctx, a, F::zero()) + } + + fn invert( + &self, + ctx: &mut Self::Context, + a: &Self::AssignedInteger, + ) -> Result { + MainGateInstructions::invert_unsafe(self, ctx, a) + } + + fn assert_equal( + &self, + ctx: &mut Self::Context, + a: &Self::AssignedInteger, + b: &Self::AssignedInteger, + ) -> Result<(), Error> { + let mut eq = true; + a.value().zip(b.value()).map(|(lhs, rhs)| { + eq &= lhs == rhs; + }); + MainGateInstructions::assert_equal(self, ctx, a, b) + .and(eq.then_some(()).ok_or(Error::Synthesis)) + } + } + + impl<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize> EccInstructions<'a, C> + for BaseFieldEccChip + { + type Context = RegionCtx<'a, C::Scalar>; + type ScalarChip = MainGate; + type AssignedEcPoint = AssignedPoint; + type Scalar = C::Scalar; + type AssignedScalar = AssignedCell; + + fn scalar_chip(&self) -> &Self::ScalarChip { + self.main_gate() + } + + fn assign_constant( + &self, + ctx: &mut Self::Context, + point: C, + ) -> Result { + self.assign_constant(ctx, point) + } + + fn assign_point( + &self, + ctx: &mut Self::Context, + point: Value, + ) -> Result { + self.assign_point(ctx, point) + } + + fn add( + &self, + ctx: &mut Self::Context, + p0: &Self::AssignedEcPoint, + p1: &Self::AssignedEcPoint, + ) -> Result { + self.add(ctx, p0, p1) + } + + fn multi_scalar_multiplication( + &mut self, + ctx: &mut Self::Context, + pairs: Vec<(Self::AssignedEcPoint, Self::AssignedScalar)>, + ) -> Result { + const WINDOW_SIZE: usize = 3; + match self.mul_batch_1d_horizontal(ctx, pairs.clone(), WINDOW_SIZE) { + Err(_) => { + if self.assign_aux(ctx, WINDOW_SIZE, pairs.len()).is_err() { + let aux_generator = Value::known(C::Curve::random(OsRng).into()); + self.assign_aux_generator(ctx, aux_generator)?; + self.assign_aux(ctx, WINDOW_SIZE, pairs.len())?; + } + self.mul_batch_1d_horizontal(ctx, pairs, WINDOW_SIZE) + } + result => result, + } + } + + fn normalize( + &self, + ctx: &mut Self::Context, + point: &Self::AssignedEcPoint, + ) -> Result { + self.normalize(ctx, point) + } + + fn assert_equal( + &self, + ctx: &mut Self::Context, + a: &Self::AssignedEcPoint, + b: &Self::AssignedEcPoint, + ) -> Result<(), Error> { + let mut eq = true; + [(a.x(), b.x()), (a.y(), b.y())].map(|(lhs, rhs)| { + lhs.integer().zip(rhs.integer()).map(|(lhs, rhs)| { + eq &= lhs.value() == rhs.value(); + }); + }); + self.assert_equal(ctx, a, b) + .and(eq.then_some(()).ok_or(Error::Synthesis)) + } + } +} diff --git a/src/loader/halo2/test.rs b/src/loader/halo2/test.rs new file mode 100644 index 00000000..08551fe0 --- /dev/null +++ b/src/loader/halo2/test.rs @@ -0,0 +1,66 @@ +use crate::{ + util::{arithmetic::CurveAffine, Itertools}, + Protocol, +}; +use halo2_proofs::circuit::Value; + +pub struct Snark { + pub protocol: Protocol, + pub instances: Vec>, + pub proof: Vec, +} + +impl Snark { + pub fn new(protocol: Protocol, instances: Vec>, proof: Vec) -> Self { + assert_eq!( + protocol.num_instance, + instances + .iter() + .map(|instances| instances.len()) + .collect_vec() + ); + Snark { + protocol, + instances, + proof, + } + } +} + +pub struct SnarkWitness { + pub protocol: Protocol, + pub instances: Vec>>, + pub proof: Value>, +} + +impl From> for SnarkWitness { + fn from(snark: Snark) -> Self { + Self { + protocol: snark.protocol, + instances: snark + .instances + .into_iter() + .map(|instances| instances.into_iter().map(Value::known).collect_vec()) + .collect(), + proof: Value::known(snark.proof), + } + } +} + +impl SnarkWitness { + pub fn without_witnesses(&self) -> Self { + SnarkWitness { + protocol: self.protocol.clone(), + instances: self + .instances + .iter() + .map(|instances| vec![Value::unknown(); instances.len()]) + .collect(), + proof: Value::unknown(), + } + } + + pub fn proof(&self) -> Value<&[u8]> { + self.proof.as_ref().map(Vec::as_slice) + } +} diff --git a/src/loader/halo2/transcript.rs b/src/loader/halo2/transcript.rs deleted file mode 100644 index 5bfe57ba..00000000 --- a/src/loader/halo2/transcript.rs +++ /dev/null @@ -1,363 +0,0 @@ -use crate::{ - loader::{ - halo2::loader::{EcPoint, Halo2Loader, Scalar, Value}, - native::NativeLoader, - }, - util::{Curve, GroupEncoding, PrimeField, Transcript, TranscriptRead}, - Error, -}; -use halo2_curves::{Coordinates, CurveAffine}; -use halo2_proofs::circuit; -use halo2_wrong_ecc::integer::rns::{Common, Integer, Rns}; -use halo2_wrong_transcript::{NativeRepresentation, PointRepresentation, TranscriptChip}; -use poseidon::{Poseidon, Spec}; -use std::{ - io::{self, Read, Write}, - marker::PhantomData, - rc::Rc, -}; - -pub struct PoseidonTranscript< - C: CurveAffine, - L, - S, - B, - E: PointRepresentation, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, -> { - loader: L, - stream: S, - buf: B, - rns: Rc>, - _marker: PhantomData<(C, E)>, -} - -impl< - 'a, - 'b, - C: CurveAffine, - R: Read, - E: PointRepresentation, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > - PoseidonTranscript< - C, - Rc>, - circuit::Value, - TranscriptChip, - E, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - pub fn new( - loader: &Rc>, - stream: circuit::Value, - ) -> Self { - let transcript_chip = TranscriptChip::new( - &mut loader.ctx_mut(), - &Spec::new(R_F, R_P), - loader.ecc_chip().clone(), - ) - .unwrap(); - Self { - loader: loader.clone(), - stream, - buf: transcript_chip, - rns: Rc::new(Rns::::construct()), - _marker: PhantomData, - } - } -} - -impl< - 'a, - 'b, - C: CurveAffine, - R: Read, - E: PointRepresentation, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > Transcript>> - for PoseidonTranscript< - C, - Rc>, - circuit::Value, - TranscriptChip, - E, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - fn squeeze_challenge(&mut self) -> Scalar<'a, 'b, C, LIMBS, BITS> { - let assigned = self.buf.squeeze(&mut self.loader.ctx_mut()).unwrap(); - self.loader.scalar(Value::Assigned(assigned)) - } - - fn common_scalar(&mut self, scalar: &Scalar<'a, 'b, C, LIMBS, BITS>) -> Result<(), Error> { - self.buf.write_scalar(&scalar.assigned()); - Ok(()) - } - - fn common_ec_point(&mut self, ec_point: &EcPoint<'a, 'b, C, LIMBS, BITS>) -> Result<(), Error> { - self.buf - .write_point(&mut self.loader.ctx_mut(), &ec_point.assigned()) - .unwrap(); - Ok(()) - } -} - -impl< - 'a, - 'b, - C: CurveAffine, - R: Read, - E: PointRepresentation, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > TranscriptRead>> - for PoseidonTranscript< - C, - Rc>, - circuit::Value, - TranscriptChip, - E, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - fn read_scalar(&mut self) -> Result, Error> { - let scalar = self.stream.as_mut().and_then(|stream| { - let mut data = ::Repr::default(); - if stream.read_exact(data.as_mut()).is_err() { - return circuit::Value::unknown(); - } - Option::::from(C::Scalar::from_repr(data)) - .map(circuit::Value::known) - .unwrap_or_else(circuit::Value::unknown) - }); - let scalar = self.loader.assign_scalar(scalar); - self.common_scalar(&scalar)?; - Ok(scalar) - } - - fn read_ec_point(&mut self) -> Result, Error> { - let ec_point = self.stream.as_mut().and_then(|stream| { - let mut compressed = C::Repr::default(); - if stream.read_exact(compressed.as_mut()).is_err() { - return circuit::Value::unknown(); - } - Option::::from(C::from_bytes(&compressed)) - .map(circuit::Value::known) - .unwrap_or_else(circuit::Value::unknown) - }); - let ec_point = self.loader.assign_ec_point(ec_point); - self.common_ec_point(&ec_point)?; - Ok(ec_point) - } -} - -impl< - C: CurveAffine, - S, - E: PointRepresentation, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > - PoseidonTranscript< - C, - NativeLoader, - S, - Poseidon, - E, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - pub fn new(stream: S) -> Self { - Self { - loader: NativeLoader, - stream, - buf: Poseidon::new(R_F, R_P), - rns: Rc::new(Rns::::construct()), - _marker: PhantomData, - } - } -} - -impl< - C: CurveAffine, - S, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > Transcript - for PoseidonTranscript< - C, - NativeLoader, - S, - Poseidon, - NativeRepresentation, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - fn squeeze_challenge(&mut self) -> C::Scalar { - self.buf.squeeze() - } - - fn common_scalar(&mut self, scalar: &C::Scalar) -> Result<(), Error> { - self.buf.update(&[*scalar]); - Ok(()) - } - - fn common_ec_point(&mut self, ec_point: &C::CurveExt) -> Result<(), Error> { - let coords: Coordinates = - Option::from(ec_point.to_affine().coordinates()).ok_or_else(|| { - Error::Transcript( - io::ErrorKind::Other, - "Cannot write points at infinity to the transcript".to_string(), - ) - })?; - let x = Integer::from_fe(*coords.x(), self.rns.clone()); - let y = Integer::from_fe(*coords.y(), self.rns.clone()); - self.buf.update(&[x.native(), y.native()]); - Ok(()) - } -} - -impl< - C: CurveAffine, - R: Read, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > TranscriptRead - for PoseidonTranscript< - C, - NativeLoader, - R, - Poseidon, - NativeRepresentation, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - fn read_scalar(&mut self) -> Result { - let mut data = ::Repr::default(); - self.stream - .read_exact(data.as_mut()) - .map_err(|err| Error::Transcript(err.kind(), err.to_string()))?; - let scalar = C::Scalar::from_repr_vartime(data).ok_or_else(|| { - Error::Transcript( - io::ErrorKind::Other, - "Invalid scalar encoding in proof".to_string(), - ) - })?; - self.common_scalar(&scalar)?; - Ok(scalar) - } - - fn read_ec_point(&mut self) -> Result { - let mut data = C::Repr::default(); - self.stream - .read_exact(data.as_mut()) - .map_err(|err| Error::Transcript(err.kind(), err.to_string()))?; - let ec_point = Option::::from( - ::from_bytes(&data).map(|ec_point| ec_point.to_curve()), - ) - .ok_or_else(|| { - Error::Transcript( - io::ErrorKind::Other, - "Invalid elliptic curve point encoding in proof".to_string(), - ) - })?; - self.common_ec_point(&ec_point)?; - Ok(ec_point) - } -} - -impl< - C: CurveAffine, - W: Write, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > - PoseidonTranscript< - C, - NativeLoader, - W, - Poseidon, - NativeRepresentation, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - pub fn stream_mut(&mut self) -> &mut W { - &mut self.stream - } - - pub fn finalize(self) -> W { - self.stream - } -} diff --git a/src/loader/native.rs b/src/loader/native.rs index d0ee9fb5..6bf9f7c4 100644 --- a/src/loader/native.rs +++ b/src/loader/native.rs @@ -1,4 +1,85 @@ -mod accumulation; -mod loader; +use crate::{ + loader::{EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader}, + util::arithmetic::{Curve, CurveAffine, FieldOps, PrimeField}, + Error, +}; +use lazy_static::lazy_static; +use std::fmt::Debug; -pub use loader::NativeLoader; +lazy_static! { + pub static ref LOADER: NativeLoader = NativeLoader; +} + +#[derive(Clone, Debug)] +pub struct NativeLoader; + +impl LoadedEcPoint for C { + type Loader = NativeLoader; + + fn loader(&self) -> &NativeLoader { + &LOADER + } + + fn multi_scalar_multiplication(pairs: impl IntoIterator) -> Self { + pairs + .into_iter() + .map(|(scalar, base)| base * scalar) + .reduce(|acc, value| acc + value) + .unwrap() + .to_affine() + } +} + +impl FieldOps for F { + fn invert(&self) -> Option { + self.invert().into() + } +} + +impl LoadedScalar for F { + type Loader = NativeLoader; + + fn loader(&self) -> &NativeLoader { + &LOADER + } +} + +impl EcPointLoader for NativeLoader { + type LoadedEcPoint = C; + + fn ec_point_load_const(&self, value: &C) -> Self::LoadedEcPoint { + *value + } + + fn ec_point_assert_eq( + &self, + annotation: &str, + lhs: &Self::LoadedEcPoint, + rhs: &Self::LoadedEcPoint, + ) -> Result<(), Error> { + lhs.eq(rhs) + .then_some(()) + .ok_or_else(|| Error::AssertionFailure(annotation.to_string())) + } +} + +impl ScalarLoader for NativeLoader { + type LoadedScalar = F; + + fn load_const(&self, value: &F) -> Self::LoadedScalar { + *value + } + + fn assert_eq( + &self, + annotation: &str, + lhs: &Self::LoadedScalar, + rhs: &Self::LoadedScalar, + ) -> Result<(), Error> { + lhs.eq(rhs) + .then_some(()) + .ok_or_else(|| Error::AssertionFailure(annotation.to_string())) + } +} + +impl Loader for NativeLoader {} diff --git a/src/loader/native/accumulation.rs b/src/loader/native/accumulation.rs deleted file mode 100644 index d0b67dc9..00000000 --- a/src/loader/native/accumulation.rs +++ /dev/null @@ -1,111 +0,0 @@ -use crate::{ - loader::native::NativeLoader, - protocol::Protocol, - scheme::kzg::{AccumulationStrategy, Accumulator, SameCurveAccumulation, MSM}, - util::{fe_from_limbs, Curve, Group, Itertools, PrimeCurveAffine, Transcript}, - Error, -}; -use halo2_curves::{ - pairing::{MillerLoopResult, MultiMillerLoop}, - CurveAffine, CurveExt, -}; - -impl - SameCurveAccumulation -{ - pub fn finalize(self, g1: C) -> (C, C) { - self.accumulator.unwrap().evaluate(g1) - } -} - -impl - SameCurveAccumulation -{ - pub fn decide>( - self, - g1: M::G1Affine, - g2: M::G2Affine, - s_g2: M::G2Affine, - ) -> bool { - let (lhs, rhs) = self.finalize(g1.to_curve()); - - let g2 = M::G2Prepared::from(g2); - let minus_s_g2 = M::G2Prepared::from(-s_g2); - - let terms = [(&lhs.into(), &g2), (&rhs.into(), &minus_s_g2)]; - M::multi_miller_loop(&terms) - .final_exponentiation() - .is_identity() - .into() - } -} - -impl AccumulationStrategy - for SameCurveAccumulation -where - C: CurveExt, - T: Transcript, -{ - type Output = P; - - fn extract_accumulator( - &self, - protocol: &Protocol, - _: &NativeLoader, - transcript: &mut T, - statements: &[Vec], - ) -> Option> { - let accumulator_indices = protocol.accumulator_indices.as_ref()?; - - let challenges = transcript.squeeze_n_challenges(accumulator_indices.len()); - let accumulators = accumulator_indices - .iter() - .map(|indices| { - assert_eq!(indices.len(), 4 * LIMBS); - let [lhs_x, lhs_y, rhs_x, rhs_y]: [_; 4] = indices - .chunks(4) - .into_iter() - .map(|indices| { - fe_from_limbs::<_, _, LIMBS, BITS>( - indices - .iter() - .map(|index| statements[index.0][index.1]) - .collect_vec() - .try_into() - .unwrap(), - ) - }) - .collect_vec() - .try_into() - .unwrap(); - let lhs = ::from_xy(lhs_x, lhs_y) - .unwrap() - .to_curve(); - let rhs = ::from_xy(rhs_x, rhs_y) - .unwrap() - .to_curve(); - Accumulator::new(MSM::base(lhs), MSM::base(rhs)) - }) - .collect_vec(); - - Some(Accumulator::random_linear_combine( - challenges.into_iter().zip(accumulators), - )) - } - - fn process( - &mut self, - _: &NativeLoader, - transcript: &mut T, - proof: P, - accumulator: Accumulator, - ) -> Result { - self.accumulator = Some(match self.accumulator.take() { - Some(curr_accumulator) => { - accumulator + curr_accumulator * &transcript.squeeze_challenge() - } - None => accumulator, - }); - Ok(proof) - } -} diff --git a/src/loader/native/loader.rs b/src/loader/native/loader.rs deleted file mode 100644 index 12bb475e..00000000 --- a/src/loader/native/loader.rs +++ /dev/null @@ -1,61 +0,0 @@ -use crate::{ - loader::{EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader}, - util::{Curve, FieldOps, PrimeField}, -}; -use lazy_static::lazy_static; -use std::fmt::Debug; - -lazy_static! { - static ref LOADER: NativeLoader = NativeLoader; -} - -impl LoadedEcPoint for C { - type Loader = NativeLoader; - - fn loader(&self) -> &NativeLoader { - &LOADER - } - - fn multi_scalar_multiplication(pairs: impl IntoIterator) -> Self { - pairs - .into_iter() - .map(|(scalar, base)| base * scalar) - .reduce(|acc, value| acc + value) - .unwrap() - } -} - -impl FieldOps for F { - fn invert(&self) -> Option { - self.invert().into() - } -} - -impl LoadedScalar for F { - type Loader = NativeLoader; - - fn loader(&self) -> &NativeLoader { - &LOADER - } -} - -#[derive(Clone, Debug)] -pub struct NativeLoader; - -impl EcPointLoader for NativeLoader { - type LoadedEcPoint = C; - - fn ec_point_load_const(&self, value: &C) -> Self::LoadedEcPoint { - *value - } -} - -impl ScalarLoader for NativeLoader { - type LoadedScalar = F; - - fn load_const(&self, value: &F) -> Self::LoadedScalar { - *value - } -} - -impl Loader for NativeLoader {} diff --git a/src/pcs.rs b/src/pcs.rs new file mode 100644 index 00000000..65804895 --- /dev/null +++ b/src/pcs.rs @@ -0,0 +1,138 @@ +use crate::{ + loader::{native::NativeLoader, Loader}, + util::{ + arithmetic::{CurveAffine, PrimeField}, + msm::Msm, + transcript::{TranscriptRead, TranscriptWrite}, + }, + Error, +}; +use rand::Rng; +use std::fmt::Debug; + +pub mod kzg; + +pub trait PolynomialCommitmentScheme: Clone + Debug +where + C: CurveAffine, + L: Loader, +{ + type Accumulator: Clone + Debug; +} + +#[derive(Clone, Debug)] +pub struct Query { + pub poly: usize, + pub shift: F, + pub eval: T, +} + +impl Query { + pub fn with_evaluation(self, eval: T) -> Query { + Query { + poly: self.poly, + shift: self.shift, + eval, + } + } +} + +pub trait MultiOpenScheme: PolynomialCommitmentScheme +where + C: CurveAffine, + L: Loader, +{ + type SuccinctVerifyingKey: Clone + Debug; + type Proof: Clone + Debug; + + fn read_proof( + svk: &Self::SuccinctVerifyingKey, + queries: &[Query], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead; + + fn succinct_verify( + svk: &Self::SuccinctVerifyingKey, + commitments: &[Msm], + point: &L::LoadedScalar, + queries: &[Query], + proof: &Self::Proof, + ) -> Result; +} + +pub trait Decider: PolynomialCommitmentScheme +where + C: CurveAffine, + L: Loader, +{ + type DecidingKey: Clone + Debug; + type Output: Clone + Debug; + + fn decide(dk: &Self::DecidingKey, accumulator: Self::Accumulator) -> Self::Output; + + fn decide_all(dk: &Self::DecidingKey, accumulators: Vec) -> Self::Output; +} + +pub trait AccumulationScheme: Clone + Debug +where + C: CurveAffine, + L: Loader, + PCS: PolynomialCommitmentScheme, +{ + type VerifyingKey: Clone + Debug; + type Proof: Clone + Debug; + + fn read_proof( + vk: &Self::VerifyingKey, + instances: &[PCS::Accumulator], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead; + + fn verify( + vk: &Self::VerifyingKey, + instances: &[PCS::Accumulator], + proof: &Self::Proof, + ) -> Result; +} + +pub trait AccumulationSchemeProver: AccumulationScheme +where + C: CurveAffine, + PCS: PolynomialCommitmentScheme, +{ + type ProvingKey: Clone + Debug; + + fn create_proof( + pk: &Self::ProvingKey, + instances: &[PCS::Accumulator], + transcript: &mut T, + rng: R, + ) -> Result + where + T: TranscriptWrite, + R: Rng; +} + +pub trait AccumulatorEncoding: Clone + Debug +where + C: CurveAffine, + L: Loader, + PCS: PolynomialCommitmentScheme, +{ + fn from_repr(repr: Vec) -> Result; +} + +impl AccumulatorEncoding for () +where + C: CurveAffine, + L: Loader, + PCS: PolynomialCommitmentScheme, +{ + fn from_repr(_: Vec) -> Result { + unimplemented!() + } +} diff --git a/src/pcs/kzg.rs b/src/pcs/kzg.rs new file mode 100644 index 00000000..9f10bd44 --- /dev/null +++ b/src/pcs/kzg.rs @@ -0,0 +1,45 @@ +use crate::{ + loader::Loader, + pcs::PolynomialCommitmentScheme, + util::arithmetic::{CurveAffine, MultiMillerLoop}, +}; +use std::{fmt::Debug, marker::PhantomData}; + +mod accumulation; +mod accumulator; +mod decider; +mod multiopen; + +pub use accumulation::{KzgAs, KzgAsProvingKey, KzgAsVerifyingKey}; +pub use accumulator::{KzgAccumulator, LimbsEncoding}; +pub use decider::KzgDecidingKey; +pub use multiopen::{Bdfg21, Bdfg21Proof, Gwc19, Gwc19Proof}; + +#[derive(Clone, Debug)] +pub struct Kzg(PhantomData<(M, MOS)>); + +impl PolynomialCommitmentScheme for Kzg +where + M: MultiMillerLoop, + L: Loader, + MOS: Clone + Debug, +{ + type Accumulator = KzgAccumulator; +} + +#[derive(Clone, Copy, Debug)] +pub struct KzgSuccinctVerifyingKey { + pub g: C, +} + +impl KzgSuccinctVerifyingKey { + pub fn new(g: C) -> Self { + Self { g } + } +} + +impl From for KzgSuccinctVerifyingKey { + fn from(g: C) -> KzgSuccinctVerifyingKey { + KzgSuccinctVerifyingKey::new(g) + } +} diff --git a/src/pcs/kzg/accumulation.rs b/src/pcs/kzg/accumulation.rs new file mode 100644 index 00000000..cd13fd00 --- /dev/null +++ b/src/pcs/kzg/accumulation.rs @@ -0,0 +1,196 @@ +use crate::{ + loader::{native::NativeLoader, LoadedScalar, Loader}, + pcs::{ + kzg::KzgAccumulator, AccumulationScheme, AccumulationSchemeProver, + PolynomialCommitmentScheme, + }, + util::{ + arithmetic::{Curve, CurveAffine, Field}, + msm::Msm, + transcript::{TranscriptRead, TranscriptWrite}, + }, + Error, +}; +use rand::Rng; +use std::marker::PhantomData; + +#[derive(Clone, Debug)] +pub struct KzgAs(PhantomData); + +impl AccumulationScheme for KzgAs +where + C: CurveAffine, + L: Loader, + PCS: PolynomialCommitmentScheme>, +{ + type VerifyingKey = KzgAsVerifyingKey; + type Proof = KzgAsProof; + + fn read_proof( + vk: &Self::VerifyingKey, + instances: &[PCS::Accumulator], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + KzgAsProof::read(vk, instances, transcript) + } + + fn verify( + _: &Self::VerifyingKey, + instances: &[PCS::Accumulator], + proof: &Self::Proof, + ) -> Result { + let (lhs, rhs) = instances + .iter() + .cloned() + .map(|accumulator| (accumulator.lhs, accumulator.rhs)) + .chain(proof.blind.clone()) + .unzip::<_, _, Vec<_>, Vec<_>>(); + + let powers_of_r = proof.r.powers(lhs.len()); + let [lhs, rhs] = [lhs, rhs].map(|msms| { + msms.into_iter() + .zip(powers_of_r.iter()) + .map(|(msm, r)| Msm::::base(msm) * r) + .sum::>() + .evaluate(None) + }); + + Ok(KzgAccumulator::new(lhs, rhs)) + } +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct KzgAsProvingKey(pub Option<(C, C)>); + +impl KzgAsProvingKey { + pub fn new(g: Option<(C, C)>) -> Self { + Self(g) + } + + pub fn zk(&self) -> bool { + self.0.is_some() + } + + pub fn vk(&self) -> KzgAsVerifyingKey { + KzgAsVerifyingKey(self.zk()) + } +} + +#[derive(Clone, Copy, Debug, Default)] +pub struct KzgAsVerifyingKey(bool); + +impl KzgAsVerifyingKey { + pub fn zk(&self) -> bool { + self.0 + } +} + +#[derive(Clone, Debug)] +pub struct KzgAsProof +where + C: CurveAffine, + L: Loader, + PCS: PolynomialCommitmentScheme>, +{ + blind: Option<(L::LoadedEcPoint, L::LoadedEcPoint)>, + r: L::LoadedScalar, + _marker: PhantomData, +} + +impl KzgAsProof +where + C: CurveAffine, + L: Loader, + PCS: PolynomialCommitmentScheme>, +{ + fn read( + vk: &KzgAsVerifyingKey, + instances: &[PCS::Accumulator], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + assert!(!instances.is_empty()); + + for accumulator in instances { + transcript.common_ec_point(&accumulator.lhs)?; + transcript.common_ec_point(&accumulator.rhs)?; + } + + let blind = vk + .zk() + .then(|| Ok((transcript.read_ec_point()?, transcript.read_ec_point()?))) + .transpose()?; + + let r = transcript.squeeze_challenge(); + + Ok(Self { + blind, + r, + _marker: PhantomData, + }) + } +} + +impl AccumulationSchemeProver for KzgAs +where + C: CurveAffine, + PCS: PolynomialCommitmentScheme>, +{ + type ProvingKey = KzgAsProvingKey; + + fn create_proof( + pk: &Self::ProvingKey, + instances: &[PCS::Accumulator], + transcript: &mut T, + rng: R, + ) -> Result + where + T: TranscriptWrite, + R: Rng, + { + assert!(!instances.is_empty()); + + for accumulator in instances { + transcript.common_ec_point(&accumulator.lhs)?; + transcript.common_ec_point(&accumulator.rhs)?; + } + + let blind = pk + .zk() + .then(|| { + let s = C::Scalar::random(rng); + let (g, s_g) = pk.0.unwrap(); + let lhs = (s_g * s).to_affine(); + let rhs = (g * s).to_affine(); + transcript.write_ec_point(lhs)?; + transcript.write_ec_point(rhs)?; + Ok((lhs, rhs)) + }) + .transpose()?; + + let r = transcript.squeeze_challenge(); + + let (lhs, rhs) = instances + .iter() + .cloned() + .map(|accumulator| (accumulator.lhs, accumulator.rhs)) + .chain(blind) + .unzip::<_, _, Vec<_>, Vec<_>>(); + + let powers_of_r = r.powers(lhs.len()); + let [lhs, rhs] = [lhs, rhs].map(|msms| { + msms.into_iter() + .zip(powers_of_r.iter()) + .map(|(msm, power_of_r)| Msm::::base(msm) * power_of_r) + .sum::>() + .evaluate(None) + }); + + Ok(KzgAccumulator::new(lhs, rhs)) + } +} diff --git a/src/pcs/kzg/accumulator.rs b/src/pcs/kzg/accumulator.rs new file mode 100644 index 00000000..17c7bf83 --- /dev/null +++ b/src/pcs/kzg/accumulator.rs @@ -0,0 +1,208 @@ +use crate::{loader::Loader, util::arithmetic::CurveAffine}; +use std::fmt::Debug; + +#[derive(Clone, Debug)] +pub struct KzgAccumulator +where + C: CurveAffine, + L: Loader, +{ + pub lhs: L::LoadedEcPoint, + pub rhs: L::LoadedEcPoint, +} + +impl KzgAccumulator +where + C: CurveAffine, + L: Loader, +{ + pub fn new(lhs: L::LoadedEcPoint, rhs: L::LoadedEcPoint) -> Self { + Self { lhs, rhs } + } +} + +/// `AccumulatorEncoding` that encodes `Accumulator` into limbs. +/// +/// Since in circuit everything are in scalar field, but `Accumulator` might contain base field elements, so we split them into limbs. +/// The const generic `LIMBS` and `BITS` respectively represents how many limbs +/// a base field element are split into and how many bits each limbs could have. +#[derive(Clone, Debug)] +pub struct LimbsEncoding; + +mod native { + use crate::{ + loader::native::NativeLoader, + pcs::{ + kzg::{KzgAccumulator, LimbsEncoding}, + AccumulatorEncoding, PolynomialCommitmentScheme, + }, + util::{ + arithmetic::{fe_from_limbs, CurveAffine}, + Itertools, + }, + Error, + }; + + impl AccumulatorEncoding + for LimbsEncoding + where + C: CurveAffine, + PCS: PolynomialCommitmentScheme< + C, + NativeLoader, + Accumulator = KzgAccumulator, + >, + { + fn from_repr(limbs: Vec) -> Result { + assert_eq!(limbs.len(), 4 * LIMBS); + + let [lhs_x, lhs_y, rhs_x, rhs_y]: [_; 4] = limbs + .chunks(LIMBS) + .into_iter() + .map(|limbs| fe_from_limbs::<_, _, LIMBS, BITS>(limbs.try_into().unwrap())) + .collect_vec() + .try_into() + .unwrap(); + let accumulator = KzgAccumulator::new( + C::from_xy(lhs_x, lhs_y).unwrap(), + C::from_xy(rhs_x, rhs_y).unwrap(), + ); + + Ok(accumulator) + } + } +} + +#[cfg(feature = "loader_evm")] +mod evm { + use crate::{ + loader::evm::{EvmLoader, Scalar}, + pcs::{ + kzg::{KzgAccumulator, LimbsEncoding}, + AccumulatorEncoding, PolynomialCommitmentScheme, + }, + util::{ + arithmetic::{CurveAffine, PrimeField}, + Itertools, + }, + Error, + }; + use std::rc::Rc; + + impl AccumulatorEncoding, PCS> + for LimbsEncoding + where + C: CurveAffine, + C::Scalar: PrimeField, + PCS: PolynomialCommitmentScheme< + C, + Rc, + Accumulator = KzgAccumulator>, + >, + { + fn from_repr(limbs: Vec) -> Result { + assert_eq!(limbs.len(), 4 * LIMBS); + + let loader = limbs[0].loader(); + + let [lhs_x, lhs_y, rhs_x, rhs_y]: [[_; LIMBS]; 4] = limbs + .chunks(LIMBS) + .into_iter() + .map(|limbs| limbs.to_vec().try_into().unwrap()) + .collect_vec() + .try_into() + .unwrap(); + let accumulator = KzgAccumulator::new( + loader.ec_point_from_limbs::(lhs_x, lhs_y), + loader.ec_point_from_limbs::(rhs_x, rhs_y), + ); + + Ok(accumulator) + } + } +} + +#[cfg(feature = "loader_halo2")] +mod halo2 { + use crate::{ + loader::halo2::{Context, EccInstructions, Halo2Loader, Scalar, Valuetools}, + pcs::{ + kzg::{KzgAccumulator, LimbsEncoding}, + AccumulatorEncoding, PolynomialCommitmentScheme, + }, + util::{ + arithmetic::{fe_from_limbs, CurveAffine}, + Itertools, + }, + Error, + }; + use halo2_proofs::circuit::Value; + use halo2_wrong_ecc::{maingate::AssignedValue, AssignedPoint}; + use std::{iter, rc::Rc}; + + fn ec_point_from_assigned_limbs( + limbs: &[AssignedValue], + ) -> Value { + assert_eq!(limbs.len(), 2 * LIMBS); + + let [x, y] = [&limbs[..LIMBS], &limbs[LIMBS..]].map(|limbs| { + limbs + .iter() + .map(|assigned| assigned.value()) + .fold_zipped(Vec::new(), |mut acc, limb| { + acc.push(*limb); + acc + }) + .map(|limbs| fe_from_limbs::<_, _, LIMBS, BITS>(limbs.try_into().unwrap())) + }); + + x.zip(y).map(|(x, y)| C::from_xy(x, y).unwrap()) + } + + impl<'a, C, PCS, EccChip, const LIMBS: usize, const BITS: usize> + AccumulatorEncoding>, PCS> for LimbsEncoding + where + C: CurveAffine, + PCS: PolynomialCommitmentScheme< + C, + Rc>, + Accumulator = KzgAccumulator>>, + >, + EccChip: EccInstructions< + 'a, + C, + AssignedEcPoint = AssignedPoint<::Base, C::Scalar, LIMBS, BITS>, + AssignedScalar = AssignedValue, + >, + { + fn from_repr(limbs: Vec>) -> Result { + assert_eq!(limbs.len(), 4 * LIMBS); + + let loader = limbs[0].loader(); + + let assigned_limbs = limbs.iter().map(|limb| limb.assigned()).collect_vec(); + let [lhs, rhs] = [&assigned_limbs[..2 * LIMBS], &assigned_limbs[2 * LIMBS..]].map( + |assigned_limbs| { + let ec_point = ec_point_from_assigned_limbs::<_, LIMBS, BITS>(assigned_limbs); + loader.assign_ec_point(ec_point) + }, + ); + + for (src, dst) in assigned_limbs.iter().zip( + iter::empty() + .chain(lhs.assigned().x().limbs()) + .chain(lhs.assigned().y().limbs()) + .chain(rhs.assigned().x().limbs()) + .chain(rhs.assigned().y().limbs()), + ) { + loader + .ctx_mut() + .constrain_equal(src.cell(), dst.as_ref().cell()) + .unwrap(); + } + let accumulator = KzgAccumulator::new(lhs, rhs); + + Ok(accumulator) + } + } +} diff --git a/src/pcs/kzg/decider.rs b/src/pcs/kzg/decider.rs new file mode 100644 index 00000000..b6957883 --- /dev/null +++ b/src/pcs/kzg/decider.rs @@ -0,0 +1,162 @@ +use crate::util::arithmetic::MultiMillerLoop; +use std::marker::PhantomData; + +#[derive(Debug, Clone, Copy)] +pub struct KzgDecidingKey { + pub g2: M::G2Affine, + pub s_g2: M::G2Affine, + _marker: PhantomData, +} + +impl KzgDecidingKey { + pub fn new(g2: M::G2Affine, s_g2: M::G2Affine) -> Self { + Self { + g2, + s_g2, + _marker: PhantomData, + } + } +} + +impl From<(M::G2Affine, M::G2Affine)> for KzgDecidingKey { + fn from((g2, s_g2): (M::G2Affine, M::G2Affine)) -> KzgDecidingKey { + KzgDecidingKey::new(g2, s_g2) + } +} + +mod native { + use crate::{ + loader::native::NativeLoader, + pcs::{ + kzg::{Kzg, KzgAccumulator, KzgDecidingKey}, + Decider, + }, + util::arithmetic::{Group, MillerLoopResult, MultiMillerLoop}, + }; + use std::fmt::Debug; + + impl Decider for Kzg + where + M: MultiMillerLoop, + MOS: Clone + Debug, + { + type DecidingKey = KzgDecidingKey; + type Output = bool; + + fn decide( + dk: &Self::DecidingKey, + KzgAccumulator { lhs, rhs }: KzgAccumulator, + ) -> bool { + let terms = [(&lhs, &dk.g2.into()), (&rhs, &(-dk.s_g2).into())]; + M::multi_miller_loop(&terms) + .final_exponentiation() + .is_identity() + .into() + } + + fn decide_all( + dk: &Self::DecidingKey, + accumulators: Vec>, + ) -> bool { + !accumulators + .into_iter() + .any(|accumulator| !Self::decide(dk, accumulator)) + } + } +} + +#[cfg(feature = "loader_evm")] +mod evm { + use crate::{ + loader::{ + evm::{loader::Value, EvmLoader}, + LoadedScalar, + }, + pcs::{ + kzg::{Kzg, KzgAccumulator, KzgDecidingKey}, + Decider, + }, + util::{ + arithmetic::{CurveAffine, MultiMillerLoop, PrimeField}, + msm::Msm, + }, + }; + use ethereum_types::U256; + use std::{fmt::Debug, rc::Rc}; + + impl Decider> for Kzg + where + M: MultiMillerLoop, + M::Scalar: PrimeField, + MOS: Clone + Debug, + { + type DecidingKey = KzgDecidingKey; + type Output = (); + + fn decide( + dk: &Self::DecidingKey, + KzgAccumulator { lhs, rhs }: KzgAccumulator>, + ) { + let loader = lhs.loader(); + let [g2, minus_s_g2] = [dk.g2, -dk.s_g2].map(|ec_point| { + let coordinates = ec_point.coordinates().unwrap(); + let x = coordinates.x().to_repr(); + let y = coordinates.y().to_repr(); + ( + U256::from_little_endian(&x.as_ref()[32..]), + U256::from_little_endian(&x.as_ref()[..32]), + U256::from_little_endian(&y.as_ref()[32..]), + U256::from_little_endian(&y.as_ref()[..32]), + ) + }); + loader.pairing(&lhs, g2, &rhs, minus_s_g2); + } + + fn decide_all( + dk: &Self::DecidingKey, + mut accumulators: Vec>>, + ) { + assert!(!accumulators.is_empty()); + + let accumulator = if accumulators.len() == 1 { + accumulators.pop().unwrap() + } else { + let loader = accumulators[0].lhs.loader(); + let (lhs, rhs) = accumulators + .iter() + .map(|KzgAccumulator { lhs, rhs }| { + let [lhs, rhs] = [&lhs, &rhs].map(|ec_point| loader.dup_ec_point(ec_point)); + (lhs, rhs) + }) + .unzip::<_, _, Vec<_>, Vec<_>>(); + + let hash_ptr = loader.keccak256(lhs[0].ptr(), lhs.len() * 0x80); + let challenge_ptr = loader.allocate(0x20); + loader + .code_mut() + .push(loader.scalar_modulus()) + .push(hash_ptr) + .mload() + .r#mod() + .push(challenge_ptr) + .mstore(); + let challenge = loader.scalar(Value::Memory(challenge_ptr)); + + let powers_of_challenge = LoadedScalar::::powers(&challenge, lhs.len()); + let [lhs, rhs] = [lhs, rhs].map(|msms| { + msms.into_iter() + .zip(powers_of_challenge.iter()) + .map(|(msm, power_of_challenge)| { + Msm::>::base(msm) * power_of_challenge + }) + .sum::>() + .evaluate(None) + }); + + KzgAccumulator::new(lhs, rhs) + }; + + Self::decide(dk, accumulator) + } + } +} diff --git a/src/pcs/kzg/multiopen.rs b/src/pcs/kzg/multiopen.rs new file mode 100644 index 00000000..d3e50e62 --- /dev/null +++ b/src/pcs/kzg/multiopen.rs @@ -0,0 +1,5 @@ +mod bdfg21; +mod gwc19; + +pub use bdfg21::{Bdfg21, Bdfg21Proof}; +pub use gwc19::{Gwc19, Gwc19Proof}; diff --git a/src/pcs/kzg/multiopen/bdfg21.rs b/src/pcs/kzg/multiopen/bdfg21.rs new file mode 100644 index 00000000..287700d7 --- /dev/null +++ b/src/pcs/kzg/multiopen/bdfg21.rs @@ -0,0 +1,381 @@ +use crate::{ + cost::{Cost, CostEstimation}, + loader::{LoadedScalar, Loader, ScalarLoader}, + pcs::{ + kzg::{Kzg, KzgAccumulator, KzgSuccinctVerifyingKey}, + MultiOpenScheme, Query, + }, + util::{ + arithmetic::{ilog2, CurveAffine, FieldExt, Fraction, MultiMillerLoop}, + msm::Msm, + transcript::TranscriptRead, + Itertools, + }, + Error, +}; +use std::{ + collections::{BTreeMap, BTreeSet}, + marker::PhantomData, +}; + +#[derive(Clone, Debug)] +pub struct Bdfg21; + +impl MultiOpenScheme for Kzg +where + M: MultiMillerLoop, + L: Loader, +{ + type SuccinctVerifyingKey = KzgSuccinctVerifyingKey; + type Proof = Bdfg21Proof; + + fn read_proof( + _: &KzgSuccinctVerifyingKey, + _: &[Query], + transcript: &mut T, + ) -> Result, Error> + where + T: TranscriptRead, + { + Bdfg21Proof::read(transcript) + } + + fn succinct_verify( + svk: &KzgSuccinctVerifyingKey, + commitments: &[Msm], + z: &L::LoadedScalar, + queries: &[Query], + proof: &Bdfg21Proof, + ) -> Result { + let f = { + let sets = query_sets(queries); + let coeffs = query_set_coeffs(&sets, z, &proof.z_prime); + + let powers_of_mu = proof + .mu + .powers(sets.iter().map(|set| set.polys.len()).max().unwrap()); + let msms = sets + .iter() + .zip(coeffs.iter()) + .map(|(set, coeff)| set.msm(coeff, commitments, &powers_of_mu)); + + msms.zip(proof.gamma.powers(sets.len()).into_iter()) + .map(|(msm, power_of_gamma)| msm * &power_of_gamma) + .sum::>() + - Msm::base(proof.w.clone()) * &coeffs[0].z_s + }; + + let rhs = Msm::base(proof.w_prime.clone()); + let lhs = f + rhs.clone() * &proof.z_prime; + + Ok(KzgAccumulator::new( + lhs.evaluate(Some(svk.g)), + rhs.evaluate(Some(svk.g)), + )) + } +} + +#[derive(Clone, Debug)] +pub struct Bdfg21Proof +where + C: CurveAffine, + L: Loader, +{ + mu: L::LoadedScalar, + gamma: L::LoadedScalar, + w: L::LoadedEcPoint, + z_prime: L::LoadedScalar, + w_prime: L::LoadedEcPoint, +} + +impl Bdfg21Proof +where + C: CurveAffine, + L: Loader, +{ + fn read>(transcript: &mut T) -> Result { + let mu = transcript.squeeze_challenge(); + let gamma = transcript.squeeze_challenge(); + let w = transcript.read_ec_point()?; + let z_prime = transcript.squeeze_challenge(); + let w_prime = transcript.read_ec_point()?; + Ok(Bdfg21Proof { + mu, + gamma, + w, + z_prime, + w_prime, + }) + } +} + +fn query_sets(queries: &[Query]) -> Vec> { + let poly_shifts = queries.iter().fold( + Vec::<(usize, Vec, Vec<&T>)>::new(), + |mut poly_shifts, query| { + if let Some(pos) = poly_shifts + .iter() + .position(|(poly, _, _)| *poly == query.poly) + { + let (_, shifts, evals) = &mut poly_shifts[pos]; + if !shifts.contains(&query.shift) { + shifts.push(query.shift); + evals.push(&query.eval); + } + } else { + poly_shifts.push((query.poly, vec![query.shift], vec![&query.eval])); + } + poly_shifts + }, + ); + + poly_shifts.into_iter().fold( + Vec::>::new(), + |mut sets, (poly, shifts, evals)| { + if let Some(pos) = sets.iter().position(|set| { + BTreeSet::from_iter(set.shifts.iter()) == BTreeSet::from_iter(shifts.iter()) + }) { + let set = &mut sets[pos]; + if !set.polys.contains(&poly) { + set.polys.push(poly); + set.evals.push( + set.shifts + .iter() + .map(|lhs| { + let idx = shifts.iter().position(|rhs| lhs == rhs).unwrap(); + evals[idx].clone() + }) + .collect(), + ); + } + } else { + let set = QuerySet { + shifts, + polys: vec![poly], + evals: vec![evals.into_iter().cloned().collect()], + }; + sets.push(set); + } + sets + }, + ) +} + +fn query_set_coeffs>( + sets: &[QuerySet], + z: &T, + z_prime: &T, +) -> Vec> { + let loader = z.loader(); + + let superset = sets + .iter() + .flat_map(|set| set.shifts.clone()) + .sorted() + .dedup(); + + let size = 2.max( + ilog2((sets.iter().map(|set| set.shifts.len()).max().unwrap() - 1).next_power_of_two()) + 1, + ); + let powers_of_z = z.powers(size); + let z_prime_minus_z_shift_i = BTreeMap::from_iter(superset.map(|shift| { + ( + shift, + z_prime.clone() - z.clone() * loader.load_const(&shift), + ) + })); + + let mut z_s_1 = None; + let mut coeffs = sets + .iter() + .map(|set| { + let coeff = QuerySetCoeff::new( + &set.shifts, + &powers_of_z, + z_prime, + &z_prime_minus_z_shift_i, + &z_s_1, + ); + if z_s_1.is_none() { + z_s_1 = Some(coeff.z_s.clone()); + }; + coeff + }) + .collect_vec(); + + T::batch_invert(coeffs.iter_mut().flat_map(QuerySetCoeff::denoms)); + T::batch_invert(coeffs.iter_mut().flat_map(QuerySetCoeff::denoms)); + coeffs.iter_mut().for_each(QuerySetCoeff::evaluate); + + coeffs +} + +#[derive(Clone, Debug)] +struct QuerySet { + shifts: Vec, + polys: Vec, + evals: Vec>, +} + +impl> QuerySet { + fn msm>( + &self, + coeff: &QuerySetCoeff, + commitments: &[Msm], + powers_of_mu: &[T], + ) -> Msm { + self.polys + .iter() + .zip(self.evals.iter()) + .zip(powers_of_mu.iter()) + .map(|((poly, evals), power_of_mu)| { + let loader = power_of_mu.loader(); + let commitment = coeff + .commitment_coeff + .as_ref() + .map(|commitment_coeff| { + commitments[*poly].clone() * commitment_coeff.evaluated() + }) + .unwrap_or_else(|| commitments[*poly].clone()); + let r_eval = loader.sum_products( + &coeff + .eval_coeffs + .iter() + .zip(evals.iter()) + .map(|(coeff, eval)| (coeff.evaluated(), eval)) + .collect_vec(), + ) * coeff.r_eval_coeff.as_ref().unwrap().evaluated(); + (commitment - Msm::constant(r_eval)) * power_of_mu + }) + .sum() + } +} + +#[derive(Clone, Debug)] +struct QuerySetCoeff { + z_s: T, + eval_coeffs: Vec>, + commitment_coeff: Option>, + r_eval_coeff: Option>, + _marker: PhantomData, +} + +impl QuerySetCoeff +where + F: FieldExt, + T: LoadedScalar, +{ + fn new( + shifts: &[F], + powers_of_z: &[T], + z_prime: &T, + z_prime_minus_z_shift_i: &BTreeMap, + z_s_1: &Option, + ) -> Self { + let loader = z_prime.loader(); + + let normalized_ell_primes = shifts + .iter() + .enumerate() + .map(|(j, shift_j)| { + shifts + .iter() + .enumerate() + .filter(|&(i, _)| i != j) + .map(|(_, shift_i)| (*shift_j - shift_i)) + .reduce(|acc, value| acc * value) + .unwrap_or_else(|| F::one()) + }) + .collect_vec(); + + let z = &powers_of_z[1].clone(); + let z_pow_k_minus_one = { + let k_minus_one = shifts.len() - 1; + powers_of_z + .iter() + .enumerate() + .skip(1) + .filter_map(|(i, power_of_z)| { + (k_minus_one & (1 << i) == 1).then(|| power_of_z.clone()) + }) + .reduce(|acc, value| acc * value) + .unwrap_or_else(|| loader.load_one()) + }; + + let barycentric_weights = shifts + .iter() + .zip(normalized_ell_primes.iter()) + .map(|(shift, normalized_ell_prime)| { + loader.sum_products_with_coeff(&[ + (*normalized_ell_prime, &z_pow_k_minus_one, z_prime), + (-(*normalized_ell_prime * shift), &z_pow_k_minus_one, z), + ]) + }) + .map(Fraction::one_over) + .collect_vec(); + + let z_s = loader.product( + &shifts + .iter() + .map(|shift| z_prime_minus_z_shift_i.get(shift).unwrap()) + .collect_vec(), + ); + let z_s_1_over_z_s = z_s_1.clone().map(|z_s_1| Fraction::new(z_s_1, z_s.clone())); + + Self { + z_s, + eval_coeffs: barycentric_weights, + commitment_coeff: z_s_1_over_z_s, + r_eval_coeff: None, + _marker: PhantomData, + } + } + + fn denoms(&mut self) -> impl IntoIterator { + if self.eval_coeffs.first().unwrap().denom().is_some() { + return self + .eval_coeffs + .iter_mut() + .chain(self.commitment_coeff.as_mut()) + .filter_map(Fraction::denom_mut) + .collect_vec(); + } + + if self.r_eval_coeff.is_none() { + let loader = self.z_s.loader(); + self.eval_coeffs + .iter_mut() + .chain(self.commitment_coeff.as_mut()) + .for_each(Fraction::evaluate); + let barycentric_weights_sum = loader.sum( + &self + .eval_coeffs + .iter() + .map(Fraction::evaluated) + .collect_vec(), + ); + self.r_eval_coeff = Some(match self.commitment_coeff.clone() { + Some(coeff) => Fraction::new(coeff.evaluated().clone(), barycentric_weights_sum), + None => Fraction::one_over(barycentric_weights_sum), + }); + return vec![self.r_eval_coeff.as_mut().unwrap().denom_mut().unwrap()]; + } + + unreachable!() + } + + fn evaluate(&mut self) { + self.r_eval_coeff.as_mut().unwrap().evaluate(); + } +} + +impl CostEstimation for Kzg +where + M: MultiMillerLoop, +{ + type Input = Vec>; + + fn estimate_cost(_: &Vec>) -> Cost { + Cost::new(0, 2, 0, 2) + } +} diff --git a/src/pcs/kzg/multiopen/gwc19.rs b/src/pcs/kzg/multiopen/gwc19.rs new file mode 100644 index 00000000..121fce8a --- /dev/null +++ b/src/pcs/kzg/multiopen/gwc19.rs @@ -0,0 +1,167 @@ +use crate::{ + cost::{Cost, CostEstimation}, + loader::{LoadedScalar, Loader}, + pcs::{ + kzg::{Kzg, KzgAccumulator, KzgSuccinctVerifyingKey}, + MultiOpenScheme, Query, + }, + util::{ + arithmetic::{CurveAffine, MultiMillerLoop, PrimeField}, + msm::Msm, + transcript::TranscriptRead, + Itertools, + }, + Error, +}; + +#[derive(Clone, Debug)] +pub struct Gwc19; + +impl MultiOpenScheme for Kzg +where + M: MultiMillerLoop, + L: Loader, +{ + type SuccinctVerifyingKey = KzgSuccinctVerifyingKey; + type Proof = Gwc19Proof; + + fn read_proof( + _: &Self::SuccinctVerifyingKey, + queries: &[Query], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + Gwc19Proof::read(queries, transcript) + } + + fn succinct_verify( + svk: &Self::SuccinctVerifyingKey, + commitments: &[Msm], + z: &L::LoadedScalar, + queries: &[Query], + proof: &Self::Proof, + ) -> Result { + let sets = query_sets(queries); + let powers_of_u = &proof.u.powers(sets.len()); + let f = { + let powers_of_v = proof + .v + .powers(sets.iter().map(|set| set.polys.len()).max().unwrap()); + sets.iter() + .map(|set| set.msm(commitments, &powers_of_v)) + .zip(powers_of_u.iter()) + .map(|(msm, power_of_u)| msm * power_of_u) + .sum::>() + }; + let z_omegas = sets + .iter() + .map(|set| z.clone() * &z.loader().load_const(&set.shift)); + + let rhs = proof + .ws + .iter() + .zip(powers_of_u.iter()) + .map(|(w, power_of_u)| Msm::base(w.clone()) * power_of_u) + .collect_vec(); + let lhs = f + rhs + .iter() + .zip(z_omegas) + .map(|(uw, z_omega)| uw.clone() * &z_omega) + .sum(); + + Ok(KzgAccumulator::new( + lhs.evaluate(Some(svk.g)), + rhs.into_iter().sum::>().evaluate(Some(svk.g)), + )) + } +} + +#[derive(Clone, Debug)] +pub struct Gwc19Proof +where + C: CurveAffine, + L: Loader, +{ + v: L::LoadedScalar, + ws: Vec, + u: L::LoadedScalar, +} + +impl Gwc19Proof +where + C: CurveAffine, + L: Loader, +{ + fn read(queries: &[Query], transcript: &mut T) -> Result + where + T: TranscriptRead, + { + let v = transcript.squeeze_challenge(); + let ws = transcript.read_n_ec_points(query_sets(queries).len())?; + let u = transcript.squeeze_challenge(); + Ok(Gwc19Proof { v, ws, u }) + } +} + +struct QuerySet { + shift: F, + polys: Vec, + evals: Vec, +} + +impl QuerySet +where + F: PrimeField, + T: Clone, +{ + fn msm>( + &self, + commitments: &[Msm], + powers_of_v: &[L::LoadedScalar], + ) -> Msm { + self.polys + .iter() + .zip(self.evals.iter()) + .map(|(poly, eval)| { + let commitment = commitments[*poly].clone(); + commitment - Msm::constant(eval.clone()) + }) + .zip(powers_of_v.iter()) + .map(|(msm, power_of_v)| msm * power_of_v) + .sum() + } +} + +fn query_sets(queries: &[Query]) -> Vec> +where + F: PrimeField, + T: Clone + PartialEq, +{ + queries.iter().fold(Vec::new(), |mut sets, query| { + if let Some(pos) = sets.iter().position(|set| set.shift == query.shift) { + sets[pos].polys.push(query.poly); + sets[pos].evals.push(query.eval.clone()); + } else { + sets.push(QuerySet { + shift: query.shift, + polys: vec![query.poly], + evals: vec![query.eval.clone()], + }); + } + sets + }) +} + +impl CostEstimation for Kzg +where + M: MultiMillerLoop, +{ + type Input = Vec>; + + fn estimate_cost(queries: &Vec>) -> Cost { + let num_w = query_sets(queries).len(); + Cost::new(0, num_w, 0, num_w) + } +} diff --git a/src/protocol.rs b/src/protocol.rs deleted file mode 100644 index af591b78..00000000 --- a/src/protocol.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::util::{Curve, Domain, Expression, Group, Itertools, Query}; - -#[cfg(feature = "halo2")] -pub mod halo2; - -#[derive(Clone, Debug)] -pub struct Protocol { - pub zk: bool, - pub domain: Domain, - pub preprocessed: Vec, - pub num_statement: Vec, - pub num_auxiliary: Vec, - pub num_challenge: Vec, - pub evaluations: Vec, - pub queries: Vec, - pub relations: Vec>, - pub transcript_initial_state: C::Scalar, - pub accumulator_indices: Option>>, -} - -impl Protocol { - pub fn vanishing_poly(&self) -> usize { - self.preprocessed.len() - + self.num_statement.len() - + self.num_auxiliary.iter().sum::() - } -} - -pub struct Snark { - pub protocol: Protocol, - pub statements: Vec::Scalar>>, - pub proof: Vec, -} - -impl Snark { - pub fn new( - protocol: Protocol, - statements: Vec::Scalar>>, - proof: Vec, - ) -> Self { - assert_eq!( - protocol.num_statement, - statements - .iter() - .map(|statements| statements.len()) - .collect_vec() - ); - Snark { - protocol, - statements, - proof, - } - } -} diff --git a/src/protocol/halo2/test.rs b/src/protocol/halo2/test.rs deleted file mode 100644 index cfbcefef..00000000 --- a/src/protocol/halo2/test.rs +++ /dev/null @@ -1,176 +0,0 @@ -use crate::{ - protocol::halo2::{compile, Config}, - scheme::kzg::{Cost, CostEstimation, PlonkAccumulationScheme}, - util::{CommonPolynomial, Expression, Query}, -}; -use halo2_curves::bn256::{Bn256, Fr, G1}; -use halo2_proofs::{ - arithmetic::FieldExt, - dev::MockProver, - plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, ProvingKey}, - poly::{ - commitment::{CommitmentScheme, Params, ParamsProver, Prover, Verifier}, - kzg::commitment::KZGCommitmentScheme, - Rotation, VerificationStrategy, - }, - transcript::{EncodedChallenge, TranscriptReadBuffer, TranscriptWriterBuffer}, -}; -use rand_chacha::{ - rand_core::{RngCore, SeedableRng}, - ChaCha20Rng, -}; -use std::assert_matches::assert_matches; - -mod circuit; -mod kzg; - -pub use circuit::{ - maingate::{ - MainGateWithPlookup, MainGateWithPlookupConfig, MainGateWithRange, MainGateWithRangeConfig, - }, - standard::StandardPlonk, -}; - -pub fn create_proof_checked<'a, S, C, P, V, VS, TW, TR, EC, R, const ZK: bool>( - params: &'a S::ParamsProver, - pk: &ProvingKey, - circuits: &[C], - instances: &[&[&[S::Scalar]]], - mut rng: R, -) -> Vec -where - S: CommitmentScheme, - S::ParamsVerifier: 'a, - C: Circuit, - P: Prover<'a, S>, - V: Verifier<'a, S>, - VS: VerificationStrategy<'a, S, V, Output = VS>, - TW: TranscriptWriterBuffer, S::Curve, EC>, - TR: TranscriptReadBuffer<&'static [u8], S::Curve, EC>, - EC: EncodedChallenge, - R: RngCore, -{ - for (circuit, instances) in circuits.iter().zip(instances.iter()) { - MockProver::run::<_, ZK>( - params.k(), - circuit, - instances.iter().map(|instance| instance.to_vec()).collect(), - ) - .unwrap() - .assert_satisfied(); - } - - let proof = { - let mut transcript = TW::init(Vec::new()); - create_proof::( - params, - pk, - circuits, - instances, - &mut rng, - &mut transcript, - ) - .unwrap(); - transcript.finalize() - }; - - let accept = { - let params = params.verifier_params(); - let strategy = VS::new(params); - let mut transcript = TR::init(Box::leak(Box::new(proof.clone()))); - verify_proof::<_, _, _, _, _, ZK>(params, pk.get_vk(), strategy, instances, &mut transcript) - .unwrap() - .finalize() - }; - assert!(accept); - - proof -} - -#[test] -fn test_compile_standard_plonk() { - let circuit = StandardPlonk::rand(ChaCha20Rng::from_seed(Default::default())); - - let params = kzg::read_or_create_srs::(9); - let vk = keygen_vk::, _, false>(¶ms, &circuit).unwrap(); - let pk = keygen_pk::, _, false>(¶ms, vk, &circuit).unwrap(); - - let protocol = compile::( - pk.get_vk(), - Config { - zk: false, - query_instance: false, - num_instance: vec![1], - num_proof: 1, - accumulator_indices: None, - }, - ); - - let [q_a, q_b, q_c, q_ab, constant, sigma_a, sigma_b, sigma_c, instance, a, b, c, z] = - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12].map(|poly| Query::new(poly, Rotation::cur())); - let z_w = Query::new(12, Rotation::next()); - let t = Query::new(13, Rotation::cur()); - - assert_eq!(protocol.preprocessed.len(), 8); - assert_eq!(protocol.num_statement, vec![1]); - assert_eq!(protocol.num_auxiliary, vec![3, 0, 1]); - assert_eq!(protocol.num_challenge, vec![1, 2, 0]); - assert_eq!( - protocol.evaluations, - vec![a, b, c, q_a, q_b, q_c, q_ab, constant, sigma_a, sigma_b, sigma_c, z, z_w] - ); - assert_eq!( - protocol.queries, - vec![a, b, c, z, z_w, q_a, q_b, q_c, q_ab, constant, sigma_a, sigma_b, sigma_c, t] - ); - assert_eq!( - format!("{:?}", protocol.relations), - format!("{:?}", { - let [q_a, q_b, q_c, q_ab, constant, sigma_a, sigma_b, sigma_c, instance, a, b, c, z, z_w, beta, gamma, l_0, identity, one, k_1, k_2] = - &[ - Expression::Polynomial(q_a), - Expression::Polynomial(q_b), - Expression::Polynomial(q_c), - Expression::Polynomial(q_ab), - Expression::Polynomial(constant), - Expression::Polynomial(sigma_a), - Expression::Polynomial(sigma_b), - Expression::Polynomial(sigma_c), - Expression::Polynomial(instance), - Expression::Polynomial(a), - Expression::Polynomial(b), - Expression::Polynomial(c), - Expression::Polynomial(z), - Expression::Polynomial(z_w), - Expression::Challenge(1), // beta - Expression::Challenge(2), // gamma - Expression::CommonPolynomial(CommonPolynomial::Lagrange(0)), // l_0 - Expression::CommonPolynomial(CommonPolynomial::Identity), // identity - Expression::Constant(Fr::one()), // one - Expression::Constant(Fr::DELTA), // k_1 - Expression::Constant(Fr::DELTA * Fr::DELTA), // k_2 - ]; - - vec![ - q_a * a + q_b * b + q_c * c + q_ab * a * b + constant + instance, - l_0 * (one - z), - z_w * ((a + beta * sigma_a + gamma) - * (b + beta * sigma_b + gamma) - * (c + beta * sigma_c + gamma)) - - z * ((a + beta * one * identity + gamma) - * (b + beta * k_1 * identity + gamma) - * (c + beta * k_2 * identity + gamma)), - ] - }) - ); - - assert_matches!( - PlonkAccumulationScheme::estimate_cost(&protocol), - Cost { - num_commitment: 9, - num_evaluation: 13, - num_msm: 20, - .. - } - ); -} diff --git a/src/protocol/halo2/test/circuit/maingate.rs b/src/protocol/halo2/test/circuit/maingate.rs deleted file mode 100644 index b03a3ff4..00000000 --- a/src/protocol/halo2/test/circuit/maingate.rs +++ /dev/null @@ -1,385 +0,0 @@ -use crate::{protocol::halo2::test::circuit::plookup::PlookupConfig, util::Itertools}; -use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{floor_planner::V1, Chip, Layouter, Value}, - plonk::{Any, Circuit, Column, ConstraintSystem, Error, Fixed}, - poly::Rotation, -}; -use halo2_wrong_ecc::{ - maingate::{ - decompose, AssignedValue, MainGate, MainGateConfig, MainGateInstructions, RangeChip, - RangeConfig, RangeInstructions, RegionCtx, Term, - }, - EccConfig, -}; -use rand::RngCore; -use std::{collections::BTreeMap, iter}; - -#[derive(Clone)] -pub struct MainGateWithRangeConfig { - main_gate_config: MainGateConfig, - range_config: RangeConfig, -} - -impl MainGateWithRangeConfig { - pub fn configure( - meta: &mut ConstraintSystem, - composition_bits: Vec, - overflow_bits: Vec, - ) -> Self { - let main_gate_config = MainGate::::configure(meta); - let range_config = - RangeChip::::configure(meta, &main_gate_config, composition_bits, overflow_bits); - MainGateWithRangeConfig { - main_gate_config, - range_config, - } - } - - pub fn ecc_config(&self) -> EccConfig { - EccConfig::new(self.range_config.clone(), self.main_gate_config.clone()) - } - - pub fn load_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - let range_chip = RangeChip::::new(self.range_config.clone()); - range_chip.load_table(layouter)?; - Ok(()) - } -} - -#[derive(Clone, Default)] -pub struct MainGateWithRange(Vec); - -impl MainGateWithRange { - pub fn new(inner: Vec) -> Self { - Self(inner) - } - - pub fn rand(mut rng: R) -> Self { - Self::new(vec![F::from(rng.next_u32() as u64)]) - } - - pub fn instances(&self) -> Vec> { - vec![self.0.clone()] - } -} - -impl Circuit for MainGateWithRange { - type Config = MainGateWithRangeConfig; - type FloorPlanner = V1; - - fn without_witnesses(&self) -> Self { - Self(vec![F::zero()]) - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - MainGateWithRangeConfig::configure(meta, vec![8], vec![4, 7]) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let main_gate = MainGate::new(config.main_gate_config); - let range_chip = RangeChip::new(config.range_config); - range_chip.load_table(&mut layouter)?; - - let a = layouter.assign_region( - || "", - |mut region| { - let mut offset = 0; - let mut ctx = RegionCtx::new(&mut region, &mut offset); - range_chip.decompose(&mut ctx, Value::known(F::from(u64::MAX)), 8, 64)?; - range_chip.decompose(&mut ctx, Value::known(F::from(u32::MAX as u64)), 8, 39)?; - let a = range_chip.assign(&mut ctx, Value::known(self.0[0]), 8, 68)?; - let b = main_gate.sub_sub_with_constant(&mut ctx, &a, &a, &a, F::from(2))?; - let cond = main_gate.assign_bit(&mut ctx, Value::known(F::one()))?; - main_gate.select(&mut ctx, &a, &b, &cond)?; - - Ok(a) - }, - )?; - - main_gate.expose_public(layouter, a, 0)?; - - Ok(()) - } -} - -#[derive(Clone, Debug)] -pub struct PlookupRangeConfig { - main_gate_config: MainGateConfig, - plookup_config: PlookupConfig, - table: [Column; 2], - q_limb: [Column; 2], - q_overflow: [Column; 2], - bits: BTreeMap, -} - -pub struct PlookupRangeChip { - n: usize, - config: PlookupRangeConfig, - main_gate: MainGate, -} - -impl PlookupRangeChip { - pub fn new(config: PlookupRangeConfig, n: usize) -> Self { - let main_gate = MainGate::new(config.main_gate_config.clone()); - Self { - n, - config, - main_gate, - } - } - - pub fn configure( - meta: &mut ConstraintSystem, - main_gate_config: MainGateConfig, - bits: impl IntoIterator, - ) -> PlookupRangeConfig { - let table = [(); 2].map(|_| meta.fixed_column()); - let q_limb = [(); 2].map(|_| meta.fixed_column()); - let q_overflow = [(); 2].map(|_| meta.fixed_column()); - let plookup_config = PlookupConfig::configure( - meta, - |meta| { - let [a, b, c, d, _] = main_gate_config.advices(); - let limbs = [a, b, c, d].map(|column| meta.query_advice(column, Rotation::cur())); - let overflow = meta.query_advice(a, Rotation::cur()); - let q_limb = q_limb.map(|column| meta.query_fixed(column, Rotation::cur())); - let q_overflow = q_overflow.map(|column| meta.query_fixed(column, Rotation::cur())); - iter::empty() - .chain(limbs.into_iter().zip(iter::repeat(q_limb))) - .chain(Some((overflow, q_overflow))) - .map(|(value, [selector, tag])| [tag, selector * value]) - .collect() - }, - table.map(Column::::from), - None, - None, - None, - None, - ); - let bits = bits - .into_iter() - .sorted() - .dedup() - .enumerate() - .map(|(tag, bit)| (bit, tag)) - .collect(); - PlookupRangeConfig { - main_gate_config, - plookup_config, - table, - q_limb, - q_overflow, - bits, - } - } - - pub fn assign_inner(&self, layouter: impl Layouter, n: usize) -> Result<(), Error> { - self.config.plookup_config.assign(layouter, n) - } -} - -impl Chip for PlookupRangeChip { - type Config = PlookupRangeConfig; - - type Loaded = (); - - fn config(&self) -> &Self::Config { - &self.config - } - - fn loaded(&self) -> &Self::Loaded { - &() - } -} - -impl RangeInstructions for PlookupRangeChip { - fn assign( - &self, - ctx: &mut RegionCtx<'_, '_, F>, - value: Value, - limb_bit: usize, - bit: usize, - ) -> Result, Error> { - let (assigned, _) = self.decompose(ctx, value, limb_bit, bit)?; - Ok(assigned) - } - - fn decompose( - &self, - ctx: &mut RegionCtx<'_, '_, F>, - value: Value, - limb_bit: usize, - bit: usize, - ) -> Result<(AssignedValue, Vec>), Error> { - let (num_limbs, overflow) = (bit / limb_bit, bit % limb_bit); - - let num_limbs = num_limbs + if overflow > 0 { 1 } else { 0 }; - let terms = value - .map(|value| decompose(value, num_limbs, limb_bit)) - .transpose_vec(num_limbs) - .into_iter() - .zip((0..num_limbs).map(|i| F::from(2).pow(&[(limb_bit * i) as u64, 0, 0, 0]))) - .map(|(limb, base)| Term::Unassigned(limb, base)) - .collect_vec(); - - self.main_gate - .decompose(ctx, &terms, F::zero(), |ctx, is_last| { - ctx.assign_fixed(|| "", self.config.q_limb[0], F::one())?; - ctx.assign_fixed( - || "", - self.config.q_limb[1], - F::from(*self.config.bits.get(&limb_bit).unwrap() as u64), - )?; - if is_last && overflow != 0 { - ctx.assign_fixed(|| "", self.config.q_overflow[0], F::one())?; - ctx.assign_fixed( - || "", - self.config.q_overflow[1], - F::from(*self.config.bits.get(&limb_bit).unwrap() as u64), - )?; - } - Ok(()) - }) - } - - fn load_table(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "", - |mut region| { - let mut offset = 0; - - for (bit, tag) in self.config.bits.iter() { - let tag = F::from(*tag as u64); - let table_values: Vec = (0..1 << bit).map(|e| F::from(e)).collect(); - for value in table_values.iter() { - region.assign_fixed( - || "table tag", - self.config.table[0], - offset, - || Value::known(tag), - )?; - region.assign_fixed( - || "table value", - self.config.table[1], - offset, - || Value::known(*value), - )?; - offset += 1; - } - } - - for offset in offset..self.n { - region.assign_fixed( - || "table tag", - self.config.table[0], - offset, - || Value::known(F::zero()), - )?; - region.assign_fixed( - || "table value", - self.config.table[1], - offset, - || Value::known(F::zero()), - )?; - } - - Ok(()) - }, - )?; - - Ok(()) - } -} - -#[derive(Clone)] -pub struct MainGateWithPlookupConfig { - main_gate_config: MainGateConfig, - plookup_range_config: PlookupRangeConfig, -} - -impl MainGateWithPlookupConfig { - pub fn configure( - meta: &mut ConstraintSystem, - bits: impl IntoIterator, - ) -> Self { - let main_gate_config = MainGate::configure(meta); - let plookup_range_config = - PlookupRangeChip::configure(meta, main_gate_config.clone(), bits); - - assert_eq!(meta.degree::(), 3); - - MainGateWithPlookupConfig { - main_gate_config, - plookup_range_config, - } - } -} - -#[derive(Clone, Default)] -pub struct MainGateWithPlookup { - n: usize, - inner: Vec, -} - -impl MainGateWithPlookup { - pub fn new(k: u32, inner: Vec) -> Self { - Self { n: 1 << k, inner } - } - - pub fn instances(&self) -> Vec> { - vec![self.inner.clone()] - } -} - -impl Circuit for MainGateWithPlookup { - type Config = MainGateWithPlookupConfig; - type FloorPlanner = V1; - - fn without_witnesses(&self) -> Self { - Self { - n: self.n, - inner: vec![F::zero()], - } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - MainGateWithPlookupConfig::configure(meta, [1, 7, 8]) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - let main_gate = MainGate::::new(config.main_gate_config.clone()); - let range_chip = PlookupRangeChip::new(config.plookup_range_config, self.n); - - range_chip.load_table(&mut layouter)?; - range_chip.assign_inner(layouter.namespace(|| ""), self.n)?; - - let a = layouter.assign_region( - || "", - |mut region| { - let mut offset = 0; - let mut ctx = RegionCtx::new(&mut region, &mut offset); - range_chip.decompose(&mut ctx, Value::known(F::from(u64::MAX)), 8, 64)?; - range_chip.decompose(&mut ctx, Value::known(F::from(u32::MAX as u64)), 8, 39)?; - let a = range_chip.assign(&mut ctx, Value::known(self.inner[0]), 8, 68)?; - let b = main_gate.sub_sub_with_constant(&mut ctx, &a, &a, &a, F::from(2))?; - let cond = main_gate.assign_bit(&mut ctx, Value::known(F::one()))?; - main_gate.select(&mut ctx, &a, &b, &cond)?; - - Ok(a) - }, - )?; - - main_gate.expose_public(layouter, a, 0)?; - - Ok(()) - } -} diff --git a/src/protocol/halo2/test/circuit/plookup.rs b/src/protocol/halo2/test/circuit/plookup.rs deleted file mode 100644 index 4e05e076..00000000 --- a/src/protocol/halo2/test/circuit/plookup.rs +++ /dev/null @@ -1,947 +0,0 @@ -use crate::util::{BatchInvert, EitherOrBoth, Field, Itertools}; -use halo2_proofs::{ - arithmetic::FieldExt, - circuit::{Layouter, Value}, - plonk::{ - Advice, Any, Challenge, Column, ConstraintSystem, Error, Expression, FirstPhase, - SecondPhase, Selector, ThirdPhase, VirtualCells, - }, - poly::Rotation, -}; -use std::{collections::BTreeMap, convert::TryFrom, iter, ops::Mul}; - -fn query( - meta: &mut ConstraintSystem, - query_fn: impl FnOnce(&mut VirtualCells<'_, F>) -> T, -) -> T { - let mut tmp = None; - meta.create_gate("", |meta| { - tmp = Some(query_fn(meta)); - Some(Expression::Constant(F::zero())) - }); - tmp.unwrap() -} - -fn first_fit_packing(cap: usize, weights: Vec) -> Vec> { - let mut bins = Vec::<(usize, Vec)>::new(); - - weights.into_iter().enumerate().for_each(|(idx, weight)| { - for (remaining, indices) in bins.iter_mut() { - if *remaining >= weight { - *remaining -= weight; - indices.push(idx); - return; - } - } - bins.push((cap - weight, vec![idx])); - }); - - bins.into_iter().map(|(_, indices)| indices).collect() -} - -fn max_advice_phase(expression: &Expression) -> u8 { - expression.evaluate( - &|_| 0, - &|_| 0, - &|_| 0, - &|query| query.phase(), - &|_| 0, - &|_| 0, - &|a| a, - &|a, b| a.max(b), - &|a, b| a.max(b), - &|a, _| a, - ) -} - -fn min_challenge_phase(expression: &Expression) -> Option { - expression.evaluate( - &|_| None, - &|_| None, - &|_| None, - &|_| None, - &|_| None, - &|challenge| Some(challenge.phase()), - &|a| a, - &|a, b| match (a, b) { - (Some(a), Some(b)) => Some(a.min(b)), - (Some(phase), None) | (None, Some(phase)) => Some(phase), - (None, None) => None, - }, - &|a, b| match (a, b) { - (Some(a), Some(b)) => Some(a.min(b)), - (Some(phase), None) | (None, Some(phase)) => Some(phase), - (None, None) => None, - }, - &|a, _| a, - ) -} - -fn advice_column_in(meta: &mut ConstraintSystem, phase: u8) -> Column { - match phase { - 0 => meta.advice_column_in(FirstPhase), - 1 => meta.advice_column_in(SecondPhase), - 2 => meta.advice_column_in(ThirdPhase), - _ => unreachable!(), - } -} - -fn challenge_usable_after(meta: &mut ConstraintSystem, phase: u8) -> Challenge { - match phase { - 0 => meta.challenge_usable_after(FirstPhase), - 1 => meta.challenge_usable_after(SecondPhase), - 2 => meta.challenge_usable_after(ThirdPhase), - _ => unreachable!(), - } -} - -#[derive(Clone, Debug)] -pub struct ShuffleConfig { - l_0: Selector, - zs: Vec>, - gamma: Option, - lhs: Vec>, - rhs: Vec>, -} - -impl ShuffleConfig { - pub fn configure( - meta: &mut ConstraintSystem, - lhs: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec>, - rhs: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec>, - l_0: Option, - ) -> Self { - let (lhs, rhs, gamma) = { - let (lhs, rhs) = query(meta, |meta| { - let (lhs, rhs) = (lhs(meta), rhs(meta)); - assert_eq!(lhs.len(), rhs.len()); - (lhs, rhs) - }); - let phase = iter::empty() - .chain(lhs.iter()) - .chain(rhs.iter()) - .map(max_advice_phase) - .max() - .unwrap(); - - let gamma = challenge_usable_after(meta, phase); - - (lhs, rhs, gamma) - }; - let lhs_with_gamma = |meta: &mut VirtualCells<'_, F>| { - let gamma = meta.query_challenge(gamma); - lhs.into_iter().zip(iter::repeat(gamma)).collect() - }; - let rhs_with_gamma = |meta: &mut VirtualCells<'_, F>| { - let gamma = meta.query_challenge(gamma); - rhs.into_iter().zip(iter::repeat(gamma)).collect() - }; - let mut config = Self::configure_with_gamma( - meta, - lhs_with_gamma, - rhs_with_gamma, - |_| None, - |_| None, - l_0, - ); - config.gamma = Some(gamma); - config - } - - pub fn configure_with_gamma( - meta: &mut ConstraintSystem, - lhs_with_gamma: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec<(Expression, Expression)>, - rhs_with_gamma: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec<(Expression, Expression)>, - lhs_coeff: impl FnOnce(&mut VirtualCells<'_, F>) -> Option>, - rhs_coeff: impl FnOnce(&mut VirtualCells<'_, F>) -> Option>, - l_0: Option, - ) -> Self { - if ZK { - todo!() - } - - let (lhs_with_gamma, rhs_with_gamma, lhs_coeff, rhs_coeff) = query(meta, |meta| { - let lhs_with_gamma = lhs_with_gamma(meta); - let rhs_with_gamma = rhs_with_gamma(meta); - let lhs_coeff = lhs_coeff(meta); - let rhs_coeff = rhs_coeff(meta); - assert_eq!(lhs_with_gamma.len(), rhs_with_gamma.len()); - - (lhs_with_gamma, rhs_with_gamma, lhs_coeff, rhs_coeff) - }); - - let gamma_phase = iter::empty() - .chain(lhs_with_gamma.iter()) - .chain(rhs_with_gamma.iter()) - .map(|(value, _)| max_advice_phase(value)) - .max() - .unwrap(); - let z_phase = gamma_phase + 1; - assert!(!lhs_with_gamma - .iter() - .any(|(_, gamma)| gamma.degree() != 0 - || min_challenge_phase(gamma).unwrap() < gamma_phase)); - assert!(!rhs_with_gamma - .iter() - .any(|(_, gamma)| gamma.degree() != 0 - || min_challenge_phase(gamma).unwrap() < gamma_phase)); - - let [lhs_bins, rhs_bins] = [&lhs_with_gamma, &rhs_with_gamma].map(|value_with_gamma| { - first_fit_packing( - meta.degree::() - 1, - value_with_gamma - .iter() - .map(|(value, _)| value.degree()) - .collect(), - ) - }); - let num_z = lhs_bins.len().max(rhs_bins.len()); - - let l_0 = l_0.unwrap_or_else(|| meta.selector()); - let zs = iter::repeat_with(|| advice_column_in(meta, z_phase)) - .take(num_z) - .collect_vec(); - - let collect_contribution = |value_with_gamma: Vec<(Expression, Expression)>, - coeff: Option>, - bins: &[Vec]| { - let mut contribution = bins - .iter() - .map(|bin| { - bin.iter() - .map(|idx| value_with_gamma[*idx].clone()) - .map(|(value, gamma)| value + gamma) - .reduce(|acc, expr| acc * expr) - .unwrap() - }) - .collect_vec(); - - if let Some(coeff) = coeff { - contribution[0] = coeff * contribution[0].clone(); - } - - contribution - }; - let lhs = collect_contribution(lhs_with_gamma, lhs_coeff, &lhs_bins); - let rhs = collect_contribution(rhs_with_gamma, rhs_coeff, &rhs_bins); - - meta.create_gate("Shuffle", |meta| { - let l_0 = meta.query_selector(l_0); - let zs = iter::empty() - .chain(zs.iter().cloned().zip(iter::repeat(Rotation::cur()))) - .chain(Some((zs[0], Rotation::next()))) - .map(|(z, at)| meta.query_advice(z, at)) - .collect_vec(); - - let one = Expression::Constant(F::one()); - let z_0 = zs[0].clone(); - - iter::once(l_0 * (one - z_0)).chain( - lhs.clone() - .into_iter() - .zip_longest(rhs.clone()) - .zip(zs.clone().into_iter().zip(zs.into_iter().skip(1))) - .map(|(pair, (z_i, z_j))| match pair { - EitherOrBoth::Left(lhs) => z_i * lhs - z_j, - EitherOrBoth::Right(rhs) => z_i - z_j * rhs, - EitherOrBoth::Both(lhs, rhs) => z_i * lhs - z_j * rhs, - }), - ) - }); - - ShuffleConfig { - l_0, - zs, - gamma: None, - lhs, - rhs, - } - } - - pub fn assign(&self, mut layouter: impl Layouter, n: usize) -> Result<(), Error> { - if ZK { - todo!() - } - - let lhs = self - .lhs - .iter() - .map(|expression| layouter.evaluate_committed(expression)) - .fold(Value::known(Vec::new()), |acc, evaluated| { - acc.zip(evaluated).map(|(mut acc, evaluated)| { - acc.extend(evaluated); - acc - }) - }); - let rhs = self - .rhs - .iter() - .map(|expression| layouter.evaluate_committed(expression)) - .fold(Value::known(Vec::new()), |acc, evaluated| { - acc.zip(evaluated).map(|(mut acc, evaluated)| { - acc.extend(evaluated); - acc - }) - }); - - let z = lhs - .zip(rhs) - .map(|(lhs, mut rhs)| { - rhs.iter_mut().batch_invert(); - - let products = lhs - .into_iter() - .zip_longest(rhs) - .map(|pair| match pair { - EitherOrBoth::Left(value) | EitherOrBoth::Right(value) => value, - EitherOrBoth::Both(lhs, rhs) => lhs * rhs, - }) - .collect_vec(); - - let mut z = vec![F::one()]; - for i in 0..n { - for j in (i..).step_by(n).take(self.zs.len()) { - z.push(products[j] * z.last().unwrap()); - } - } - - let _last = z.pop().unwrap(); - #[cfg(feature = "sanity-check")] - assert_eq!(_last, F::one()); - - z - }) - .transpose_vec(self.zs.len() * n); - - layouter.assign_region( - || "zs", - |mut region| { - self.l_0.enable(&mut region, 0)?; - - let mut z = z.iter(); - for offset in 0..n { - for column in self.zs.iter() { - region.assign_advice(|| "", *column, offset, || *z.next().unwrap())?; - } - } - - Ok(()) - }, - ) - } -} - -fn binomial_coeffs(n: usize) -> Vec { - debug_assert!(n > 0); - - match n { - 1 => vec![1], - _ => { - let last_row = binomial_coeffs(n - 1); - iter::once(0) - .chain(last_row.iter().cloned()) - .zip(last_row.iter().cloned().chain(iter::once(0))) - .map(|(n, m)| n + m) - .collect() - } - } -} - -fn powers>(one: T, base: T) -> impl Iterator { - iter::successors(Some(one), move |power| Some(base.clone() * power.clone())) -} - -fn ordered_multiset(inputs: &[Vec], table: &[F]) -> Vec { - let mut input_counts = inputs - .iter() - .flatten() - .fold(BTreeMap::new(), |mut map, value| { - map.entry(value) - .and_modify(|count| *count += 1) - .or_insert(1); - map - }); - - let mut ordered = Vec::with_capacity((inputs.len() + 1) * inputs[0].len()); - for (count, value) in table.iter().dedup_with_count() { - let count = input_counts - .remove(value) - .map(|input_count| input_count + count) - .unwrap_or(count); - ordered.extend(iter::repeat(*value).take(count)); - } - - #[cfg(feature = "sanity-check")] - { - assert_eq!(input_counts.len(), 0); - assert_eq!(ordered.len(), ordered.capacity()); - } - - ordered.extend(iter::repeat(*ordered.last().unwrap()).take(ordered.capacity() - ordered.len())); - - ordered -} - -#[allow(dead_code)] -#[derive(Clone, Debug)] -pub struct PlookupConfig { - shuffle: ShuffleConfig, - compressed_inputs: Vec>, - compressed_table: Expression, - mixes: Vec>, - theta: Option, - beta: Challenge, - gamma: Challenge, -} - -impl PlookupConfig { - pub fn configure( - meta: &mut ConstraintSystem, - inputs: impl FnOnce(&mut VirtualCells<'_, F>) -> Vec<[Expression; W]>, - table: [Column; W], - l_0: Option, - theta: Option, - beta: Option, - gamma: Option, - ) -> Self { - if ZK { - todo!() - } - - let inputs = query(meta, inputs); - let t = inputs.len(); - let theta_phase = iter::empty() - .chain(inputs.iter().flatten()) - .map(max_advice_phase) - .chain(table.iter().map(|column| { - Column::::try_from(*column) - .map(|column| column.column_type().phase()) - .unwrap_or_default() - })) - .max() - .unwrap(); - let mixes_phase = theta_phase + 1; - - let theta = if W > 1 { - Some(match theta { - Some(theta) => { - assert!(theta.phase() >= theta_phase); - theta - } - None => challenge_usable_after(meta, theta_phase), - }) - } else { - assert!(theta.is_none()); - None - }; - let mixes = iter::repeat_with(|| advice_column_in(meta, mixes_phase)) - .take(t + 1) - .collect_vec(); - let [beta, gamma] = [beta, gamma].map(|challenge| match challenge { - Some(challenge) => { - assert!(challenge.phase() >= mixes_phase); - challenge - } - None => challenge_usable_after(meta, mixes_phase), - }); - assert_ne!(theta, Some(beta)); - assert_ne!(theta, Some(gamma)); - assert_ne!(beta, gamma); - - let (compressed_inputs, compressed_table, compressed_table_w) = query(meta, |meta| { - let [table, table_w] = [Rotation::cur(), Rotation::next()] - .map(|at| table.map(|column| meta.query_any(column, at))); - let theta = theta.map(|theta| meta.query_challenge(theta)); - - let compressed_inputs = inputs - .iter() - .map(|input| { - input - .iter() - .cloned() - .reduce(|acc, expr| acc * theta.clone().unwrap() + expr) - .unwrap() - }) - .collect_vec(); - let compressed_table = table - .iter() - .cloned() - .reduce(|acc, expr| acc * theta.clone().unwrap() + expr) - .unwrap(); - let compressed_table_w = table_w - .iter() - .cloned() - .reduce(|acc, expr| acc * theta.clone().unwrap() + expr) - .unwrap(); - - (compressed_inputs, compressed_table, compressed_table_w) - }); - let lhs_with_gamma = |meta: &mut VirtualCells<'_, F>| { - let [beta, gamma] = [beta, gamma].map(|challenge| meta.query_challenge(challenge)); - let one = Expression::Constant(F::one()); - let gamma_prime = (one + beta.clone()) * gamma.clone(); - - let values = compressed_inputs.clone().into_iter().chain(Some( - compressed_table.clone() + compressed_table_w.clone() * beta, - )); - let gammas = iter::empty() - .chain(iter::repeat(gamma).take(t)) - .chain(Some(gamma_prime)); - values.zip(gammas).collect() - }; - let rhs_with_gamma = |meta: &mut VirtualCells<'_, F>| { - let mixes = iter::empty() - .chain(mixes.iter().cloned().zip(iter::repeat(Rotation::cur()))) - .chain(Some((mixes[0], Rotation::next()))) - .map(|(column, at)| meta.query_advice(column, at)) - .collect_vec(); - let [beta, gamma] = [beta, gamma].map(|challenge| meta.query_challenge(challenge)); - let one = Expression::Constant(F::one()); - let gamma_prime = (one + beta.clone()) * gamma; - - let values = mixes - .iter() - .cloned() - .zip(mixes.iter().skip(1).cloned()) - .zip(iter::repeat(beta)) - .map(|((mix_i, mix_j), beta)| mix_i + mix_j * beta); - let gammas = iter::repeat(gamma_prime).take(t + 1); - values.zip(gammas).collect() - }; - let lhs_coeff = |meta: &mut VirtualCells<'_, F>| { - let beta = meta.query_challenge(beta); - let one = Expression::Constant(F::one()); - binomial_coeffs(t + 1) - .into_iter() - .zip(powers(one, beta)) - .map(|(coeff, power_of_beta)| Expression::Constant(F::from(coeff)) * power_of_beta) - .reduce(|acc, expr| acc + expr) - }; - let shuffle = ShuffleConfig::configure_with_gamma( - meta, - lhs_with_gamma, - rhs_with_gamma, - lhs_coeff, - |_| None, - l_0, - ); - - Self { - shuffle, - compressed_inputs, - compressed_table, - mixes, - theta, - beta, - gamma, - } - } - - pub fn assign(&self, mut layouter: impl Layouter, n: usize) -> Result<(), Error> { - if ZK { - todo!() - } - - let compressed_inputs = self - .compressed_inputs - .iter() - .map(|expression| layouter.evaluate_committed(expression)) - .fold(Value::known(Vec::new()), |acc, compressed_input| { - acc.zip(compressed_input) - .map(|(mut acc, compressed_input)| { - acc.push(compressed_input); - acc - }) - }); - let compressed_table = layouter.evaluate_committed(&self.compressed_table); - - let mix = compressed_inputs - .zip(compressed_table.as_ref()) - .map(|(compressed_inputs, compressed_table)| { - ordered_multiset(&compressed_inputs, compressed_table) - }) - .transpose_vec(self.mixes.len() * n); - - layouter.assign_region( - || "mixes", - |mut region| { - let mut mix = mix.iter(); - for offset in 0..n { - for column in self.mixes.iter() { - region.assign_advice(|| "", *column, offset, || *mix.next().unwrap())?; - } - } - - Ok(()) - }, - )?; - - self.shuffle.assign(layouter.namespace(|| "Shuffle"), n)?; - - Ok(()) - } -} - -#[cfg(test)] -mod test { - use super::{PlookupConfig, ShuffleConfig}; - use crate::util::Itertools; - use halo2_curves::{bn256::Fr, FieldExt}; - use halo2_proofs::{ - circuit::{floor_planner::V1, Layouter, Value}, - dev::{metadata::Constraint, FailureLocation, MockProver, VerifyFailure}, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed}, - poly::Rotation, - }; - use rand::{rngs::OsRng, RngCore}; - use std::{iter, mem}; - - fn shuffled( - mut values: [Vec; T], - mut rng: R, - ) -> [Vec; T] { - let n = values[0].len(); - let mut swap = |lhs: usize, rhs: usize| { - let tmp = mem::take(&mut values[lhs / n][lhs % n]); - values[lhs / n][lhs % n] = mem::replace(&mut values[rhs / n][rhs % n], tmp); - }; - - for row in (1..n * T).rev() { - let rand_row = (rng.next_u32() as usize) % row; - swap(row, rand_row); - } - - values - } - - #[derive(Clone)] - pub struct Shuffler { - n: usize, - lhs: Value<[Vec; T]>, - rhs: Value<[Vec; T]>, - } - - impl Shuffler { - pub fn rand(k: u32, mut rng: R) -> Self { - let n = 1 << k; - let lhs = [(); T].map(|_| { - let rng = &mut rng; - iter::repeat_with(|| F::random(&mut *rng)) - .take(n) - .collect_vec() - }); - let rhs = shuffled( - lhs.iter() - .map(|lhs| lhs.iter().map(F::square).collect()) - .collect_vec() - .try_into() - .unwrap(), - rng, - ); - Self { - n, - lhs: Value::known(lhs), - rhs: Value::known(rhs), - } - } - } - - impl Circuit for Shuffler { - type Config = ( - [Column; T], - [Column; T], - ShuffleConfig, - ); - type FloorPlanner = V1; - - fn without_witnesses(&self) -> Self { - Self { - n: self.n, - lhs: Value::unknown(), - rhs: Value::unknown(), - } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let lhs = [(); T].map(|_| meta.advice_column()); - let rhs = [(); T].map(|_| meta.advice_column()); - let shuffle = ShuffleConfig::configure( - meta, - |meta| { - lhs.map(|column| { - let lhs = meta.query_advice(column, Rotation::cur()); - lhs.clone() * lhs - }) - .to_vec() - }, - |meta| { - rhs.map(|column| meta.query_advice(column, Rotation::cur())) - .to_vec() - }, - None, - ); - - (lhs, rhs, shuffle) - } - - fn synthesize( - &self, - (lhs, rhs, shuffle): Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - layouter.assign_region( - || "", - |mut region| { - for (idx, column) in lhs.into_iter().enumerate() { - let values = self.lhs.as_ref().map(|lhs| lhs[idx].clone()); - for (offset, value) in - values.clone().transpose_vec(self.n).into_iter().enumerate() - { - region.assign_advice(|| "", column, offset, || value)?; - } - } - for (idx, column) in rhs.into_iter().enumerate() { - let values = self.rhs.as_ref().map(|rhs| rhs[idx].clone()); - for (offset, value) in - values.clone().transpose_vec(self.n).into_iter().enumerate() - { - region.assign_advice(|| "", column, offset, || value)?; - } - } - Ok(()) - }, - )?; - shuffle.assign(layouter.namespace(|| "Shuffle"), self.n)?; - - Ok(()) - } - } - - #[derive(Clone)] - pub struct Plookuper { - n: usize, - inputs: Value<[Vec<[F; W]>; T]>, - table: Vec<[F; W]>, - } - - impl Plookuper { - pub fn rand(k: u32, mut rng: R) -> Self { - let n = 1 << k; - let m = rng.next_u32() as usize % n; - let mut table = iter::repeat_with(|| [(); W].map(|_| F::random(&mut rng))) - .take(m) - .collect_vec(); - table.extend( - iter::repeat( - table - .first() - .cloned() - .unwrap_or_else(|| [(); W].map(|_| F::random(&mut rng))), - ) - .take(n - m), - ); - let inputs = [(); T].map(|_| { - iter::repeat_with(|| table[rng.next_u32() as usize % n]) - .take(n) - .collect() - }); - Self { - n, - inputs: Value::known(inputs), - table, - } - } - } - - impl Circuit - for Plookuper - { - type Config = ( - [[Column; W]; T], - [Column; W], - PlookupConfig, - ); - type FloorPlanner = V1; - - fn without_witnesses(&self) -> Self { - Self { - n: self.n, - inputs: Value::unknown(), - table: self.table.clone(), - } - } - - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - let inputs = [(); T].map(|_| [(); W].map(|_| meta.advice_column())); - let table = [(); W].map(|_| meta.fixed_column()); - let plookup = PlookupConfig::configure( - meta, - |meta| { - inputs - .iter() - .map(|input| input.map(|column| meta.query_advice(column, Rotation::cur()))) - .collect() - }, - table.map(|fixed| fixed.into()), - None, - None, - None, - None, - ); - - (inputs, table, plookup) - } - - fn synthesize( - &self, - (inputs, table, plookup): Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), Error> { - layouter.assign_region( - || "", - |mut region| { - for (offset, value) in self.table.iter().enumerate() { - for (column, value) in table.iter().zip(value.iter()) { - region.assign_fixed(|| "", *column, offset, || Value::known(*value))?; - } - } - Ok(()) - }, - )?; - layouter.assign_region( - || "", - |mut region| { - for (idx, columns) in inputs.iter().enumerate() { - let values = self.inputs.as_ref().map(|inputs| inputs[idx].clone()); - for (offset, value) in values.transpose_vec(self.n).into_iter().enumerate() - { - for (column, value) in columns.iter().zip(value.transpose_array()) { - region.assign_advice(|| "", *column, offset, || value)?; - } - } - } - Ok(()) - }, - )?; - plookup.assign(layouter.namespace(|| "Plookup"), self.n)?; - Ok(()) - } - } - - #[allow(dead_code)] - fn assert_constraint_not_satisfied( - result: Result<(), Vec>, - failures: Vec<(Constraint, FailureLocation)>, - ) { - match result { - Err(expected) => { - assert_eq!( - expected - .into_iter() - .map(|failure| match failure { - VerifyFailure::ConstraintNotSatisfied { - constraint, - location, - .. - } => (constraint, location), - _ => panic!("MockProver::verify has unexpected failure"), - }) - .collect_vec(), - failures - ) - } - Ok(_) => { - panic!("MockProver::verify unexpectedly succeeds") - } - } - } - - #[test] - fn test_shuffle() { - const T: usize = 9; - const ZK: bool = false; - - let k = 9; - let circuit = Shuffler::::rand(k, OsRng); - - let mut cs = ConstraintSystem::default(); - Shuffler::::configure(&mut cs); - assert_eq!(cs.degree::(), 3); - - MockProver::run::<_, ZK>(k, &circuit, Vec::new()) - .unwrap() - .assert_satisfied(); - - #[cfg(not(feature = "sanity-check"))] - { - let n = 1 << k; - let mut circuit = circuit; - circuit.lhs = mem::take(&mut circuit.lhs).map(|mut value| { - value[0][0] += Fr::one(); - value - }); - assert_constraint_not_satisfied( - MockProver::run::<_, ZK>(k, &circuit, Vec::new()) - .unwrap() - .verify(), - vec![( - ( - (2, "Shuffle").into(), - (T * 2).div_ceil(cs.degree::() - 1), - "", - ) - .into(), - FailureLocation::InRegion { - region: (0, "").into(), - offset: n - 1, - }, - )], - ); - } - } - - #[test] - fn test_plookup() { - const W: usize = 2; - const T: usize = 5; - const ZK: bool = false; - - let k = 9; - let circuit = Plookuper::::rand(k, OsRng); - - let mut cs = ConstraintSystem::default(); - Plookuper::::configure(&mut cs); - assert_eq!(cs.degree::(), 3); - - MockProver::run::<_, ZK>(k, &circuit, Vec::new()) - .unwrap() - .assert_satisfied(); - - #[cfg(not(feature = "sanity-check"))] - { - let n = 1 << k; - let mut circuit = circuit; - circuit.inputs = mem::take(&mut circuit.inputs).map(|mut inputs| { - inputs[0][0][0] += Fr::one(); - inputs - }); - assert_constraint_not_satisfied( - MockProver::run::<_, ZK>(k, &circuit, Vec::new()) - .unwrap() - .verify(), - vec![( - ( - (3, "Shuffle").into(), - (T + 1).div_ceil(cs.degree::() - 1), - "", - ) - .into(), - FailureLocation::InRegion { - region: (0, "").into(), - offset: n - 1, - }, - )], - ); - } - } -} diff --git a/src/protocol/halo2/test/kzg.rs b/src/protocol/halo2/test/kzg.rs deleted file mode 100644 index 771e1a70..00000000 --- a/src/protocol/halo2/test/kzg.rs +++ /dev/null @@ -1,232 +0,0 @@ -use crate::{ - protocol::halo2::test::{MainGateWithPlookup, MainGateWithRange}, - util::fe_to_limbs, -}; -use halo2_curves::{pairing::Engine, CurveAffine}; -use halo2_proofs::poly::{ - commitment::{CommitmentScheme, Params, ParamsProver}, - kzg::commitment::{KZGCommitmentScheme, ParamsKZG}, -}; -use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; -use std::{fmt::Debug, fs}; - -mod halo2; -mod native; - -#[cfg(feature = "evm")] -mod evm; - -pub const LIMBS: usize = 4; -pub const BITS: usize = 68; - -pub fn read_or_create_srs(k: u32) -> ParamsKZG { - const DIR: &str = "./src/protocol/halo2/test/kzg/fixture"; - let path = format!("{}/k-{}.srs", DIR, k); - match fs::File::open(path.as_str()) { - Ok(mut file) => ParamsKZG::::read(&mut file).unwrap(), - Err(_) => { - fs::create_dir_all(DIR).unwrap(); - let params = - KZGCommitmentScheme::::new_params(k, ChaCha20Rng::from_seed(Default::default())); - let mut file = fs::File::create(path.as_str()).unwrap(); - params.write(&mut file).unwrap(); - params - } - } -} - -pub fn main_gate_with_range_with_mock_kzg_accumulator( -) -> MainGateWithRange { - let g = read_or_create_srs::(3).get_g(); - let [g1, s_g1] = [g[0], g[1]].map(|point| point.coordinates().unwrap()); - MainGateWithRange::new( - [*s_g1.x(), *s_g1.y(), *g1.x(), *g1.y()] - .iter() - .cloned() - .flat_map(fe_to_limbs::<_, _, LIMBS, BITS>) - .collect(), - ) -} - -pub fn main_gate_with_plookup_with_mock_kzg_accumulator( - k: u32, -) -> MainGateWithPlookup { - let g = read_or_create_srs::(3).get_g(); - let [g1, s_g1] = [g[0], g[1]].map(|point| point.coordinates().unwrap()); - MainGateWithPlookup::new( - k, - [*s_g1.x(), *s_g1.y(), *g1.x(), *g1.y()] - .iter() - .cloned() - .flat_map(fe_to_limbs::<_, _, LIMBS, BITS>) - .collect(), - ) -} - -#[macro_export] -macro_rules! halo2_kzg_config { - ($zk:expr, $num_proof:expr) => { - $crate::protocol::halo2::Config { - zk: $zk, - query_instance: false, - num_instance: Vec::new(), - num_proof: $num_proof, - accumulator_indices: None, - } - }; - ($zk:expr, $num_proof:expr, $accumulator_indices:expr) => { - $crate::protocol::halo2::Config { - zk: $zk, - query_instance: false, - num_instance: Vec::new(), - num_proof: $num_proof, - accumulator_indices: Some($accumulator_indices), - } - }; -} - -#[macro_export] -macro_rules! halo2_kzg_prepare { - ($k:expr, $config:expr, $create_circuit:expr) => {{ - use $crate::{ - protocol::halo2::{compile, test::kzg::read_or_create_srs}, - util::{GroupEncoding, Itertools}, - }; - use halo2_curves::bn256::{Bn256, G1}; - use halo2_proofs::{ - plonk::{keygen_pk, keygen_vk}, - poly::kzg::commitment::KZGCommitmentScheme, - }; - use std::{iter}; - - let circuits = iter::repeat_with(|| $create_circuit) - .take($config.num_proof) - .collect_vec(); - - let params = read_or_create_srs::($k); - let pk = if $config.zk { - let vk = keygen_vk::, _, true>(¶ms, &circuits[0]).unwrap(); - let pk = keygen_pk::, _, true>(¶ms, vk, &circuits[0]).unwrap(); - pk - } else { - let vk = keygen_vk::, _, false>(¶ms, &circuits[0]).unwrap(); - let pk = keygen_pk::, _, false>(¶ms, vk, &circuits[0]).unwrap(); - pk - }; - - let mut config = $config; - config.num_instance = circuits[0].instances().iter().map(|instances| instances.len()).collect(); - let protocol = compile::(pk.get_vk(), config); - assert_eq!( - protocol.preprocessed.len(), - protocol.preprocessed - .iter() - .map(|ec_point| <[u8; 32]>::try_from(ec_point.to_bytes().as_ref().to_vec()).unwrap()) - .unique() - .count() - ); - - (params, pk, protocol, circuits) - }}; -} - -#[macro_export] -macro_rules! halo2_kzg_create_snark { - ($params:expr, $pk:expr, $protocol:expr, $circuits:expr, $prover:ty, $verifier:ty, $verification_strategy:ty, $transcript_read:ty, $transcript_write:ty, $encoded_challenge:ty) => {{ - use halo2_proofs::poly::kzg::commitment::KZGCommitmentScheme; - use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; - use $crate::{ - collect_slice, - protocol::{halo2::test::create_proof_checked, Snark}, - util::Itertools, - }; - - let instances = $circuits - .iter() - .map(|circuit| circuit.instances()) - .collect_vec(); - let proof = { - collect_slice!(instances, 2); - #[allow(clippy::needless_borrow)] - if $protocol.zk { - create_proof_checked::< - KZGCommitmentScheme<_>, - _, - $prover, - $verifier, - $verification_strategy, - $transcript_read, - $transcript_write, - $encoded_challenge, - _, - true, - >( - $params, - $pk, - $circuits, - &instances, - &mut ChaCha20Rng::from_seed(Default::default()), - ) - } else { - create_proof_checked::< - KZGCommitmentScheme<_>, - _, - $prover, - $verifier, - $verification_strategy, - $transcript_read, - $transcript_write, - $encoded_challenge, - _, - false, - >( - $params, - $pk, - $circuits, - &instances, - &mut ChaCha20Rng::from_seed(Default::default()), - ) - } - }; - - Snark::new( - $protocol.clone(), - instances.into_iter().flatten().collect_vec(), - proof, - ) - }}; -} - -#[macro_export] -macro_rules! halo2_kzg_native_accumulate { - ($protocol:expr, $statements:expr, $scheme:ty, $transcript:expr, $stretagy:expr) => {{ - use $crate::{loader::native::NativeLoader, scheme::kzg::AccumulationScheme}; - - <$scheme>::accumulate( - $protocol, - &NativeLoader, - $statements, - $transcript, - $stretagy, - ) - .unwrap(); - }}; -} - -#[macro_export] -macro_rules! halo2_kzg_native_verify { - ($params:ident, $protocol:expr, $statements:expr, $scheme:ty, $transcript:expr) => {{ - use halo2_curves::bn256::Bn256; - use halo2_proofs::poly::commitment::ParamsProver; - use $crate::{ - halo2_kzg_native_accumulate, - protocol::halo2::test::kzg::{BITS, LIMBS}, - scheme::kzg::SameCurveAccumulation, - }; - - let mut stretagy = SameCurveAccumulation::<_, _, LIMBS, BITS>::default(); - halo2_kzg_native_accumulate!($protocol, $statements, $scheme, $transcript, &mut stretagy); - - assert!(stretagy.decide::($params.get_g()[0], $params.g2(), $params.s_g2())); - }}; -} diff --git a/src/protocol/halo2/test/kzg/evm.rs b/src/protocol/halo2/test/kzg/evm.rs deleted file mode 100644 index 6caf0e68..00000000 --- a/src/protocol/halo2/test/kzg/evm.rs +++ /dev/null @@ -1,168 +0,0 @@ -use crate::{ - halo2_kzg_config, halo2_kzg_create_snark, halo2_kzg_evm_verify, halo2_kzg_native_verify, - halo2_kzg_prepare, - loader::evm::EvmTranscript, - protocol::halo2::{ - test::{ - kzg::{ - halo2::Accumulation, main_gate_with_plookup_with_mock_kzg_accumulator, - main_gate_with_range_with_mock_kzg_accumulator, LIMBS, - }, - StandardPlonk, - }, - util::evm::ChallengeEvm, - }, - scheme::kzg::PlonkAccumulationScheme, -}; -use halo2_proofs::poly::kzg::{ - multiopen::{ProverGWC, VerifierGWC}, - strategy::AccumulatorStrategy, -}; -use paste::paste; -use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; - -#[macro_export] -macro_rules! halo2_kzg_evm_verify { - ($params:expr, $protocol:expr, $statements:expr, $proof:expr, $scheme:ty) => {{ - use halo2_curves::bn256::{Fq, Fr}; - use halo2_proofs::poly::commitment::ParamsProver; - use std::{iter, rc::Rc}; - use $crate::{ - loader::evm::{encode_calldata, execute, EvmLoader, EvmTranscript}, - protocol::halo2::test::kzg::{BITS, LIMBS}, - scheme::kzg::{AccumulationScheme, SameCurveAccumulation}, - util::{Itertools, TranscriptRead}, - }; - - let loader = EvmLoader::new::(); - let mut transcript = EvmTranscript::<_, Rc, _, _>::new(loader.clone()); - let statements = $statements - .iter() - .map(|instance| { - iter::repeat_with(|| transcript.read_scalar().unwrap()) - .take(instance.len()) - .collect_vec() - }) - .collect_vec(); - let mut strategy = SameCurveAccumulation::<_, _, LIMBS, BITS>::default(); - <$scheme>::accumulate( - $protocol, - &loader, - statements, - &mut transcript, - &mut strategy, - ) - .unwrap(); - let code = strategy.code($params.get_g()[0], $params.g2(), $params.s_g2()); - let (accept, total_cost, costs) = execute(code, encode_calldata($statements, $proof)); - loader.print_gas_metering(costs); - println!("Total: {}", total_cost); - assert!(accept); - }}; -} - -macro_rules! test { - (@ #[$($attr:meta),*], $name:ident, $k:expr, $config:expr, $create_circuit:expr) => { - paste! { - $(#[$attr])* - fn []() { - let (params, pk, protocol, circuits) = halo2_kzg_prepare!( - $k, - $config, - $create_circuit - ); - let snark = halo2_kzg_create_snark!( - ¶ms, - &pk, - &protocol, - &circuits, - ProverGWC<_>, - VerifierGWC<_>, - AccumulatorStrategy<_>, - EvmTranscript<_, _, _, _>, - EvmTranscript<_, _, _, _>, - ChallengeEvm<_> - ); - halo2_kzg_native_verify!( - params, - &snark.protocol, - snark.statements.clone(), - PlonkAccumulationScheme, - &mut EvmTranscript::<_, NativeLoader, _, _>::new(snark.proof.as_slice()) - ); - halo2_kzg_evm_verify!( - params, - &snark.protocol, - snark.statements, - snark.proof, - PlonkAccumulationScheme - ); - } - } - }; - ($name:ident, $k:expr, $config:expr, $create_circuit:expr) => { - test!(@ #[test], $name, $k, $config, $create_circuit); - }; - (#[ignore = $reason:literal], $name:ident, $k:expr, $config:expr, $create_circuit:expr) => { - test!(@ #[test, ignore = $reason], $name, $k, $config, $create_circuit); - }; -} - -test!( - zk_standard_plonk_rand, - 9, - halo2_kzg_config!(true, 1), - StandardPlonk::<_>::rand(ChaCha20Rng::from_seed(Default::default())) -); -test!( - zk_main_gate_with_range_with_mock_kzg_accumulator, - 9, - halo2_kzg_config!(true, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), - main_gate_with_range_with_mock_kzg_accumulator::() -); -test!( - #[ignore = "cause it requires 16GB memory to run"], - zk_accumulation_two_snark, - 21, - halo2_kzg_config!(true, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), - Accumulation::two_snark(true) -); -test!( - #[ignore = "cause it requires 32GB memory to run"], - zk_accumulation_two_snark_with_accumulator, - 22, - halo2_kzg_config!(true, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), - Accumulation::two_snark_with_accumulator(true) -); -test!( - standard_plonk_rand, - 9, - halo2_kzg_config!(false, 1), - StandardPlonk::<_>::rand(ChaCha20Rng::from_seed(Default::default())) -); -test!( - main_gate_with_range_with_mock_kzg_accumulator, - 9, - halo2_kzg_config!(false, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), - main_gate_with_range_with_mock_kzg_accumulator::() -); -test!( - main_gate_with_plookup_with_mock_kzg_accumulator, - 9, - halo2_kzg_config!(false, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), - main_gate_with_plookup_with_mock_kzg_accumulator::(9) -); -test!( - #[ignore = "cause it requires 16GB memory to run"], - accumulation_two_snark, - 21, - halo2_kzg_config!(false, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), - Accumulation::two_snark(false) -); -test!( - #[ignore = "cause it requires 32GB memory to run"], - accumulation_two_snark_with_accumulator, - 22, - halo2_kzg_config!(false, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), - Accumulation::two_snark_with_accumulator(false) -); diff --git a/src/protocol/halo2/test/kzg/halo2.rs b/src/protocol/halo2/test/kzg/halo2.rs deleted file mode 100644 index cd8e884b..00000000 --- a/src/protocol/halo2/test/kzg/halo2.rs +++ /dev/null @@ -1,380 +0,0 @@ -use crate::{ - collect_slice, halo2_kzg_config, halo2_kzg_create_snark, halo2_kzg_native_accumulate, - halo2_kzg_native_verify, halo2_kzg_prepare, - loader::{halo2, native::NativeLoader}, - protocol::{ - halo2::{ - test::{ - kzg::{BITS, LIMBS}, - MainGateWithRange, MainGateWithRangeConfig, StandardPlonk, - }, - util::halo2::ChallengeScalar, - }, - Protocol, Snark, - }, - scheme::kzg::{self, AccumulationScheme, ShplonkAccumulationScheme}, - util::{fe_to_limbs, Curve, Group, Itertools, PrimeCurveAffine}, -}; -use halo2_curves::bn256::{Fr, G1Affine, G1}; -use halo2_proofs::{ - circuit::{floor_planner::V1, Layouter, Value}, - plonk, - plonk::Circuit, - poly::{ - commitment::ParamsProver, - kzg::{ - multiopen::{ProverSHPLONK, VerifierSHPLONK}, - strategy::AccumulatorStrategy, - }, - }, - transcript::{Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer}, -}; -use halo2_wrong_ecc::{self, maingate::RegionCtx}; -use halo2_wrong_transcript::NativeRepresentation; -use paste::paste; -use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; -use std::rc::Rc; - -const T: usize = 5; -const RATE: usize = 4; -const R_F: usize = 8; -const R_P: usize = 57; - -type BaseFieldEccChip = halo2_wrong_ecc::BaseFieldEccChip; -type Halo2Loader<'a, 'b, C> = halo2::Halo2Loader<'a, 'b, C, LIMBS, BITS>; -type PoseidonTranscript = - halo2::PoseidonTranscript; -type SameCurveAccumulation = kzg::SameCurveAccumulation; - -pub struct SnarkWitness { - protocol: Protocol, - statements: Vec::Scalar>>>, - proof: Value>, -} - -impl From> for SnarkWitness { - fn from(snark: Snark) -> Self { - Self { - protocol: snark.protocol, - statements: snark - .statements - .into_iter() - .map(|statements| statements.into_iter().map(Value::known).collect_vec()) - .collect(), - proof: Value::known(snark.proof), - } - } -} - -impl SnarkWitness { - pub fn without_witnesses(&self) -> Self { - SnarkWitness { - protocol: self.protocol.clone(), - statements: self - .statements - .iter() - .map(|statements| vec![Value::unknown(); statements.len()]) - .collect(), - proof: Value::unknown(), - } - } -} - -pub fn accumulate<'a, 'b>( - loader: &Rc>, - stretagy: &mut SameCurveAccumulation>>, - snark: &SnarkWitness, -) -> Result<(), plonk::Error> { - let mut transcript = PoseidonTranscript::<_, Rc>, _, _>::new( - loader, - snark.proof.as_ref().map(|proof| proof.as_slice()), - ); - let statements = snark - .statements - .iter() - .map(|statements| { - statements - .iter() - .map(|statement| loader.assign_scalar(*statement)) - .collect_vec() - }) - .collect_vec(); - ShplonkAccumulationScheme::accumulate( - &snark.protocol, - loader, - statements, - &mut transcript, - stretagy, - ) - .map_err(|_| plonk::Error::Synthesis)?; - Ok(()) -} - -pub struct Accumulation { - g1: G1Affine, - snarks: Vec>, - instances: Vec, -} - -impl Accumulation { - pub fn accumulator_indices() -> Vec<(usize, usize)> { - (0..4 * LIMBS).map(|idx| (0, idx)).collect() - } - - pub fn two_snark(zk: bool) -> Self { - const K: u32 = 9; - - let (params, snark1) = { - let (params, pk, protocol, circuits) = halo2_kzg_prepare!( - K, - halo2_kzg_config!(zk, 1), - StandardPlonk::<_>::rand(ChaCha20Rng::from_seed(Default::default())) - ); - let snark = halo2_kzg_create_snark!( - ¶ms, - &pk, - &protocol, - &circuits, - ProverSHPLONK<_>, - VerifierSHPLONK<_>, - AccumulatorStrategy<_>, - PoseidonTranscript<_, _, _, _>, - PoseidonTranscript<_, _, _, _>, - ChallengeScalar<_> - ); - (params, snark) - }; - let snark2 = { - let (params, pk, protocol, circuits) = halo2_kzg_prepare!( - K, - halo2_kzg_config!(zk, 1), - MainGateWithRange::<_>::rand(ChaCha20Rng::from_seed(Default::default())) - ); - halo2_kzg_create_snark!( - ¶ms, - &pk, - &protocol, - &circuits, - ProverSHPLONK<_>, - VerifierSHPLONK<_>, - AccumulatorStrategy<_>, - PoseidonTranscript<_, _, _, _>, - PoseidonTranscript<_, _, _, _>, - ChallengeScalar<_> - ) - }; - - let mut strategy = SameCurveAccumulation::::default(); - halo2_kzg_native_accumulate!( - &snark1.protocol, - snark1.statements.clone(), - ShplonkAccumulationScheme, - &mut PoseidonTranscript::::init(snark1.proof.as_slice()), - &mut strategy - ); - halo2_kzg_native_accumulate!( - &snark2.protocol, - snark2.statements.clone(), - ShplonkAccumulationScheme, - &mut PoseidonTranscript::::init(snark2.proof.as_slice()), - &mut strategy - ); - - let g1 = params.get_g()[0]; - let accumulator = strategy.finalize(g1.to_curve()); - let instances = [ - accumulator.0.to_affine().x, - accumulator.0.to_affine().y, - accumulator.1.to_affine().x, - accumulator.1.to_affine().y, - ] - .map(fe_to_limbs::<_, _, LIMBS, BITS>) - .concat(); - - Self { - g1, - snarks: vec![snark1.into(), snark2.into()], - instances, - } - } - - pub fn two_snark_with_accumulator(zk: bool) -> Self { - const K: u32 = 21; - - let (params, pk, protocol, circuits) = halo2_kzg_prepare!( - K, - halo2_kzg_config!(zk, 2, Self::accumulator_indices()), - Self::two_snark(zk) - ); - let snark = halo2_kzg_create_snark!( - ¶ms, - &pk, - &protocol, - &circuits, - ProverSHPLONK<_>, - VerifierSHPLONK<_>, - AccumulatorStrategy<_>, - PoseidonTranscript<_, _, _, _>, - PoseidonTranscript<_, _, _, _>, - ChallengeScalar<_> - ); - - let mut strategy = SameCurveAccumulation::::default(); - halo2_kzg_native_accumulate!( - &snark.protocol, - snark.statements.clone(), - ShplonkAccumulationScheme, - &mut PoseidonTranscript::::init(snark.proof.as_slice()), - &mut strategy - ); - - let g1 = params.get_g()[0]; - let accumulator = strategy.finalize(g1.to_curve()); - let instances = [ - accumulator.0.to_affine().x, - accumulator.0.to_affine().y, - accumulator.1.to_affine().x, - accumulator.1.to_affine().y, - ] - .map(fe_to_limbs::<_, _, LIMBS, BITS>) - .concat(); - - Self { - g1, - snarks: vec![snark.into()], - instances, - } - } - - pub fn instances(&self) -> Vec> { - vec![self.instances.clone()] - } -} - -impl Circuit for Accumulation { - type Config = MainGateWithRangeConfig; - type FloorPlanner = V1; - - fn without_witnesses(&self) -> Self { - Self { - g1: self.g1, - snarks: self - .snarks - .iter() - .map(SnarkWitness::without_witnesses) - .collect(), - instances: Vec::new(), - } - } - - fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - MainGateWithRangeConfig::configure::( - meta, - vec![BITS / LIMBS], - BaseFieldEccChip::::rns().overflow_lengths(), - ) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), plonk::Error> { - config.load_table(&mut layouter)?; - - let (lhs, rhs) = layouter.assign_region( - || "", - |mut region| { - let mut offset = 0; - let ctx = RegionCtx::new(&mut region, &mut offset); - - let loader = Halo2Loader::::new(config.ecc_config(), ctx); - let mut stretagy = SameCurveAccumulation::default(); - for snark in self.snarks.iter() { - accumulate(&loader, &mut stretagy, snark)?; - } - let (lhs, rhs) = stretagy.finalize(self.g1); - - loader.print_row_metering(); - println!("Total: {}", offset); - - Ok((lhs, rhs)) - }, - )?; - - let ecc_chip = BaseFieldEccChip::::new(config.ecc_config()); - ecc_chip.expose_public(layouter.namespace(|| ""), lhs, 0)?; - ecc_chip.expose_public(layouter.namespace(|| ""), rhs, 2 * LIMBS)?; - - Ok(()) - } -} - -macro_rules! test { - (@ #[$($attr:meta),*], $name:ident, $k:expr, $config:expr, $create_circuit:expr) => { - paste! { - $(#[$attr])* - fn []() { - let (params, pk, protocol, circuits) = halo2_kzg_prepare!( - $k, - $config, - $create_circuit - ); - let snark = halo2_kzg_create_snark!( - ¶ms, - &pk, - &protocol, - &circuits, - ProverSHPLONK<_>, - VerifierSHPLONK<_>, - AccumulatorStrategy<_>, - Blake2bWrite<_, _, _>, - Blake2bRead<_, _, _>, - Challenge255<_> - ); - halo2_kzg_native_verify!( - params, - &snark.protocol, - snark.statements, - ShplonkAccumulationScheme, - &mut Blake2bRead::<_, G1Affine, _>::init(snark.proof.as_slice()) - ); - } - } - }; - ($name:ident, $k:expr, $config:expr, $create_circuit:expr) => { - test!(@ #[test], $name, $k, $config, $create_circuit); - }; - (#[ignore = $reason:literal], $name:ident, $k:expr, $config:expr, $create_circuit:expr) => { - test!(@ #[test, ignore = $reason], $name, $k, $config, $create_circuit); - }; -} - -test!( - #[ignore = "cause it requires 16GB memory to run"], - zk_accumulation_two_snark, - 21, - halo2_kzg_config!(true, 1, Accumulation::accumulator_indices()), - Accumulation::two_snark(true) -); -test!( - #[ignore = "cause it requires 32GB memory to run"], - zk_accumulation_two_snark_with_accumulator, - 22, - halo2_kzg_config!(true, 1, Accumulation::accumulator_indices()), - Accumulation::two_snark_with_accumulator(true) -); -test!( - #[ignore = "cause it requires 16GB memory to run"], - accumulation_two_snark, - 21, - halo2_kzg_config!(false, 1, Accumulation::accumulator_indices()), - Accumulation::two_snark(false) -); -test!( - #[ignore = "cause it requires 32GB memory to run"], - accumulation_two_snark_with_accumulator, - 22, - halo2_kzg_config!(false, 1, Accumulation::accumulator_indices()), - Accumulation::two_snark_with_accumulator(false) -); diff --git a/src/protocol/halo2/util.rs b/src/protocol/halo2/util.rs deleted file mode 100644 index 437d59cb..00000000 --- a/src/protocol/halo2/util.rs +++ /dev/null @@ -1,81 +0,0 @@ -use crate::{ - loader::native::NativeLoader, - util::{ - Curve, Itertools, PrimeCurveAffine, PrimeField, Transcript, TranscriptRead, - UncompressedEncoding, - }, - Error, -}; -use halo2_proofs::{ - arithmetic::{CurveAffine, CurveExt}, - transcript::{Blake2bRead, Challenge255}, -}; -use std::{io::Read, iter}; - -pub mod halo2; - -#[cfg(feature = "evm")] -pub mod evm; - -impl UncompressedEncoding for C -where - ::Base: PrimeField, -{ - type Uncompressed = [u8; 64]; - - fn to_uncompressed(&self) -> [u8; 64] { - let coordinates = self.to_affine().coordinates().unwrap(); - iter::empty() - .chain(coordinates.x().to_repr().as_ref()) - .chain(coordinates.y().to_repr().as_ref()) - .cloned() - .collect_vec() - .try_into() - .unwrap() - } - - fn from_uncompressed(uncompressed: [u8; 64]) -> Option { - let x = Option::from(::Base::from_repr( - uncompressed[..32].to_vec().try_into().unwrap(), - ))?; - let y = Option::from(::Base::from_repr( - uncompressed[32..].to_vec().try_into().unwrap(), - ))?; - C::AffineExt::from_xy(x, y) - .map(|ec_point| ec_point.to_curve()) - .into() - } -} - -impl Transcript - for Blake2bRead> -{ - fn squeeze_challenge(&mut self) -> C::Scalar { - *halo2_proofs::transcript::Transcript::squeeze_challenge_scalar::(self) - } - - fn common_ec_point(&mut self, ec_point: &C::CurveExt) -> Result<(), Error> { - halo2_proofs::transcript::Transcript::common_point(self, ec_point.to_affine()) - .map_err(|err| Error::Transcript(err.kind(), err.to_string())) - } - - fn common_scalar(&mut self, scalar: &C::Scalar) -> Result<(), Error> { - halo2_proofs::transcript::Transcript::common_scalar(self, *scalar) - .map_err(|err| Error::Transcript(err.kind(), err.to_string())) - } -} - -impl TranscriptRead - for Blake2bRead> -{ - fn read_scalar(&mut self) -> Result { - halo2_proofs::transcript::TranscriptRead::read_scalar(self) - .map_err(|err| Error::Transcript(err.kind(), err.to_string())) - } - - fn read_ec_point(&mut self) -> Result { - halo2_proofs::transcript::TranscriptRead::read_point(self) - .map(|ec_point| ec_point.to_curve()) - .map_err(|err| Error::Transcript(err.kind(), err.to_string())) - } -} diff --git a/src/protocol/halo2/util/evm.rs b/src/protocol/halo2/util/evm.rs deleted file mode 100644 index c8da8fe9..00000000 --- a/src/protocol/halo2/util/evm.rs +++ /dev/null @@ -1,142 +0,0 @@ -use crate::{ - loader::{ - evm::{u256_to_field, EvmTranscript}, - native::NativeLoader, - }, - util::{self, Curve, PrimeField, UncompressedEncoding}, - Error, -}; -use ethereum_types::U256; -use halo2_curves::{Coordinates, CurveAffine}; -use halo2_proofs::transcript::{ - EncodedChallenge, Transcript, TranscriptRead, TranscriptReadBuffer, TranscriptWrite, - TranscriptWriterBuffer, -}; -use std::io::{self, Read, Write}; - -pub struct ChallengeEvm(C::Scalar) -where - C::CurveExt: Curve + UncompressedEncoding, - C::Scalar: PrimeField; - -impl EncodedChallenge for ChallengeEvm -where - C::CurveExt: Curve + UncompressedEncoding, - C::Scalar: PrimeField, -{ - type Input = [u8; 32]; - - fn new(challenge_input: &[u8; 32]) -> Self { - ChallengeEvm(u256_to_field(U256::from_big_endian(challenge_input))) - } - - fn get_scalar(&self) -> C::Scalar { - self.0 - } -} - -impl Transcript> - for EvmTranscript> -where - C::CurveExt: Curve + UncompressedEncoding, - C::Scalar: PrimeField, -{ - fn squeeze_challenge(&mut self) -> ChallengeEvm { - ChallengeEvm(util::Transcript::squeeze_challenge(self)) - } - - fn common_point(&mut self, ec_point: C) -> io::Result<()> { - match util::Transcript::common_ec_point(self, &ec_point.to_curve()) { - Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), - Err(_) => unreachable!(), - _ => Ok(()), - } - } - - fn common_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { - match util::Transcript::common_scalar(self, &scalar) { - Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), - Err(_) => unreachable!(), - _ => Ok(()), - } - } -} - -impl TranscriptRead> - for EvmTranscript> -where - C::CurveExt: Curve + UncompressedEncoding, - C::Scalar: PrimeField, -{ - fn read_point(&mut self) -> io::Result { - match util::TranscriptRead::read_ec_point(self) { - Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), - Err(_) => unreachable!(), - Ok(value) => Ok(value.to_affine()), - } - } - - fn read_scalar(&mut self) -> io::Result { - match util::TranscriptRead::read_scalar(self) { - Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), - Err(_) => unreachable!(), - Ok(value) => Ok(value), - } - } -} - -impl TranscriptReadBuffer> - for EvmTranscript> -where - C::CurveExt: Curve + UncompressedEncoding, - C::Scalar: PrimeField, -{ - fn init(reader: R) -> Self { - Self::new(reader) - } -} - -impl TranscriptWrite> - for EvmTranscript> -where - C::CurveExt: Curve + UncompressedEncoding, - C::Scalar: PrimeField, -{ - fn write_point(&mut self, ec_point: C) -> io::Result<()> { - Transcript::>::common_point(self, ec_point)?; - let coords: Coordinates = Option::from(ec_point.coordinates()).ok_or_else(|| { - io::Error::new( - io::ErrorKind::Other, - "Cannot write points at infinity to the transcript", - ) - })?; - let mut x = coords.x().to_repr(); - let mut y = coords.y().to_repr(); - x.as_mut().reverse(); - y.as_mut().reverse(); - self.stream_mut().write_all(x.as_ref())?; - self.stream_mut().write_all(y.as_ref()) - } - - fn write_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { - Transcript::>::common_scalar(self, scalar)?; - let mut data = scalar.to_repr(); - data.as_mut().reverse(); - self.stream_mut().write_all(data.as_ref()) - } -} - -impl TranscriptWriterBuffer> - for EvmTranscript> -where - C::CurveExt: Curve + UncompressedEncoding, - C::Scalar: PrimeField, -{ - fn init(writer: W) -> Self { - Self::new(writer) - } - - fn finalize(self) -> W { - self.finalize() - } -} diff --git a/src/protocol/halo2/util/halo2.rs b/src/protocol/halo2/util/halo2.rs deleted file mode 100644 index dfda15a8..00000000 --- a/src/protocol/halo2/util/halo2.rs +++ /dev/null @@ -1,212 +0,0 @@ -use crate::{ - loader::{halo2::PoseidonTranscript, native::NativeLoader}, - util::{self, Curve, PrimeField}, - Error, -}; -use halo2_curves::CurveAffine; -use halo2_proofs::transcript::{ - EncodedChallenge, Transcript, TranscriptRead, TranscriptReadBuffer, TranscriptWrite, - TranscriptWriterBuffer, -}; -use halo2_wrong_transcript::NativeRepresentation; -use poseidon::Poseidon; -use std::io::{self, Read, Write}; - -pub struct ChallengeScalar(C::Scalar); - -impl EncodedChallenge for ChallengeScalar { - type Input = C::Scalar; - - fn new(challenge_input: &C::Scalar) -> Self { - ChallengeScalar(*challenge_input) - } - - fn get_scalar(&self) -> C::Scalar { - self.0 - } -} - -impl< - C: CurveAffine, - S, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > Transcript> - for PoseidonTranscript< - C, - NativeLoader, - S, - Poseidon, - NativeRepresentation, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - fn squeeze_challenge(&mut self) -> ChallengeScalar { - ChallengeScalar::new(&util::Transcript::squeeze_challenge(self)) - } - - fn common_point(&mut self, ec_point: C) -> io::Result<()> { - match util::Transcript::common_ec_point(self, &ec_point.to_curve()) { - Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), - Err(_) => unreachable!(), - _ => Ok(()), - } - } - - fn common_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { - match util::Transcript::common_scalar(self, &scalar) { - Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), - Err(_) => unreachable!(), - _ => Ok(()), - } - } -} - -impl< - C: CurveAffine, - R: Read, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > TranscriptRead> - for PoseidonTranscript< - C, - NativeLoader, - R, - Poseidon, - NativeRepresentation, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - fn read_point(&mut self) -> io::Result { - match util::TranscriptRead::read_ec_point(self) { - Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), - Err(_) => unreachable!(), - Ok(value) => Ok(value.to_affine()), - } - } - - fn read_scalar(&mut self) -> io::Result { - match util::TranscriptRead::read_scalar(self) { - Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), - Err(_) => unreachable!(), - Ok(value) => Ok(value), - } - } -} - -impl< - C: CurveAffine, - R: Read, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > TranscriptReadBuffer> - for PoseidonTranscript< - C, - NativeLoader, - R, - Poseidon, - NativeRepresentation, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - fn init(reader: R) -> Self { - Self::new(reader) - } -} - -impl< - C: CurveAffine, - W: Write, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > TranscriptWrite> - for PoseidonTranscript< - C, - NativeLoader, - W, - Poseidon, - NativeRepresentation, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - fn write_point(&mut self, ec_point: C) -> io::Result<()> { - Transcript::>::common_point(self, ec_point)?; - let data = ec_point.to_bytes(); - self.stream_mut().write_all(data.as_ref()) - } - - fn write_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { - Transcript::>::common_scalar(self, scalar)?; - let data = scalar.to_repr(); - self.stream_mut().write_all(data.as_ref()) - } -} - -impl< - C: CurveAffine, - W: Write, - const LIMBS: usize, - const BITS: usize, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > TranscriptWriterBuffer> - for PoseidonTranscript< - C, - NativeLoader, - W, - Poseidon, - NativeRepresentation, - LIMBS, - BITS, - T, - RATE, - R_F, - R_P, - > -{ - fn init(writer: W) -> Self { - Self::new(writer) - } - - fn finalize(self) -> W { - self.finalize() - } -} diff --git a/src/scheme.rs b/src/scheme.rs deleted file mode 100644 index d883d742..00000000 --- a/src/scheme.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod kzg; diff --git a/src/scheme/kzg.rs b/src/scheme/kzg.rs deleted file mode 100644 index e1f949ab..00000000 --- a/src/scheme/kzg.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::{ - protocol::Protocol, - util::{Curve, Expression}, -}; - -mod accumulation; -mod cost; -mod msm; - -pub use accumulation::{ - plonk::PlonkAccumulationScheme, shplonk::ShplonkAccumulationScheme, AccumulationScheme, - AccumulationStrategy, Accumulator, SameCurveAccumulation, -}; -pub use cost::{Cost, CostEstimation}; -pub use msm::MSM; - -pub fn langranges( - protocol: &Protocol, - statements: &[Vec], -) -> impl IntoIterator { - protocol - .relations - .iter() - .cloned() - .sum::>() - .used_langrange() - .into_iter() - .chain( - 0..statements - .iter() - .map(|statement| statement.len()) - .max() - .unwrap_or_default() as i32, - ) -} diff --git a/src/scheme/kzg/accumulation.rs b/src/scheme/kzg/accumulation.rs deleted file mode 100644 index 6931639d..00000000 --- a/src/scheme/kzg/accumulation.rs +++ /dev/null @@ -1,171 +0,0 @@ -use crate::{ - loader::Loader, - protocol::Protocol, - scheme::kzg::msm::MSM, - util::{Curve, Transcript}, - Error, -}; -use std::ops::{Add, AddAssign, Mul, MulAssign}; - -pub mod plonk; -pub mod shplonk; - -pub trait AccumulationScheme -where - C: Curve, - L: Loader, - T: Transcript, - S: AccumulationStrategy, -{ - type Proof; - - fn accumulate( - protocol: &Protocol, - loader: &L, - statements: Vec>, - transcript: &mut T, - strategy: &mut S, - ) -> Result; -} - -pub trait AccumulationStrategy -where - C: Curve, - L: Loader, - T: Transcript, -{ - type Output; - - fn extract_accumulator( - &self, - _: &Protocol, - _: &L, - _: &mut T, - _: &[Vec], - ) -> Option> { - None - } - - fn process( - &mut self, - loader: &L, - transcript: &mut T, - proof: P, - accumulator: Accumulator, - ) -> Result; -} - -#[derive(Clone, Debug)] -pub struct Accumulator -where - C: Curve, - L: Loader, -{ - lhs: MSM, - rhs: MSM, -} - -impl Accumulator -where - C: Curve, - L: Loader, -{ - pub fn new(lhs: MSM, rhs: MSM) -> Self { - Self { lhs, rhs } - } - - pub fn scale(&mut self, scalar: &L::LoadedScalar) { - self.lhs *= scalar; - self.rhs *= scalar; - } - - pub fn extend(&mut self, other: Self) { - self.lhs += other.lhs; - self.rhs += other.rhs; - } - - pub fn evaluate(self, g1: C) -> (L::LoadedEcPoint, L::LoadedEcPoint) { - (self.lhs.evaluate(g1), self.rhs.evaluate(g1)) - } - - pub fn random_linear_combine( - scaled_accumulators: impl IntoIterator, - ) -> Self { - scaled_accumulators - .into_iter() - .map(|(scalar, accumulator)| accumulator * &scalar) - .reduce(|acc, scaled_accumulator| acc + scaled_accumulator) - .unwrap_or_default() - } -} - -impl Default for Accumulator -where - C: Curve, - L: Loader, -{ - fn default() -> Self { - Self { - lhs: MSM::default(), - rhs: MSM::default(), - } - } -} - -impl Add for Accumulator -where - C: Curve, - L: Loader, -{ - type Output = Self; - - fn add(mut self, rhs: Self) -> Self::Output { - self.extend(rhs); - self - } -} - -impl AddAssign for Accumulator -where - C: Curve, - L: Loader, -{ - fn add_assign(&mut self, rhs: Self) { - self.extend(rhs); - } -} - -impl Mul<&L::LoadedScalar> for Accumulator -where - C: Curve, - L: Loader, -{ - type Output = Self; - - fn mul(mut self, rhs: &L::LoadedScalar) -> Self::Output { - self.scale(rhs); - self - } -} - -impl MulAssign<&L::LoadedScalar> for Accumulator -where - C: Curve, - L: Loader, -{ - fn mul_assign(&mut self, rhs: &L::LoadedScalar) { - self.scale(rhs); - } -} - -pub struct SameCurveAccumulation, const LIMBS: usize, const BITS: usize> { - pub accumulator: Option>, -} - -impl, const LIMBS: usize, const BITS: usize> Default - for SameCurveAccumulation -{ - fn default() -> Self { - Self { accumulator: None } - } -} diff --git a/src/scheme/kzg/accumulation/plonk.rs b/src/scheme/kzg/accumulation/plonk.rs deleted file mode 100644 index 10c91eed..00000000 --- a/src/scheme/kzg/accumulation/plonk.rs +++ /dev/null @@ -1,373 +0,0 @@ -use crate::{ - loader::{LoadedScalar, Loader}, - protocol::Protocol, - scheme::kzg::{ - accumulation::{AccumulationScheme, AccumulationStrategy, Accumulator}, - cost::{Cost, CostEstimation}, - langranges, - msm::MSM, - }, - util::{ - CommonPolynomial, CommonPolynomialEvaluation, Curve, Expression, Field, Itertools, Query, - Rotation, TranscriptRead, - }, - Error, -}; -use std::{collections::HashMap, iter}; - -#[derive(Default)] -pub struct PlonkAccumulationScheme; - -impl AccumulationScheme for PlonkAccumulationScheme -where - C: Curve, - L: Loader, - T: TranscriptRead, - S: AccumulationStrategy>, -{ - type Proof = PlonkProof; - - fn accumulate( - protocol: &Protocol, - loader: &L, - statements: Vec>, - transcript: &mut T, - strategy: &mut S, - ) -> Result { - transcript.common_scalar(&loader.load_const(&protocol.transcript_initial_state))?; - - let proof = PlonkProof::read(protocol, statements, transcript)?; - let old_accumulator = - strategy.extract_accumulator(protocol, loader, transcript, &proof.statements); - - let common_poly_eval = { - let mut common_poly_eval = CommonPolynomialEvaluation::new( - &protocol.domain, - loader, - langranges(protocol, &proof.statements), - &proof.z, - ); - - L::LoadedScalar::batch_invert(common_poly_eval.denoms()); - - common_poly_eval - }; - - let commitments = proof.commitments(protocol, loader, &common_poly_eval); - let evaluations = proof.evaluations(protocol, loader, &common_poly_eval)?; - - let sets = rotation_sets(protocol); - let powers_of_u = &proof.u.powers(sets.len()); - let f = { - let powers_of_v = proof - .v - .powers(sets.iter().map(|set| set.polys.len()).max().unwrap()); - sets.iter() - .map(|set| set.msm(&commitments, &evaluations, &powers_of_v)) - .zip(powers_of_u.iter()) - .map(|(msm, power_of_u)| msm * power_of_u) - .sum::>() - }; - let z_omegas = sets.iter().map(|set| { - loader.load_const( - &protocol - .domain - .rotate_scalar(C::Scalar::one(), set.rotation), - ) * &proof.z - }); - - let rhs = proof - .ws - .iter() - .zip(powers_of_u.iter()) - .map(|(w, power_of_u)| MSM::base(w.clone()) * power_of_u) - .collect_vec(); - let lhs = f + rhs - .iter() - .zip(z_omegas) - .map(|(uw, z_omega)| uw.clone() * &z_omega) - .sum(); - - let mut accumulator = Accumulator::new(lhs, rhs.into_iter().sum()); - if let Some(old_accumulator) = old_accumulator { - accumulator += old_accumulator; - } - strategy.process(loader, transcript, proof, accumulator) - } -} - -pub struct PlonkProof> { - statements: Vec>, - auxiliaries: Vec, - challenges: Vec, - alpha: L::LoadedScalar, - quotients: Vec, - z: L::LoadedScalar, - evaluations: Vec, - v: L::LoadedScalar, - ws: Vec, - u: L::LoadedScalar, -} - -impl> PlonkProof { - fn read>( - protocol: &Protocol, - statements: Vec>, - transcript: &mut T, - ) -> Result { - if protocol.num_statement - != statements - .iter() - .map(|statements| statements.len()) - .collect_vec() - { - return Err(Error::InvalidInstances); - } - for statements in statements.iter() { - for statement in statements.iter() { - transcript.common_scalar(statement)?; - } - } - - let (auxiliaries, challenges) = { - let (auxiliaries, challenges) = protocol - .num_auxiliary - .iter() - .zip(protocol.num_challenge.iter()) - .map(|(&n, &m)| { - Ok(( - transcript.read_n_ec_points(n)?, - transcript.squeeze_n_challenges(m), - )) - }) - .collect::, Error>>()? - .into_iter() - .unzip::<_, _, Vec<_>, Vec<_>>(); - - ( - auxiliaries.into_iter().flatten().collect_vec(), - challenges.into_iter().flatten().collect_vec(), - ) - }; - - let alpha = transcript.squeeze_challenge(); - let quotients = { - let max_degree = protocol - .relations - .iter() - .map(Expression::degree) - .max() - .unwrap(); - transcript.read_n_ec_points(max_degree - 1)? - }; - - let z = transcript.squeeze_challenge(); - let evaluations = transcript.read_n_scalars(protocol.evaluations.len())?; - - let v = transcript.squeeze_challenge(); - let ws = transcript.read_n_ec_points(rotation_sets(protocol).len())?; - let u = transcript.squeeze_challenge(); - - Ok(Self { - statements, - auxiliaries, - challenges, - alpha, - quotients, - z, - evaluations, - v, - ws, - u, - }) - } - - fn commitments( - &self, - protocol: &Protocol, - loader: &L, - common_poly_eval: &CommonPolynomialEvaluation, - ) -> HashMap> { - iter::empty() - .chain( - protocol - .preprocessed - .iter() - .map(|value| MSM::base(loader.ec_point_load_const(value))) - .enumerate(), - ) - .chain({ - let auxiliary_offset = protocol.preprocessed.len() + protocol.num_statement.len(); - self.auxiliaries - .iter() - .cloned() - .enumerate() - .map(move |(i, auxiliary)| (auxiliary_offset + i, MSM::base(auxiliary))) - }) - .chain(iter::once(( - protocol.vanishing_poly(), - common_poly_eval - .zn() - .powers(self.quotients.len()) - .into_iter() - .zip(self.quotients.iter().cloned().map(MSM::base)) - .map(|(coeff, piece)| piece * &coeff) - .sum(), - ))) - .collect() - } - - fn evaluations( - &self, - protocol: &Protocol, - loader: &L, - common_poly_eval: &CommonPolynomialEvaluation, - ) -> Result, Error> { - let statement_evaluations = self.statements.iter().map(|statements| { - L::LoadedScalar::sum( - &statements - .iter() - .enumerate() - .map(|(i, statement)| { - common_poly_eval.get(CommonPolynomial::Lagrange(i as i32)) * statement - }) - .collect_vec(), - ) - }); - let mut evaluations = HashMap::::from_iter( - iter::empty() - .chain( - statement_evaluations - .into_iter() - .enumerate() - .map(|(i, evaluation)| { - ( - Query { - poly: protocol.preprocessed.len() + i, - rotation: Rotation::cur(), - }, - evaluation, - ) - }), - ) - .chain( - protocol - .evaluations - .iter() - .cloned() - .zip(self.evaluations.iter().cloned()), - ), - ); - - let powers_of_alpha = self.alpha.powers(protocol.relations.len()); - let quotient_evaluation = L::LoadedScalar::sum( - &powers_of_alpha - .into_iter() - .rev() - .zip(protocol.relations.iter()) - .map(|(power_of_alpha, relation)| { - relation - .evaluate( - &|scalar| Ok(loader.load_const(&scalar)), - &|poly| Ok(common_poly_eval.get(poly)), - &|index| { - evaluations - .get(&index) - .cloned() - .ok_or(Error::MissingQuery(index)) - }, - &|index| { - self.challenges - .get(index) - .cloned() - .ok_or(Error::MissingChallenge(index)) - }, - &|a| a.map(|a| -a), - &|a, b| a.and_then(|a| Ok(a + b?)), - &|a, b| a.and_then(|a| Ok(a * b?)), - &|a, scalar| a.map(|a| a * loader.load_const(&scalar)), - ) - .map(|evaluation| power_of_alpha * evaluation) - }) - .collect::, Error>>()?, - ) * &common_poly_eval.zn_minus_one_inv(); - - evaluations.insert( - Query { - poly: protocol.vanishing_poly(), - rotation: Rotation::cur(), - }, - quotient_evaluation, - ); - - Ok(evaluations) - } -} - -struct RotationSet { - rotation: Rotation, - polys: Vec, -} - -impl RotationSet { - fn msm>( - &self, - commitments: &HashMap>, - evaluations: &HashMap, - powers_of_v: &[L::LoadedScalar], - ) -> MSM { - self.polys - .iter() - .map(|poly| { - let commitment = commitments.get(poly).unwrap().clone(); - let evalaution = evaluations - .get(&Query::new(*poly, self.rotation)) - .unwrap() - .clone(); - commitment - MSM::scalar(evalaution) - }) - .zip(powers_of_v.iter()) - .map(|(msm, power_of_v)| msm * power_of_v) - .sum() - } -} - -fn rotation_sets(protocol: &Protocol) -> Vec { - protocol.queries.iter().fold(Vec::new(), |mut sets, query| { - if let Some(pos) = sets.iter().position(|set| set.rotation == query.rotation) { - sets[pos].polys.push(query.poly) - } else { - sets.push(RotationSet { - rotation: query.rotation, - polys: vec![query.poly], - }) - } - sets - }) -} - -impl CostEstimation for PlonkAccumulationScheme { - fn estimate_cost(protocol: &Protocol) -> Cost { - let num_quotient = protocol - .relations - .iter() - .map(Expression::degree) - .max() - .unwrap() - - 1; - let num_w = rotation_sets(protocol).len(); - let num_accumulator = protocol - .accumulator_indices - .as_ref() - .map(|accumulator_indices| accumulator_indices.len()) - .unwrap_or_default(); - - let num_statement = protocol.num_statement.iter().sum(); - let num_commitment = protocol.num_auxiliary.iter().sum::() + num_quotient + num_w; - let num_evaluation = protocol.evaluations.len(); - let num_msm = - protocol.preprocessed.len() + num_commitment + 1 + num_w + 2 * num_accumulator; - - Cost::new(num_statement, num_commitment, num_evaluation, num_msm) - } -} diff --git a/src/scheme/kzg/accumulation/shplonk.rs b/src/scheme/kzg/accumulation/shplonk.rs deleted file mode 100644 index e9c31aa8..00000000 --- a/src/scheme/kzg/accumulation/shplonk.rs +++ /dev/null @@ -1,593 +0,0 @@ -use crate::{ - loader::{LoadedScalar, Loader}, - protocol::Protocol, - scheme::kzg::{ - accumulation::{AccumulationScheme, AccumulationStrategy, Accumulator}, - cost::{Cost, CostEstimation}, - langranges, - msm::MSM, - }, - util::{ - CommonPolynomial, CommonPolynomialEvaluation, Curve, Domain, Expression, Field, Fraction, - Itertools, Query, Rotation, TranscriptRead, - }, - Error, -}; -use std::{ - collections::{BTreeSet, HashMap}, - iter, -}; - -#[derive(Default)] -pub struct ShplonkAccumulationScheme; - -impl AccumulationScheme for ShplonkAccumulationScheme -where - C: Curve, - L: Loader, - T: TranscriptRead, - S: AccumulationStrategy>, -{ - type Proof = ShplonkProof; - - fn accumulate( - protocol: &Protocol, - loader: &L, - statements: Vec>, - transcript: &mut T, - strategy: &mut S, - ) -> Result { - transcript.common_scalar(&loader.load_const(&protocol.transcript_initial_state))?; - - let proof = ShplonkProof::read(protocol, statements, transcript)?; - let old_accumulator = - strategy.extract_accumulator(protocol, loader, transcript, &proof.statements); - - let (common_poly_eval, sets) = { - let mut common_poly_eval = CommonPolynomialEvaluation::new( - &protocol.domain, - loader, - langranges(protocol, &proof.statements), - &proof.z, - ); - let mut sets = intermediate_sets(protocol, loader, &proof.z, &proof.z_prime); - - L::LoadedScalar::batch_invert( - iter::empty() - .chain(common_poly_eval.denoms()) - .chain(sets.iter_mut().flat_map(IntermediateSet::denoms)), - ); - L::LoadedScalar::batch_invert(sets.iter_mut().flat_map(IntermediateSet::denoms)); - - (common_poly_eval, sets) - }; - - let commitments = proof.commitments(protocol, loader, &common_poly_eval); - let evaluations = proof.evaluations(protocol, loader, &common_poly_eval)?; - - let f = { - let powers_of_mu = proof - .mu - .powers(sets.iter().map(|set| set.polys.len()).max().unwrap()); - let msms = sets - .iter() - .map(|set| set.msm(&commitments, &evaluations, &powers_of_mu)); - - msms.zip(proof.gamma.powers(sets.len()).into_iter()) - .map(|(msm, power_of_gamma)| msm * &power_of_gamma) - .sum::>() - - MSM::base(proof.w.clone()) * &sets[0].z_s - }; - - let rhs = MSM::base(proof.w_prime.clone()); - let lhs = f + rhs.clone() * &proof.z_prime; - - let mut accumulator = Accumulator::new(lhs, rhs); - if let Some(old_accumulator) = old_accumulator { - accumulator += old_accumulator; - } - strategy.process(loader, transcript, proof, accumulator) - } -} - -pub struct ShplonkProof> { - statements: Vec>, - auxiliaries: Vec, - challenges: Vec, - alpha: L::LoadedScalar, - quotients: Vec, - z: L::LoadedScalar, - evaluations: Vec, - mu: L::LoadedScalar, - gamma: L::LoadedScalar, - w: L::LoadedEcPoint, - z_prime: L::LoadedScalar, - w_prime: L::LoadedEcPoint, -} - -impl> ShplonkProof { - fn read>( - protocol: &Protocol, - statements: Vec>, - transcript: &mut T, - ) -> Result { - if protocol.num_statement - != statements - .iter() - .map(|statements| statements.len()) - .collect_vec() - { - return Err(Error::InvalidInstances); - } - for statements in statements.iter() { - for statement in statements.iter() { - transcript.common_scalar(statement)?; - } - } - - let (auxiliaries, challenges) = { - let (auxiliaries, challenges) = protocol - .num_auxiliary - .iter() - .zip(protocol.num_challenge.iter()) - .map(|(&n, &m)| { - Ok(( - transcript.read_n_ec_points(n)?, - transcript.squeeze_n_challenges(m), - )) - }) - .collect::, Error>>()? - .into_iter() - .unzip::<_, _, Vec<_>, Vec<_>>(); - - ( - auxiliaries.into_iter().flatten().collect_vec(), - challenges.into_iter().flatten().collect_vec(), - ) - }; - - let alpha = transcript.squeeze_challenge(); - let quotients = { - let max_degree = protocol - .relations - .iter() - .map(Expression::degree) - .max() - .unwrap(); - transcript.read_n_ec_points(max_degree - 1)? - }; - - let z = transcript.squeeze_challenge(); - let evaluations = transcript.read_n_scalars(protocol.evaluations.len())?; - - let mu = transcript.squeeze_challenge(); - let gamma = transcript.squeeze_challenge(); - let w = transcript.read_ec_point()?; - let z_prime = transcript.squeeze_challenge(); - let w_prime = transcript.read_ec_point()?; - - Ok(Self { - statements, - auxiliaries, - challenges, - alpha, - quotients, - z, - evaluations, - mu, - gamma, - w, - z_prime, - w_prime, - }) - } - - fn commitments( - &self, - protocol: &Protocol, - loader: &L, - common_poly_eval: &CommonPolynomialEvaluation, - ) -> HashMap> { - iter::empty() - .chain( - protocol - .preprocessed - .iter() - .map(|value| MSM::base(loader.ec_point_load_const(value))) - .enumerate(), - ) - .chain({ - let auxiliary_offset = protocol.preprocessed.len() + protocol.num_statement.len(); - self.auxiliaries - .iter() - .cloned() - .enumerate() - .map(move |(i, auxiliary)| (auxiliary_offset + i, MSM::base(auxiliary))) - }) - .chain(iter::once(( - protocol.vanishing_poly(), - common_poly_eval - .zn() - .powers(self.quotients.len()) - .into_iter() - .zip(self.quotients.iter().cloned().map(MSM::base)) - .map(|(coeff, piece)| piece * &coeff) - .sum(), - ))) - .collect() - } - - fn evaluations( - &self, - protocol: &Protocol, - loader: &L, - common_poly_eval: &CommonPolynomialEvaluation, - ) -> Result, Error> { - let statement_evaluations = self.statements.iter().map(|statements| { - L::LoadedScalar::sum( - &statements - .iter() - .enumerate() - .map(|(i, statement)| { - statement.clone() - * common_poly_eval.get(CommonPolynomial::Lagrange(i as i32)) - }) - .collect_vec(), - ) - }); - let mut evaluations = HashMap::::from_iter( - iter::empty() - .chain( - statement_evaluations - .into_iter() - .enumerate() - .map(|(i, evaluation)| { - ( - Query { - poly: protocol.preprocessed.len() + i, - rotation: Rotation::cur(), - }, - evaluation, - ) - }), - ) - .chain( - protocol - .evaluations - .iter() - .cloned() - .zip(self.evaluations.iter().cloned()), - ), - ); - - let powers_of_alpha = self.alpha.powers(protocol.relations.len()); - let quotient_evaluation = L::LoadedScalar::sum( - &powers_of_alpha - .into_iter() - .rev() - .zip(protocol.relations.iter()) - .map(|(power_of_alpha, relation)| { - relation - .evaluate( - &|scalar| Ok(loader.load_const(&scalar)), - &|poly| Ok(common_poly_eval.get(poly)), - &|index| { - evaluations - .get(&index) - .cloned() - .ok_or(Error::MissingQuery(index)) - }, - &|index| { - self.challenges - .get(index) - .cloned() - .ok_or(Error::MissingChallenge(index)) - }, - &|a| a.map(|a| -a), - &|a, b| a.and_then(|a| Ok(a + b?)), - &|a, b| a.and_then(|a| Ok(a * b?)), - &|a, scalar| a.map(|a| a * loader.load_const(&scalar)), - ) - .map(|evaluation| power_of_alpha * evaluation) - }) - .collect::, Error>>()?, - ) * &common_poly_eval.zn_minus_one_inv(); - - evaluations.insert( - Query { - poly: protocol.vanishing_poly(), - rotation: Rotation::cur(), - }, - quotient_evaluation, - ); - - Ok(evaluations) - } -} - -struct IntermediateSet> { - rotations: Vec, - polys: Vec, - z_s: L::LoadedScalar, - evaluation_coeffs: Vec>, - commitment_coeff: Option>, - remainder_coeff: Option>, -} - -impl> IntermediateSet { - fn new( - domain: &Domain, - loader: &L, - rotations: Vec, - powers_of_z: &[L::LoadedScalar], - z_prime: &L::LoadedScalar, - z_prime_minus_z_omega_i: &HashMap, - z_s_1: &Option, - ) -> Self { - let omegas = rotations - .iter() - .map(|rotation| domain.rotate_scalar(C::Scalar::one(), *rotation)) - .collect_vec(); - - let normalized_ell_primes = omegas - .iter() - .enumerate() - .map(|(j, omega_j)| { - omegas - .iter() - .enumerate() - .filter(|&(i, _)| i != j) - .fold(C::Scalar::one(), |acc, (_, omega_i)| { - acc * (*omega_j - omega_i) - }) - }) - .collect_vec(); - - let z = &powers_of_z[1].clone(); - let z_pow_k_minus_one = { - let k_minus_one = rotations.len() - 1; - powers_of_z.iter().enumerate().skip(1).fold( - loader.load_one(), - |acc, (i, power_of_z)| { - if k_minus_one & (1 << i) == 1 { - acc * power_of_z - } else { - acc - } - }, - ) - }; - - let barycentric_weights = omegas - .iter() - .zip(normalized_ell_primes.iter()) - .map(|(omega, normalized_ell_prime)| { - L::LoadedScalar::sum_products_with_coeff_and_constant( - &[ - ( - *normalized_ell_prime, - z_pow_k_minus_one.clone(), - z_prime.clone(), - ), - ( - -(*normalized_ell_prime * omega), - z_pow_k_minus_one.clone(), - z.clone(), - ), - ], - &C::Scalar::zero(), - ) - }) - .map(Fraction::one_over) - .collect_vec(); - - let z_s = rotations - .iter() - .map(|rotation| z_prime_minus_z_omega_i.get(rotation).unwrap().clone()) - .reduce(|acc, z_prime_minus_z_omega_i| acc * z_prime_minus_z_omega_i) - .unwrap(); - let z_s_1_over_z_s = z_s_1.clone().map(|z_s_1| Fraction::new(z_s_1, z_s.clone())); - - Self { - rotations, - polys: Vec::new(), - z_s, - evaluation_coeffs: barycentric_weights, - commitment_coeff: z_s_1_over_z_s, - remainder_coeff: None, - } - } - - fn denoms(&mut self) -> impl IntoIterator { - if self.evaluation_coeffs.first().unwrap().denom().is_some() { - self.evaluation_coeffs - .iter_mut() - .chain(self.commitment_coeff.as_mut()) - .filter_map(Fraction::denom_mut) - .collect_vec() - } else if self.remainder_coeff.is_none() { - let barycentric_weights_sum = L::LoadedScalar::sum( - &self - .evaluation_coeffs - .iter() - .map(Fraction::evaluate) - .collect_vec(), - ); - self.remainder_coeff = Some(match self.commitment_coeff.clone() { - Some(coeff) => Fraction::new(coeff.evaluate(), barycentric_weights_sum), - None => Fraction::one_over(barycentric_weights_sum), - }); - vec![self.remainder_coeff.as_mut().unwrap().denom_mut().unwrap()] - } else { - unreachable!() - } - } - - fn msm( - &self, - commitments: &HashMap>, - evaluations: &HashMap, - powers_of_mu: &[L::LoadedScalar], - ) -> MSM { - self.polys - .iter() - .zip(powers_of_mu.iter()) - .map(|(poly, power_of_mu)| { - let commitment = self - .commitment_coeff - .as_ref() - .map(|commitment_coeff| { - commitments.get(poly).unwrap().clone() * &commitment_coeff.evaluate() - }) - .unwrap_or_else(|| commitments.get(poly).unwrap().clone()); - let remainder = self.remainder_coeff.as_ref().unwrap().evaluate() - * L::LoadedScalar::sum( - &self - .rotations - .iter() - .zip(self.evaluation_coeffs.iter()) - .map(|(rotation, coeff)| { - coeff.evaluate() - * evaluations - .get(&Query { - poly: *poly, - rotation: *rotation, - }) - .unwrap() - }) - .collect_vec(), - ); - (commitment - MSM::scalar(remainder)) * power_of_mu - }) - .sum() - } -} - -fn intermediate_sets>( - protocol: &Protocol, - loader: &L, - z: &L::LoadedScalar, - z_prime: &L::LoadedScalar, -) -> Vec> { - let rotations_sets = rotations_sets(protocol); - let superset = rotations_sets - .iter() - .flat_map(|set| set.rotations.clone()) - .sorted() - .dedup(); - - let size = 2.max( - (rotations_sets - .iter() - .map(|set| set.rotations.len()) - .max() - .unwrap() - - 1) - .next_power_of_two() - .log2() as usize - + 1, - ); - let powers_of_z = z.powers(size); - let z_prime_minus_z_omega_i = HashMap::from_iter( - superset - .map(|rotation| { - ( - rotation, - loader.load_const(&protocol.domain.rotate_scalar(C::Scalar::one(), rotation)), - ) - }) - .map(|(rotation, omega)| (rotation, z_prime.clone() - z.clone() * omega)), - ); - - let mut z_s_1 = None; - rotations_sets - .into_iter() - .map(|set| { - let intermetidate_set = IntermediateSet { - polys: set.polys, - ..IntermediateSet::new( - &protocol.domain, - loader, - set.rotations, - &powers_of_z, - z_prime, - &z_prime_minus_z_omega_i, - &z_s_1, - ) - }; - if z_s_1.is_none() { - z_s_1 = Some(intermetidate_set.z_s.clone()); - }; - intermetidate_set - }) - .collect() -} - -struct RotationsSet { - rotations: Vec, - polys: Vec, -} - -fn rotations_sets(protocol: &Protocol) -> Vec { - let poly_rotations = protocol.queries.iter().fold( - Vec::<(usize, Vec)>::new(), - |mut poly_rotations, query| { - if let Some(pos) = poly_rotations - .iter() - .position(|(poly, _)| *poly == query.poly) - { - let (_, rotations) = &mut poly_rotations[pos]; - if !rotations.contains(&query.rotation) { - rotations.push(query.rotation); - } - } else { - poly_rotations.push((query.poly, vec![query.rotation])); - } - poly_rotations - }, - ); - - poly_rotations - .into_iter() - .fold(Vec::::new(), |mut sets, (poly, rotations)| { - if let Some(pos) = sets.iter().position(|set| { - BTreeSet::from_iter(set.rotations.iter()) == BTreeSet::from_iter(rotations.iter()) - }) { - let set = &mut sets[pos]; - if !set.polys.contains(&poly) { - set.polys.push(poly); - } - } else { - let set = RotationsSet { - rotations, - polys: vec![poly], - }; - sets.push(set); - } - sets - }) -} - -impl CostEstimation for ShplonkAccumulationScheme { - fn estimate_cost(protocol: &Protocol) -> Cost { - let num_quotient = protocol - .relations - .iter() - .map(Expression::degree) - .max() - .unwrap() - - 1; - let num_accumulator = protocol - .accumulator_indices - .as_ref() - .map(|accumulator_indices| accumulator_indices.len()) - .unwrap_or_default(); - - let num_statement = protocol.num_statement.iter().sum(); - let num_commitment = protocol.num_auxiliary.iter().sum::() + num_quotient + 2; - let num_evaluation = protocol.evaluations.len(); - let num_msm = protocol.preprocessed.len() + num_commitment + 3 + 2 * num_accumulator; - - Cost::new(num_statement, num_commitment, num_evaluation, num_msm) - } -} diff --git a/src/scheme/kzg/cost.rs b/src/scheme/kzg/cost.rs deleted file mode 100644 index f83f7dd1..00000000 --- a/src/scheme/kzg/cost.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::{protocol::Protocol, util::Curve}; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Cost { - pub num_statement: usize, - pub num_commitment: usize, - pub num_evaluation: usize, - pub num_msm: usize, -} - -impl Cost { - pub fn new( - num_statement: usize, - num_commitment: usize, - num_evaluation: usize, - num_msm: usize, - ) -> Self { - Self { - num_statement, - num_commitment, - num_evaluation, - num_msm, - } - } -} - -pub trait CostEstimation { - fn estimate_cost(protocol: &Protocol) -> Cost; -} diff --git a/src/scheme/kzg/msm.rs b/src/scheme/kzg/msm.rs deleted file mode 100644 index db5e4ce2..00000000 --- a/src/scheme/kzg/msm.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::{ - loader::{LoadedEcPoint, Loader}, - util::Curve, -}; -use std::{ - default::Default, - iter::{self, Sum}, - ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, -}; - -#[derive(Clone, Debug)] -pub struct MSM> { - pub scalar: Option, - bases: Vec, - scalars: Vec, -} - -impl> Default for MSM { - fn default() -> Self { - Self { - scalar: None, - scalars: Vec::new(), - bases: Vec::new(), - } - } -} - -impl> MSM { - pub fn scalar(scalar: L::LoadedScalar) -> Self { - MSM { - scalar: Some(scalar), - ..Default::default() - } - } - - pub fn base(base: L::LoadedEcPoint) -> Self { - let one = base.loader().load_one(); - MSM { - scalars: vec![one], - bases: vec![base], - ..Default::default() - } - } - - pub fn evaluate(self, gen: C) -> L::LoadedEcPoint { - let gen = self - .bases - .first() - .unwrap() - .loader() - .ec_point_load_const(&gen); - L::LoadedEcPoint::multi_scalar_multiplication( - iter::empty() - .chain(self.scalar.map(|scalar| (scalar, gen))) - .chain(self.scalars.into_iter().zip(self.bases.into_iter())), - ) - } - - pub fn scale(&mut self, factor: &L::LoadedScalar) { - if let Some(scalar) = self.scalar.as_mut() { - *scalar *= factor; - } - for scalar in self.scalars.iter_mut() { - *scalar *= factor - } - } - - pub fn push(&mut self, scalar: L::LoadedScalar, base: L::LoadedEcPoint) { - if let Some(pos) = self.bases.iter().position(|exist| exist.eq(&base)) { - self.scalars[pos] += scalar; - } else { - self.scalars.push(scalar); - self.bases.push(base); - } - } - - pub fn extend(&mut self, mut other: Self) { - match (self.scalar.as_mut(), other.scalar.as_ref()) { - (Some(lhs), Some(rhs)) => *lhs += rhs, - (None, Some(_)) => self.scalar = other.scalar.take(), - _ => {} - }; - for (scalar, base) in other.scalars.into_iter().zip(other.bases) { - self.push(scalar, base); - } - } -} - -impl> Add> for MSM { - type Output = MSM; - - fn add(mut self, rhs: MSM) -> Self::Output { - self.extend(rhs); - self - } -} - -impl> AddAssign> for MSM { - fn add_assign(&mut self, rhs: MSM) { - self.extend(rhs); - } -} - -impl> Sub> for MSM { - type Output = MSM; - - fn sub(mut self, rhs: MSM) -> Self::Output { - self.extend(-rhs); - self - } -} - -impl> SubAssign> for MSM { - fn sub_assign(&mut self, rhs: MSM) { - self.extend(-rhs); - } -} - -impl> Mul<&L::LoadedScalar> for MSM { - type Output = MSM; - - fn mul(mut self, rhs: &L::LoadedScalar) -> Self::Output { - self.scale(rhs); - self - } -} - -impl> MulAssign<&L::LoadedScalar> for MSM { - fn mul_assign(&mut self, rhs: &L::LoadedScalar) { - self.scale(rhs); - } -} - -impl> Neg for MSM { - type Output = MSM; - fn neg(mut self) -> MSM { - self.scalar = self.scalar.map(|scalar| -scalar); - for scalar in self.scalars.iter_mut() { - *scalar = -scalar.clone(); - } - self - } -} - -impl> Sum for MSM { - fn sum>(iter: I) -> Self { - iter.reduce(|acc, item| acc + item).unwrap_or_default() - } -} diff --git a/src/system.rs b/src/system.rs new file mode 100644 index 00000000..5d5aa99c --- /dev/null +++ b/src/system.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "system_halo2")] +pub mod halo2; diff --git a/src/protocol/halo2.rs b/src/system/halo2.rs similarity index 76% rename from src/protocol/halo2.rs rename to src/system/halo2.rs index 6c30bf5d..bf3e4091 100644 --- a/src/protocol/halo2.rs +++ b/src/system/halo2.rs @@ -1,40 +1,99 @@ use crate::{ - protocol::Protocol, - util::{CommonPolynomial, Domain, Expression, Itertools, Query, Rotation}, + util::{ + arithmetic::{root_of_unity, CurveAffine, Domain, FieldExt, Rotation}, + protocol::{ + CommonPolynomial, Expression, InstanceCommittingKey, Query, QuotientPolynomial, + }, + Itertools, + }, + Protocol, }; use halo2_proofs::{ - arithmetic::{CurveAffine, CurveExt, FieldExt}, plonk::{self, Any, ConstraintSystem, FirstPhase, SecondPhase, ThirdPhase, VerifyingKey}, - poly, + poly::{self, commitment::Params}, transcript::{EncodedChallenge, Transcript}, }; -use std::{io, iter}; +use num_integer::Integer; +use std::{io, iter, mem::size_of}; -mod util; +pub mod transcript; #[cfg(test)] -mod test; +pub(crate) mod test; +#[derive(Clone, Debug, Default)] pub struct Config { - zk: bool, - query_instance: bool, - num_instance: Vec, - num_proof: usize, - accumulator_indices: Option>, + pub zk: bool, + pub query_instance: bool, + pub num_proof: usize, + pub num_instance: Vec, + pub accumulator_indices: Option>, } -pub fn compile(vk: &VerifyingKey, config: Config) -> Protocol { +impl Config { + pub fn kzg() -> Self { + Self { + zk: true, + query_instance: false, + num_proof: 1, + ..Default::default() + } + } + + pub fn ipa() -> Self { + Self { + zk: true, + query_instance: true, + num_proof: 1, + ..Default::default() + } + } + + pub fn set_zk(mut self, zk: bool) -> Self { + self.zk = zk; + self + } + + pub fn set_query_instance(mut self, query_instance: bool) -> Self { + self.query_instance = query_instance; + self + } + + pub fn with_num_proof(mut self, num_proof: usize) -> Self { + assert!(num_proof > 0); + self.num_proof = num_proof; + self + } + + pub fn with_num_instance(mut self, num_instance: Vec) -> Self { + self.num_instance = num_instance; + self + } + + pub fn with_accumulator_indices(mut self, accumulator_indices: Vec<(usize, usize)>) -> Self { + self.accumulator_indices = Some(accumulator_indices); + self + } +} + +pub fn compile<'a, C: CurveAffine, P: Params<'a, C>>( + params: &P, + vk: &VerifyingKey, + config: Config, +) -> Protocol { + assert_eq!(vk.get_domain().k(), params.k()); + let cs = vk.cs(); let Config { zk, - num_instance, query_instance, num_proof, + num_instance, accumulator_indices, } = config; - let k = vk.get_domain().empty_lagrange().len().log2(); - let domain = Domain::new(k as usize); + let k = params.k() as usize; + let domain = Domain::new(k, root_of_unity(k)); let preprocessed = vk .fixed_commitments() @@ -66,35 +125,39 @@ pub fn compile(vk: &VerifyingKey, config: Config) -> }) .chain(polynomials.fixed_queries()) .chain(polynomials.permutation_fixed_queries()) - .chain(iter::once(polynomials.vanishing_query())) + .chain(iter::once(polynomials.quotient_query())) .chain(polynomials.random_query()) .collect(); - let relations = (0..num_proof) - .flat_map(|t| { - iter::empty() - .chain(polynomials.gate_relations(t)) - .chain(polynomials.permutation_relations(t)) - .chain(polynomials.lookup_relations(t)) - }) - .collect(); - let transcript_initial_state = transcript_initial_state::(vk); + let instance_committing_key = query_instance.then(|| { + instance_committing_key( + params, + polynomials + .num_instance() + .into_iter() + .max() + .unwrap_or_default(), + ) + }); + let accumulator_indices = accumulator_indices - .map(|accumulator_indices| polynomials.accumulator_indices(accumulator_indices)); + .map(|accumulator_indices| polynomials.accumulator_indices(accumulator_indices)) + .unwrap_or_default(); Protocol { - zk: config.zk, domain, preprocessed, - num_statement: polynomials.num_statement(), - num_auxiliary: polynomials.num_auxiliary(), + num_instance: polynomials.num_instance(), + num_witness: polynomials.num_witness(), num_challenge: polynomials.num_challenge(), evaluations, queries, - relations, - transcript_initial_state, + quotient: polynomials.quotient(), + transcript_initial_state: Some(transcript_initial_state), + instance_committing_key, + linearization: None, accumulator_indices, } } @@ -131,11 +194,8 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { num_instance: Vec, num_proof: usize, ) -> Self { - let degree = if zk { - cs.degree::() - } else { - cs.degree::() - }; + // TODO: Re-enable optional-zk when it's merged in pse/halo2. + let degree = if zk { cs.degree() } else { unimplemented!() }; let permutation_chunk_size = if zk || cs.permutation().get_columns().len() >= degree { degree - 2 } else { @@ -155,7 +215,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { state[*phase as usize] += 1; Some(index) }) - .collect_vec(); + .collect::>(); (num, index) }; @@ -164,8 +224,6 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { assert_eq!(num_advice.iter().sum::(), cs.num_advice_columns()); assert_eq!(num_challenge.iter().sum::(), cs.num_challenges()); - assert_eq!(cs.num_instance_columns(), num_instance.len()); - Self { cs, zk, @@ -180,11 +238,10 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { challenge_index, num_lookup_permuted: 2 * cs.lookups().len(), permutation_chunk_size, - num_permutation_z: cs - .permutation() - .get_columns() - .len() - .div_ceil(permutation_chunk_size), + num_permutation_z: Integer::div_ceil( + &cs.permutation().get_columns().len(), + &permutation_chunk_size, + ), num_lookup_z: cs.lookups().len(), } } @@ -193,14 +250,14 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { self.num_fixed + self.num_permutation_fixed } - fn num_statement(&self) -> Vec { + fn num_instance(&self) -> Vec { iter::repeat(self.num_instance.clone()) .take(self.num_proof) .flatten() .collect() } - fn num_auxiliary(&self) -> Vec { + fn num_witness(&self) -> Vec { iter::empty() .chain( self.num_advice @@ -222,7 +279,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { .chain(num_challenge) .chain([ 2, // beta, gamma - 0, + 1, // alpha ]) .collect() } @@ -231,14 +288,14 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { self.num_preprocessed() } - fn auxiliary_offset(&self) -> usize { - self.instance_offset() + self.num_statement().len() + fn witness_offset(&self) -> usize { + self.instance_offset() + self.num_instance().len() } - fn cs_auxiliary_offset(&self) -> usize { - self.auxiliary_offset() + fn cs_witness_offset(&self) -> usize { + self.witness_offset() + self - .num_auxiliary() + .num_witness() .iter() .take(self.num_advice.len()) .sum::() @@ -260,9 +317,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { * self.num_advice[..advice.phase() as usize] .iter() .sum::(); - self.auxiliary_offset() - + phase_offset - + t * self.num_advice[advice.phase() as usize] + self.witness_offset() + phase_offset + t * self.num_advice[advice.phase() as usize] } }; Query::new(offset + column_index, rotation.into()) @@ -270,14 +325,14 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { fn instance_queries(&'a self, t: usize) -> impl IntoIterator + 'a { self.query_instance - .then_some( + .then(|| { self.cs .instance_queries() .iter() .map(move |(column, rotation)| { self.query(*column.column_type(), column.index(), *rotation, t) - }), - ) + }) + }) .into_iter() .flatten() } @@ -305,7 +360,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { } fn permutation_poly(&'a self, t: usize, i: usize) -> usize { - let z_offset = self.cs_auxiliary_offset() + self.num_auxiliary()[self.num_advice.len()]; + let z_offset = self.cs_witness_offset() + self.num_witness()[self.num_advice.len()]; z_offset + t * self.num_permutation_z + i } @@ -346,9 +401,9 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { } fn lookup_poly(&'a self, t: usize, i: usize) -> (usize, usize, usize) { - let permuted_offset = self.cs_auxiliary_offset(); + let permuted_offset = self.cs_witness_offset(); let z_offset = permuted_offset - + self.num_auxiliary()[self.num_advice.len()] + + self.num_witness()[self.num_advice.len()] + self.num_proof * self.num_permutation_z; let z = z_offset + t * self.num_lookup_z + i; let permuted_input = permuted_offset + 2 * (t * self.num_lookup_z + i); @@ -382,18 +437,20 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { }) } - fn vanishing_query(&self) -> Query { + fn quotient_query(&self) -> Query { Query::new( - self.auxiliary_offset() + self.num_auxiliary().iter().sum::(), + self.witness_offset() + self.num_witness().iter().sum::(), 0, ) } fn random_query(&self) -> Option { - self.zk.then_some(Query::new( - self.auxiliary_offset() + self.num_auxiliary().iter().sum::() - 1, - 0, - )) + self.zk.then(|| { + Query::new( + self.witness_offset() + self.num_witness().iter().sum::() - 1, + 0, + ) + }) } fn convert(&self, expression: &plonk::Expression, t: usize) -> Expression { @@ -435,7 +492,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { ) } - fn gate_relations(&'a self, t: usize) -> impl IntoIterator> + 'a { + fn gate_constraints(&'a self, t: usize) -> impl IntoIterator> + 'a { self.cs.gates().iter().flat_map(move |gate| { gate.polynomials() .iter() @@ -444,7 +501,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { } fn rotation_last(&self) -> Rotation { - Rotation(-((self.cs.blinding_factors::() + 1) as i32)) + Rotation(-((self.cs.blinding_factors() + 1) as i32)) } fn l_last(&self) -> Expression { @@ -483,7 +540,11 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { Expression::Challenge(self.system_challenge_offset() + 2) } - fn permutation_relations(&'a self, t: usize) -> impl IntoIterator> + 'a { + fn alpha(&self) -> Expression { + Expression::Challenge(self.system_challenge_offset() + 3) + } + + fn permutation_constraints(&'a self, t: usize) -> impl IntoIterator> + 'a { let one = &Expression::Constant(F::one()); let l_0 = &Expression::::CommonPolynomial(CommonPolynomial::Lagrange(0)); let l_last = &self.l_last(); @@ -519,7 +580,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { .chain(zs.first().map(|(z_0, _, _)| l_0 * (one - z_0))) .chain( zs.last() - .and_then(|(z_l, _, _)| self.zk.then_some(l_last * (z_l * z_l - z_l))), + .and_then(|(z_l, _, _)| self.zk.then(|| l_last * (z_l * z_l - z_l))), ) .chain(if self.zk { zs.iter() @@ -575,12 +636,11 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { .collect_vec() } - fn lookup_relations(&'a self, t: usize) -> impl IntoIterator> + 'a { + fn lookup_constraints(&'a self, t: usize) -> impl IntoIterator> + 'a { let one = &Expression::Constant(F::one()); let l_0 = &Expression::::CommonPolynomial(CommonPolynomial::Lagrange(0)); let l_last = &self.l_last(); let l_active = &self.l_active(); - let theta = &self.theta(); let beta = &self.beta(); let gamma = &self.gamma(); @@ -598,15 +658,13 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { .collect_vec(); let compress = |expressions: &'a [plonk::Expression]| { - expressions - .iter() - .rev() - .zip(iter::successors(Some(one.clone()), |power_of_theta| { - Some(power_of_theta * theta) - })) - .map(|(expression, power_of_theta)| power_of_theta * self.convert(expression, t)) - .reduce(|acc, expr| acc + expr) - .unwrap() + Expression::DistributePowers( + expressions + .iter() + .map(|expression| self.convert(expression, t)) + .collect(), + self.theta().into(), + ) }; self.cs @@ -619,7 +677,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { let table = compress(lookup.table_expressions()); iter::empty() .chain(Some(l_0 * (one - z))) - .chain(self.zk.then_some(l_last * (z * z - z))) + .chain(self.zk.then(|| l_last * (z * z - z))) .chain(Some(if self.zk { l_active * (z_w * (permuted_input + beta) * (permuted_table + gamma) @@ -628,7 +686,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { z_w * (permuted_input + beta) * (permuted_table + gamma) - z * (input + beta) * (table + gamma) })) - .chain(self.zk.then_some(l_0 * (permuted_input - permuted_table))) + .chain(self.zk.then(|| l_0 * (permuted_input - permuted_table))) .chain(Some(if self.zk { l_active * (permuted_input - permuted_table) @@ -642,6 +700,22 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { .collect_vec() } + fn quotient(&self) -> QuotientPolynomial { + let constraints = (0..self.num_proof) + .flat_map(|t| { + iter::empty() + .chain(self.gate_constraints(t)) + .chain(self.permutation_constraints(t)) + .chain(self.lookup_constraints(t)) + }) + .collect_vec(); + let numerator = Expression::DistributePowers(constraints, self.alpha().into()); + QuotientPolynomial { + chunk_degree: 1, + numerator, + } + } + fn accumulator_indices( &self, accumulator_indices: Vec<(usize, usize)>, @@ -690,8 +764,47 @@ impl Transcript for MockTranscript } } -fn transcript_initial_state(vk: &VerifyingKey) -> C::ScalarExt { +fn transcript_initial_state(vk: &VerifyingKey) -> C::Scalar { let mut transcript = MockTranscript::default(); vk.hash_into(&mut transcript).unwrap(); transcript.0 } + +fn instance_committing_key<'a, C: CurveAffine, P: Params<'a, C>>( + params: &P, + len: usize, +) -> InstanceCommittingKey { + let buf = { + let mut buf = Vec::new(); + params.write(&mut buf).unwrap(); + buf + }; + + let repr = C::Repr::default(); + let repr_len = repr.as_ref().len(); + let offset = size_of::() + (1 << params.k()) * repr_len; + + let bases = (offset..) + .step_by(repr_len) + .map(|offset| { + let mut repr = C::Repr::default(); + repr.as_mut() + .copy_from_slice(&buf[offset..offset + repr_len]); + C::from_bytes(&repr).unwrap() + }) + .take(len) + .collect(); + + let w = { + let offset = size_of::() + (2 << params.k()) * repr_len; + let mut repr = C::Repr::default(); + repr.as_mut() + .copy_from_slice(&buf[offset..offset + repr_len]); + C::from_bytes(&repr).unwrap() + }; + + InstanceCommittingKey { + bases, + constant: Some(w), + } +} diff --git a/src/system/halo2/test.rs b/src/system/halo2/test.rs new file mode 100644 index 00000000..9cd4a2fc --- /dev/null +++ b/src/system/halo2/test.rs @@ -0,0 +1,221 @@ +use crate::util::arithmetic::CurveAffine; +use halo2_proofs::{ + dev::MockProver, + plonk::{create_proof, verify_proof, Circuit, ProvingKey}, + poly::{ + commitment::{CommitmentScheme, Params, ParamsProver, Prover, Verifier}, + VerificationStrategy, + }, + transcript::{EncodedChallenge, TranscriptReadBuffer, TranscriptWriterBuffer}, +}; +use rand_chacha::rand_core::RngCore; +use std::{fs, io::Cursor}; + +mod circuit; +mod kzg; + +pub use circuit::{ + maingate::{MainGateWithRange, MainGateWithRangeConfig}, + standard::StandardPlonk, +}; + +pub fn read_or_create_srs<'a, C: CurveAffine, P: ParamsProver<'a, C>>( + dir: &str, + k: u32, + setup: impl Fn(u32) -> P, +) -> P { + let path = format!("{}/k-{}.srs", dir, k); + match fs::File::open(path.as_str()) { + Ok(mut file) => P::read(&mut file).unwrap(), + Err(_) => { + fs::create_dir_all(dir).unwrap(); + let params = setup(k); + params.write(&mut fs::File::create(path).unwrap()).unwrap(); + params + } + } +} + +pub fn create_proof_checked<'a, S, C, P, V, VS, TW, TR, EC, R>( + params: &'a S::ParamsProver, + pk: &ProvingKey, + circuits: &[C], + instances: &[&[&[S::Scalar]]], + mut rng: R, + finalize: impl Fn(Vec, VS::Output) -> Vec, +) -> Vec +where + S: CommitmentScheme, + S::ParamsVerifier: 'a, + C: Circuit, + P: Prover<'a, S>, + V: Verifier<'a, S>, + VS: VerificationStrategy<'a, S, V>, + TW: TranscriptWriterBuffer, S::Curve, EC>, + TR: TranscriptReadBuffer>, S::Curve, EC>, + EC: EncodedChallenge, + R: RngCore, +{ + for (circuit, instances) in circuits.iter().zip(instances.iter()) { + MockProver::run( + params.k(), + circuit, + instances.iter().map(|instance| instance.to_vec()).collect(), + ) + .unwrap() + .assert_satisfied(); + } + + let proof = { + let mut transcript = TW::init(Vec::new()); + create_proof::( + params, + pk, + circuits, + instances, + &mut rng, + &mut transcript, + ) + .unwrap(); + transcript.finalize() + }; + + let output = { + let params = params.verifier_params(); + let strategy = VS::new(params); + let mut transcript = TR::init(Cursor::new(proof.clone())); + verify_proof(params, pk.get_vk(), strategy, instances, &mut transcript).unwrap() + }; + + finalize(proof, output) +} + +macro_rules! halo2_prepare { + ($dir:expr, $k:expr, $setup:expr, $config:expr, $create_circuit:expr) => {{ + use halo2_proofs::plonk::{keygen_pk, keygen_vk}; + use std::iter; + use $crate::{ + system::halo2::{compile, test::read_or_create_srs}, + util::{arithmetic::GroupEncoding, Itertools}, + }; + + let params = read_or_create_srs($dir, $k, $setup); + + let circuits = iter::repeat_with(|| $create_circuit) + .take($config.num_proof) + .collect_vec(); + + let pk = if $config.zk { + let vk = keygen_vk(¶ms, &circuits[0]).unwrap(); + let pk = keygen_pk(¶ms, vk, &circuits[0]).unwrap(); + pk + } else { + // TODO: Re-enable optional-zk when it's merged in pse/halo2. + unimplemented!() + }; + + let num_instance = circuits[0] + .instances() + .iter() + .map(|instances| instances.len()) + .collect(); + let protocol = compile( + ¶ms, + pk.get_vk(), + $config.with_num_instance(num_instance), + ); + assert_eq!( + protocol.preprocessed.len(), + protocol + .preprocessed + .iter() + .map( + |ec_point| <[u8; 32]>::try_from(ec_point.to_bytes().as_ref().to_vec()).unwrap() + ) + .unique() + .count() + ); + + (params, pk, protocol, circuits) + }}; +} + +macro_rules! halo2_create_snark { + ( + $commitment_scheme:ty, + $prover:ty, + $verifier:ty, + $verification_strategy:ty, + $transcript_read:ty, + $transcript_write:ty, + $encoded_challenge:ty, + $finalize:expr, + $params:expr, + $pk:expr, + $protocol:expr, + $circuits:expr + ) => {{ + use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; + use $crate::{ + loader::halo2::test::Snark, system::halo2::test::create_proof_checked, util::Itertools, + }; + + let instances = $circuits + .iter() + .map(|circuit| circuit.instances()) + .collect_vec(); + let proof = { + #[allow(clippy::needless_borrow)] + let instances = instances + .iter() + .map(|instances| instances.iter().map(Vec::as_slice).collect_vec()) + .collect_vec(); + let instances = instances.iter().map(Vec::as_slice).collect_vec(); + create_proof_checked::< + $commitment_scheme, + _, + $prover, + $verifier, + $verification_strategy, + $transcript_read, + $transcript_write, + $encoded_challenge, + _, + >( + $params, + $pk, + $circuits, + &instances, + &mut ChaCha20Rng::from_seed(Default::default()), + $finalize, + ) + }; + + Snark::new( + $protocol.clone(), + instances.into_iter().flatten().collect_vec(), + proof, + ) + }}; +} + +macro_rules! halo2_native_verify { + ( + $plonk_verifier:ty, + $params:expr, + $protocol:expr, + $instances:expr, + $transcript:expr, + $svk:expr, + $dk:expr + ) => {{ + use halo2_proofs::poly::commitment::ParamsProver; + use $crate::verifier::PlonkVerifier; + + let proof = + <$plonk_verifier>::read_proof($svk, $protocol, $instances, $transcript).unwrap(); + assert!(<$plonk_verifier>::verify($svk, $dk, $protocol, $instances, &proof).unwrap()) + }}; +} + +pub(crate) use {halo2_create_snark, halo2_native_verify, halo2_prepare}; diff --git a/src/protocol/halo2/test/circuit.rs b/src/system/halo2/test/circuit.rs similarity index 67% rename from src/protocol/halo2/test/circuit.rs rename to src/system/halo2/test/circuit.rs index a87cb997..87a005fb 100644 --- a/src/protocol/halo2/test/circuit.rs +++ b/src/system/halo2/test/circuit.rs @@ -1,3 +1,2 @@ pub mod maingate; -pub mod plookup; pub mod standard; diff --git a/src/system/halo2/test/circuit/maingate.rs b/src/system/halo2/test/circuit/maingate.rs new file mode 100644 index 00000000..82d63b5e --- /dev/null +++ b/src/system/halo2/test/circuit/maingate.rs @@ -0,0 +1,111 @@ +use crate::util::arithmetic::{CurveAffine, FieldExt}; +use halo2_proofs::{ + circuit::{floor_planner::V1, Layouter, Value}, + plonk::{Circuit, ConstraintSystem, Error}, +}; +use halo2_wrong_ecc::{ + maingate::{ + MainGate, MainGateConfig, MainGateInstructions, RangeChip, RangeConfig, RangeInstructions, + RegionCtx, + }, + BaseFieldEccChip, EccConfig, +}; +use rand::RngCore; + +#[derive(Clone)] +pub struct MainGateWithRangeConfig { + main_gate_config: MainGateConfig, + range_config: RangeConfig, +} + +impl MainGateWithRangeConfig { + pub fn configure( + meta: &mut ConstraintSystem, + composition_bits: Vec, + overflow_bits: Vec, + ) -> Self { + let main_gate_config = MainGate::::configure(meta); + let range_config = + RangeChip::::configure(meta, &main_gate_config, composition_bits, overflow_bits); + MainGateWithRangeConfig { + main_gate_config, + range_config, + } + } + + pub fn main_gate(&self) -> MainGate { + MainGate::new(self.main_gate_config.clone()) + } + + pub fn range_chip(&self) -> RangeChip { + RangeChip::new(self.range_config.clone()) + } + + pub fn ecc_chip( + &self, + ) -> BaseFieldEccChip { + BaseFieldEccChip::new(EccConfig::new( + self.range_config.clone(), + self.main_gate_config.clone(), + )) + } +} + +#[derive(Clone, Default)] +pub struct MainGateWithRange(Vec); + +impl MainGateWithRange { + pub fn new(inner: Vec) -> Self { + Self(inner) + } + + pub fn rand(mut rng: R) -> Self { + Self::new(vec![F::from(rng.next_u32() as u64)]) + } + + pub fn instances(&self) -> Vec> { + vec![self.0.clone()] + } +} + +impl Circuit for MainGateWithRange { + type Config = MainGateWithRangeConfig; + type FloorPlanner = V1; + + fn without_witnesses(&self) -> Self { + Self(vec![F::zero()]) + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + MainGateWithRangeConfig::configure(meta, vec![8], vec![4, 7]) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + let main_gate = config.main_gate(); + let range_chip = config.range_chip(); + range_chip.load_table(&mut layouter)?; + + let a = layouter.assign_region( + || "", + |region| { + let mut ctx = RegionCtx::new(region, 0); + range_chip.decompose(&mut ctx, Value::known(F::from(u64::MAX)), 8, 64)?; + range_chip.decompose(&mut ctx, Value::known(F::from(u32::MAX as u64)), 8, 39)?; + let a = range_chip.assign(&mut ctx, Value::known(self.0[0]), 8, 68)?; + let b = main_gate.sub_sub_with_constant(&mut ctx, &a, &a, &a, F::from(2))?; + let cond = main_gate.assign_bit(&mut ctx, Value::known(F::one()))?; + main_gate.select(&mut ctx, &a, &b, &cond)?; + + Ok(a) + }, + )?; + + main_gate.expose_public(layouter, a, 0)?; + + Ok(()) + } +} diff --git a/src/protocol/halo2/test/circuit/standard.rs b/src/system/halo2/test/circuit/standard.rs similarity index 69% rename from src/protocol/halo2/test/circuit/standard.rs rename to src/system/halo2/test/circuit/standard.rs index 0773f360..90f30f2b 100644 --- a/src/protocol/halo2/test/circuit/standard.rs +++ b/src/system/halo2/test/circuit/standard.rs @@ -1,7 +1,7 @@ +use crate::util::arithmetic::FieldExt; use halo2_proofs::{ - arithmetic::FieldExt, circuit::{floor_planner::V1, Layouter, Value}, - plonk::{Advice, Any, Circuit, Column, ConstraintSystem, Error, Fixed, Instance}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance}, poly::Rotation, }; use rand::RngCore; @@ -22,39 +22,29 @@ pub struct StandardPlonkConfig { impl StandardPlonkConfig { pub fn configure(meta: &mut ConstraintSystem) -> Self { - let a = meta.advice_column(); - let b = meta.advice_column(); - let c = meta.advice_column(); - - let q_a = meta.fixed_column(); - let q_b = meta.fixed_column(); - let q_c = meta.fixed_column(); - - let q_ab = meta.fixed_column(); - - let constant = meta.fixed_column(); + let [a, b, c] = [(); 3].map(|_| meta.advice_column()); + let [q_a, q_b, q_c, q_ab, constant] = [(); 5].map(|_| meta.fixed_column()); let instance = meta.instance_column(); - meta.enable_equality(a); - meta.enable_equality(b); - meta.enable_equality(c); - - meta.create_gate("", |meta| { - let [a, b, c, q_a, q_b, q_c, q_ab, constant, instance] = [ - a.into(), - b.into(), - c.into(), - q_a.into(), - q_b.into(), - q_c.into(), - q_ab.into(), - constant.into(), - instance.into(), - ] - .map(|column: Column| meta.query_any(column, Rotation::cur())); - - vec![q_a * a.clone() + q_b * b.clone() + q_c * c + q_ab * a * b + constant + instance] - }); + [a, b, c].map(|column| meta.enable_equality(column)); + + meta.create_gate( + "q_a·a + q_b·b + q_c·c + q_ab·a·b + constant + instance = 0", + |meta| { + let [a, b, c] = [a, b, c].map(|column| meta.query_advice(column, Rotation::cur())); + let [q_a, q_b, q_c, q_ab, constant] = [q_a, q_b, q_c, q_ab, constant] + .map(|column| meta.query_fixed(column, Rotation::cur())); + let instance = meta.query_instance(instance, Rotation::cur()); + Some( + q_a * a.clone() + + q_b * b.clone() + + q_c * c + + q_ab * a * b + + constant + + instance, + ) + }, + ); StandardPlonkConfig { a, diff --git a/src/system/halo2/test/kzg.rs b/src/system/halo2/test/kzg.rs new file mode 100644 index 00000000..0b071175 --- /dev/null +++ b/src/system/halo2/test/kzg.rs @@ -0,0 +1,120 @@ +use crate::{ + system::halo2::test::{read_or_create_srs, MainGateWithRange}, + util::arithmetic::{fe_to_limbs, CurveAffine, MultiMillerLoop}, +}; +use halo2_proofs::poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG}; +use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; + +mod native; + +#[cfg(feature = "loader_evm")] +mod evm; + +#[cfg(feature = "loader_halo2")] +mod halo2; + +pub const TESTDATA_DIR: &str = "./src/system/halo2/test/kzg/testdata"; + +pub const LIMBS: usize = 4; +pub const BITS: usize = 68; + +pub fn setup(k: u32) -> ParamsKZG { + ParamsKZG::::setup(k, ChaCha20Rng::from_seed(Default::default())) +} + +pub fn main_gate_with_range_with_mock_kzg_accumulator( +) -> MainGateWithRange { + let srs = read_or_create_srs(TESTDATA_DIR, 1, setup::); + let [g1, s_g1] = [srs.get_g()[0], srs.get_g()[1]].map(|point| point.coordinates().unwrap()); + MainGateWithRange::new( + [*s_g1.x(), *s_g1.y(), *g1.x(), *g1.y()] + .iter() + .cloned() + .flat_map(fe_to_limbs::<_, _, LIMBS, BITS>) + .collect(), + ) +} + +macro_rules! halo2_kzg_config { + ($zk:expr, $num_proof:expr) => { + $crate::system::halo2::Config::kzg() + .set_zk($zk) + .with_num_proof($num_proof) + }; + ($zk:expr, $num_proof:expr, $accumulator_indices:expr) => { + $crate::system::halo2::Config::kzg() + .set_zk($zk) + .with_num_proof($num_proof) + .with_accumulator_indices($accumulator_indices) + }; +} + +macro_rules! halo2_kzg_prepare { + ($k:expr, $config:expr, $create_circuit:expr) => {{ + use halo2_curves::bn256::Bn256; + use $crate::system::halo2::test::{ + halo2_prepare, + kzg::{setup, TESTDATA_DIR}, + }; + + halo2_prepare!(TESTDATA_DIR, $k, setup::, $config, $create_circuit) + }}; +} + +macro_rules! halo2_kzg_create_snark { + ( + $prover:ty, + $verifier:ty, + $transcript_read:ty, + $transcript_write:ty, + $encoded_challenge:ty, + $params:expr, + $pk:expr, + $protocol:expr, + $circuits:expr + ) => {{ + use halo2_proofs::poly::kzg::{commitment::KZGCommitmentScheme, strategy::SingleStrategy}; + use $crate::system::halo2::test::halo2_create_snark; + + halo2_create_snark!( + KZGCommitmentScheme<_>, + $prover, + $verifier, + SingleStrategy<_>, + $transcript_read, + $transcript_write, + $encoded_challenge, + |proof, _| proof, + $params, + $pk, + $protocol, + $circuits + ) + }}; +} + +macro_rules! halo2_kzg_native_verify { + ( + $plonk_verifier:ty, + $params:expr, + $protocol:expr, + $instances:expr, + $transcript:expr + ) => {{ + use $crate::system::halo2::test::halo2_native_verify; + + halo2_native_verify!( + $plonk_verifier, + $params, + $protocol, + $instances, + $transcript, + &$params.get_g()[0].into(), + &($params.g2(), $params.s_g2()).into() + ) + }}; +} + +pub(crate) use { + halo2_kzg_config, halo2_kzg_create_snark, halo2_kzg_native_verify, halo2_kzg_prepare, +}; diff --git a/src/system/halo2/test/kzg/evm.rs b/src/system/halo2/test/kzg/evm.rs new file mode 100644 index 00000000..4ce850c1 --- /dev/null +++ b/src/system/halo2/test/kzg/evm.rs @@ -0,0 +1,138 @@ +use crate::{ + loader::native::NativeLoader, + pcs::kzg::{Bdfg21, Gwc19, Kzg, LimbsEncoding}, + system::halo2::{ + test::{ + kzg::{ + self, halo2_kzg_config, halo2_kzg_create_snark, halo2_kzg_native_verify, + halo2_kzg_prepare, main_gate_with_range_with_mock_kzg_accumulator, BITS, LIMBS, + }, + StandardPlonk, + }, + transcript::evm::{ChallengeEvm, EvmTranscript}, + }, + verifier::Plonk, +}; +use halo2_curves::bn256::{Bn256, G1Affine}; +use halo2_proofs::poly::kzg::multiopen::{ProverGWC, ProverSHPLONK, VerifierGWC, VerifierSHPLONK}; +use paste::paste; +use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; + +macro_rules! halo2_kzg_evm_verify { + ($plonk_verifier:ty, $params:expr, $protocol:expr, $instances:expr, $proof:expr) => {{ + use halo2_curves::bn256::{Bn256, Fq, Fr}; + use halo2_proofs::poly::commitment::ParamsProver; + use std::rc::Rc; + use $crate::{ + loader::evm::{encode_calldata, execute, EvmLoader}, + system::halo2::{ + test::kzg::{BITS, LIMBS}, + transcript::evm::EvmTranscript, + }, + util::Itertools, + verifier::PlonkVerifier, + }; + + let loader = EvmLoader::new::(); + let runtime_code = { + let svk = $params.get_g()[0].into(); + let dk = ($params.g2(), $params.s_g2()).into(); + let mut transcript = EvmTranscript::<_, Rc, _, _>::new(loader.clone()); + let instances = transcript.load_instances( + $instances + .iter() + .map(|instances| instances.len()) + .collect_vec(), + ); + let proof = <$plonk_verifier>::read_proof(&svk, $protocol, &instances, &mut transcript) + .unwrap(); + <$plonk_verifier>::verify(&svk, &dk, $protocol, &instances, &proof).unwrap(); + + loader.runtime_code() + }; + + let (accept, total_cost, costs) = + execute(runtime_code, encode_calldata($instances, &$proof)); + + loader.print_gas_metering(costs); + println!("Total gas cost: {}", total_cost); + + assert!(accept); + }}; +} + +macro_rules! test { + (@ $(#[$attr:meta],)* $prefix:ident, $name:ident, $k:expr, $config:expr, $create_circuit:expr, $prover:ty, $verifier:ty, $plonk_verifier:ty) => { + paste! { + $(#[$attr])* + fn []() { + let (params, pk, protocol, circuits) = halo2_kzg_prepare!( + $k, + $config, + $create_circuit + ); + let snark = halo2_kzg_create_snark!( + $prover, + $verifier, + EvmTranscript, + EvmTranscript, + ChallengeEvm<_>, + ¶ms, + &pk, + &protocol, + &circuits + ); + halo2_kzg_native_verify!( + $plonk_verifier, + params, + &snark.protocol, + &snark.instances, + &mut EvmTranscript::<_, NativeLoader, _, _>::new(snark.proof.as_slice()) + ); + halo2_kzg_evm_verify!( + $plonk_verifier, + params, + &snark.protocol, + &snark.instances, + snark.proof + ); + } + } + }; + ($name:ident, $k:expr, $config:expr, $create_circuit:expr) => { + test!(@ #[test], shplonk, $name, $k, $config, $create_circuit, ProverSHPLONK<_>, VerifierSHPLONK<_>, Plonk, LimbsEncoding>); + test!(@ #[test], plonk, $name, $k, $config, $create_circuit, ProverGWC<_>, VerifierGWC<_>, Plonk, LimbsEncoding>); + }; + ($(#[$attr:meta],)* $name:ident, $k:expr, $config:expr, $create_circuit:expr) => { + test!(@ #[test] $(,#[$attr])*, plonk, $name, $k, $config, $create_circuit, ProverGWC<_>, VerifierGWC<_>, Plonk, LimbsEncoding>); + }; +} + +test!( + zk_standard_plonk_rand, + 9, + halo2_kzg_config!(true, 1), + StandardPlonk::rand(ChaCha20Rng::from_seed(Default::default())) +); +test!( + zk_main_gate_with_range_with_mock_kzg_accumulator, + 9, + halo2_kzg_config!(true, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), + main_gate_with_range_with_mock_kzg_accumulator::() +); +test!( + #[cfg(feature = "loader_halo2")], + #[ignore = "cause it requires 32GB memory to run"], + zk_accumulation_two_snark, + 22, + halo2_kzg_config!(true, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), + kzg::halo2::Accumulation::two_snark() +); +test!( + #[cfg(feature = "loader_halo2")], + #[ignore = "cause it requires 32GB memory to run"], + zk_accumulation_two_snark_with_accumulator, + 22, + halo2_kzg_config!(true, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), + kzg::halo2::Accumulation::two_snark_with_accumulator() +); diff --git a/src/system/halo2/test/kzg/halo2.rs b/src/system/halo2/test/kzg/halo2.rs new file mode 100644 index 00000000..1bd332a0 --- /dev/null +++ b/src/system/halo2/test/kzg/halo2.rs @@ -0,0 +1,372 @@ +use crate::{ + loader, + loader::{ + halo2::test::{Snark, SnarkWitness}, + native::NativeLoader, + }, + pcs::{ + kzg::{ + Bdfg21, Kzg, KzgAccumulator, KzgAs, KzgAsProvingKey, KzgAsVerifyingKey, + KzgSuccinctVerifyingKey, LimbsEncoding, + }, + AccumulationScheme, AccumulationSchemeProver, + }, + system::{ + self, + halo2::{ + test::{ + kzg::{ + halo2_kzg_config, halo2_kzg_create_snark, halo2_kzg_native_verify, + halo2_kzg_prepare, BITS, LIMBS, + }, + MainGateWithRange, MainGateWithRangeConfig, StandardPlonk, + }, + transcript::halo2::ChallengeScalar, + }, + }, + util::{arithmetic::fe_to_limbs, Itertools}, + verifier::{self, PlonkVerifier}, +}; +use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; +use halo2_proofs::{ + circuit::{floor_planner::V1, Layouter, Value}, + plonk, + plonk::Circuit, + poly::{ + commitment::ParamsProver, + kzg::{ + commitment::ParamsKZG, + multiopen::{ProverSHPLONK, VerifierSHPLONK}, + }, + }, + transcript::{Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer}, +}; +use halo2_wrong_ecc::{ + self, + integer::rns::Rns, + maingate::{MainGateInstructions, RangeInstructions, RegionCtx}, +}; +use paste::paste; +use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; +use std::{iter, rc::Rc}; + +const T: usize = 5; +const RATE: usize = 4; +const R_F: usize = 8; +const R_P: usize = 60; + +type BaseFieldEccChip = halo2_wrong_ecc::BaseFieldEccChip; +type Halo2Loader<'a> = loader::halo2::Halo2Loader<'a, G1Affine, BaseFieldEccChip>; +type PoseidonTranscript = + system::halo2::transcript::halo2::PoseidonTranscript; + +type Pcs = Kzg; +type Svk = KzgSuccinctVerifyingKey; +type As = KzgAs; +type AsPk = KzgAsProvingKey; +type AsVk = KzgAsVerifyingKey; +type Plonk = verifier::Plonk>; + +pub fn accumulate<'a>( + svk: &Svk, + loader: &Rc>, + snarks: &[SnarkWitness], + as_vk: &AsVk, + as_proof: Value<&'_ [u8]>, +) -> KzgAccumulator>> { + let assign_instances = |instances: &[Vec>]| { + instances + .iter() + .map(|instances| { + instances + .iter() + .map(|instance| loader.assign_scalar(*instance)) + .collect_vec() + }) + .collect_vec() + }; + + let mut accumulators = snarks + .iter() + .flat_map(|snark| { + let instances = assign_instances(&snark.instances); + let mut transcript = + PoseidonTranscript::, _>::new(loader, snark.proof()); + let proof = + Plonk::read_proof(svk, &snark.protocol, &instances, &mut transcript).unwrap(); + Plonk::succinct_verify(svk, &snark.protocol, &instances, &proof).unwrap() + }) + .collect_vec(); + + let acccumulator = if accumulators.len() > 1 { + let mut transcript = PoseidonTranscript::, _>::new(loader, as_proof); + let proof = As::read_proof(as_vk, &accumulators, &mut transcript).unwrap(); + As::verify(as_vk, &accumulators, &proof).unwrap() + } else { + accumulators.pop().unwrap() + }; + + acccumulator +} + +pub struct Accumulation { + svk: Svk, + snarks: Vec>, + instances: Vec, + as_vk: AsVk, + as_proof: Value>, +} + +impl Accumulation { + pub fn accumulator_indices() -> Vec<(usize, usize)> { + (0..4 * LIMBS).map(|idx| (0, idx)).collect() + } + + pub fn new( + params: &ParamsKZG, + snarks: impl IntoIterator>, + ) -> Self { + let svk = params.get_g()[0].into(); + let snarks = snarks.into_iter().collect_vec(); + + let mut accumulators = snarks + .iter() + .flat_map(|snark| { + let mut transcript = + PoseidonTranscript::::new(snark.proof.as_slice()); + let proof = + Plonk::read_proof(&svk, &snark.protocol, &snark.instances, &mut transcript) + .unwrap(); + Plonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof).unwrap() + }) + .collect_vec(); + + let as_pk = AsPk::new(Some((params.get_g()[0], params.get_g()[1]))); + let (accumulator, as_proof) = if accumulators.len() > 1 { + let mut transcript = PoseidonTranscript::::new(Vec::new()); + let accumulator = As::create_proof( + &as_pk, + &accumulators, + &mut transcript, + ChaCha20Rng::from_seed(Default::default()), + ) + .unwrap(); + (accumulator, Value::known(transcript.finalize())) + } else { + (accumulators.pop().unwrap(), Value::unknown()) + }; + + let KzgAccumulator { lhs, rhs } = accumulator; + let instances = [lhs.x, lhs.y, rhs.x, rhs.y] + .map(fe_to_limbs::<_, _, LIMBS, BITS>) + .concat(); + + Self { + svk, + snarks: snarks.into_iter().map_into().collect(), + instances, + as_vk: as_pk.vk(), + as_proof, + } + } + + pub fn two_snark() -> Self { + let (params, snark1) = { + const K: u32 = 9; + let (params, pk, protocol, circuits) = halo2_kzg_prepare!( + K, + halo2_kzg_config!(true, 1), + StandardPlonk::<_>::rand(ChaCha20Rng::from_seed(Default::default())) + ); + let snark = halo2_kzg_create_snark!( + ProverSHPLONK<_>, + VerifierSHPLONK<_>, + PoseidonTranscript<_, _>, + PoseidonTranscript<_, _>, + ChallengeScalar<_>, + ¶ms, + &pk, + &protocol, + &circuits + ); + (params, snark) + }; + let snark2 = { + const K: u32 = 9; + let (params, pk, protocol, circuits) = halo2_kzg_prepare!( + K, + halo2_kzg_config!(true, 1), + MainGateWithRange::rand(ChaCha20Rng::from_seed(Default::default())) + ); + halo2_kzg_create_snark!( + ProverSHPLONK<_>, + VerifierSHPLONK<_>, + PoseidonTranscript<_, _>, + PoseidonTranscript<_, _>, + ChallengeScalar<_>, + ¶ms, + &pk, + &protocol, + &circuits + ) + }; + Self::new(¶ms, [snark1, snark2]) + } + + pub fn two_snark_with_accumulator() -> Self { + let (params, pk, protocol, circuits) = { + const K: u32 = 22; + halo2_kzg_prepare!( + K, + halo2_kzg_config!(true, 2, Self::accumulator_indices()), + Self::two_snark() + ) + }; + let snark = halo2_kzg_create_snark!( + ProverSHPLONK<_>, + VerifierSHPLONK<_>, + PoseidonTranscript<_, _>, + PoseidonTranscript<_, _>, + ChallengeScalar<_>, + ¶ms, + &pk, + &protocol, + &circuits + ); + Self::new(¶ms, [snark]) + } + + pub fn instances(&self) -> Vec> { + vec![self.instances.clone()] + } + + pub fn as_proof(&self) -> Value<&[u8]> { + self.as_proof.as_ref().map(Vec::as_slice) + } +} + +impl Circuit for Accumulation { + type Config = MainGateWithRangeConfig; + type FloorPlanner = V1; + + fn without_witnesses(&self) -> Self { + Self { + svk: self.svk, + snarks: self + .snarks + .iter() + .map(SnarkWitness::without_witnesses) + .collect(), + instances: Vec::new(), + as_vk: self.as_vk, + as_proof: Value::unknown(), + } + } + + fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { + MainGateWithRangeConfig::configure( + meta, + vec![BITS / LIMBS], + Rns::::construct().overflow_lengths(), + ) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), plonk::Error> { + let main_gate = config.main_gate(); + let range_chip = config.range_chip(); + + range_chip.load_table(&mut layouter)?; + + let (lhs, rhs) = layouter.assign_region( + || "", + |region| { + let ctx = RegionCtx::new(region, 0); + + let ecc_chip = config.ecc_chip(); + let loader = Halo2Loader::new(ecc_chip, ctx); + let KzgAccumulator { lhs, rhs } = accumulate( + &self.svk, + &loader, + &self.snarks, + &self.as_vk, + self.as_proof(), + ); + + loader.print_row_metering(); + println!("Total row cost: {}", loader.ctx().offset()); + + Ok((lhs.assigned(), rhs.assigned())) + }, + )?; + + for (limb, row) in iter::empty() + .chain(lhs.x().limbs()) + .chain(lhs.y().limbs()) + .chain(rhs.x().limbs()) + .chain(rhs.y().limbs()) + .zip(0..) + { + main_gate.expose_public(layouter.namespace(|| ""), limb.into(), row)?; + } + + Ok(()) + } +} + +macro_rules! test { + (@ $(#[$attr:meta],)* $name:ident, $k:expr, $config:expr, $create_circuit:expr) => { + paste! { + $(#[$attr])* + fn []() { + let (params, pk, protocol, circuits) = halo2_kzg_prepare!( + $k, + $config, + $create_circuit + ); + let snark = halo2_kzg_create_snark!( + ProverSHPLONK<_>, + VerifierSHPLONK<_>, + Blake2bWrite<_, _, _>, + Blake2bRead<_, _, _>, + Challenge255<_>, + ¶ms, + &pk, + &protocol, + &circuits + ); + halo2_kzg_native_verify!( + Plonk, + params, + &snark.protocol, + &snark.instances, + &mut Blake2bRead::<_, G1Affine, _>::init(snark.proof.as_slice()) + ); + } + } + }; + ($name:ident, $k:expr, $config:expr, $create_circuit:expr) => { + test!(@ #[test], $name, $k, $config, $create_circuit); + }; + ($(#[$attr:meta],)* $name:ident, $k:expr, $config:expr, $create_circuit:expr) => { + test!(@ #[test] $(,#[$attr])*, $name, $k, $config, $create_circuit); + }; +} + +test!( + #[ignore = "cause it requires 32GB memory to run"], + zk_accumulation_two_snark, + 22, + halo2_kzg_config!(true, 1, Accumulation::accumulator_indices()), + Accumulation::two_snark() +); +test!( + #[ignore = "cause it requires 32GB memory to run"], + zk_accumulation_two_snark_with_accumulator, + 22, + halo2_kzg_config!(true, 1, Accumulation::accumulator_indices()), + Accumulation::two_snark_with_accumulator() +); diff --git a/src/protocol/halo2/test/kzg/native.rs b/src/system/halo2/test/kzg/native.rs similarity index 50% rename from src/protocol/halo2/test/kzg/native.rs rename to src/system/halo2/test/kzg/native.rs index 4273e7d0..e52ceb38 100644 --- a/src/protocol/halo2/test/kzg/native.rs +++ b/src/system/halo2/test/kzg/native.rs @@ -1,61 +1,56 @@ use crate::{ - collect_slice, halo2_kzg_config, halo2_kzg_create_snark, halo2_kzg_native_verify, - halo2_kzg_prepare, - protocol::halo2::test::{ + pcs::kzg::{Bdfg21, Gwc19, Kzg, LimbsEncoding}, + system::halo2::test::{ kzg::{ - main_gate_with_plookup_with_mock_kzg_accumulator, - main_gate_with_range_with_mock_kzg_accumulator, LIMBS, + halo2_kzg_config, halo2_kzg_create_snark, halo2_kzg_native_verify, halo2_kzg_prepare, + main_gate_with_range_with_mock_kzg_accumulator, BITS, LIMBS, }, StandardPlonk, }, - scheme::kzg::{PlonkAccumulationScheme, ShplonkAccumulationScheme}, + verifier::Plonk, }; -use halo2_curves::bn256::G1Affine; +use halo2_curves::bn256::{Bn256, G1Affine}; use halo2_proofs::{ - poly::kzg::{ - multiopen::{ProverGWC, ProverSHPLONK, VerifierGWC, VerifierSHPLONK}, - strategy::AccumulatorStrategy, - }, + poly::kzg::multiopen::{ProverGWC, ProverSHPLONK, VerifierGWC, VerifierSHPLONK}, transcript::{Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer}, }; use paste::paste; use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; macro_rules! test { - (@ $prefix:ident, $name:ident, $k:expr, $config:expr, $create_cirucit:expr, $prover:ty, $verifier:ty, $scheme:ty) => { + (@ $prefix:ident, $name:ident, $k:expr, $config:expr, $create_cirucit:expr, $prover:ty, $verifier:ty, $plonk_verifier:ty) => { paste! { #[test] - fn []() { + fn []() { let (params, pk, protocol, circuits) = halo2_kzg_prepare!( $k, $config, $create_cirucit ); let snark = halo2_kzg_create_snark!( - ¶ms, - &pk, - &protocol, - &circuits, $prover, $verifier, - AccumulatorStrategy<_>, Blake2bWrite<_, _, _>, Blake2bRead<_, _, _>, - Challenge255<_> + Challenge255<_>, + ¶ms, + &pk, + &protocol, + &circuits ); halo2_kzg_native_verify!( + $plonk_verifier, params, &snark.protocol, - snark.statements, - $scheme, + &snark.instances, &mut Blake2bRead::<_, G1Affine, _>::init(snark.proof.as_slice()) ); } } }; ($name:ident, $k:expr, $config:expr, $create_cirucit:expr) => { - test!(@ shplonk, $name, $k, $config, $create_cirucit, ProverSHPLONK<_>, VerifierSHPLONK<_>, ShplonkAccumulationScheme); - test!(@ plonk, $name, $k, $config, $create_cirucit, ProverGWC<_>, VerifierGWC<_>, PlonkAccumulationScheme); + test!(@ shplonk, $name, $k, $config, $create_cirucit, ProverSHPLONK<_>, VerifierSHPLONK<_>, Plonk, LimbsEncoding>); + test!(@ plonk, $name, $k, $config, $create_cirucit, ProverGWC<_>, VerifierGWC<_>, Plonk, LimbsEncoding>); } } @@ -63,7 +58,7 @@ test!( zk_standard_plonk_rand, 9, halo2_kzg_config!(true, 2), - StandardPlonk::<_>::rand(ChaCha20Rng::from_seed(Default::default())) + StandardPlonk::rand(ChaCha20Rng::from_seed(Default::default())) ); test!( zk_main_gate_with_range_with_mock_kzg_accumulator, @@ -71,21 +66,3 @@ test!( halo2_kzg_config!(true, 2, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), main_gate_with_range_with_mock_kzg_accumulator::() ); -test!( - standard_plonk_rand, - 9, - halo2_kzg_config!(false, 2), - StandardPlonk::<_>::rand(ChaCha20Rng::from_seed(Default::default())) -); -test!( - main_gate_with_range_with_mock_kzg_accumulator, - 9, - halo2_kzg_config!(false, 2, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), - main_gate_with_range_with_mock_kzg_accumulator::() -); -test!( - main_gate_with_plookup_with_mock_kzg_accumulator, - 9, - halo2_kzg_config!(false, 1, (0..4 * LIMBS).map(|idx| (0, idx)).collect()), - main_gate_with_plookup_with_mock_kzg_accumulator::(9) -); diff --git a/src/system/halo2/transcript.rs b/src/system/halo2/transcript.rs new file mode 100644 index 00000000..2200bbf4 --- /dev/null +++ b/src/system/halo2/transcript.rs @@ -0,0 +1,82 @@ +use crate::{ + loader::native::{self, NativeLoader}, + util::{ + arithmetic::CurveAffine, + transcript::{Transcript, TranscriptRead, TranscriptWrite}, + }, + Error, +}; +use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite, Challenge255}; +use std::io::{Read, Write}; + +#[cfg(feature = "loader_evm")] +pub mod evm; + +#[cfg(feature = "loader_halo2")] +pub mod halo2; + +impl Transcript for Blake2bRead> { + fn loader(&self) -> &NativeLoader { + &native::LOADER + } + + fn squeeze_challenge(&mut self) -> C::Scalar { + *halo2_proofs::transcript::Transcript::squeeze_challenge_scalar::(self) + } + + fn common_ec_point(&mut self, ec_point: &C) -> Result<(), Error> { + halo2_proofs::transcript::Transcript::common_point(self, *ec_point) + .map_err(|err| Error::Transcript(err.kind(), err.to_string())) + } + + fn common_scalar(&mut self, scalar: &C::Scalar) -> Result<(), Error> { + halo2_proofs::transcript::Transcript::common_scalar(self, *scalar) + .map_err(|err| Error::Transcript(err.kind(), err.to_string())) + } +} + +impl TranscriptRead + for Blake2bRead> +{ + fn read_scalar(&mut self) -> Result { + halo2_proofs::transcript::TranscriptRead::read_scalar(self) + .map_err(|err| Error::Transcript(err.kind(), err.to_string())) + } + + fn read_ec_point(&mut self) -> Result { + halo2_proofs::transcript::TranscriptRead::read_point(self) + .map_err(|err| Error::Transcript(err.kind(), err.to_string())) + } +} + +impl Transcript for Blake2bWrite> { + fn loader(&self) -> &NativeLoader { + &native::LOADER + } + + fn squeeze_challenge(&mut self) -> C::Scalar { + *halo2_proofs::transcript::Transcript::squeeze_challenge_scalar::(self) + } + + fn common_ec_point(&mut self, ec_point: &C) -> Result<(), Error> { + halo2_proofs::transcript::Transcript::common_point(self, *ec_point) + .map_err(|err| Error::Transcript(err.kind(), err.to_string())) + } + + fn common_scalar(&mut self, scalar: &C::Scalar) -> Result<(), Error> { + halo2_proofs::transcript::Transcript::common_scalar(self, *scalar) + .map_err(|err| Error::Transcript(err.kind(), err.to_string())) + } +} + +impl TranscriptWrite for Blake2bWrite, C, Challenge255> { + fn write_scalar(&mut self, scalar: C::Scalar) -> Result<(), Error> { + halo2_proofs::transcript::TranscriptWrite::write_scalar(self, scalar) + .map_err(|err| Error::Transcript(err.kind(), err.to_string())) + } + + fn write_ec_point(&mut self, ec_point: C) -> Result<(), Error> { + halo2_proofs::transcript::TranscriptWrite::write_point(self, ec_point) + .map_err(|err| Error::Transcript(err.kind(), err.to_string())) + } +} diff --git a/src/system/halo2/transcript/evm.rs b/src/system/halo2/transcript/evm.rs new file mode 100644 index 00000000..77aca5cf --- /dev/null +++ b/src/system/halo2/transcript/evm.rs @@ -0,0 +1,400 @@ +use crate::{ + loader::{ + evm::{loader::Value, u256_to_fe, EcPoint, EvmLoader, MemoryChunk, Scalar}, + native::{self, NativeLoader}, + Loader, + }, + util::{ + arithmetic::{Coordinates, CurveAffine, PrimeField}, + hash::{Digest, Keccak256}, + transcript::{Transcript, TranscriptRead}, + Itertools, + }, + Error, +}; +use ethereum_types::U256; +use halo2_proofs::transcript::EncodedChallenge; +use std::{ + io::{self, Read, Write}, + iter, + marker::PhantomData, + rc::Rc, +}; +pub struct EvmTranscript, S, B> { + loader: L, + stream: S, + buf: B, + _marker: PhantomData, +} + +impl EvmTranscript, usize, MemoryChunk> +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + pub fn new(loader: Rc) -> Self { + let ptr = loader.allocate(0x20); + assert_eq!(ptr, 0); + let mut buf = MemoryChunk::new(ptr); + buf.extend(0x20); + Self { + loader, + stream: 0, + buf, + _marker: PhantomData, + } + } + + pub fn load_instances(&mut self, num_instance: Vec) -> Vec> { + num_instance + .into_iter() + .map(|len| { + iter::repeat_with(|| { + let scalar = self.loader.calldataload_scalar(self.stream); + self.stream += 0x20; + scalar + }) + .take(len) + .collect_vec() + }) + .collect() + } +} + +impl Transcript> for EvmTranscript, usize, MemoryChunk> +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn loader(&self) -> &Rc { + &self.loader + } + + fn squeeze_challenge(&mut self) -> Scalar { + let len = if self.buf.len() == 0x20 { + assert_eq!(self.loader.ptr(), self.buf.end()); + self.loader + .code_mut() + .push(1) + .push(self.buf.end()) + .mstore8(); + 0x21 + } else { + self.buf.len() + }; + let hash_ptr = self.loader.keccak256(self.buf.ptr(), len); + + let challenge_ptr = self.loader.allocate(0x20); + let dup_hash_ptr = self.loader.allocate(0x20); + self.loader + .code_mut() + .push(hash_ptr) + .mload() + .push(self.loader.scalar_modulus()) + .dup(1) + .r#mod() + .push(challenge_ptr) + .mstore() + .push(dup_hash_ptr) + .mstore(); + + self.buf.reset(dup_hash_ptr); + self.buf.extend(0x20); + + self.loader.scalar(Value::Memory(challenge_ptr)) + } + + fn common_ec_point(&mut self, ec_point: &EcPoint) -> Result<(), Error> { + if let Value::Memory(ptr) = ec_point.value() { + assert_eq!(self.buf.end(), ptr); + self.buf.extend(0x40); + } else { + unreachable!() + } + Ok(()) + } + + fn common_scalar(&mut self, scalar: &Scalar) -> Result<(), Error> { + match scalar.value() { + Value::Constant(_) if self.buf.ptr() == 0 => { + self.loader.copy_scalar(scalar, self.buf.ptr()); + } + Value::Memory(ptr) => { + assert_eq!(self.buf.end(), ptr); + self.buf.extend(0x20); + } + _ => unreachable!(), + } + Ok(()) + } +} + +impl TranscriptRead> for EvmTranscript, usize, MemoryChunk> +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn read_scalar(&mut self) -> Result { + let scalar = self.loader.calldataload_scalar(self.stream); + self.stream += 0x20; + self.common_scalar(&scalar)?; + Ok(scalar) + } + + fn read_ec_point(&mut self) -> Result { + let ec_point = self.loader.calldataload_ec_point(self.stream); + self.stream += 0x40; + self.common_ec_point(&ec_point)?; + Ok(ec_point) + } +} + +impl EvmTranscript> +where + C: CurveAffine, +{ + pub fn new(stream: S) -> Self { + Self { + loader: NativeLoader, + stream, + buf: Vec::new(), + _marker: PhantomData, + } + } +} + +impl Transcript for EvmTranscript> +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn loader(&self) -> &NativeLoader { + &native::LOADER + } + + fn squeeze_challenge(&mut self) -> C::Scalar { + let data = self + .buf + .iter() + .cloned() + .chain(if self.buf.len() == 0x20 { + Some(1) + } else { + None + }) + .collect_vec(); + let hash: [u8; 32] = Keccak256::digest(data).into(); + self.buf = hash.to_vec(); + u256_to_fe(U256::from_big_endian(hash.as_slice())) + } + + fn common_ec_point(&mut self, ec_point: &C) -> Result<(), Error> { + let coordinates = + Option::>::from(ec_point.coordinates()).ok_or_else(|| { + Error::Transcript( + io::ErrorKind::Other, + "Cannot write points at infinity to the transcript".to_string(), + ) + })?; + + [coordinates.x(), coordinates.y()].map(|coordinate| { + self.buf + .extend(coordinate.to_repr().as_ref().iter().rev().cloned()); + }); + + Ok(()) + } + + fn common_scalar(&mut self, scalar: &C::Scalar) -> Result<(), Error> { + self.buf.extend(scalar.to_repr().as_ref().iter().rev()); + + Ok(()) + } +} + +impl TranscriptRead for EvmTranscript> +where + C: CurveAffine, + C::Scalar: PrimeField, + S: Read, +{ + fn read_scalar(&mut self) -> Result { + let mut data = [0; 32]; + self.stream + .read_exact(data.as_mut()) + .map_err(|err| Error::Transcript(err.kind(), err.to_string()))?; + data.reverse(); + let scalar = C::Scalar::from_repr_vartime(data).ok_or_else(|| { + Error::Transcript( + io::ErrorKind::Other, + "Invalid scalar encoding in proof".to_string(), + ) + })?; + self.common_scalar(&scalar)?; + Ok(scalar) + } + + fn read_ec_point(&mut self) -> Result { + let [mut x, mut y] = [::Repr::default(); 2]; + for repr in [&mut x, &mut y] { + self.stream + .read_exact(repr.as_mut()) + .map_err(|err| Error::Transcript(err.kind(), err.to_string()))?; + repr.as_mut().reverse(); + } + let x = Option::from(::from_repr(x)); + let y = Option::from(::from_repr(y)); + let ec_point = x + .zip(y) + .and_then(|(x, y)| Option::from(C::from_xy(x, y))) + .ok_or_else(|| { + Error::Transcript( + io::ErrorKind::Other, + "Invalid elliptic curve point encoding in proof".to_string(), + ) + })?; + self.common_ec_point(&ec_point)?; + Ok(ec_point) + } +} + +impl EvmTranscript> +where + C: CurveAffine, + S: Write, +{ + pub fn stream_mut(&mut self) -> &mut S { + &mut self.stream + } + + pub fn finalize(self) -> S { + self.stream + } +} + +pub struct ChallengeEvm(C::Scalar) +where + C: CurveAffine, + C::Scalar: PrimeField; + +impl EncodedChallenge for ChallengeEvm +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + type Input = [u8; 32]; + + fn new(challenge_input: &[u8; 32]) -> Self { + ChallengeEvm(u256_to_fe(U256::from_big_endian(challenge_input))) + } + + fn get_scalar(&self) -> C::Scalar { + self.0 + } +} + +impl halo2_proofs::transcript::Transcript> + for EvmTranscript> +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn squeeze_challenge(&mut self) -> ChallengeEvm { + ChallengeEvm(Transcript::squeeze_challenge(self)) + } + + fn common_point(&mut self, ec_point: C) -> io::Result<()> { + match Transcript::common_ec_point(self, &ec_point) { + Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), + Err(_) => unreachable!(), + _ => Ok(()), + } + } + + fn common_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { + match Transcript::common_scalar(self, &scalar) { + Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), + Err(_) => unreachable!(), + _ => Ok(()), + } + } +} + +impl halo2_proofs::transcript::TranscriptRead> + for EvmTranscript> +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn read_point(&mut self) -> io::Result { + match TranscriptRead::read_ec_point(self) { + Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), + Err(_) => unreachable!(), + Ok(value) => Ok(value), + } + } + + fn read_scalar(&mut self) -> io::Result { + match TranscriptRead::read_scalar(self) { + Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), + Err(_) => unreachable!(), + Ok(value) => Ok(value), + } + } +} + +impl halo2_proofs::transcript::TranscriptReadBuffer> + for EvmTranscript> +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn init(reader: R) -> Self { + Self::new(reader) + } +} + +impl halo2_proofs::transcript::TranscriptWrite> + for EvmTranscript> +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn write_point(&mut self, ec_point: C) -> io::Result<()> { + halo2_proofs::transcript::Transcript::>::common_point(self, ec_point)?; + let coords: Coordinates = Option::from(ec_point.coordinates()).ok_or_else(|| { + io::Error::new( + io::ErrorKind::Other, + "Cannot write points at infinity to the transcript", + ) + })?; + let mut x = coords.x().to_repr(); + let mut y = coords.y().to_repr(); + x.as_mut().reverse(); + y.as_mut().reverse(); + self.stream_mut().write_all(x.as_ref())?; + self.stream_mut().write_all(y.as_ref()) + } + + fn write_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { + halo2_proofs::transcript::Transcript::>::common_scalar(self, scalar)?; + let mut data = scalar.to_repr(); + data.as_mut().reverse(); + self.stream_mut().write_all(data.as_ref()) + } +} + +impl halo2_proofs::transcript::TranscriptWriterBuffer> + for EvmTranscript> +where + C: CurveAffine, + C::Scalar: PrimeField, +{ + fn init(writer: W) -> Self { + Self::new(writer) + } + + fn finalize(self) -> W { + self.finalize() + } +} diff --git a/src/system/halo2/transcript/halo2.rs b/src/system/halo2/transcript/halo2.rs new file mode 100644 index 00000000..43701bd7 --- /dev/null +++ b/src/system/halo2/transcript/halo2.rs @@ -0,0 +1,439 @@ +use crate::{ + loader::{ + halo2::{self, EcPoint, EccInstructions, Halo2Loader, IntegerInstructions, Scalar}, + native::{self, NativeLoader}, + Loader, ScalarLoader, + }, + util::{ + arithmetic::{fe_from_big, fe_to_big, CurveAffine, FieldExt, PrimeField}, + hash::Poseidon, + transcript::{Transcript, TranscriptRead, TranscriptWrite}, + Itertools, + }, + Error, +}; +use halo2_proofs::{ + circuit::{AssignedCell, Value}, + transcript::EncodedChallenge, +}; +use std::{ + io::{self, Read, Write}, + marker::PhantomData, + rc::Rc, +}; + +pub trait EncodeNative<'a, C: CurveAffine, N: FieldExt>: EccInstructions<'a, C> { + fn encode_native( + &self, + ctx: &mut Self::Context, + ec_point: &Self::AssignedEcPoint, + ) -> Result>, Error>; +} + +pub struct PoseidonTranscript< + C: CurveAffine, + L: Loader, + S, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, +> { + loader: L, + stream: S, + buf: Poseidon>::LoadedScalar, T, RATE>, + _marker: PhantomData, +} + +impl< + 'a, + C: CurveAffine, + R: Read, + EccChip: EncodeNative<'a, C, C::Scalar, AssignedScalar = AssignedCell>, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + > PoseidonTranscript>, Value, T, RATE, R_F, R_P> +{ + pub fn new(loader: &Rc>, stream: Value) -> Self { + Self { + loader: loader.clone(), + stream, + buf: Poseidon::new(loader.clone(), R_F, R_P), + _marker: PhantomData, + } + } +} + +impl< + 'a, + C: CurveAffine, + R: Read, + EccChip: EncodeNative<'a, C, C::Scalar, AssignedScalar = AssignedCell>, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + > Transcript>> + for PoseidonTranscript>, Value, T, RATE, R_F, R_P> +{ + fn loader(&self) -> &Rc> { + &self.loader + } + + fn squeeze_challenge(&mut self) -> Scalar<'a, C, EccChip> { + self.buf.squeeze() + } + + fn common_scalar(&mut self, scalar: &Scalar<'a, C, EccChip>) -> Result<(), Error> { + self.buf.update(&[scalar.clone()]); + Ok(()) + } + + fn common_ec_point(&mut self, ec_point: &EcPoint<'a, C, EccChip>) -> Result<(), Error> { + let encoded = self + .loader + .ecc_chip() + .encode_native(&mut self.loader.ctx_mut(), &ec_point.assigned()) + .map(|encoded| { + encoded + .into_iter() + .map(|encoded| self.loader.scalar(halo2::loader::Value::Assigned(encoded))) + .collect_vec() + }) + .map_err(|_| Error::Transcript(io::ErrorKind::Other, "".to_string()))?; + self.buf.update(&encoded); + Ok(()) + } +} + +impl< + 'a, + C: CurveAffine, + R: Read, + EccChip: EncodeNative<'a, C, C::Scalar, AssignedScalar = AssignedCell>, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + > TranscriptRead>> + for PoseidonTranscript>, Value, T, RATE, R_F, R_P> +{ + fn read_scalar(&mut self) -> Result, Error> { + let scalar = self.stream.as_mut().and_then(|stream| { + let mut data = ::Repr::default(); + if stream.read_exact(data.as_mut()).is_err() { + return Value::unknown(); + } + Option::::from(C::Scalar::from_repr(data)) + .map(|scalar| Value::known(self.loader.scalar_chip().integer(scalar))) + .unwrap_or_else(Value::unknown) + }); + let scalar = self.loader.assign_scalar(scalar); + self.common_scalar(&scalar)?; + Ok(scalar) + } + + fn read_ec_point(&mut self) -> Result, Error> { + let ec_point = self.stream.as_mut().and_then(|stream| { + let mut compressed = C::Repr::default(); + if stream.read_exact(compressed.as_mut()).is_err() { + return Value::unknown(); + } + Option::::from(C::from_bytes(&compressed)) + .map(Value::known) + .unwrap_or_else(Value::unknown) + }); + let ec_point = self.loader.assign_ec_point(ec_point); + self.common_ec_point(&ec_point)?; + Ok(ec_point) + } +} + +// + +impl + PoseidonTranscript +{ + pub fn new(stream: S) -> Self { + Self { + loader: NativeLoader, + stream, + buf: Poseidon::new(NativeLoader, R_F, R_P), + _marker: PhantomData, + } + } +} + +impl + Transcript for PoseidonTranscript +{ + fn loader(&self) -> &NativeLoader { + &native::LOADER + } + + fn squeeze_challenge(&mut self) -> C::Scalar { + self.buf.squeeze() + } + + fn common_scalar(&mut self, scalar: &C::Scalar) -> Result<(), Error> { + self.buf.update(&[*scalar]); + Ok(()) + } + + fn common_ec_point(&mut self, ec_point: &C) -> Result<(), Error> { + let encoded: Vec<_> = Option::from(ec_point.coordinates().map(|coordinates| { + [coordinates.x(), coordinates.y()] + .into_iter() + .map(|fe| fe_from_big(fe_to_big(*fe))) + .collect_vec() + })) + .ok_or_else(|| { + Error::Transcript( + io::ErrorKind::Other, + "Invalid elliptic curve point encoding in proof".to_string(), + ) + })?; + self.buf.update(&encoded); + Ok(()) + } +} + +impl< + C: CurveAffine, + R: Read, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + > TranscriptRead + for PoseidonTranscript +{ + fn read_scalar(&mut self) -> Result { + let mut data = ::Repr::default(); + self.stream + .read_exact(data.as_mut()) + .map_err(|err| Error::Transcript(err.kind(), err.to_string()))?; + let scalar = C::Scalar::from_repr_vartime(data).ok_or_else(|| { + Error::Transcript( + io::ErrorKind::Other, + "Invalid scalar encoding in proof".to_string(), + ) + })?; + self.common_scalar(&scalar)?; + Ok(scalar) + } + + fn read_ec_point(&mut self) -> Result { + let mut data = C::Repr::default(); + self.stream + .read_exact(data.as_mut()) + .map_err(|err| Error::Transcript(err.kind(), err.to_string()))?; + let ec_point = Option::::from(C::from_bytes(&data)).ok_or_else(|| { + Error::Transcript( + io::ErrorKind::Other, + "Invalid elliptic curve point encoding in proof".to_string(), + ) + })?; + self.common_ec_point(&ec_point)?; + Ok(ec_point) + } +} + +impl< + C: CurveAffine, + W: Write, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + > PoseidonTranscript +{ + pub fn stream_mut(&mut self) -> &mut W { + &mut self.stream + } + + pub fn finalize(self) -> W { + self.stream + } +} + +impl< + C: CurveAffine, + W: Write, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + > TranscriptWrite for PoseidonTranscript +{ + fn write_scalar(&mut self, scalar: C::Scalar) -> Result<(), Error> { + self.common_scalar(&scalar)?; + let data = scalar.to_repr(); + self.stream_mut().write_all(data.as_ref()).map_err(|err| { + Error::Transcript( + err.kind(), + "Failed to write scalar to transcript".to_string(), + ) + }) + } + + fn write_ec_point(&mut self, ec_point: C) -> Result<(), Error> { + self.common_ec_point(&ec_point)?; + let data = ec_point.to_bytes(); + self.stream_mut().write_all(data.as_ref()).map_err(|err| { + Error::Transcript( + err.kind(), + "Failed to write elliptic curve to transcript".to_string(), + ) + }) + } +} + +pub struct ChallengeScalar(C::Scalar); + +impl EncodedChallenge for ChallengeScalar { + type Input = C::Scalar; + + fn new(challenge_input: &C::Scalar) -> Self { + ChallengeScalar(*challenge_input) + } + + fn get_scalar(&self) -> C::Scalar { + self.0 + } +} + +impl + halo2_proofs::transcript::Transcript> + for PoseidonTranscript +{ + fn squeeze_challenge(&mut self) -> ChallengeScalar { + ChallengeScalar::new(&Transcript::squeeze_challenge(self)) + } + + fn common_point(&mut self, ec_point: C) -> io::Result<()> { + match Transcript::common_ec_point(self, &ec_point) { + Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), + Err(_) => unreachable!(), + _ => Ok(()), + } + } + + fn common_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { + match Transcript::common_scalar(self, &scalar) { + Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), + Err(_) => unreachable!(), + _ => Ok(()), + } + } +} + +impl< + C: CurveAffine, + R: Read, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + > halo2_proofs::transcript::TranscriptRead> + for PoseidonTranscript +{ + fn read_point(&mut self) -> io::Result { + match TranscriptRead::read_ec_point(self) { + Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), + Err(_) => unreachable!(), + Ok(value) => Ok(value), + } + } + + fn read_scalar(&mut self) -> io::Result { + match TranscriptRead::read_scalar(self) { + Err(Error::Transcript(kind, msg)) => Err(io::Error::new(kind, msg)), + Err(_) => unreachable!(), + Ok(value) => Ok(value), + } + } +} + +impl< + C: CurveAffine, + R: Read, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + > halo2_proofs::transcript::TranscriptReadBuffer> + for PoseidonTranscript +{ + fn init(reader: R) -> Self { + Self::new(reader) + } +} + +impl< + C: CurveAffine, + W: Write, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + > halo2_proofs::transcript::TranscriptWrite> + for PoseidonTranscript +{ + fn write_point(&mut self, ec_point: C) -> io::Result<()> { + halo2_proofs::transcript::Transcript::>::common_point( + self, ec_point, + )?; + let data = ec_point.to_bytes(); + self.stream_mut().write_all(data.as_ref()) + } + + fn write_scalar(&mut self, scalar: C::Scalar) -> io::Result<()> { + halo2_proofs::transcript::Transcript::>::common_scalar(self, scalar)?; + let data = scalar.to_repr(); + self.stream_mut().write_all(data.as_ref()) + } +} + +impl< + C: CurveAffine, + W: Write, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + > halo2_proofs::transcript::TranscriptWriterBuffer> + for PoseidonTranscript +{ + fn init(writer: W) -> Self { + Self::new(writer) + } + + fn finalize(self) -> W { + self.finalize() + } +} + +mod halo2_wrong { + use crate::system::halo2::transcript::halo2::EncodeNative; + use halo2_curves::CurveAffine; + use halo2_proofs::circuit::AssignedCell; + use halo2_wrong_ecc::BaseFieldEccChip; + + impl<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize> EncodeNative<'a, C, C::Scalar> + for BaseFieldEccChip + { + fn encode_native( + &self, + _: &mut Self::Context, + ec_point: &Self::AssignedEcPoint, + ) -> Result>, crate::Error> { + Ok(vec![ + ec_point.x().native().clone(), + ec_point.y().native().clone(), + ]) + } + } +} diff --git a/src/util.rs b/src/util.rs index eb38e56a..3d5d0d79 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,34 +1,7 @@ -mod arithmetic; -mod expression; -mod transcript; +pub mod arithmetic; +pub mod hash; +pub mod msm; +pub mod protocol; +pub mod transcript; -pub use arithmetic::{ - batch_invert, batch_invert_and_mul, fe_from_limbs, fe_to_limbs, BatchInvert, Curve, Domain, - Field, FieldOps, Fraction, Group, GroupEncoding, GroupOps, PrimeCurveAffine, PrimeField, - Rotation, UncompressedEncoding, -}; -pub use expression::{CommonPolynomial, CommonPolynomialEvaluation, Expression, Query}; -pub use transcript::{Transcript, TranscriptRead}; - -pub use itertools::{EitherOrBoth, Itertools}; - -#[macro_export] -macro_rules! collect_slice { - ($vec:ident) => { - use $crate::util::Itertools; - - let $vec = $vec.iter().map(|vec| vec.as_slice()).collect_vec(); - }; - ($vec:ident, 2) => { - use $crate::util::Itertools; - - let $vec = $vec - .iter() - .map(|vec| { - collect_slice!(vec); - vec - }) - .collect_vec(); - let $vec = $vec.iter().map(|vec| vec.as_slice()).collect_vec(); - }; -} +pub(crate) use itertools::Itertools; diff --git a/src/util/arithmetic.rs b/src/util/arithmetic.rs index 0ba1929b..b9a5c7c6 100644 --- a/src/util/arithmetic.rs +++ b/src/util/arithmetic.rs @@ -8,43 +8,34 @@ use std::{ ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; -pub use ff::{BatchInvert, Field, PrimeField}; -pub use group::{prime::PrimeCurveAffine, Curve, Group, GroupEncoding}; +pub use halo2_curves::{ + group::{ + ff::{BatchInvert, Field, PrimeField}, + prime::PrimeCurveAffine, + Curve, Group, GroupEncoding, + }, + pairing::MillerLoopResult, + Coordinates, CurveAffine, CurveExt, FieldExt, +}; + +pub trait MultiMillerLoop: halo2_curves::pairing::MultiMillerLoop + Debug {} + +impl MultiMillerLoop for M {} -pub trait GroupOps: +pub trait FieldOps: Sized + + Neg + Add + Sub - + Neg + + Mul + for<'a> Add<&'a Self, Output = Self> + for<'a> Sub<&'a Self, Output = Self> + + for<'a> Mul<&'a Self, Output = Self> + AddAssign + SubAssign + + MulAssign + for<'a> AddAssign<&'a Self> + for<'a> SubAssign<&'a Self> -{ -} - -impl GroupOps for T where - T: Sized - + Add - + Sub - + Neg - + for<'a> Add<&'a Self, Output = Self> - + for<'a> Sub<&'a Self, Output = Self> - + AddAssign - + SubAssign - + for<'a> AddAssign<&'a Self> - + for<'a> SubAssign<&'a Self> -{ -} - -pub trait FieldOps: - Sized - + GroupOps - + Mul - + for<'a> Mul<&'a Self, Output = Self> - + MulAssign + for<'a> MulAssign<&'a Self> { fn invert(&self) -> Option; @@ -78,12 +69,13 @@ pub fn batch_invert(values: &mut [F]) { batch_invert_and_mul(values, &F::one()) } -pub trait UncompressedEncoding: Sized { - type Uncompressed: AsRef<[u8]> + AsMut<[u8]>; +pub fn root_of_unity(k: usize) -> F { + assert!(k <= F::S as usize); - fn to_uncompressed(&self) -> Self::Uncompressed; - - fn from_uncompressed(uncompressed: Self::Uncompressed) -> Option; + iter::successors(Some(F::root_of_unity()), |acc| Some(acc.square())) + .take(F::S as usize - k + 1) + .last() + .unwrap() } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -119,15 +111,9 @@ pub struct Domain { } impl Domain { - pub fn new(k: usize) -> Self { - assert!(k <= F::S as usize); - + pub fn new(k: usize, gen: F) -> Self { let n = 1 << k; let n_inv = F::from(n as u64).invert().unwrap(); - let gen = iter::successors(Some(F::root_of_unity()), |acc| Some(acc.square())) - .take(F::S as usize - k + 1) - .last() - .unwrap(); let gen_inv = gen.invert().unwrap(); Self { @@ -149,30 +135,33 @@ impl Domain { } #[derive(Clone, Debug)] -pub struct Fraction { - numer: Option, - denom: F, +pub struct Fraction { + numer: Option, + denom: T, + eval: Option, inv: bool, } -impl Fraction { - pub fn new(numer: F, denom: F) -> Self { +impl Fraction { + pub fn new(numer: T, denom: T) -> Self { Self { numer: Some(numer), denom, + eval: None, inv: false, } } - pub fn one_over(denom: F) -> Self { + pub fn one_over(denom: T) -> Self { Self { numer: None, denom, + eval: None, inv: false, } } - pub fn denom(&self) -> Option<&F> { + pub fn denom(&self) -> Option<&T> { if !self.inv { Some(&self.denom) } else { @@ -180,7 +169,7 @@ impl Fraction { } } - pub fn denom_mut(&mut self) -> Option<&mut F> { + pub fn denom_mut(&mut self) -> Option<&mut T> { if !self.inv { self.inv = true; Some(&mut self.denom) @@ -190,21 +179,35 @@ impl Fraction { } } -impl Fraction { - pub fn evaluate(&self) -> F { - let denom = if self.inv { - self.denom.clone() - } else { - self.denom.invert().unwrap() - }; - self.numer - .clone() - .map(|numer| numer * &denom) - .unwrap_or(denom) +impl Fraction { + pub fn evaluate(&mut self) { + assert!(self.inv); + assert!(self.eval.is_none()); + + self.eval = Some( + self.numer + .as_ref() + .map(|numer| numer.clone() * &self.denom) + .unwrap_or_else(|| self.denom.clone()), + ); } + + pub fn evaluated(&self) -> &T { + assert!(self.inv); + + self.eval.as_ref().unwrap() + } +} + +pub fn ilog2(value: usize) -> usize { + (usize::BITS - value.leading_zeros() - 1) as usize } -pub fn big_to_fe(big: BigUint) -> F { +pub fn modulus() -> BigUint { + fe_to_big(-F::one()) + 1usize +} + +pub fn fe_from_big(big: BigUint) -> F { let bytes = big.to_bytes_le(); let mut repr = F::Repr::default(); assert!(bytes.len() <= repr.as_ref().len()); @@ -212,10 +215,18 @@ pub fn big_to_fe(big: BigUint) -> F { F::from_repr(repr).unwrap() } +pub fn fe_to_big(fe: F) -> BigUint { + BigUint::from_bytes_le(fe.to_repr().as_ref()) +} + +pub fn fe_to_fe(fe: F1) -> F2 { + fe_from_big(fe_to_big(fe) % modulus::()) +} + pub fn fe_from_limbs( limbs: [F1; LIMBS], ) -> F2 { - big_to_fe( + fe_from_big( limbs .iter() .map(|limb| BigUint::from_bytes_le(limb.to_repr().as_ref())) @@ -234,8 +245,15 @@ pub fn fe_to_limbs> shift) & &mask)) + .map(move |shift| fe_from_big((&big >> shift) & &mask)) .collect_vec() .try_into() .unwrap() } + +pub fn powers(scalar: F) -> impl Iterator +where + for<'a> F: Mul<&'a F, Output = F> + One + Clone, +{ + iter::successors(Some(F::one()), move |power| Some(scalar.clone() * power)) +} diff --git a/src/util/hash.rs b/src/util/hash.rs new file mode 100644 index 00000000..17ede0b3 --- /dev/null +++ b/src/util/hash.rs @@ -0,0 +1,6 @@ +mod poseidon; + +pub use crate::util::hash::poseidon::Poseidon; + +#[cfg(feature = "loader_evm")] +pub use sha3::{Digest, Keccak256}; diff --git a/src/util/hash/poseidon.rs b/src/util/hash/poseidon.rs new file mode 100644 index 00000000..878b69ce --- /dev/null +++ b/src/util/hash/poseidon.rs @@ -0,0 +1,178 @@ +use crate::{ + loader::{LoadedScalar, ScalarLoader}, + util::{arithmetic::FieldExt, Itertools}, +}; +use poseidon::{self, SparseMDSMatrix, Spec}; +use std::{iter, marker::PhantomData, mem}; + +struct State { + inner: [L; T], + _marker: PhantomData, +} + +impl, const T: usize, const RATE: usize> State { + fn new(inner: [L; T]) -> Self { + Self { + inner, + _marker: PhantomData, + } + } + + fn loader(&self) -> &L::Loader { + self.inner[0].loader() + } + + fn power5_with_constant(value: &L, constant: &F) -> L { + value + .loader() + .sum_products_with_const(&[(value, &value.square().square())], *constant) + } + + fn sbox_full(&mut self, constants: &[F; T]) { + for (state, constant) in self.inner.iter_mut().zip(constants.iter()) { + *state = Self::power5_with_constant(state, constant); + } + } + + fn sbox_part(&mut self, constant: &F) { + self.inner[0] = Self::power5_with_constant(&self.inner[0], constant); + } + + fn absorb_with_pre_constants(&mut self, inputs: &[L], pre_constants: &[F; T]) { + assert!(inputs.len() < T); + + self.inner[0] = self + .loader() + .sum_with_const(&[&self.inner[0]], pre_constants[0]); + self.inner + .iter_mut() + .zip(pre_constants.iter()) + .skip(1) + .zip(inputs) + .for_each(|((state, constant), input)| { + *state = state.loader().sum_with_const(&[state, input], *constant); + }); + self.inner + .iter_mut() + .zip(pre_constants.iter()) + .skip(1 + inputs.len()) + .enumerate() + .for_each(|(idx, (state, constant))| { + *state = state.loader().sum_with_const( + &[state], + if idx == 0 { + F::one() + constant + } else { + *constant + }, + ); + }); + } + + fn apply_mds(&mut self, mds: &[[F; T]; T]) { + self.inner = mds + .iter() + .map(|row| { + self.loader() + .sum_with_coeff(&row.iter().cloned().zip(self.inner.iter()).collect_vec()) + }) + .collect_vec() + .try_into() + .unwrap(); + } + + fn apply_sparse_mds(&mut self, mds: &SparseMDSMatrix) { + self.inner = iter::once( + self.loader().sum_with_coeff( + &mds.row() + .iter() + .cloned() + .zip(self.inner.iter()) + .collect_vec(), + ), + ) + .chain( + mds.col_hat() + .iter() + .zip(self.inner.iter().skip(1)) + .map(|(coeff, state)| { + self.loader() + .sum_with_coeff(&[(*coeff, &self.inner[0]), (F::one(), state)]) + }), + ) + .collect_vec() + .try_into() + .unwrap(); + } +} + +pub struct Poseidon { + spec: Spec, + state: State, + buf: Vec, +} + +impl, const T: usize, const RATE: usize> Poseidon { + pub fn new(loader: L::Loader, r_f: usize, r_p: usize) -> Self { + Self { + spec: Spec::new(r_f, r_p), + state: State::new( + poseidon::State::default() + .words() + .map(|state| loader.load_const(&state)), + ), + buf: Vec::new(), + } + } + + pub fn update(&mut self, elements: &[L]) { + self.buf.extend_from_slice(elements); + } + + pub fn squeeze(&mut self) -> L { + let buf = mem::take(&mut self.buf); + let exact = buf.len() % RATE == 0; + + for chunk in buf.chunks(RATE) { + self.permutation(chunk); + } + if exact { + self.permutation(&[]); + } + + self.state.inner[1].clone() + } + + fn permutation(&mut self, inputs: &[L]) { + let r_f = self.spec.r_f() / 2; + let mds = self.spec.mds_matrices().mds().rows(); + let pre_sparse_mds = self.spec.mds_matrices().pre_sparse_mds().rows(); + let sparse_matrices = self.spec.mds_matrices().sparse_matrices(); + + // First half of the full rounds + let constants = self.spec.constants().start(); + self.state.absorb_with_pre_constants(inputs, &constants[0]); + for constants in constants.iter().skip(1).take(r_f - 1) { + self.state.sbox_full(constants); + self.state.apply_mds(&mds); + } + self.state.sbox_full(constants.last().unwrap()); + self.state.apply_mds(&pre_sparse_mds); + + // Partial rounds + let constants = self.spec.constants().partial(); + for (constant, sparse_mds) in constants.iter().zip(sparse_matrices.iter()) { + self.state.sbox_part(constant); + self.state.apply_sparse_mds(sparse_mds); + } + + // Second half of the full rounds + let constants = self.spec.constants().end(); + for constants in constants.iter() { + self.state.sbox_full(constants); + self.state.apply_mds(&mds); + } + self.state.sbox_full(&[F::zero(); T]); + self.state.apply_mds(&mds); + } +} diff --git a/src/util/msm.rs b/src/util/msm.rs new file mode 100644 index 00000000..a7a3d45d --- /dev/null +++ b/src/util/msm.rs @@ -0,0 +1,203 @@ +use crate::{ + loader::{LoadedEcPoint, Loader}, + util::arithmetic::CurveAffine, +}; +use std::{ + default::Default, + iter::{self, Sum}, + ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, +}; + +#[derive(Clone, Debug)] +pub struct Msm> { + constant: Option, + scalars: Vec, + bases: Vec, +} + +impl Default for Msm +where + C: CurveAffine, + L: Loader, +{ + fn default() -> Self { + Self { + constant: None, + scalars: Vec::new(), + bases: Vec::new(), + } + } +} + +impl Msm +where + C: CurveAffine, + L: Loader, +{ + pub fn constant(constant: L::LoadedScalar) -> Self { + Msm { + constant: Some(constant), + ..Default::default() + } + } + + pub fn base(base: L::LoadedEcPoint) -> Self { + let one = base.loader().load_one(); + Msm { + scalars: vec![one], + bases: vec![base], + ..Default::default() + } + } + + pub(crate) fn size(&self) -> usize { + self.bases.len() + } + + pub(crate) fn split(mut self) -> (Self, Option) { + let constant = self.constant.take(); + (self, constant) + } + + pub(crate) fn try_into_constant(self) -> Option { + self.bases.is_empty().then(|| self.constant.unwrap()) + } + + pub fn evaluate(self, gen: Option) -> L::LoadedEcPoint { + let gen = gen.map(|gen| { + self.bases + .first() + .unwrap() + .loader() + .ec_point_load_const(&gen) + }); + L::LoadedEcPoint::multi_scalar_multiplication( + iter::empty() + .chain(self.constant.map(|constant| (constant, gen.unwrap()))) + .chain(self.scalars.into_iter().zip(self.bases.into_iter())), + ) + } + + pub fn scale(&mut self, factor: &L::LoadedScalar) { + if let Some(constant) = self.constant.as_mut() { + *constant *= factor; + } + for scalar in self.scalars.iter_mut() { + *scalar *= factor + } + } + + pub fn push(&mut self, scalar: L::LoadedScalar, base: L::LoadedEcPoint) { + if let Some(pos) = self.bases.iter().position(|exist| exist.eq(&base)) { + self.scalars[pos] += scalar; + } else { + self.scalars.push(scalar); + self.bases.push(base); + } + } + + pub fn extend(&mut self, mut other: Self) { + match (self.constant.as_mut(), other.constant.as_ref()) { + (Some(lhs), Some(rhs)) => *lhs += rhs, + (None, Some(_)) => self.constant = other.constant.take(), + _ => {} + }; + for (scalar, base) in other.scalars.into_iter().zip(other.bases) { + self.push(scalar, base); + } + } +} + +impl Add> for Msm +where + C: CurveAffine, + L: Loader, +{ + type Output = Msm; + + fn add(mut self, rhs: Msm) -> Self::Output { + self.extend(rhs); + self + } +} + +impl AddAssign> for Msm +where + C: CurveAffine, + L: Loader, +{ + fn add_assign(&mut self, rhs: Msm) { + self.extend(rhs); + } +} + +impl Sub> for Msm +where + C: CurveAffine, + L: Loader, +{ + type Output = Msm; + + fn sub(mut self, rhs: Msm) -> Self::Output { + self.extend(-rhs); + self + } +} + +impl SubAssign> for Msm +where + C: CurveAffine, + L: Loader, +{ + fn sub_assign(&mut self, rhs: Msm) { + self.extend(-rhs); + } +} + +impl Mul<&L::LoadedScalar> for Msm +where + C: CurveAffine, + L: Loader, +{ + type Output = Msm; + + fn mul(mut self, rhs: &L::LoadedScalar) -> Self::Output { + self.scale(rhs); + self + } +} + +impl MulAssign<&L::LoadedScalar> for Msm +where + C: CurveAffine, + L: Loader, +{ + fn mul_assign(&mut self, rhs: &L::LoadedScalar) { + self.scale(rhs); + } +} + +impl Neg for Msm +where + C: CurveAffine, + L: Loader, +{ + type Output = Msm; + fn neg(mut self) -> Msm { + self.constant = self.constant.map(|constant| -constant); + for scalar in self.scalars.iter_mut() { + *scalar = -scalar.clone(); + } + self + } +} + +impl Sum for Msm +where + C: CurveAffine, + L: Loader, +{ + fn sum>(iter: I) -> Self { + iter.reduce(|acc, item| acc + item).unwrap_or_default() + } +} diff --git a/src/util/expression.rs b/src/util/protocol.rs similarity index 65% rename from src/util/expression.rs rename to src/util/protocol.rs index 41b04ded..bae363ff 100644 --- a/src/util/expression.rs +++ b/src/util/protocol.rs @@ -1,7 +1,12 @@ use crate::{ loader::{LoadedScalar, Loader}, - util::{Curve, Domain, Field, Fraction, Itertools, Rotation}, + util::{ + arithmetic::{CurveAffine, Domain, Field, Fraction, Rotation}, + Itertools, + }, }; +use num_integer::Integer; +use num_traits::One; use std::{ cmp::max, collections::{BTreeMap, BTreeSet}, @@ -19,10 +24,11 @@ pub enum CommonPolynomial { #[derive(Clone, Debug)] pub struct CommonPolynomialEvaluation where - C: Curve, + C: CurveAffine, L: Loader, { zn: L::LoadedScalar, + zn_minus_one: L::LoadedScalar, zn_minus_one_inv: Fraction, identity: L::LoadedScalar, lagrange: BTreeMap>, @@ -30,28 +36,29 @@ where impl CommonPolynomialEvaluation where - C: Curve, + C: CurveAffine, L: Loader, { pub fn new( domain: &Domain, - loader: &L, langranges: impl IntoIterator, z: &L::LoadedScalar, ) -> Self { + let loader = z.loader(); + let zn = z.pow_const(domain.n as u64); let langranges = langranges.into_iter().sorted().dedup().collect_vec(); let one = loader.load_one(); let zn_minus_one = zn.clone() - one; + let zn_minus_one_inv = Fraction::one_over(zn_minus_one.clone()); + let n_inv = loader.load_const(&domain.n_inv); let numer = zn_minus_one.clone() * n_inv; - let omegas = langranges .iter() .map(|&i| loader.load_const(&domain.rotate_scalar(C::Scalar::one(), Rotation(i)))) .collect_vec(); - let lagrange_evals = omegas .iter() .map(|omega| Fraction::new(numer.clone() * omega, z.clone() - omega)) @@ -59,24 +66,29 @@ where Self { zn, - zn_minus_one_inv: Fraction::one_over(zn_minus_one), + zn_minus_one, + zn_minus_one_inv, identity: z.clone(), lagrange: langranges.into_iter().zip(lagrange_evals).collect(), } } - pub fn zn(&self) -> L::LoadedScalar { - self.zn.clone() + pub fn zn(&self) -> &L::LoadedScalar { + &self.zn + } + + pub fn zn_minus_one(&self) -> &L::LoadedScalar { + &self.zn_minus_one } - pub fn zn_minus_one_inv(&self) -> L::LoadedScalar { - self.zn_minus_one_inv.evaluate() + pub fn zn_minus_one_inv(&self) -> &L::LoadedScalar { + self.zn_minus_one_inv.evaluated() } - pub fn get(&self, poly: CommonPolynomial) -> L::LoadedScalar { + pub fn get(&self, poly: CommonPolynomial) -> &L::LoadedScalar { match poly { - CommonPolynomial::Identity => self.identity.clone(), - CommonPolynomial::Lagrange(i) => self.lagrange.get(&i).unwrap().evaluate(), + CommonPolynomial::Identity => &self.identity, + CommonPolynomial::Lagrange(i) => self.lagrange.get(&i).unwrap().evaluated(), } } @@ -87,6 +99,26 @@ where .chain(iter::once(self.zn_minus_one_inv.denom_mut())) .flatten() } + + pub fn evaluate(&mut self) { + self.lagrange + .iter_mut() + .map(|(_, value)| value) + .chain(iter::once(&mut self.zn_minus_one_inv)) + .for_each(Fraction::evaluate) + } +} + +#[derive(Clone, Debug)] +pub struct QuotientPolynomial { + pub chunk_degree: usize, + pub numerator: Expression, +} + +impl QuotientPolynomial { + pub fn num_chunk(&self) -> usize { + Integer::div_ceil(&(self.numerator.degree() - 1), &self.chunk_degree) + } } #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -114,10 +146,11 @@ pub enum Expression { Sum(Box>, Box>), Product(Box>, Box>), Scaled(Box>, F), + DistributePowers(Vec>, Box>), } impl Expression { - pub fn evaluate( + pub fn evaluate( &self, constant: &impl Fn(F) -> T, common_poly: &impl Fn(CommonPolynomial) -> T, @@ -128,83 +161,53 @@ impl Expression { product: &impl Fn(T, T) -> T, scaled: &impl Fn(T, F) -> T, ) -> T { + let evaluate = |expr: &Expression| { + expr.evaluate( + constant, + common_poly, + poly, + challenge, + negated, + sum, + product, + scaled, + ) + }; match self { Expression::Constant(scalar) => constant(scalar.clone()), Expression::CommonPolynomial(poly) => common_poly(*poly), Expression::Polynomial(query) => poly(*query), Expression::Challenge(index) => challenge(*index), Expression::Negated(a) => { - let a = a.evaluate( - constant, - common_poly, - poly, - challenge, - negated, - sum, - product, - scaled, - ); + let a = evaluate(a); negated(a) } Expression::Sum(a, b) => { - let a = a.evaluate( - constant, - common_poly, - poly, - challenge, - negated, - sum, - product, - scaled, - ); - let b = b.evaluate( - constant, - common_poly, - poly, - challenge, - negated, - sum, - product, - scaled, - ); + let a = evaluate(a); + let b = evaluate(b); sum(a, b) } Expression::Product(a, b) => { - let a = a.evaluate( - constant, - common_poly, - poly, - challenge, - negated, - sum, - product, - scaled, - ); - let b = b.evaluate( - constant, - common_poly, - poly, - challenge, - negated, - sum, - product, - scaled, - ); + let a = evaluate(a); + let b = evaluate(b); product(a, b) } Expression::Scaled(a, scalar) => { - let a = a.evaluate( - constant, - common_poly, - poly, - challenge, - negated, - sum, - product, - scaled, - ); + let a = evaluate(a); scaled(a, scalar.clone()) } + Expression::DistributePowers(exprs, scalar) => { + assert!(!exprs.is_empty()); + if exprs.len() == 1 { + return evaluate(exprs.first().unwrap()); + } + let mut exprs = exprs.iter(); + let first = evaluate(exprs.next().unwrap()); + let scalar = evaluate(scalar); + exprs.fold(first, |acc, expr| { + sum(product(acc, scalar.clone()), evaluate(expr)) + }) + } } } @@ -218,6 +221,12 @@ impl Expression { Expression::Sum(a, b) => max(a.degree(), b.degree()), Expression::Product(a, b) => a.degree() + b.degree(), Expression::Scaled(a, _) => a.degree(), + Expression::DistributePowers(a, b) => a + .iter() + .chain(Some(b.as_ref())) + .map(Self::degree) + .max() + .unwrap_or_default(), } } @@ -237,6 +246,20 @@ impl Expression { ) .unwrap_or_default() } + + pub fn used_query(&self) -> BTreeSet { + self.evaluate( + &|_| None, + &|_| None, + &|query| Some(BTreeSet::from_iter([query])), + &|_| None, + &|a| a, + &merge_left_right, + &merge_left_right, + &|a, _| a, + ) + .unwrap_or_default() + } } impl From for Expression { @@ -306,6 +329,12 @@ impl Sum for Expression { } } +impl One for Expression { + fn one() -> Self { + Expression::Constant(F::one()) + } +} + fn merge_left_right(a: Option>, b: Option>) -> Option> { match (a, b) { (Some(a), None) | (None, Some(a)) => Some(a), @@ -316,3 +345,21 @@ fn merge_left_right(a: Option>, b: Option>) -> O _ => None, } } + +#[derive(Clone, Debug)] +pub enum LinearizationStrategy { + /// Older linearization strategy of GWC19, which has linearization + /// polynomial that doesn't evaluate to 0, and requires prover to send extra + /// evaluation of it to verifier. + WithoutConstant, + /// Current linearization strategy of GWC19, which has linearization + /// polynomial that evaluate to 0 by subtracting product of vanishing and + /// quotient polynomials. + MinusVanishingTimesQuotient, +} + +#[derive(Clone, Debug, Default)] +pub struct InstanceCommittingKey { + pub bases: Vec, + pub constant: Option, +} diff --git a/src/util/transcript.rs b/src/util/transcript.rs index a42d5e70..3337324d 100644 --- a/src/util/transcript.rs +++ b/src/util/transcript.rs @@ -1,13 +1,15 @@ use crate::{ - loader::Loader, - {util::Curve, Error}, + loader::{native::NativeLoader, Loader}, + {util::arithmetic::CurveAffine, Error}, }; pub trait Transcript where - C: Curve, + C: CurveAffine, L: Loader, { + fn loader(&self) -> &L; + fn squeeze_challenge(&mut self) -> L::LoadedScalar; fn squeeze_n_challenges(&mut self, n: usize) -> Vec { @@ -21,7 +23,7 @@ where pub trait TranscriptRead: Transcript where - C: Curve, + C: CurveAffine, L: Loader, { fn read_scalar(&mut self) -> Result; @@ -36,3 +38,9 @@ where (0..n).map(|_| self.read_ec_point()).collect() } } + +pub trait TranscriptWrite: Transcript { + fn write_scalar(&mut self, scalar: C::Scalar) -> Result<(), Error>; + + fn write_ec_point(&mut self, ec_point: C) -> Result<(), Error>; +} diff --git a/src/verifier.rs b/src/verifier.rs new file mode 100644 index 00000000..07529603 --- /dev/null +++ b/src/verifier.rs @@ -0,0 +1,51 @@ +use crate::{ + loader::Loader, + pcs::{Decider, MultiOpenScheme}, + util::{arithmetic::CurveAffine, transcript::TranscriptRead}, + Error, Protocol, +}; +use std::fmt::Debug; + +mod plonk; + +pub use plonk::{Plonk, PlonkProof}; + +pub trait PlonkVerifier +where + C: CurveAffine, + L: Loader, + MOS: MultiOpenScheme, +{ + type Proof: Clone + Debug; + + fn read_proof( + svk: &MOS::SuccinctVerifyingKey, + protocol: &Protocol, + instances: &[Vec], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead; + + fn succinct_verify( + svk: &MOS::SuccinctVerifyingKey, + protocol: &Protocol, + instances: &[Vec], + proof: &Self::Proof, + ) -> Result, Error>; + + fn verify( + svk: &MOS::SuccinctVerifyingKey, + dk: &MOS::DecidingKey, + protocol: &Protocol, + instances: &[Vec], + proof: &Self::Proof, + ) -> Result + where + MOS: Decider, + { + let accumulators = Self::succinct_verify(svk, protocol, instances, proof)?; + let output = MOS::decide_all(dk, accumulators); + Ok(output) + } +} diff --git a/src/verifier/plonk.rs b/src/verifier/plonk.rs new file mode 100644 index 00000000..9e08e585 --- /dev/null +++ b/src/verifier/plonk.rs @@ -0,0 +1,464 @@ +use crate::{ + cost::{Cost, CostEstimation}, + loader::{native::NativeLoader, LoadedScalar, Loader}, + pcs::{self, AccumulatorEncoding, MultiOpenScheme}, + util::{ + arithmetic::{CurveAffine, Field, Rotation}, + msm::Msm, + protocol::{ + CommonPolynomial::Lagrange, CommonPolynomialEvaluation, LinearizationStrategy, Query, + }, + transcript::TranscriptRead, + Itertools, + }, + verifier::PlonkVerifier, + Error, Protocol, +}; +use std::{collections::HashMap, iter, marker::PhantomData}; + +pub struct Plonk(PhantomData<(MOS, AE)>); + +impl PlonkVerifier for Plonk +where + C: CurveAffine, + L: Loader, + MOS: MultiOpenScheme, + AE: AccumulatorEncoding, +{ + type Proof = PlonkProof; + + fn read_proof( + svk: &MOS::SuccinctVerifyingKey, + protocol: &Protocol, + instances: &[Vec], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + PlonkProof::read::(svk, protocol, instances, transcript) + } + + fn succinct_verify( + svk: &MOS::SuccinctVerifyingKey, + protocol: &Protocol, + instances: &[Vec], + proof: &Self::Proof, + ) -> Result, Error> { + let common_poly_eval = { + let mut common_poly_eval = CommonPolynomialEvaluation::new( + &protocol.domain, + langranges(protocol, instances), + &proof.z, + ); + + L::LoadedScalar::batch_invert(common_poly_eval.denoms()); + common_poly_eval.evaluate(); + + common_poly_eval + }; + + let mut evaluations = proof.evaluations(protocol, instances, &common_poly_eval)?; + let commitments = proof.commitments(protocol, &common_poly_eval, &mut evaluations)?; + let queries = proof.queries(protocol, evaluations); + + let accumulator = MOS::succinct_verify(svk, &commitments, &proof.z, &queries, &proof.pcs)?; + + let accumulators = iter::empty() + .chain(Some(accumulator)) + .chain(proof.old_accumulators.iter().cloned()) + .collect(); + + Ok(accumulators) + } +} + +#[derive(Clone, Debug)] +pub struct PlonkProof +where + C: CurveAffine, + L: Loader, + MOS: MultiOpenScheme, +{ + pub committed_instances: Option>, + pub witnesses: Vec, + pub challenges: Vec, + pub quotients: Vec, + pub z: L::LoadedScalar, + pub evaluations: Vec, + pub pcs: MOS::Proof, + pub old_accumulators: Vec, +} + +impl PlonkProof +where + C: CurveAffine, + L: Loader, + MOS: MultiOpenScheme, +{ + fn read( + svk: &MOS::SuccinctVerifyingKey, + protocol: &Protocol, + instances: &[Vec], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + AE: AccumulatorEncoding, + { + let loader = transcript.loader(); + if let Some(transcript_initial_state) = &protocol.transcript_initial_state { + transcript.common_scalar(&loader.load_const(transcript_initial_state))?; + } + + if protocol.num_instance + != instances + .iter() + .map(|instances| instances.len()) + .collect_vec() + { + return Err(Error::InvalidInstances); + } + + let committed_instances = if let Some(ick) = &protocol.instance_committing_key { + let loader = transcript.loader(); + let bases = ick + .bases + .iter() + .map(|value| loader.ec_point_load_const(value)) + .collect_vec(); + let constant = ick + .constant + .as_ref() + .map(|value| loader.ec_point_load_const(value)); + + let committed_instances = instances + .iter() + .map(|instances| { + instances + .iter() + .zip(bases.iter()) + .map(|(scalar, base)| Msm::::base(base.clone()) * scalar) + .chain(constant.clone().map(|constant| Msm::base(constant))) + .sum::>() + .evaluate(None) + }) + .collect_vec(); + for committed_instance in committed_instances.iter() { + transcript.common_ec_point(committed_instance)?; + } + + Some(committed_instances) + } else { + for instances in instances.iter() { + for instance in instances.iter() { + transcript.common_scalar(instance)?; + } + } + + None + }; + + let (witnesses, challenges) = { + let (witnesses, challenges) = protocol + .num_witness + .iter() + .zip(protocol.num_challenge.iter()) + .map(|(&n, &m)| { + Ok(( + transcript.read_n_ec_points(n)?, + transcript.squeeze_n_challenges(m), + )) + }) + .collect::, Error>>()? + .into_iter() + .unzip::<_, _, Vec<_>, Vec<_>>(); + + ( + witnesses.into_iter().flatten().collect_vec(), + challenges.into_iter().flatten().collect_vec(), + ) + }; + + let quotients = transcript.read_n_ec_points(protocol.quotient.num_chunk())?; + + let z = transcript.squeeze_challenge(); + let evaluations = transcript.read_n_scalars(protocol.evaluations.len())?; + + let pcs = MOS::read_proof(svk, &Self::empty_queries(protocol), transcript)?; + + let old_accumulators = protocol + .accumulator_indices + .iter() + .map(|accumulator_indices| { + accumulator_indices + .iter() + .map(|&(i, j)| instances[i][j].clone()) + .collect() + }) + .map(AE::from_repr) + .collect::, _>>()?; + + Ok(Self { + committed_instances, + witnesses, + challenges, + quotients, + z, + evaluations, + pcs, + old_accumulators, + }) + } + + fn empty_queries(protocol: &Protocol) -> Vec> { + protocol + .queries + .iter() + .map(|query| pcs::Query { + poly: query.poly, + shift: protocol + .domain + .rotate_scalar(C::Scalar::one(), query.rotation), + eval: (), + }) + .collect() + } + + fn queries( + &self, + protocol: &Protocol, + mut evaluations: HashMap, + ) -> Vec> { + Self::empty_queries(protocol) + .into_iter() + .zip( + protocol + .queries + .iter() + .map(|query| evaluations.remove(query).unwrap()), + ) + .map(|(query, eval)| query.with_evaluation(eval)) + .collect() + } + + fn commitments( + &self, + protocol: &Protocol, + common_poly_eval: &CommonPolynomialEvaluation, + evaluations: &mut HashMap, + ) -> Result>, Error> { + let loader = common_poly_eval.zn().loader(); + let mut commitments = iter::empty() + .chain( + protocol + .preprocessed + .iter() + .map(|value| Msm::base(loader.ec_point_load_const(value))), + ) + .chain( + self.committed_instances + .clone() + .map(|committed_instances| { + committed_instances.into_iter().map(Msm::base).collect_vec() + }) + .unwrap_or_else(|| { + iter::repeat_with(Default::default) + .take(protocol.num_instance.len()) + .collect_vec() + }), + ) + .chain(self.witnesses.iter().cloned().map(Msm::base)) + .collect_vec(); + + let numerator = protocol.quotient.numerator.evaluate( + &|scalar| Ok(Msm::constant(loader.load_const(&scalar))), + &|poly| Ok(Msm::constant(common_poly_eval.get(poly).clone())), + &|query| { + evaluations + .get(&query) + .cloned() + .map(Msm::constant) + .or_else(|| { + (query.rotation == Rotation::cur()) + .then(|| commitments.get(query.poly).cloned()) + .flatten() + }) + .ok_or(Error::InvalidQuery(query)) + }, + &|index| { + self.challenges + .get(index) + .cloned() + .map(Msm::constant) + .ok_or(Error::InvalidChallenge(index)) + }, + &|a| Ok(-a?), + &|a, b| Ok(a? + b?), + &|a, b| { + let (a, b) = (a?, b?); + match (a.size(), b.size()) { + (0, _) => Ok(b * &a.try_into_constant().unwrap()), + (_, 0) => Ok(a * &b.try_into_constant().unwrap()), + (_, _) => Err(Error::InvalidLinearization), + } + }, + &|a, scalar| Ok(a? * &loader.load_const(&scalar)), + )?; + + let quotient_query = Query::new( + protocol.preprocessed.len() + protocol.num_instance.len() + self.witnesses.len(), + Rotation::cur(), + ); + let quotient = common_poly_eval + .zn() + .pow_const(protocol.quotient.chunk_degree as u64) + .powers(self.quotients.len()) + .into_iter() + .zip(self.quotients.iter().cloned().map(Msm::base)) + .map(|(coeff, chunk)| chunk * &coeff) + .sum::>(); + match protocol.linearization { + Some(LinearizationStrategy::WithoutConstant) => { + let linearization_query = Query::new(quotient_query.poly + 1, Rotation::cur()); + let (msm, constant) = numerator.split(); + commitments.push(quotient); + commitments.push(msm); + evaluations.insert( + quotient_query, + (constant.unwrap_or_else(|| loader.load_zero()) + + evaluations.get(&linearization_query).unwrap()) + * common_poly_eval.zn_minus_one_inv(), + ); + } + Some(LinearizationStrategy::MinusVanishingTimesQuotient) => { + let (msm, constant) = + (numerator - quotient * common_poly_eval.zn_minus_one()).split(); + commitments.push(msm); + evaluations.insert( + quotient_query, + constant.unwrap_or_else(|| loader.load_zero()), + ); + } + None => { + commitments.push(quotient); + evaluations.insert( + quotient_query, + numerator + .try_into_constant() + .ok_or(Error::InvalidLinearization)? + * common_poly_eval.zn_minus_one_inv(), + ); + } + } + + Ok(commitments) + } + + fn evaluations( + &self, + protocol: &Protocol, + instances: &[Vec], + common_poly_eval: &CommonPolynomialEvaluation, + ) -> Result, Error> { + let loader = common_poly_eval.zn().loader(); + let instance_evals = protocol.instance_committing_key.is_none().then(|| { + let offset = protocol.preprocessed.len(); + let queries = { + let range = offset..offset + protocol.num_instance.len(); + protocol + .quotient + .numerator + .used_query() + .into_iter() + .filter(move |query| range.contains(&query.poly)) + }; + queries + .map(move |query| { + let instances = instances[query.poly - offset].iter(); + let l_i_minus_r = (-query.rotation.0..) + .map(|i_minus_r| common_poly_eval.get(Lagrange(i_minus_r))); + let eval = loader.sum_products(&instances.zip(l_i_minus_r).collect_vec()); + (query, eval) + }) + .collect_vec() + }); + + let evals = iter::empty() + .chain(instance_evals.into_iter().flatten()) + .chain( + protocol + .evaluations + .iter() + .cloned() + .zip(self.evaluations.iter().cloned()), + ) + .collect(); + + Ok(evals) + } +} + +impl CostEstimation<(C, MOS)> for Plonk +where + C: CurveAffine, + MOS: MultiOpenScheme + CostEstimation>>, +{ + type Input = Protocol; + + fn estimate_cost(protocol: &Protocol) -> Cost { + let plonk_cost = { + let num_accumulator = protocol.accumulator_indices.len(); + let num_instance = protocol.num_instance.iter().sum(); + let num_commitment = + protocol.num_witness.iter().sum::() + protocol.quotient.num_chunk(); + let num_evaluation = protocol.evaluations.len(); + let num_msm = protocol.preprocessed.len() + num_commitment + 1 + 2 * num_accumulator; + Cost::new(num_instance, num_commitment, num_evaluation, num_msm) + }; + let pcs_cost = { + let queries = PlonkProof::::empty_queries(protocol); + MOS::estimate_cost(&queries) + }; + plonk_cost + pcs_cost + } +} + +fn langranges(protocol: &Protocol, instances: &[Vec]) -> impl IntoIterator +where + C: CurveAffine, +{ + let instance_eval_lagrange = protocol.instance_committing_key.is_none().then(|| { + let queries = { + let offset = protocol.preprocessed.len(); + let range = offset..offset + protocol.num_instance.len(); + protocol + .quotient + .numerator + .used_query() + .into_iter() + .filter(move |query| range.contains(&query.poly)) + }; + let (min_rotation, max_rotation) = queries.fold((0, 0), |(min, max), query| { + if query.rotation.0 < min { + (query.rotation.0, max) + } else if query.rotation.0 > max { + (min, query.rotation.0) + } else { + (min, max) + } + }); + let max_instance_len = instances + .iter() + .map(|instance| instance.len()) + .max() + .unwrap_or_default(); + -max_rotation..max_instance_len as i32 + min_rotation.abs() + }); + protocol + .quotient + .numerator + .used_langrange() + .into_iter() + .chain(instance_eval_lagrange.into_iter().flatten()) +} From 2cd8b9d1e57949979db1cbfa8506518e63d27e93 Mon Sep 17 00:00:00 2001 From: Han Date: Fri, 28 Oct 2022 07:26:06 -0700 Subject: [PATCH 02/73] Generalized `Halo2Loader` (#12) * feat: generalize `Protocol` for further usage * feat: add `EccInstruction::{fixed_base_msm,variable_base_msm,sum_with_const}` * chore: move `rand_chacha` as dev dependency --- Cargo.toml | 2 +- examples/evm-verifier-with-accumulator.rs | 11 +- examples/evm-verifier.rs | 3 +- src/lib.rs | 10 +- src/loader.rs | 33 ++-- src/loader/evm/loader.rs | 148 ++++++++------- src/loader/halo2.rs | 42 +++++ src/loader/halo2/loader.rs | 220 +++++++++++++--------- src/loader/halo2/shim.rs | 59 ++++-- src/loader/native.rs | 20 +- src/pcs/kzg/multiopen/bdfg21.rs | 4 +- src/system/halo2.rs | 9 +- src/system/halo2/test/kzg.rs | 2 +- src/system/halo2/test/kzg/evm.rs | 7 +- src/system/halo2/test/kzg/halo2.rs | 6 +- src/system/halo2/transcript/evm.rs | 4 +- src/system/halo2/transcript/halo2.rs | 14 +- src/util/hash/poseidon.rs | 2 +- src/util/msm.rs | 12 +- src/util/protocol.rs | 32 ++++ src/verifier.rs | 6 +- src/verifier/plonk.rs | 29 +-- 22 files changed, 423 insertions(+), 252 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index de037c4c..803beade 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,6 @@ num-bigint = "0.4.3" num-integer = "0.1.45" num-traits = "0.2.15" rand = "0.8" -rand_chacha = "0.3.1" halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.0", package = "halo2curves" } # system_halo2 @@ -25,6 +24,7 @@ halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2 poseidon = { git = "https://github.com/privacy-scaling-explorations/poseidon", tag = "v2022_10_22", optional = true } [dev-dependencies] +rand_chacha = "0.3.1" paste = "1.0.7" # system_halo2 diff --git a/examples/evm-verifier-with-accumulator.rs b/examples/evm-verifier-with-accumulator.rs index 69def21e..66fa8ddf 100644 --- a/examples/evm-verifier-with-accumulator.rs +++ b/examples/evm-verifier-with-accumulator.rs @@ -280,12 +280,12 @@ mod aggregation { let accumulators = snarks .iter() .flat_map(|snark| { + let protocol = snark.protocol.loaded(loader); let instances = assign_instances(&snark.instances); let mut transcript = PoseidonTranscript::, _>::new(loader, snark.proof()); - let proof = - Plonk::read_proof(svk, &snark.protocol, &instances, &mut transcript).unwrap(); - Plonk::succinct_verify(svk, &snark.protocol, &instances, &proof).unwrap() + let proof = Plonk::read_proof(svk, &protocol, &instances, &mut transcript).unwrap(); + Plonk::succinct_verify(svk, &protocol, &instances, &proof).unwrap() }) .collect_vec(); @@ -555,11 +555,12 @@ fn gen_aggregation_evm_verifier( vk, Config::kzg() .with_num_instance(num_instance.clone()) - .with_accumulator_indices(accumulator_indices), + .with_accumulator_indices(Some(accumulator_indices)), ); let loader = EvmLoader::new::(); - let mut transcript = EvmTranscript::<_, Rc, _, _>::new(loader.clone()); + let protocol = protocol.loaded(&loader); + let mut transcript = EvmTranscript::<_, Rc, _, _>::new(&loader); let instances = transcript.load_instances(num_instance); let proof = Plonk::read_proof(&svk, &protocol, &instances, &mut transcript).unwrap(); diff --git a/examples/evm-verifier.rs b/examples/evm-verifier.rs index b51a9a30..9ed70b36 100644 --- a/examples/evm-verifier.rs +++ b/examples/evm-verifier.rs @@ -216,7 +216,8 @@ fn gen_evm_verifier( ); let loader = EvmLoader::new::(); - let mut transcript = EvmTranscript::<_, Rc, _, _>::new(loader.clone()); + let protocol = protocol.loaded(&loader); + let mut transcript = EvmTranscript::<_, Rc, _, _>::new(&loader); let instances = transcript.load_instances(num_instance); let proof = Plonk::read_proof(&svk, &protocol, &instances, &mut transcript).unwrap(); diff --git a/src/lib.rs b/src/lib.rs index 4e8da5fb..9749924d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,10 +20,14 @@ pub enum Error { } #[derive(Clone, Debug)] -pub struct Protocol { +pub struct Protocol +where + C: util::arithmetic::CurveAffine, + L: loader::Loader, +{ // Common description pub domain: util::arithmetic::Domain, - pub preprocessed: Vec, + pub preprocessed: Vec, pub num_instance: Vec, pub num_witness: Vec, pub num_challenge: Vec, @@ -31,7 +35,7 @@ pub struct Protocol { pub queries: Vec, pub quotient: util::protocol::QuotientPolynomial, // Minor customization - pub transcript_initial_state: Option, + pub transcript_initial_state: Option, pub instance_committing_key: Option>, pub linearization: Option, pub accumulator_indices: Vec>, diff --git a/src/loader.rs b/src/loader.rs index 8c39bae0..5a040f9f 100644 --- a/src/loader.rs +++ b/src/loader.rs @@ -19,15 +19,6 @@ pub trait LoadedEcPoint: Clone + Debug + PartialEq { type Loader: Loader; fn loader(&self) -> &Self::Loader; - - fn multi_scalar_multiplication( - pairs: impl IntoIterator< - Item = ( - >::LoadedScalar, - Self, - ), - >, - ) -> Self; } pub trait LoadedScalar: Clone + Debug + PartialEq + FieldOps { @@ -43,15 +34,6 @@ pub trait LoadedScalar: Clone + Debug + PartialEq + FieldOps { FieldOps::invert(self) } - fn batch_invert<'a>(values: impl IntoIterator) - where - Self: 'a, - { - values - .into_iter() - .for_each(|value| *value = LoadedScalar::invert(value).unwrap_or_else(|| value.clone())) - } - fn pow_const(&self, mut exp: u64) -> Self { assert!(exp > 0); @@ -102,6 +84,12 @@ pub trait EcPointLoader { lhs: &Self::LoadedEcPoint, rhs: &Self::LoadedEcPoint, ) -> Result<(), Error>; + + fn multi_scalar_multiplication( + pairs: &[(Self::LoadedScalar, Self::LoadedEcPoint)], + ) -> Self::LoadedEcPoint + where + Self: ScalarLoader; } pub trait ScalarLoader { @@ -226,6 +214,15 @@ pub trait ScalarLoader { .iter() .fold(self.load_one(), |acc, value| acc * *value) } + + fn batch_invert<'a>(values: impl IntoIterator) + where + Self::LoadedScalar: 'a, + { + values + .into_iter() + .for_each(|value| *value = LoadedScalar::invert(value).unwrap_or_else(|| value.clone())) + } } pub trait Loader: diff --git a/src/loader/evm/loader.rs b/src/loader/evm/loader.rs index 06ab7fd8..7d1dbb94 100644 --- a/src/loader/evm/loader.rs +++ b/src/loader/evm/loader.rs @@ -596,17 +596,6 @@ where fn loader(&self) -> &Rc { &self.loader } - - fn multi_scalar_multiplication(pairs: impl IntoIterator) -> Self { - pairs - .into_iter() - .map(|(scalar, ec_point)| match scalar.value { - Value::Constant(constant) if constant == U256::one() => ec_point, - _ => ec_point.loader.ec_point_scalar_mul(&ec_point, &scalar), - }) - .reduce(|acc, ec_point| acc.loader.ec_point_add(&acc, &ec_point)) - .unwrap() - } } #[derive(Clone)] @@ -759,73 +748,12 @@ impl> LoadedScalar for Scalar { fn loader(&self) -> &Rc { &self.loader } - - fn batch_invert<'a>(values: impl IntoIterator) { - let values = values.into_iter().collect_vec(); - let loader = &values.first().unwrap().loader; - let products = iter::once(values[0].clone()) - .chain( - iter::repeat_with(|| loader.allocate(0x20)) - .map(|ptr| loader.scalar(Value::Memory(ptr))) - .take(values.len() - 1), - ) - .collect_vec(); - - loader.code.borrow_mut().push(loader.scalar_modulus); - for _ in 2..values.len() { - loader.code.borrow_mut().dup(0); - } - - loader.push(products.first().unwrap()); - for (idx, (value, product)) in values.iter().zip(products.iter()).skip(1).enumerate() { - loader.push(value); - loader.code.borrow_mut().mulmod(); - if idx < values.len() - 2 { - loader.code.borrow_mut().dup(0); - } - loader.code.borrow_mut().push(product.ptr()).mstore(); - } - - let inv = loader.invert(products.last().unwrap()); - - loader.code.borrow_mut().push(loader.scalar_modulus); - for _ in 2..values.len() { - loader.code.borrow_mut().dup(0); - } - - loader.push(&inv); - for (value, product) in values.iter().rev().zip( - products - .iter() - .rev() - .skip(1) - .map(Some) - .chain(iter::once(None)), - ) { - if let Some(product) = product { - loader.push(value); - loader - .code - .borrow_mut() - .dup(2) - .dup(2) - .push(product.ptr()) - .mload() - .mulmod() - .push(value.ptr()) - .mstore() - .mulmod(); - } else { - loader.code.borrow_mut().push(value.ptr()).mstore(); - } - } - } } impl EcPointLoader for Rc where C: CurveAffine, - C::Scalar: PrimeField, + C::ScalarExt: PrimeField, { type LoadedEcPoint = EcPoint; @@ -839,6 +767,19 @@ where fn ec_point_assert_eq(&self, _: &str, _: &EcPoint, _: &EcPoint) -> Result<(), Error> { unimplemented!() } + + fn multi_scalar_multiplication( + pairs: &[(>::LoadedScalar, EcPoint)], + ) -> EcPoint { + pairs + .iter() + .map(|(scalar, ec_point)| match scalar.value { + Value::Constant(constant) if U256::one() == constant => ec_point.clone(), + _ => ec_point.loader.ec_point_scalar_mul(ec_point, scalar), + }) + .reduce(|acc, ec_point| acc.loader.ec_point_add(&acc, &ec_point)) + .unwrap() + } } impl> ScalarLoader for Rc { @@ -977,6 +918,67 @@ impl> ScalarLoader for Rc { self.scalar(Value::Memory(ptr)) } + + fn batch_invert<'a>(values: impl IntoIterator) { + let values = values.into_iter().collect_vec(); + let loader = &values.first().unwrap().loader; + let products = iter::once(values[0].clone()) + .chain( + iter::repeat_with(|| loader.allocate(0x20)) + .map(|ptr| loader.scalar(Value::Memory(ptr))) + .take(values.len() - 1), + ) + .collect_vec(); + + loader.code.borrow_mut().push(loader.scalar_modulus); + for _ in 2..values.len() { + loader.code.borrow_mut().dup(0); + } + + loader.push(products.first().unwrap()); + for (idx, (value, product)) in values.iter().zip(products.iter()).skip(1).enumerate() { + loader.push(value); + loader.code.borrow_mut().mulmod(); + if idx < values.len() - 2 { + loader.code.borrow_mut().dup(0); + } + loader.code.borrow_mut().push(product.ptr()).mstore(); + } + + let inv = loader.invert(products.last().unwrap()); + + loader.code.borrow_mut().push(loader.scalar_modulus); + for _ in 2..values.len() { + loader.code.borrow_mut().dup(0); + } + + loader.push(&inv); + for (value, product) in values.iter().rev().zip( + products + .iter() + .rev() + .skip(1) + .map(Some) + .chain(iter::once(None)), + ) { + if let Some(product) = product { + loader.push(value); + loader + .code + .borrow_mut() + .dup(2) + .dup(2) + .push(product.ptr()) + .mload() + .mulmod() + .push(value.ptr()) + .mstore() + .mulmod(); + } else { + loader.code.borrow_mut().push(value.ptr()).mstore(); + } + } + } } impl Loader for Rc diff --git a/src/loader/halo2.rs b/src/loader/halo2.rs index 9eae74e3..39e95c23 100644 --- a/src/loader/halo2.rs +++ b/src/loader/halo2.rs @@ -1,3 +1,7 @@ +use crate::{util::arithmetic::CurveAffine, Protocol}; +use halo2_proofs::circuit; +use std::rc::Rc; + pub(crate) mod loader; mod shim; @@ -27,3 +31,41 @@ mod util { impl>> Valuetools for I {} } + +impl Protocol +where + C: CurveAffine, +{ + pub fn loaded_preprocessed_as_witness<'a, EccChip: EccInstructions<'a, C>>( + &self, + loader: &Rc>, + ) -> Protocol>> { + let preprocessed = self + .preprocessed + .iter() + .map(|preprocessed| loader.assign_ec_point(circuit::Value::known(*preprocessed))) + .collect(); + let transcript_initial_state = + self.transcript_initial_state + .as_ref() + .map(|transcript_initial_state| { + loader.assign_scalar(circuit::Value::known( + loader.scalar_chip().integer(*transcript_initial_state), + )) + }); + Protocol { + domain: self.domain.clone(), + preprocessed, + num_instance: self.num_instance.clone(), + num_witness: self.num_witness.clone(), + num_challenge: self.num_challenge.clone(), + evaluations: self.evaluations.clone(), + queries: self.queries.clone(), + quotient: self.quotient.clone(), + transcript_initial_state, + instance_committing_key: self.instance_committing_key.clone(), + linearization: self.linearization.clone(), + accumulator_indices: self.accumulator_indices.clone(), + } + } +} diff --git a/src/loader/halo2/loader.rs b/src/loader/halo2/loader.rs index 0d288ce7..d446c716 100644 --- a/src/loader/halo2/loader.rs +++ b/src/loader/halo2/loader.rs @@ -11,9 +11,7 @@ use crate::{ use halo2_proofs::circuit; use std::{ cell::{Ref, RefCell, RefMut}, - collections::btree_map::{BTreeMap, Entry}, fmt::{self, Debug}, - iter, marker::PhantomData, ops::{Add, AddAssign, Deref, Mul, MulAssign, Neg, Sub, SubAssign}, rc::Rc, @@ -25,7 +23,6 @@ pub struct Halo2Loader<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { ctx: RefCell, num_scalar: RefCell, num_ec_point: RefCell, - const_ec_point: RefCell>>, _marker: PhantomData, #[cfg(test)] row_meterings: RefCell>, @@ -38,7 +35,6 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc ctx: RefCell::new(ctx), num_scalar: RefCell::default(), num_ec_point: RefCell::default(), - const_ec_point: RefCell::default(), #[cfg(test)] row_meterings: RefCell::default(), _marker: PhantomData, @@ -61,16 +57,16 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc self.ctx.borrow() } - pub(crate) fn ctx_mut(&self) -> RefMut<'_, EccChip::Context> { + pub fn ctx_mut(&self) -> RefMut<'_, EccChip::Context> { self.ctx.borrow_mut() } - pub fn assign_const_scalar(self: &Rc, constant: C::Scalar) -> Scalar<'a, C, EccChip> { + fn assign_const_scalar(self: &Rc, constant: C::Scalar) -> Scalar<'a, C, EccChip> { let assigned = self .scalar_chip() .assign_constant(&mut self.ctx_mut(), constant) .unwrap(); - self.scalar(Value::Assigned(assigned)) + self.scalar_from_assigned(assigned) } pub fn assign_scalar( @@ -81,10 +77,17 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc .scalar_chip() .assign_integer(&mut self.ctx_mut(), scalar) .unwrap(); + self.scalar_from_assigned(assigned) + } + + pub fn scalar_from_assigned( + self: &Rc, + assigned: EccChip::AssignedScalar, + ) -> Scalar<'a, C, EccChip> { self.scalar(Value::Assigned(assigned)) } - pub(crate) fn scalar( + fn scalar( self: &Rc, value: Value, ) -> Scalar<'a, C, EccChip> { @@ -97,23 +100,12 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc } } - pub fn assign_const_ec_point(self: &Rc, constant: C) -> EcPoint<'a, C, EccChip> { - let coordinates = constant.coordinates().unwrap(); - match self - .const_ec_point - .borrow_mut() - .entry((*coordinates.x(), *coordinates.y())) - { - Entry::Occupied(entry) => entry.get().clone(), - Entry::Vacant(entry) => { - let assigned = self - .ecc_chip() - .assign_point(&mut self.ctx_mut(), circuit::Value::known(constant)) - .unwrap(); - let ec_point = self.ec_point(assigned); - entry.insert(ec_point).clone() - } - } + fn assign_const_ec_point(self: &Rc, constant: C) -> EcPoint<'a, C, EccChip> { + self.ec_point_from_assigned( + self.ecc_chip() + .assign_constant(&mut self.ctx_mut(), constant) + .unwrap(), + ) } pub fn assign_ec_point( @@ -124,16 +116,26 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc .ecc_chip() .assign_point(&mut self.ctx_mut(), ec_point) .unwrap(); - self.ec_point(assigned) + self.ec_point_from_assigned(assigned) + } + + pub fn ec_point_from_assigned( + self: &Rc, + assigned: EccChip::AssignedEcPoint, + ) -> EcPoint<'a, C, EccChip> { + self.ec_point(Value::Assigned(assigned)) } - fn ec_point(self: &Rc, assigned: EccChip::AssignedEcPoint) -> EcPoint<'a, C, EccChip> { + fn ec_point( + self: &Rc, + value: Value, + ) -> EcPoint<'a, C, EccChip> { let index = *self.num_ec_point.borrow(); *self.num_ec_point.borrow_mut() += 1; EcPoint { loader: self.clone(), index, - assigned, + value, } } @@ -305,7 +307,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Scalar<'a, C, EccChip> &self.loader } - pub(crate) fn assigned(&self) -> EccChip::AssignedScalar { + pub fn assigned(&self) -> EccChip::AssignedScalar { match &self.value { Value::Constant(constant) => self.loader.assign_const_scalar(*constant).assigned(), Value::Assigned(assigned) => assigned.clone(), @@ -451,12 +453,15 @@ impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> MulAssign<&'b Self pub struct EcPoint<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { loader: Rc>, index: usize, - assigned: EccChip::AssignedEcPoint, + value: Value, } impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPoint<'a, C, EccChip> { pub fn assigned(&self) -> EccChip::AssignedEcPoint { - self.assigned.clone() + match &self.value { + Value::Constant(constant) => self.loader.assign_const_ec_point(*constant).assigned(), + Value::Assigned(assigned) => assigned.clone(), + } } } @@ -474,65 +479,13 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> LoadedEcPoint fn loader(&self) -> &Self::Loader { &self.loader } - - fn multi_scalar_multiplication( - pairs: impl IntoIterator, Self)>, - ) -> Self { - let pairs = pairs.into_iter().collect_vec(); - let loader = &pairs[0].0.loader; - - let (non_scaled, scaled) = pairs.iter().fold( - (Vec::new(), Vec::new()), - |(mut non_scaled, mut scaled), (scalar, ec_point)| { - if matches!(scalar.value, Value::Constant(constant) if constant == C::Scalar::one()) - { - non_scaled.push(ec_point.assigned()); - } else { - scaled.push((ec_point.assigned(), scalar.assigned())) - } - (non_scaled, scaled) - }, - ); - - let output = iter::empty() - .chain(if scaled.is_empty() { - None - } else { - Some( - loader - .ecc_chip - .borrow_mut() - .multi_scalar_multiplication(&mut loader.ctx_mut(), scaled) - .unwrap(), - ) - }) - .chain(non_scaled) - .reduce(|acc, ec_point| { - EccInstructions::add( - loader.ecc_chip().deref(), - &mut loader.ctx_mut(), - &acc, - &ec_point, - ) - .unwrap() - }) - .map(|output| { - loader - .ecc_chip() - .normalize(&mut loader.ctx_mut(), &output) - .unwrap() - }) - .unwrap(); - - loader.ec_point(output) - } } impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Debug for EcPoint<'a, C, EccChip> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EcPoint") .field("index", &self.index) - .field("assigned", &self.assigned) + .field("value", &self.value) .finish() } } @@ -596,7 +549,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPointLoader type LoadedEcPoint = EcPoint<'a, C, EccChip>; fn ec_point_load_const(&self, ec_point: &C) -> EcPoint<'a, C, EccChip> { - self.assign_const_ec_point(*ec_point) + self.ec_point(Value::Constant(*ec_point)) } fn ec_point_assert_eq( @@ -605,9 +558,100 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPointLoader lhs: &EcPoint<'a, C, EccChip>, rhs: &EcPoint<'a, C, EccChip>, ) -> Result<(), crate::Error> { - self.ecc_chip() - .assert_equal(&mut self.ctx_mut(), &lhs.assigned(), &rhs.assigned()) - .map_err(|_| crate::Error::AssertionFailure(annotation.to_string())) + match (&lhs.value, &rhs.value) { + (Value::Constant(lhs), Value::Constant(rhs)) => { + assert_eq!(lhs, rhs); + Ok(()) + } + (Value::Constant(constant), Value::Assigned(assigned)) + | (Value::Assigned(assigned), Value::Constant(constant)) => { + let constant = self.assign_const_ec_point(*constant).assigned(); + self.ecc_chip() + .assert_equal(&mut self.ctx_mut(), assigned, &constant) + .map_err(|_| crate::Error::AssertionFailure(annotation.to_string())) + } + (Value::Assigned(lhs), Value::Assigned(rhs)) => self + .ecc_chip() + .assert_equal(&mut self.ctx_mut(), lhs, rhs) + .map_err(|_| crate::Error::AssertionFailure(annotation.to_string())), + } + } + + fn multi_scalar_multiplication( + pairs: &[( + >::LoadedScalar, + EcPoint<'a, C, EccChip>, + )], + ) -> EcPoint<'a, C, EccChip> { + let loader = &pairs[0].0.loader; + + let (constant, fixed_base, variable_base_non_scaled, variable_base_scaled) = + pairs.iter().fold( + (C::identity(), Vec::new(), Vec::new(), Vec::new()), + |( + mut constant, + mut fixed_base, + mut variable_base_non_scaled, + mut variable_base_scaled, + ), + (scalar, ec_point)| { + match (&ec_point.value, &scalar.value) { + (Value::Constant(ec_point), Value::Constant(scalar)) => { + constant = (*ec_point * scalar + constant).into() + } + (Value::Constant(ec_point), Value::Assigned(scalar)) => { + fixed_base.push((scalar.clone(), *ec_point)) + } + (Value::Assigned(ec_point), Value::Constant(scalar)) + if scalar.eq(&C::Scalar::one()) => + { + variable_base_non_scaled.push(ec_point.clone()); + } + (Value::Assigned(ec_point), _) => { + variable_base_scaled.push((scalar.assigned(), ec_point.clone())) + } + }; + ( + constant, + fixed_base, + variable_base_non_scaled, + variable_base_scaled, + ) + }, + ); + + let fixed_base_msm = (!fixed_base.is_empty()).then(|| { + loader + .ecc_chip + .borrow_mut() + .fixed_base_msm(&mut loader.ctx_mut(), &fixed_base) + .unwrap() + }); + let variable_base_msm = (!variable_base_scaled.is_empty()).then(|| { + loader + .ecc_chip + .borrow_mut() + .variable_base_msm(&mut loader.ctx_mut(), &variable_base_scaled) + .unwrap() + }); + let output = loader + .ecc_chip() + .sum_with_const( + &mut loader.ctx_mut(), + &variable_base_non_scaled + .into_iter() + .chain(fixed_base_msm) + .chain(variable_base_msm) + .collect_vec(), + constant, + ) + .unwrap(); + let normalized = loader + .ecc_chip() + .normalize(&mut loader.ctx_mut(), &output) + .unwrap(); + + loader.ec_point_from_assigned(normalized) } } diff --git a/src/loader/halo2/shim.rs b/src/loader/halo2/shim.rs index 67f06cc9..97921d24 100644 --- a/src/loader/halo2/shim.rs +++ b/src/loader/halo2/shim.rs @@ -98,17 +98,23 @@ pub trait EccInstructions<'a, C: CurveAffine>: Clone + Debug { point: Value, ) -> Result; - fn add( + fn sum_with_const( &self, ctx: &mut Self::Context, - p0: &Self::AssignedEcPoint, - p1: &Self::AssignedEcPoint, + values: &[Self::AssignedEcPoint], + constant: C, ) -> Result; - fn multi_scalar_multiplication( + fn fixed_base_msm( &mut self, ctx: &mut Self::Context, - pairs: Vec<(Self::AssignedEcPoint, Self::AssignedScalar)>, + pairs: &[(Self::AssignedScalar, C)], + ) -> Result; + + fn variable_base_msm( + &mut self, + ctx: &mut Self::Context, + pairs: &[(Self::AssignedScalar, Self::AssignedEcPoint)], ) -> Result; fn normalize( @@ -146,6 +152,7 @@ mod halo2_wrong { AssignedPoint, BaseFieldEccChip, }; use rand::rngs::OsRng; + use std::iter; impl<'a, F: FieldExt> Context for RegionCtx<'a, F> { fn constrain_equal(&mut self, lhs: Cell, rhs: Cell) -> Result<(), Error> { @@ -348,21 +355,51 @@ mod halo2_wrong { self.assign_point(ctx, point) } - fn add( + fn sum_with_const( &self, ctx: &mut Self::Context, - p0: &Self::AssignedEcPoint, - p1: &Self::AssignedEcPoint, + values: &[Self::AssignedEcPoint], + constant: C, + ) -> Result { + if values.is_empty() { + return self.assign_constant(ctx, constant); + } + + iter::empty() + .chain( + (!bool::from(constant.is_identity())) + .then(|| self.assign_constant(ctx, constant)), + ) + .chain(values.iter().cloned().map(Ok)) + .reduce(|acc, ec_point| self.add(ctx, &acc?, &ec_point?)) + .unwrap() + } + + fn fixed_base_msm( + &mut self, + ctx: &mut Self::Context, + pairs: &[(Self::AssignedScalar, C)], ) -> Result { - self.add(ctx, p0, p1) + // FIXME: Implement fixed base MSM in halo2_wrong + let pairs = pairs + .iter() + .map(|(scalar, base)| { + Ok::<_, Error>((scalar.clone(), self.assign_constant(ctx, *base)?)) + }) + .collect::, _>>()?; + self.variable_base_msm(ctx, &pairs) } - fn multi_scalar_multiplication( + fn variable_base_msm( &mut self, ctx: &mut Self::Context, - pairs: Vec<(Self::AssignedEcPoint, Self::AssignedScalar)>, + pairs: &[(Self::AssignedScalar, Self::AssignedEcPoint)], ) -> Result { const WINDOW_SIZE: usize = 3; + let pairs = pairs + .iter() + .map(|(scalar, base)| (base.clone(), scalar.clone())) + .collect_vec(); match self.mul_batch_1d_horizontal(ctx, pairs.clone(), WINDOW_SIZE) { Err(_) => { if self.assign_aux(ctx, WINDOW_SIZE, pairs.len()).is_err() { diff --git a/src/loader/native.rs b/src/loader/native.rs index 6bf9f7c4..1451ff76 100644 --- a/src/loader/native.rs +++ b/src/loader/native.rs @@ -19,15 +19,6 @@ impl LoadedEcPoint for C { fn loader(&self) -> &NativeLoader { &LOADER } - - fn multi_scalar_multiplication(pairs: impl IntoIterator) -> Self { - pairs - .into_iter() - .map(|(scalar, base)| base * scalar) - .reduce(|acc, value| acc + value) - .unwrap() - .to_affine() - } } impl FieldOps for F { @@ -61,6 +52,17 @@ impl EcPointLoader for NativeLoader { .then_some(()) .ok_or_else(|| Error::AssertionFailure(annotation.to_string())) } + + fn multi_scalar_multiplication( + pairs: &[(>::LoadedScalar, C)], + ) -> C { + pairs + .iter() + .map(|(scalar, base)| *base * scalar) + .reduce(|acc, value| acc + value) + .unwrap() + .to_affine() + } } impl ScalarLoader for NativeLoader { diff --git a/src/pcs/kzg/multiopen/bdfg21.rs b/src/pcs/kzg/multiopen/bdfg21.rs index 287700d7..7f70ca61 100644 --- a/src/pcs/kzg/multiopen/bdfg21.rs +++ b/src/pcs/kzg/multiopen/bdfg21.rs @@ -203,8 +203,8 @@ fn query_set_coeffs>( }) .collect_vec(); - T::batch_invert(coeffs.iter_mut().flat_map(QuerySetCoeff::denoms)); - T::batch_invert(coeffs.iter_mut().flat_map(QuerySetCoeff::denoms)); + T::Loader::batch_invert(coeffs.iter_mut().flat_map(QuerySetCoeff::denoms)); + T::Loader::batch_invert(coeffs.iter_mut().flat_map(QuerySetCoeff::denoms)); coeffs.iter_mut().for_each(QuerySetCoeff::evaluate); coeffs diff --git a/src/system/halo2.rs b/src/system/halo2.rs index bf3e4091..3d7cf140 100644 --- a/src/system/halo2.rs +++ b/src/system/halo2.rs @@ -70,8 +70,11 @@ impl Config { self } - pub fn with_accumulator_indices(mut self, accumulator_indices: Vec<(usize, usize)>) -> Self { - self.accumulator_indices = Some(accumulator_indices); + pub fn with_accumulator_indices( + mut self, + accumulator_indices: Option>, + ) -> Self { + self.accumulator_indices = accumulator_indices; self } } @@ -202,7 +205,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { degree - 1 }; - let num_phase = *cs.advice_column_phase().iter().max().unwrap() as usize + 1; + let num_phase = *cs.advice_column_phase().iter().max().unwrap_or(&0) as usize + 1; let remapping = |phase: Vec| { let num = phase.iter().fold(vec![0; num_phase], |mut num, phase| { num[*phase as usize] += 1; diff --git a/src/system/halo2/test/kzg.rs b/src/system/halo2/test/kzg.rs index 0b071175..3b7e1694 100644 --- a/src/system/halo2/test/kzg.rs +++ b/src/system/halo2/test/kzg.rs @@ -45,7 +45,7 @@ macro_rules! halo2_kzg_config { $crate::system::halo2::Config::kzg() .set_zk($zk) .with_num_proof($num_proof) - .with_accumulator_indices($accumulator_indices) + .with_accumulator_indices(Some($accumulator_indices)) }; } diff --git a/src/system/halo2/test/kzg/evm.rs b/src/system/halo2/test/kzg/evm.rs index 4ce850c1..4e57d369 100644 --- a/src/system/halo2/test/kzg/evm.rs +++ b/src/system/halo2/test/kzg/evm.rs @@ -37,16 +37,17 @@ macro_rules! halo2_kzg_evm_verify { let runtime_code = { let svk = $params.get_g()[0].into(); let dk = ($params.g2(), $params.s_g2()).into(); - let mut transcript = EvmTranscript::<_, Rc, _, _>::new(loader.clone()); + let protocol = $protocol.loaded(&loader); + let mut transcript = EvmTranscript::<_, Rc, _, _>::new(&loader); let instances = transcript.load_instances( $instances .iter() .map(|instances| instances.len()) .collect_vec(), ); - let proof = <$plonk_verifier>::read_proof(&svk, $protocol, &instances, &mut transcript) + let proof = <$plonk_verifier>::read_proof(&svk, &protocol, &instances, &mut transcript) .unwrap(); - <$plonk_verifier>::verify(&svk, &dk, $protocol, &instances, &proof).unwrap(); + <$plonk_verifier>::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); loader.runtime_code() }; diff --git a/src/system/halo2/test/kzg/halo2.rs b/src/system/halo2/test/kzg/halo2.rs index 1bd332a0..18767c98 100644 --- a/src/system/halo2/test/kzg/halo2.rs +++ b/src/system/halo2/test/kzg/halo2.rs @@ -89,12 +89,12 @@ pub fn accumulate<'a>( let mut accumulators = snarks .iter() .flat_map(|snark| { + let protocol = snark.protocol.loaded(loader); let instances = assign_instances(&snark.instances); let mut transcript = PoseidonTranscript::, _>::new(loader, snark.proof()); - let proof = - Plonk::read_proof(svk, &snark.protocol, &instances, &mut transcript).unwrap(); - Plonk::succinct_verify(svk, &snark.protocol, &instances, &proof).unwrap() + let proof = Plonk::read_proof(svk, &protocol, &instances, &mut transcript).unwrap(); + Plonk::succinct_verify(svk, &protocol, &instances, &proof).unwrap() }) .collect_vec(); diff --git a/src/system/halo2/transcript/evm.rs b/src/system/halo2/transcript/evm.rs index 77aca5cf..e461bc05 100644 --- a/src/system/halo2/transcript/evm.rs +++ b/src/system/halo2/transcript/evm.rs @@ -32,13 +32,13 @@ where C: CurveAffine, C::Scalar: PrimeField, { - pub fn new(loader: Rc) -> Self { + pub fn new(loader: &Rc) -> Self { let ptr = loader.allocate(0x20); assert_eq!(ptr, 0); let mut buf = MemoryChunk::new(ptr); buf.extend(0x20); Self { - loader, + loader: loader.clone(), stream: 0, buf, _marker: PhantomData, diff --git a/src/system/halo2/transcript/halo2.rs b/src/system/halo2/transcript/halo2.rs index 43701bd7..bb7e8e23 100644 --- a/src/system/halo2/transcript/halo2.rs +++ b/src/system/halo2/transcript/halo2.rs @@ -1,11 +1,11 @@ use crate::{ loader::{ - halo2::{self, EcPoint, EccInstructions, Halo2Loader, IntegerInstructions, Scalar}, + halo2::{EcPoint, EccInstructions, Halo2Loader, IntegerInstructions, Scalar}, native::{self, NativeLoader}, Loader, ScalarLoader, }, util::{ - arithmetic::{fe_from_big, fe_to_big, CurveAffine, FieldExt, PrimeField}, + arithmetic::{fe_to_fe, CurveAffine, FieldExt, PrimeField}, hash::Poseidon, transcript::{Transcript, TranscriptRead, TranscriptWrite}, Itertools, @@ -57,10 +57,11 @@ impl< > PoseidonTranscript>, Value, T, RATE, R_F, R_P> { pub fn new(loader: &Rc>, stream: Value) -> Self { + let buf = Poseidon::new(loader, R_F, R_P); Self { loader: loader.clone(), stream, - buf: Poseidon::new(loader.clone(), R_F, R_P), + buf, _marker: PhantomData, } } @@ -99,7 +100,7 @@ impl< .map(|encoded| { encoded .into_iter() - .map(|encoded| self.loader.scalar(halo2::loader::Value::Assigned(encoded))) + .map(|encoded| self.loader.scalar_from_assigned(encoded)) .collect_vec() }) .map_err(|_| Error::Transcript(io::ErrorKind::Other, "".to_string()))?; @@ -160,7 +161,7 @@ impl = Option::from(ec_point.coordinates().map(|coordinates| { [coordinates.x(), coordinates.y()] .into_iter() - .map(|fe| fe_from_big(fe_to_big(*fe))) + .cloned() + .map(fe_to_fe) .collect_vec() })) .ok_or_else(|| { diff --git a/src/util/hash/poseidon.rs b/src/util/hash/poseidon.rs index 878b69ce..c0fc03a6 100644 --- a/src/util/hash/poseidon.rs +++ b/src/util/hash/poseidon.rs @@ -113,7 +113,7 @@ pub struct Poseidon { } impl, const T: usize, const RATE: usize> Poseidon { - pub fn new(loader: L::Loader, r_f: usize, r_p: usize) -> Self { + pub fn new(loader: &L::Loader, r_f: usize, r_p: usize) -> Self { Self { spec: Spec::new(r_f, r_p), state: State::new( diff --git a/src/util/msm.rs b/src/util/msm.rs index a7a3d45d..a15eab9d 100644 --- a/src/util/msm.rs +++ b/src/util/msm.rs @@ -1,6 +1,6 @@ use crate::{ loader::{LoadedEcPoint, Loader}, - util::arithmetic::CurveAffine, + util::{arithmetic::CurveAffine, Itertools}, }; use std::{ default::Default, @@ -71,11 +71,11 @@ where .loader() .ec_point_load_const(&gen) }); - L::LoadedEcPoint::multi_scalar_multiplication( - iter::empty() - .chain(self.constant.map(|constant| (constant, gen.unwrap()))) - .chain(self.scalars.into_iter().zip(self.bases.into_iter())), - ) + let pairs = iter::empty() + .chain(self.constant.map(|constant| (constant, gen.unwrap()))) + .chain(self.scalars.into_iter().zip(self.bases.into_iter())) + .collect_vec(); + L::multi_scalar_multiplication(&pairs) } pub fn scale(&mut self, factor: &L::LoadedScalar) { diff --git a/src/util/protocol.rs b/src/util/protocol.rs index bae363ff..e9ecd9f0 100644 --- a/src/util/protocol.rs +++ b/src/util/protocol.rs @@ -4,6 +4,7 @@ use crate::{ arithmetic::{CurveAffine, Domain, Field, Fraction, Rotation}, Itertools, }, + Protocol, }; use num_integer::Integer; use num_traits::One; @@ -15,6 +16,37 @@ use std::{ ops::{Add, Mul, Neg, Sub}, }; +impl Protocol +where + C: CurveAffine, +{ + pub fn loaded>(&self, loader: &L) -> Protocol { + let preprocessed = self + .preprocessed + .iter() + .map(|preprocessed| loader.ec_point_load_const(preprocessed)) + .collect(); + let transcript_initial_state = self + .transcript_initial_state + .as_ref() + .map(|transcript_initial_state| loader.load_const(transcript_initial_state)); + Protocol { + domain: self.domain.clone(), + preprocessed, + num_instance: self.num_instance.clone(), + num_witness: self.num_witness.clone(), + num_challenge: self.num_challenge.clone(), + evaluations: self.evaluations.clone(), + queries: self.queries.clone(), + quotient: self.quotient.clone(), + transcript_initial_state, + instance_committing_key: self.instance_committing_key.clone(), + linearization: self.linearization.clone(), + accumulator_indices: self.accumulator_indices.clone(), + } + } +} + #[derive(Clone, Copy, Debug)] pub enum CommonPolynomial { Identity, diff --git a/src/verifier.rs b/src/verifier.rs index 07529603..0eef23d2 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -20,7 +20,7 @@ where fn read_proof( svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, + protocol: &Protocol, instances: &[Vec], transcript: &mut T, ) -> Result @@ -29,7 +29,7 @@ where fn succinct_verify( svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, + protocol: &Protocol, instances: &[Vec], proof: &Self::Proof, ) -> Result, Error>; @@ -37,7 +37,7 @@ where fn verify( svk: &MOS::SuccinctVerifyingKey, dk: &MOS::DecidingKey, - protocol: &Protocol, + protocol: &Protocol, instances: &[Vec], proof: &Self::Proof, ) -> Result diff --git a/src/verifier/plonk.rs b/src/verifier/plonk.rs index 9e08e585..c3276af4 100644 --- a/src/verifier/plonk.rs +++ b/src/verifier/plonk.rs @@ -29,7 +29,7 @@ where fn read_proof( svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, + protocol: &Protocol, instances: &[Vec], transcript: &mut T, ) -> Result @@ -41,7 +41,7 @@ where fn succinct_verify( svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, + protocol: &Protocol, instances: &[Vec], proof: &Self::Proof, ) -> Result, Error> { @@ -52,7 +52,7 @@ where &proof.z, ); - L::LoadedScalar::batch_invert(common_poly_eval.denoms()); + L::batch_invert(common_poly_eval.denoms()); common_poly_eval.evaluate(); common_poly_eval @@ -96,9 +96,9 @@ where L: Loader, MOS: MultiOpenScheme, { - fn read( + pub fn read( svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, + protocol: &Protocol, instances: &[Vec], transcript: &mut T, ) -> Result @@ -106,9 +106,8 @@ where T: TranscriptRead, AE: AccumulatorEncoding, { - let loader = transcript.loader(); if let Some(transcript_initial_state) = &protocol.transcript_initial_state { - transcript.common_scalar(&loader.load_const(transcript_initial_state))?; + transcript.common_scalar(transcript_initial_state)?; } if protocol.num_instance @@ -211,7 +210,7 @@ where }) } - fn empty_queries(protocol: &Protocol) -> Vec> { + pub fn empty_queries(protocol: &Protocol) -> Vec> { protocol .queries .iter() @@ -227,7 +226,7 @@ where fn queries( &self, - protocol: &Protocol, + protocol: &Protocol, mut evaluations: HashMap, ) -> Vec> { Self::empty_queries(protocol) @@ -244,7 +243,7 @@ where fn commitments( &self, - protocol: &Protocol, + protocol: &Protocol, common_poly_eval: &CommonPolynomialEvaluation, evaluations: &mut HashMap, ) -> Result>, Error> { @@ -254,7 +253,7 @@ where protocol .preprocessed .iter() - .map(|value| Msm::base(loader.ec_point_load_const(value))), + .map(|value| Msm::base(value.clone())), ) .chain( self.committed_instances @@ -357,7 +356,7 @@ where fn evaluations( &self, - protocol: &Protocol, + protocol: &Protocol, instances: &[Vec], common_poly_eval: &CommonPolynomialEvaluation, ) -> Result, Error> { @@ -424,9 +423,13 @@ where } } -fn langranges(protocol: &Protocol, instances: &[Vec]) -> impl IntoIterator +fn langranges( + protocol: &Protocol, + instances: &[Vec], +) -> impl IntoIterator where C: CurveAffine, + L: Loader, { let instance_eval_lagrange = protocol.instance_committing_key.is_none().then(|| { let queries = { From 25dbaf524e7a81f52e65aa6ae45a8f1e7ac509c3 Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 8 Nov 2022 10:21:24 -0800 Subject: [PATCH 03/73] General refactor for further integration (#13) * feat: remove dev-dependency `foundry` and vendor necessary part of it * refactor: simplify traits and remove unused stuff * refactor: much less clone * feat: generalized `AccumulatorEncoding` for `EccInstructions` --- Cargo.toml | 15 +- examples/evm-verifier-with-accumulator.rs | 48 +- examples/evm-verifier.rs | 13 +- src/loader.rs | 13 +- src/loader/evm.rs | 4 +- src/loader/evm/loader.rs | 11 +- src/loader/evm/test.rs | 22 +- src/loader/evm/test/tui.rs | 57 +- src/loader/evm/util.rs | 4 + src/loader/evm/util/executor.rs | 868 ++++++++++++++++++++++ src/loader/halo2.rs | 8 +- src/loader/halo2/loader.rs | 221 +++--- src/loader/halo2/shim.rs | 168 +++-- src/loader/native.rs | 3 +- src/pcs.rs | 4 +- src/pcs/kzg.rs | 3 + src/pcs/kzg/accumulation.rs | 14 +- src/pcs/kzg/accumulator.rs | 132 +++- src/pcs/kzg/decider.rs | 2 +- src/pcs/kzg/multiopen/bdfg21.rs | 35 +- src/pcs/kzg/multiopen/gwc19.rs | 20 +- src/system/halo2.rs | 22 +- src/system/halo2/test/kzg.rs | 4 +- src/system/halo2/test/kzg/halo2.rs | 33 +- src/system/halo2/transcript/halo2.rs | 191 ++--- src/util/arithmetic.rs | 17 +- src/util/msm.rs | 62 +- src/util/protocol.rs | 8 +- src/verifier/plonk.rs | 36 +- 29 files changed, 1488 insertions(+), 550 deletions(-) create mode 100644 src/loader/evm/util/executor.rs diff --git a/Cargo.toml b/Cargo.toml index 803beade..e5bbb0d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,14 +10,18 @@ num-bigint = "0.4.3" num-integer = "0.1.45" num-traits = "0.2.15" rand = "0.8" +hex = "0.4" halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.0", package = "halo2curves" } # system_halo2 halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2022_10_22", optional = true } # loader_evm -ethereum_types = { package = "ethereum-types", version = "0.13.1", default-features = false, features = ["std"], optional = true } -sha3 = { version = "0.10.1", optional = true } +ethereum_types = { package = "ethereum-types", version = "0.13", default-features = false, features = ["std"], optional = true } +sha3 = { version = "0.10", optional = true } +revm = { version = "2.1.0", optional = true } +bytes = { version = "1.2", optional = true } +rlp = { version = "0.5", default-features = false, features = ["std"], optional = true } # loader_halo2 halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc", optional = true } @@ -31,14 +35,13 @@ paste = "1.0.7" halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc" } # loader_evm -foundry_evm = { git = "https://github.com/foundry-rs/foundry", package = "foundry-evm", rev = "6b1ee60e" } -crossterm = { version = "0.22.1" } -tui = { version = "0.16.0", default-features = false, features = ["crossterm"] } +crossterm = { version = "0.25" } +tui = { version = "0.19", default-features = false, features = ["crossterm"] } [features] default = ["loader_evm", "loader_halo2", "system_halo2"] -loader_evm = ["dep:ethereum_types", "dep:sha3"] +loader_evm = ["dep:ethereum_types", "dep:sha3", "dep:revm", "dep:bytes", "dep:rlp"] loader_halo2 = ["dep:halo2_proofs", "dep:halo2_wrong_ecc", "dep:poseidon"] system_halo2 = ["dep:halo2_proofs"] diff --git a/examples/evm-verifier-with-accumulator.rs b/examples/evm-verifier-with-accumulator.rs index 66fa8ddf..10a7b269 100644 --- a/examples/evm-verifier-with-accumulator.rs +++ b/examples/evm-verifier-with-accumulator.rs @@ -1,5 +1,4 @@ use ethereum_types::Address; -use foundry_evm::executor::{fork::MultiFork, Backend, ExecutorBuilder}; use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ dev::MockProver, @@ -18,7 +17,7 @@ use halo2_proofs::{ use itertools::Itertools; use plonk_verifier::{ loader::{ - evm::{encode_calldata, EvmLoader}, + evm::{encode_calldata, EvmLoader, ExecutorBuilder}, native::NativeLoader, }, pcs::kzg::{Gwc19, Kzg, KzgAs, LimbsEncoding}, @@ -167,7 +166,7 @@ mod aggregation { use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, - plonk::{self, Circuit, ConstraintSystem}, + plonk::{self, Circuit, ConstraintSystem, Error}, poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG}, }; use halo2_wrong_ecc::{ @@ -182,7 +181,7 @@ mod aggregation { use plonk_verifier::{ loader::{self, native::NativeLoader}, pcs::{ - kzg::{KzgAccumulator, KzgSuccinctVerifyingKey}, + kzg::{KzgAccumulator, KzgSuccinctVerifyingKey, LimbsEncodingInstructions}, AccumulationScheme, AccumulationSchemeProver, }, system, @@ -191,7 +190,7 @@ mod aggregation { Protocol, }; use rand::rngs::OsRng; - use std::{iter, rc::Rc}; + use std::rc::Rc; const T: usize = 5; const RATE: usize = 4; @@ -434,28 +433,33 @@ mod aggregation { range_chip.load_table(&mut layouter)?; - let (lhs, rhs) = layouter.assign_region( + let accumulator_limbs = layouter.assign_region( || "", |region| { let ctx = RegionCtx::new(region, 0); let ecc_chip = config.ecc_chip(); let loader = Halo2Loader::new(ecc_chip, ctx); - let KzgAccumulator { lhs, rhs } = - aggregate(&self.svk, &loader, &self.snarks, self.as_proof()); + let accumulator = aggregate(&self.svk, &loader, &self.snarks, self.as_proof()); - Ok((lhs.assigned(), rhs.assigned())) + let accumulator_limbs = [accumulator.lhs, accumulator.rhs] + .iter() + .map(|ec_point| { + loader.ecc_chip().assign_ec_point_to_limbs( + &mut loader.ctx_mut(), + ec_point.assigned(), + ) + }) + .collect::, Error>>()? + .into_iter() + .flatten(); + + Ok(accumulator_limbs) }, )?; - for (limb, row) in iter::empty() - .chain(lhs.x().limbs()) - .chain(lhs.y().limbs()) - .chain(rhs.x().limbs()) - .chain(rhs.y().limbs()) - .zip(0..) - { - main_gate.expose_public(layouter.namespace(|| ""), limb.into(), row)?; + for (row, limb) in accumulator_limbs.enumerate() { + main_gate.expose_public(layouter.namespace(|| ""), limb, row)?; } Ok(()) @@ -574,16 +578,14 @@ fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) let success = { let mut evm = ExecutorBuilder::default() .with_gas_limit(u64::MAX.into()) - .build(Backend::new(MultiFork::new().0, None)); + .build(); let caller = Address::from_low_u64_be(0xfe); let verifier = evm - .deploy(caller, deployment_code.into(), 0.into(), None) - .unwrap() - .address; - let result = evm - .call_raw(caller, verifier, calldata.into(), 0.into()) + .deploy(caller, deployment_code.into(), 0.into()) + .address .unwrap(); + let result = evm.call_raw(caller, verifier, calldata.into(), 0.into()); dbg!(result.gas_used); diff --git a/examples/evm-verifier.rs b/examples/evm-verifier.rs index 9ed70b36..4ff5c682 100644 --- a/examples/evm-verifier.rs +++ b/examples/evm-verifier.rs @@ -1,5 +1,4 @@ use ethereum_types::Address; -use foundry_evm::executor::{fork::MultiFork, Backend, ExecutorBuilder}; use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, @@ -21,7 +20,7 @@ use halo2_proofs::{ }; use itertools::Itertools; use plonk_verifier::{ - loader::evm::{encode_calldata, EvmLoader}, + loader::evm::{encode_calldata, EvmLoader, ExecutorBuilder}, pcs::kzg::{Gwc19, Kzg}, system::halo2::{compile, transcript::evm::EvmTranscript, Config}, verifier::{self, PlonkVerifier}, @@ -231,16 +230,14 @@ fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) let success = { let mut evm = ExecutorBuilder::default() .with_gas_limit(u64::MAX.into()) - .build(Backend::new(MultiFork::new().0, None)); + .build(); let caller = Address::from_low_u64_be(0xfe); let verifier = evm - .deploy(caller, deployment_code.into(), 0.into(), None) - .unwrap() - .address; - let result = evm - .call_raw(caller, verifier, calldata.into(), 0.into()) + .deploy(caller, deployment_code.into(), 0.into()) + .address .unwrap(); + let result = evm.call_raw(caller, verifier, calldata.into(), 0.into()); dbg!(result.gas_used); diff --git a/src/loader.rs b/src/loader.rs index 5a040f9f..297390d0 100644 --- a/src/loader.rs +++ b/src/loader.rs @@ -5,7 +5,7 @@ use crate::{ }, Error, }; -use std::{fmt::Debug, iter}; +use std::{borrow::Cow, fmt::Debug, iter, ops::Deref}; pub mod native; @@ -86,7 +86,7 @@ pub trait EcPointLoader { ) -> Result<(), Error>; fn multi_scalar_multiplication( - pairs: &[(Self::LoadedScalar, Self::LoadedEcPoint)], + pairs: &[(&Self::LoadedScalar, &Self::LoadedEcPoint)], ) -> Self::LoadedEcPoint where Self: ScalarLoader; @@ -126,17 +126,18 @@ pub trait ScalarLoader { .chain(if constant == F::zero() { None } else { - Some(loader.load_const(&constant)) + Some(Cow::Owned(loader.load_const(&constant))) }) .chain(values.iter().map(|&(coeff, value)| { if coeff == F::one() { - value.clone() + Cow::Borrowed(value) } else { - loader.load_const(&coeff) * value + Cow::Owned(loader.load_const(&coeff) * value) } })) - .reduce(|acc, term| acc + term) + .reduce(|acc, term| Cow::Owned(acc.into_owned() + term.deref())) .unwrap() + .into_owned() } fn sum_products_with_coeff_and_const( diff --git a/src/loader/evm.rs b/src/loader/evm.rs index 7a07670c..fa80b97e 100644 --- a/src/loader/evm.rs +++ b/src/loader/evm.rs @@ -6,7 +6,9 @@ mod util; mod test; pub use loader::{EcPoint, EvmLoader, Scalar}; -pub use util::{encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, MemoryChunk}; +pub use util::{ + encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, ExecutorBuilder, MemoryChunk, +}; pub use ethereum_types::U256; diff --git a/src/loader/evm/loader.rs b/src/loader/evm/loader.rs index 7d1dbb94..9e8b8e2a 100644 --- a/src/loader/evm/loader.rs +++ b/src/loader/evm/loader.rs @@ -37,7 +37,7 @@ impl PartialEq for Value { impl Value { fn identifier(&self) -> String { - match &self { + match self { Value::Constant(_) | Value::Memory(_) => format!("{:?}", self), Value::Negated(value) => format!("-({:?})", value), Value::Sum(lhs, rhs) => format!("({:?} + {:?})", lhs, rhs), @@ -222,13 +222,13 @@ impl EvmLoader { pub fn ec_point_from_limbs( self: &Rc, - x_limbs: [Scalar; LIMBS], - y_limbs: [Scalar; LIMBS], + x_limbs: [&Scalar; LIMBS], + y_limbs: [&Scalar; LIMBS], ) -> EcPoint { let ptr = self.allocate(0x40); for (ptr, limbs) in [(ptr, x_limbs), (ptr + 0x20, y_limbs)] { for (idx, limb) in limbs.into_iter().enumerate() { - self.push(&limb); + self.push(limb); // [..., success, acc] if idx > 0 { self.code @@ -769,10 +769,11 @@ where } fn multi_scalar_multiplication( - pairs: &[(>::LoadedScalar, EcPoint)], + pairs: &[(&>::LoadedScalar, &EcPoint)], ) -> EcPoint { pairs .iter() + .cloned() .map(|(scalar, ec_point)| match scalar.value { Value::Constant(constant) if U256::one() == constant => ec_point.clone(), _ => ec_point.loader.ec_point_scalar_mul(ec_point, scalar), diff --git a/src/loader/evm/test.rs b/src/loader/evm/test.rs index e204c1b8..f81c5f54 100644 --- a/src/loader/evm/test.rs +++ b/src/loader/evm/test.rs @@ -1,10 +1,9 @@ -use crate::{loader::evm::test::tui::Tui, util::Itertools}; -use foundry_evm::{ - executor::{backend::Backend, fork::MultiFork, ExecutorBuilder}, - revm::{AccountInfo, Bytecode}, - utils::h256_to_u256_be, - Address, +use crate::{ + loader::evm::{test::tui::Tui, util::ExecutorBuilder}, + util::Itertools, }; +use ethereum_types::{Address, U256}; +use revm::{AccountInfo, Bytecode}; use std::env::var_os; mod tui; @@ -29,23 +28,20 @@ pub fn execute(code: Vec, calldata: Vec) -> (bool, u64, Vec) { let mut evm = ExecutorBuilder::default() .with_gas_limit(u64::MAX.into()) - .set_tracing(debug) .set_debugger(debug) - .build(Backend::new(MultiFork::new().0, None)); + .build(); - evm.backend_mut().insert_account_info( + evm.db_mut().insert_account_info( callee, AccountInfo::new(0.into(), 1, Bytecode::new_raw(code.into())), ); - let result = evm - .call_raw(caller, callee, calldata.into(), 0.into()) - .unwrap(); + let result = evm.call_raw(caller, callee, calldata.into(), 0.into()); let costs = result .logs .into_iter() - .map(|log| h256_to_u256_be(log.topics[0]).as_u64()) + .map(|log| U256::from_big_endian(log.topics[0].as_bytes()).as_u64()) .collect_vec(); if debug { diff --git a/src/loader/evm/test/tui.rs b/src/loader/evm/test/tui.rs index fcaef36c..c0c4d7f8 100644 --- a/src/loader/evm/test/tui.rs +++ b/src/loader/evm/test/tui.rs @@ -1,5 +1,6 @@ //! Copied and modified from https://github.com/foundry-rs/foundry/blob/master/ui/src/lib.rs +use crate::loader::evm::util::executor::{CallKind, DebugStep}; use crossterm::{ event::{ self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers, @@ -8,11 +9,8 @@ use crossterm::{ execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; -use foundry_evm::{ - debug::{DebugStep, Instruction}, - revm::opcode, - Address, CallKind, -}; +use ethereum_types::Address; +use revm::opcode; use std::{ cmp::{max, min}, io, @@ -90,7 +88,7 @@ impl Tui { self.terminal.clear().unwrap(); let mut draw_memory: DrawMemory = DrawMemory::default(); - let debug_call: Vec<(Address, Vec, CallKind)> = self.debug_arena.clone(); + let debug_call = &self.debug_arena; let mut opcode_list: Vec = debug_call[0] .1 .iter() @@ -207,7 +205,7 @@ impl Tui { } KeyCode::Char('s') => { for _ in 0..Tui::buffer_as_number(&self.key_buffer, 1) { - let remaining_ops = opcode_list[self.current_step..].to_vec().clone(); + let remaining_ops = &opcode_list[self.current_step..]; self.current_step += remaining_ops .iter() .enumerate() @@ -233,7 +231,7 @@ impl Tui { } KeyCode::Char('a') => { for _ in 0..Tui::buffer_as_number(&self.key_buffer, 1) { - let prev_ops = opcode_list[..self.current_step].to_vec().clone(); + let prev_ops = &opcode_list[..self.current_step]; self.current_step = prev_ops .iter() .enumerate() @@ -618,12 +616,7 @@ impl Tui { .borders(Borders::ALL); let min_len = usize::max(format!("{}", stack.len()).len(), 2); - let indices_affected = - if let Instruction::OpCode(op) = debug_steps[current_step].instruction { - stack_indices_affected(op) - } else { - vec![] - }; + let indices_affected = stack_indices_affected(debug_steps[current_step].instruction.0); let text: Vec = stack .iter() @@ -699,33 +692,29 @@ impl Tui { let mut word = None; let mut color = None; - if let Instruction::OpCode(op) = debug_steps[current_step].instruction { - let stack_len = debug_steps[current_step].stack.len(); - if stack_len > 0 { - let w = debug_steps[current_step].stack[stack_len - 1]; - match op { - opcode::MLOAD => { - word = Some(w.as_usize() / 32); - color = Some(Color::Cyan); - } - opcode::MSTORE => { - word = Some(w.as_usize() / 32); - color = Some(Color::Red); - } - _ => {} + let stack_len = debug_steps[current_step].stack.len(); + if stack_len > 0 { + let w = debug_steps[current_step].stack[stack_len - 1]; + match debug_steps[current_step].instruction.0 { + opcode::MLOAD => { + word = Some(w.as_usize() / 32); + color = Some(Color::Cyan); } + opcode::MSTORE => { + word = Some(w.as_usize() / 32); + color = Some(Color::Red); + } + _ => {} } } if current_step > 0 { let prev_step = current_step - 1; let stack_len = debug_steps[prev_step].stack.len(); - if let Instruction::OpCode(op) = debug_steps[prev_step].instruction { - if op == opcode::MSTORE { - let prev_top = debug_steps[prev_step].stack[stack_len - 1]; - word = Some(prev_top.as_usize() / 32); - color = Some(Color::Green); - } + if debug_steps[prev_step].instruction.0 == opcode::MSTORE { + let prev_top = debug_steps[prev_step].stack[stack_len - 1]; + word = Some(prev_top.as_usize() / 32); + color = Some(Color::Green); } } diff --git a/src/loader/evm/util.rs b/src/loader/evm/util.rs index 0d9698bd..0a772513 100644 --- a/src/loader/evm/util.rs +++ b/src/loader/evm/util.rs @@ -5,6 +5,10 @@ use crate::{ use ethereum_types::U256; use std::iter; +pub(crate) mod executor; + +pub use executor::ExecutorBuilder; + pub struct MemoryChunk { ptr: usize, len: usize, diff --git a/src/loader/evm/util/executor.rs b/src/loader/evm/util/executor.rs new file mode 100644 index 00000000..ec9695e0 --- /dev/null +++ b/src/loader/evm/util/executor.rs @@ -0,0 +1,868 @@ +//! Copied and modified from https://github.com/foundry-rs/foundry/blob/master/evm/src/executor/mod.rs + +use bytes::Bytes; +use ethereum_types::{Address, H256, U256, U64}; +use revm::{ + evm_inner, opcode, spec_opcode_gas, Account, BlockEnv, CallInputs, CallScheme, CreateInputs, + CreateScheme, Database, DatabaseCommit, EVMData, Env, ExecutionResult, Gas, GasInspector, + InMemoryDB, Inspector, Interpreter, Memory, OpCode, Return, TransactOut, TransactTo, TxEnv, +}; +use sha3::{Digest, Keccak256}; +use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc}; + +macro_rules! return_ok { + () => { + Return::Continue | Return::Stop | Return::Return | Return::SelfDestruct + }; +} + +fn keccak256(data: impl AsRef<[u8]>) -> [u8; 32] { + Keccak256::digest(data.as_ref()).into() +} + +fn get_contract_address(sender: impl Into
, nonce: impl Into) -> Address { + let mut stream = rlp::RlpStream::new(); + stream.begin_list(2); + stream.append(&sender.into()); + stream.append(&nonce.into()); + + let hash = keccak256(&stream.out()); + + let mut bytes = [0u8; 20]; + bytes.copy_from_slice(&hash[12..]); + Address::from(bytes) +} + +fn get_create2_address( + from: impl Into
, + salt: [u8; 32], + init_code: impl Into, +) -> Address { + get_create2_address_from_hash(from, salt, keccak256(init_code.into().as_ref()).to_vec()) +} + +fn get_create2_address_from_hash( + from: impl Into
, + salt: [u8; 32], + init_code_hash: impl Into, +) -> Address { + let bytes = [ + &[0xff], + from.into().as_bytes(), + salt.as_slice(), + init_code_hash.into().as_ref(), + ] + .concat(); + + let hash = keccak256(&bytes); + + let mut bytes = [0u8; 20]; + bytes.copy_from_slice(&hash[12..]); + Address::from(bytes) +} + +fn get_create_address(call: &CreateInputs, nonce: u64) -> Address { + match call.scheme { + CreateScheme::Create => get_contract_address(call.caller, nonce), + CreateScheme::Create2 { salt } => { + let mut buffer: [u8; 4 * 8] = [0; 4 * 8]; + salt.to_big_endian(&mut buffer); + get_create2_address(call.caller, buffer, call.init_code.clone()) + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct Log { + pub address: Address, + pub topics: Vec, + pub data: Bytes, + pub block_hash: Option, + pub block_number: Option, + pub transaction_hash: Option, + pub transaction_index: Option, + pub log_index: Option, + pub transaction_log_index: Option, + pub log_type: Option, + pub removed: Option, +} + +#[derive(Clone, Debug, Default)] +struct LogCollector { + logs: Vec, +} + +impl Inspector for LogCollector { + fn log(&mut self, _: &mut EVMData<'_, DB>, address: &Address, topics: &[H256], data: &Bytes) { + self.logs.push(Log { + address: *address, + topics: topics.to_vec(), + data: data.clone(), + ..Default::default() + }); + } + + fn call( + &mut self, + _: &mut EVMData<'_, DB>, + call: &mut CallInputs, + _: bool, + ) -> (Return, Gas, Bytes) { + (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) + } +} + +#[derive(Clone, Debug, Copy)] +pub enum CallKind { + Call, + StaticCall, + CallCode, + DelegateCall, + Create, + Create2, +} + +impl Default for CallKind { + fn default() -> Self { + CallKind::Call + } +} + +impl From for CallKind { + fn from(scheme: CallScheme) -> Self { + match scheme { + CallScheme::Call => CallKind::Call, + CallScheme::StaticCall => CallKind::StaticCall, + CallScheme::CallCode => CallKind::CallCode, + CallScheme::DelegateCall => CallKind::DelegateCall, + } + } +} + +impl From for CallKind { + fn from(create: CreateScheme) -> Self { + match create { + CreateScheme::Create => CallKind::Create, + CreateScheme::Create2 { .. } => CallKind::Create2, + } + } +} + +#[derive(Clone, Debug, Default)] +pub struct DebugArena { + pub arena: Vec, +} + +impl DebugArena { + fn push_node(&mut self, mut new_node: DebugNode) -> usize { + fn recursively_push( + arena: &mut Vec, + entry: usize, + mut new_node: DebugNode, + ) -> usize { + match new_node.depth { + _ if arena[entry].depth == new_node.depth - 1 => { + let id = arena.len(); + new_node.location = arena[entry].children.len(); + new_node.parent = Some(entry); + arena[entry].children.push(id); + arena.push(new_node); + id + } + _ => { + let child = *arena[entry].children.last().unwrap(); + recursively_push(arena, child, new_node) + } + } + } + + if self.arena.is_empty() { + self.arena.push(new_node); + 0 + } else if new_node.depth == 0 { + let id = self.arena.len(); + new_node.location = self.arena[0].children.len(); + new_node.parent = Some(0); + self.arena[0].children.push(id); + self.arena.push(new_node); + id + } else { + recursively_push(&mut self.arena, 0, new_node) + } + } + + #[cfg(test)] + pub fn flatten(&self, entry: usize) -> Vec<(Address, Vec, CallKind)> { + let node = &self.arena[entry]; + + let mut flattened = vec![]; + if !node.steps.is_empty() { + flattened.push((node.address, node.steps.clone(), node.kind)); + } + flattened.extend(node.children.iter().flat_map(|child| self.flatten(*child))); + + flattened + } +} + +#[derive(Clone, Debug, Default)] +pub struct DebugNode { + pub parent: Option, + pub children: Vec, + pub location: usize, + pub address: Address, + pub kind: CallKind, + pub depth: usize, + pub steps: Vec, +} + +#[derive(Clone, Debug)] +pub struct DebugStep { + pub stack: Vec, + pub memory: Memory, + pub instruction: Instruction, + pub push_bytes: Option>, + pub pc: usize, + pub total_gas_used: u64, +} + +impl Default for DebugStep { + fn default() -> Self { + Self { + stack: vec![], + memory: Memory::new(), + instruction: Instruction(revm::opcode::INVALID), + push_bytes: None, + pc: 0, + total_gas_used: 0, + } + } +} + +impl DebugStep { + #[cfg(test)] + pub fn pretty_opcode(&self) -> String { + if let Some(push_bytes) = &self.push_bytes { + format!("{}(0x{})", self.instruction, hex::encode(push_bytes)) + } else { + self.instruction.to_string() + } + } +} + +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub struct Instruction(pub u8); + +impl From for Instruction { + fn from(op: u8) -> Instruction { + Instruction(op) + } +} + +impl Display for Instruction { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{}", + OpCode::try_from_u8(self.0).map_or_else( + || format!("UNDEFINED(0x{:02x})", self.0), + |opcode| opcode.as_str().to_string(), + ) + ) + } +} + +#[derive(Clone, Debug)] +struct Debugger { + arena: DebugArena, + head: usize, + context: Address, + gas_inspector: Rc>, +} + +impl Debugger { + fn new(gas_inspector: Rc>) -> Self { + Self { + arena: Default::default(), + head: Default::default(), + context: Default::default(), + gas_inspector, + } + } + + fn enter(&mut self, depth: usize, address: Address, kind: CallKind) { + self.context = address; + self.head = self.arena.push_node(DebugNode { + depth, + address, + kind, + ..Default::default() + }); + } + + fn exit(&mut self) { + if let Some(parent_id) = self.arena.arena[self.head].parent { + let DebugNode { + depth, + address, + kind, + .. + } = self.arena.arena[parent_id]; + self.context = address; + self.head = self.arena.push_node(DebugNode { + depth, + address, + kind, + ..Default::default() + }); + } + } +} + +impl Inspector for Debugger { + fn step( + &mut self, + interpreter: &mut Interpreter, + data: &mut EVMData<'_, DB>, + _is_static: bool, + ) -> Return { + let pc = interpreter.program_counter(); + let op = interpreter.contract.bytecode.bytecode()[pc]; + + let opcode_infos = spec_opcode_gas(data.env.cfg.spec_id); + let opcode_info = &opcode_infos[op as usize]; + + let push_size = if opcode_info.is_push() { + (op - opcode::PUSH1 + 1) as usize + } else { + 0 + }; + let push_bytes = match push_size { + 0 => None, + n => { + let start = pc + 1; + let end = start + n; + Some(interpreter.contract.bytecode.bytecode()[start..end].to_vec()) + } + }; + + let spent = interpreter.gas.limit() - self.gas_inspector.borrow().gas_remaining(); + let total_gas_used = spent - (interpreter.gas.refunded() as u64).min(spent / 5); + + self.arena.arena[self.head].steps.push(DebugStep { + pc, + stack: interpreter.stack().data().clone(), + memory: interpreter.memory.clone(), + instruction: Instruction(op), + push_bytes, + total_gas_used, + }); + + Return::Continue + } + + fn call( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CallInputs, + _: bool, + ) -> (Return, Gas, Bytes) { + self.enter( + data.journaled_state.depth() as usize, + call.context.code_address, + call.context.scheme.into(), + ); + + (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) + } + + fn call_end( + &mut self, + _: &mut EVMData<'_, DB>, + _: &CallInputs, + gas: Gas, + status: Return, + retdata: Bytes, + _: bool, + ) -> (Return, Gas, Bytes) { + self.exit(); + + (status, gas, retdata) + } + + fn create( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CreateInputs, + ) -> (Return, Option
, Gas, Bytes) { + let nonce = data.journaled_state.account(call.caller).info.nonce; + self.enter( + data.journaled_state.depth() as usize, + get_create_address(call, nonce), + CallKind::Create, + ); + + ( + Return::Continue, + None, + Gas::new(call.gas_limit), + Bytes::new(), + ) + } + + fn create_end( + &mut self, + _: &mut EVMData<'_, DB>, + _: &CreateInputs, + status: Return, + address: Option
, + gas: Gas, + retdata: Bytes, + ) -> (Return, Option
, Gas, Bytes) { + self.exit(); + + (status, address, gas, retdata) + } +} + +#[macro_export] +macro_rules! call_inspectors { + ($id:ident, [ $($inspector:expr),+ ], $call:block) => { + $({ + if let Some($id) = $inspector { + $call; + } + })+ + } +} + +struct InspectorData { + logs: Vec, + debug: Option, +} + +#[derive(Default)] +struct InspectorStack { + gas: Option>>, + logs: Option, + debugger: Option, +} + +impl InspectorStack { + fn collect_inspector_states(self) -> InspectorData { + InspectorData { + logs: self.logs.map(|logs| logs.logs).unwrap_or_default(), + debug: self.debugger.map(|debugger| debugger.arena), + } + } +} + +impl Inspector for InspectorStack { + fn initialize_interp( + &mut self, + interpreter: &mut Interpreter, + data: &mut EVMData<'_, DB>, + is_static: bool, + ) -> Return { + call_inspectors!( + inspector, + [ + &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), + &mut self.logs, + &mut self.debugger + ], + { + let status = inspector.initialize_interp(interpreter, data, is_static); + + if status != Return::Continue { + return status; + } + } + ); + + Return::Continue + } + + fn step( + &mut self, + interpreter: &mut Interpreter, + data: &mut EVMData<'_, DB>, + is_static: bool, + ) -> Return { + call_inspectors!( + inspector, + [ + &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), + &mut self.logs, + &mut self.debugger + ], + { + let status = inspector.step(interpreter, data, is_static); + + if status != Return::Continue { + return status; + } + } + ); + + Return::Continue + } + + fn log( + &mut self, + evm_data: &mut EVMData<'_, DB>, + address: &Address, + topics: &[H256], + data: &Bytes, + ) { + call_inspectors!(inspector, [&mut self.logs], { + inspector.log(evm_data, address, topics, data); + }); + } + + fn step_end( + &mut self, + interpreter: &mut Interpreter, + data: &mut EVMData<'_, DB>, + is_static: bool, + status: Return, + ) -> Return { + call_inspectors!( + inspector, + [ + &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), + &mut self.logs, + &mut self.debugger + ], + { + let status = inspector.step_end(interpreter, data, is_static, status); + + if status != Return::Continue { + return status; + } + } + ); + + Return::Continue + } + + fn call( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CallInputs, + is_static: bool, + ) -> (Return, Gas, Bytes) { + call_inspectors!( + inspector, + [ + &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), + &mut self.logs, + &mut self.debugger + ], + { + let (status, gas, retdata) = inspector.call(data, call, is_static); + + if status != Return::Continue { + return (status, gas, retdata); + } + } + ); + + (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) + } + + fn call_end( + &mut self, + data: &mut EVMData<'_, DB>, + call: &CallInputs, + remaining_gas: Gas, + status: Return, + retdata: Bytes, + is_static: bool, + ) -> (Return, Gas, Bytes) { + call_inspectors!( + inspector, + [ + &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), + &mut self.logs, + &mut self.debugger + ], + { + let (new_status, new_gas, new_retdata) = inspector.call_end( + data, + call, + remaining_gas, + status, + retdata.clone(), + is_static, + ); + + if new_status != status || (new_status == Return::Revert && new_retdata != retdata) + { + return (new_status, new_gas, new_retdata); + } + } + ); + + (status, remaining_gas, retdata) + } + + fn create( + &mut self, + data: &mut EVMData<'_, DB>, + call: &mut CreateInputs, + ) -> (Return, Option
, Gas, Bytes) { + call_inspectors!( + inspector, + [ + &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), + &mut self.logs, + &mut self.debugger + ], + { + let (status, addr, gas, retdata) = inspector.create(data, call); + + if status != Return::Continue { + return (status, addr, gas, retdata); + } + } + ); + + ( + Return::Continue, + None, + Gas::new(call.gas_limit), + Bytes::new(), + ) + } + + fn create_end( + &mut self, + data: &mut EVMData<'_, DB>, + call: &CreateInputs, + status: Return, + address: Option
, + remaining_gas: Gas, + retdata: Bytes, + ) -> (Return, Option
, Gas, Bytes) { + call_inspectors!( + inspector, + [ + &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), + &mut self.logs, + &mut self.debugger + ], + { + let (new_status, new_address, new_gas, new_retdata) = inspector.create_end( + data, + call, + status, + address, + remaining_gas, + retdata.clone(), + ); + + if new_status != status { + return (new_status, new_address, new_gas, new_retdata); + } + } + ); + + (status, address, remaining_gas, retdata) + } + + fn selfdestruct(&mut self) { + call_inspectors!(inspector, [&mut self.logs, &mut self.debugger], { + Inspector::::selfdestruct(inspector); + }); + } +} + +pub struct RawCallResult { + pub exit_reason: Return, + pub reverted: bool, + pub result: Bytes, + pub gas_used: u64, + pub gas_refunded: u64, + pub logs: Vec, + pub debug: Option, + pub state_changeset: Option>, + pub env: Env, + pub out: TransactOut, +} + +#[derive(Clone, Debug)] +pub struct DeployResult { + pub exit_reason: Return, + pub reverted: bool, + pub address: Option
, + pub gas_used: u64, + pub gas_refunded: u64, + pub logs: Vec, + pub debug: Option, + pub env: Env, +} + +#[derive(Debug, Default)] +pub struct ExecutorBuilder { + debugger: bool, + gas_limit: Option, +} + +impl ExecutorBuilder { + pub fn set_debugger(mut self, enable: bool) -> Self { + self.debugger = enable; + self + } + + pub fn with_gas_limit(mut self, gas_limit: U256) -> Self { + self.gas_limit = Some(gas_limit); + self + } + + pub fn build(self) -> Executor { + Executor::new(self.debugger, self.gas_limit.unwrap_or(U256::MAX)) + } +} + +#[derive(Clone, Debug)] +pub struct Executor { + db: InMemoryDB, + debugger: bool, + gas_limit: U256, +} + +impl Executor { + fn new(debugger: bool, gas_limit: U256) -> Self { + Executor { + db: InMemoryDB::default(), + debugger, + gas_limit, + } + } + + pub fn db_mut(&mut self) -> &mut InMemoryDB { + &mut self.db + } + + pub fn deploy(&mut self, from: Address, code: Bytes, value: U256) -> DeployResult { + let env = self.build_test_env(from, TransactTo::Create(CreateScheme::Create), code, value); + let result = self.call_raw_with_env(env); + self.commit(&result); + + let RawCallResult { + exit_reason, + out, + gas_used, + gas_refunded, + logs, + debug, + env, + .. + } = result; + + let address = match (exit_reason, out) { + (return_ok!(), TransactOut::Create(_, Some(address))) => Some(address), + _ => None, + }; + + DeployResult { + exit_reason, + reverted: !matches!(exit_reason, return_ok!()), + address, + gas_used, + gas_refunded, + logs, + debug, + env, + } + } + + pub fn call_raw( + &self, + from: Address, + to: Address, + calldata: Bytes, + value: U256, + ) -> RawCallResult { + let env = self.build_test_env(from, TransactTo::Call(to), calldata, value); + self.call_raw_with_env(env) + } + + fn call_raw_with_env(&self, mut env: Env) -> RawCallResult { + let mut inspector = self.inspector(); + let result = + evm_inner::<_, true>(&mut env, &mut self.db.clone(), &mut inspector).transact(); + let (exec_result, state_changeset) = result; + let ExecutionResult { + exit_reason, + gas_refunded, + gas_used, + out, + .. + } = exec_result; + + let result = match out { + TransactOut::Call(ref data) => data.to_owned(), + _ => Bytes::default(), + }; + let InspectorData { logs, debug } = inspector.collect_inspector_states(); + + RawCallResult { + exit_reason, + reverted: !matches!(exit_reason, return_ok!()), + result, + gas_used, + gas_refunded, + logs: logs.to_vec(), + debug, + state_changeset: Some(state_changeset.into_iter().collect()), + env, + out, + } + } + + fn commit(&mut self, result: &RawCallResult) { + if let Some(state_changeset) = result.state_changeset.as_ref() { + self.db + .commit(state_changeset.clone().into_iter().collect()); + } + } + + fn inspector(&self) -> InspectorStack { + let mut stack = InspectorStack { + logs: Some(LogCollector::default()), + ..Default::default() + }; + if self.debugger { + let gas_inspector = Rc::new(RefCell::new(GasInspector::default())); + stack.gas = Some(gas_inspector.clone()); + stack.debugger = Some(Debugger::new(gas_inspector)); + } + stack + } + + fn build_test_env( + &self, + caller: Address, + transact_to: TransactTo, + data: Bytes, + value: U256, + ) -> Env { + Env { + block: BlockEnv { + gas_limit: self.gas_limit, + ..BlockEnv::default() + }, + tx: TxEnv { + caller, + transact_to, + data, + value, + gas_limit: self.gas_limit.as_u64(), + ..TxEnv::default() + }, + ..Env::default() + } + } +} diff --git a/src/loader/halo2.rs b/src/loader/halo2.rs index 39e95c23..5b3361fa 100644 --- a/src/loader/halo2.rs +++ b/src/loader/halo2.rs @@ -23,7 +23,7 @@ mod util { Self: Sized, F: FnMut(B, V) -> B, { - self.into_iter().fold(Value::known(init), |acc, value| { + self.fold(Value::known(init), |acc, value| { acc.zip(value).map(|(acc, value)| f(acc, value)) }) } @@ -49,9 +49,7 @@ where self.transcript_initial_state .as_ref() .map(|transcript_initial_state| { - loader.assign_scalar(circuit::Value::known( - loader.scalar_chip().integer(*transcript_initial_state), - )) + loader.assign_scalar(circuit::Value::known(*transcript_initial_state)) }); Protocol { domain: self.domain.clone(), @@ -64,7 +62,7 @@ where quotient: self.quotient.clone(), transcript_initial_state, instance_committing_key: self.instance_committing_key.clone(), - linearization: self.linearization.clone(), + linearization: self.linearization, accumulator_indices: self.accumulator_indices.clone(), } } diff --git a/src/loader/halo2/loader.rs b/src/loader/halo2/loader.rs index d446c716..67c2b12d 100644 --- a/src/loader/halo2/loader.rs +++ b/src/loader/halo2/loader.rs @@ -45,15 +45,15 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc self.ctx.into_inner() } - pub fn ecc_chip(&self) -> Ref<'_, EccChip> { + pub fn ecc_chip(&self) -> Ref { self.ecc_chip.borrow() } - pub fn scalar_chip(&self) -> Ref<'_, EccChip::ScalarChip> { + pub fn scalar_chip(&self) -> Ref { Ref::map(self.ecc_chip(), |ecc_chip| ecc_chip.scalar_chip()) } - pub fn ctx(&self) -> Ref<'_, EccChip::Context> { + pub fn ctx(&self) -> Ref { self.ctx.borrow() } @@ -61,17 +61,15 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc self.ctx.borrow_mut() } - fn assign_const_scalar(self: &Rc, constant: C::Scalar) -> Scalar<'a, C, EccChip> { - let assigned = self - .scalar_chip() + fn assign_const_scalar(self: &Rc, constant: C::Scalar) -> EccChip::AssignedScalar { + self.scalar_chip() .assign_constant(&mut self.ctx_mut(), constant) - .unwrap(); - self.scalar_from_assigned(assigned) + .unwrap() } pub fn assign_scalar( self: &Rc, - scalar: circuit::Value, + scalar: circuit::Value, ) -> Scalar<'a, C, EccChip> { let assigned = self .scalar_chip() @@ -96,16 +94,14 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc Scalar { loader: self.clone(), index, - value, + value: value.into(), } } - fn assign_const_ec_point(self: &Rc, constant: C) -> EcPoint<'a, C, EccChip> { - self.ec_point_from_assigned( - self.ecc_chip() - .assign_constant(&mut self.ctx_mut(), constant) - .unwrap(), - ) + fn assign_const_ec_point(self: &Rc, constant: C) -> EccChip::AssignedEcPoint { + self.ecc_chip() + .assign_constant(&mut self.ctx_mut(), constant) + .unwrap() } pub fn assign_ec_point( @@ -135,7 +131,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc EcPoint { loader: self.clone(), index, - value, + value: value.into(), } } @@ -144,14 +140,14 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc lhs: &Scalar<'a, C, EccChip>, rhs: &Scalar<'a, C, EccChip>, ) -> Scalar<'a, C, EccChip> { - let output = match (&lhs.value, &rhs.value) { + let output = match (lhs.value().deref(), rhs.value().deref()) { (Value::Constant(lhs), Value::Constant(rhs)) => Value::Constant(*lhs + rhs), (Value::Assigned(assigned), Value::Constant(constant)) | (Value::Constant(constant), Value::Assigned(assigned)) => self .scalar_chip() .sum_with_coeff_and_const( &mut self.ctx_mut(), - &[(C::Scalar::one(), assigned.clone())], + &[(C::Scalar::one(), assigned)], *constant, ) .map(Value::Assigned) @@ -160,10 +156,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc .scalar_chip() .sum_with_coeff_and_const( &mut self.ctx_mut(), - &[ - (C::Scalar::one(), lhs.clone()), - (C::Scalar::one(), rhs.clone()), - ], + &[(C::Scalar::one(), lhs), (C::Scalar::one(), rhs)], C::Scalar::zero(), ) .map(Value::Assigned) @@ -177,13 +170,13 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc lhs: &Scalar<'a, C, EccChip>, rhs: &Scalar<'a, C, EccChip>, ) -> Scalar<'a, C, EccChip> { - let output = match (&lhs.value, &rhs.value) { + let output = match (lhs.value().deref(), rhs.value().deref()) { (Value::Constant(lhs), Value::Constant(rhs)) => Value::Constant(*lhs - rhs), (Value::Constant(constant), Value::Assigned(assigned)) => self .scalar_chip() .sum_with_coeff_and_const( &mut self.ctx_mut(), - &[(-C::Scalar::one(), assigned.clone())], + &[(-C::Scalar::one(), assigned)], *constant, ) .map(Value::Assigned) @@ -192,7 +185,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc .scalar_chip() .sum_with_coeff_and_const( &mut self.ctx_mut(), - &[(C::Scalar::one(), assigned.clone())], + &[(C::Scalar::one(), assigned)], -*constant, ) .map(Value::Assigned) @@ -211,14 +204,14 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc lhs: &Scalar<'a, C, EccChip>, rhs: &Scalar<'a, C, EccChip>, ) -> Scalar<'a, C, EccChip> { - let output = match (&lhs.value, &rhs.value) { + let output = match (lhs.value().deref(), rhs.value().deref()) { (Value::Constant(lhs), Value::Constant(rhs)) => Value::Constant(*lhs * rhs), (Value::Assigned(assigned), Value::Constant(constant)) | (Value::Constant(constant), Value::Assigned(assigned)) => self .scalar_chip() .sum_with_coeff_and_const( &mut self.ctx_mut(), - &[(*constant, assigned.clone())], + &[(*constant, assigned)], C::Scalar::zero(), ) .map(Value::Assigned) @@ -227,7 +220,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc .scalar_chip() .sum_products_with_coeff_and_const( &mut self.ctx_mut(), - &[(C::Scalar::one(), lhs.clone(), rhs.clone())], + &[(C::Scalar::one(), lhs, rhs)], C::Scalar::zero(), ) .map(Value::Assigned) @@ -237,7 +230,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc } fn neg(self: &Rc, scalar: &Scalar<'a, C, EccChip>) -> Scalar<'a, C, EccChip> { - let output = match &scalar.value { + let output = match scalar.value().deref() { Value::Constant(constant) => Value::Constant(constant.neg()), Value::Assigned(assigned) => { IntegerInstructions::neg(self.scalar_chip().deref(), &mut self.ctx_mut(), assigned) @@ -249,7 +242,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc } fn invert(self: &Rc, scalar: &Scalar<'a, C, EccChip>) -> Scalar<'a, C, EccChip> { - let output = match &scalar.value { + let output = match scalar.value().deref() { Value::Constant(constant) => Value::Constant(Field::invert(constant).unwrap()), Value::Assigned(assigned) => Value::Assigned( IntegerInstructions::invert( @@ -295,11 +288,30 @@ pub enum Value { Assigned(L), } +impl Value { + fn maybe_const(&self) -> Option + where + T: Copy, + { + match self { + Value::Constant(constant) => Some(*constant), + _ => None, + } + } + + fn assigned(&self) -> &L { + match self { + Value::Assigned(assigned) => assigned, + _ => unreachable!(), + } + } +} + #[derive(Clone)] pub struct Scalar<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { loader: Rc>, index: usize, - value: Value, + value: RefCell>, } impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Scalar<'a, C, EccChip> { @@ -307,11 +319,19 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Scalar<'a, C, EccChip> &self.loader } - pub fn assigned(&self) -> EccChip::AssignedScalar { - match &self.value { - Value::Constant(constant) => self.loader.assign_const_scalar(*constant).assigned(), - Value::Assigned(assigned) => assigned.clone(), + pub fn assigned(&self) -> Ref { + if let Some(constant) = self.maybe_const() { + *self.value.borrow_mut() = Value::Assigned(self.loader.assign_const_scalar(constant)) } + Ref::map(self.value.borrow(), Value::assigned) + } + + fn value(&self) -> Ref> { + self.value.borrow() + } + + fn maybe_const(&self) -> Option { + self.value().deref().maybe_const() } } @@ -453,16 +473,31 @@ impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> MulAssign<&'b Self pub struct EcPoint<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { loader: Rc>, index: usize, - value: Value, + value: RefCell>, } impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPoint<'a, C, EccChip> { - pub fn assigned(&self) -> EccChip::AssignedEcPoint { - match &self.value { - Value::Constant(constant) => self.loader.assign_const_ec_point(*constant).assigned(), - Value::Assigned(assigned) => assigned.clone(), + pub fn into_assigned(self) -> EccChip::AssignedEcPoint { + match self.value.into_inner() { + Value::Constant(constant) => self.loader.assign_const_ec_point(constant), + Value::Assigned(assigned) => assigned, } } + + pub fn assigned(&self) -> Ref { + if let Some(constant) = self.maybe_const() { + *self.value.borrow_mut() = Value::Assigned(self.loader.assign_const_ec_point(constant)) + } + Ref::map(self.value.borrow(), Value::assigned) + } + + fn value(&self) -> Ref> { + self.value.borrow() + } + + fn maybe_const(&self) -> Option { + self.value().deref().maybe_const() + } } impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> PartialEq for EcPoint<'a, C, EccChip> { @@ -558,35 +593,30 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPointLoader lhs: &EcPoint<'a, C, EccChip>, rhs: &EcPoint<'a, C, EccChip>, ) -> Result<(), crate::Error> { - match (&lhs.value, &rhs.value) { - (Value::Constant(lhs), Value::Constant(rhs)) => { - assert_eq!(lhs, rhs); - Ok(()) - } - (Value::Constant(constant), Value::Assigned(assigned)) - | (Value::Assigned(assigned), Value::Constant(constant)) => { - let constant = self.assign_const_ec_point(*constant).assigned(); - self.ecc_chip() - .assert_equal(&mut self.ctx_mut(), assigned, &constant) - .map_err(|_| crate::Error::AssertionFailure(annotation.to_string())) - } - (Value::Assigned(lhs), Value::Assigned(rhs)) => self - .ecc_chip() - .assert_equal(&mut self.ctx_mut(), lhs, rhs) - .map_err(|_| crate::Error::AssertionFailure(annotation.to_string())), + if let (Value::Constant(lhs), Value::Constant(rhs)) = + (lhs.value().deref(), rhs.value().deref()) + { + assert_eq!(lhs, rhs); + Ok(()) + } else { + let lhs = lhs.assigned(); + let rhs = rhs.assigned(); + self.ecc_chip() + .assert_equal(&mut self.ctx_mut(), lhs.deref(), rhs.deref()) + .map_err(|_| crate::Error::AssertionFailure(annotation.to_string())) } } fn multi_scalar_multiplication( pairs: &[( - >::LoadedScalar, - EcPoint<'a, C, EccChip>, + &>::LoadedScalar, + &EcPoint<'a, C, EccChip>, )], ) -> EcPoint<'a, C, EccChip> { let loader = &pairs[0].0.loader; let (constant, fixed_base, variable_base_non_scaled, variable_base_scaled) = - pairs.iter().fold( + pairs.iter().cloned().fold( (C::identity(), Vec::new(), Vec::new(), Vec::new()), |( mut constant, @@ -594,22 +624,20 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPointLoader mut variable_base_non_scaled, mut variable_base_scaled, ), - (scalar, ec_point)| { - match (&ec_point.value, &scalar.value) { - (Value::Constant(ec_point), Value::Constant(scalar)) => { - constant = (*ec_point * scalar + constant).into() + (scalar, base)| { + match (scalar.value().deref(), base.value().deref()) { + (Value::Constant(scalar), Value::Constant(base)) => { + constant = (*base * scalar + constant).into() } - (Value::Constant(ec_point), Value::Assigned(scalar)) => { - fixed_base.push((scalar.clone(), *ec_point)) + (Value::Assigned(_), Value::Constant(base)) => { + fixed_base.push((scalar, *base)) } - (Value::Assigned(ec_point), Value::Constant(scalar)) + (Value::Constant(scalar), Value::Assigned(_)) if scalar.eq(&C::Scalar::one()) => { - variable_base_non_scaled.push(ec_point.clone()); - } - (Value::Assigned(ec_point), _) => { - variable_base_scaled.push((scalar.assigned(), ec_point.clone())) + variable_base_non_scaled.push(base); } + _ => variable_base_scaled.push((scalar, base)), }; ( constant, @@ -620,38 +648,47 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPointLoader }, ); - let fixed_base_msm = (!fixed_base.is_empty()).then(|| { - loader - .ecc_chip - .borrow_mut() - .fixed_base_msm(&mut loader.ctx_mut(), &fixed_base) - .unwrap() - }); - let variable_base_msm = (!variable_base_scaled.is_empty()).then(|| { - loader - .ecc_chip - .borrow_mut() - .variable_base_msm(&mut loader.ctx_mut(), &variable_base_scaled) - .unwrap() - }); + let fixed_base_msm = (!fixed_base.is_empty()) + .then(|| { + let fixed_base = fixed_base + .into_iter() + .map(|(scalar, base)| (scalar.assigned(), base)) + .collect_vec(); + loader + .ecc_chip + .borrow_mut() + .fixed_base_msm(&mut loader.ctx_mut(), &fixed_base) + .unwrap() + }) + .map(RefCell::new); + let variable_base_msm = (!variable_base_scaled.is_empty()) + .then(|| { + let variable_base_scaled = variable_base_scaled + .into_iter() + .map(|(scalar, base)| (scalar.assigned(), base.assigned())) + .collect_vec(); + loader + .ecc_chip + .borrow_mut() + .variable_base_msm(&mut loader.ctx_mut(), &variable_base_scaled) + .unwrap() + }) + .map(RefCell::new); let output = loader .ecc_chip() .sum_with_const( &mut loader.ctx_mut(), &variable_base_non_scaled .into_iter() - .chain(fixed_base_msm) - .chain(variable_base_msm) + .map(EcPoint::assigned) + .chain(fixed_base_msm.as_ref().map(RefCell::borrow)) + .chain(variable_base_msm.as_ref().map(RefCell::borrow)) .collect_vec(), constant, ) .unwrap(); - let normalized = loader - .ecc_chip() - .normalize(&mut loader.ctx_mut(), &output) - .unwrap(); - loader.ec_point_from_assigned(normalized) + loader.ec_point_from_assigned(output) } } diff --git a/src/loader/halo2/shim.rs b/src/loader/halo2/shim.rs index 97921d24..1d7b6258 100644 --- a/src/loader/halo2/shim.rs +++ b/src/loader/halo2/shim.rs @@ -3,7 +3,7 @@ use halo2_proofs::{ circuit::{Cell, Value}, plonk::Error, }; -use std::fmt::Debug; +use std::{fmt::Debug, ops::Deref}; pub trait Context: Debug { fn constrain_equal(&mut self, lhs: Cell, rhs: Cell) -> Result<(), Error>; @@ -13,15 +13,13 @@ pub trait Context: Debug { pub trait IntegerInstructions<'a, F: FieldExt>: Clone + Debug { type Context: Context; - type Integer: Clone + Debug; + type AssignedCell: Clone + Debug; type AssignedInteger: Clone + Debug; - fn integer(&self, fe: F) -> Self::Integer; - fn assign_integer( &self, ctx: &mut Self::Context, - integer: Value, + integer: Value, ) -> Result; fn assign_constant( @@ -33,41 +31,45 @@ pub trait IntegerInstructions<'a, F: FieldExt>: Clone + Debug { fn sum_with_coeff_and_const( &self, ctx: &mut Self::Context, - values: &[(F::Scalar, Self::AssignedInteger)], + values: &[(F::Scalar, impl Deref)], constant: F::Scalar, ) -> Result; fn sum_products_with_coeff_and_const( &self, ctx: &mut Self::Context, - values: &[(F::Scalar, Self::AssignedInteger, Self::AssignedInteger)], + values: &[( + F::Scalar, + impl Deref, + impl Deref, + )], constant: F::Scalar, ) -> Result; fn sub( &self, ctx: &mut Self::Context, - a: &Self::AssignedInteger, - b: &Self::AssignedInteger, + lhs: &Self::AssignedInteger, + rhs: &Self::AssignedInteger, ) -> Result; fn neg( &self, ctx: &mut Self::Context, - a: &Self::AssignedInteger, + value: &Self::AssignedInteger, ) -> Result; fn invert( &self, ctx: &mut Self::Context, - a: &Self::AssignedInteger, + value: &Self::AssignedInteger, ) -> Result; fn assert_equal( &self, ctx: &mut Self::Context, - a: &Self::AssignedInteger, - b: &Self::AssignedInteger, + lhs: &Self::AssignedInteger, + rhs: &Self::AssignedInteger, ) -> Result<(), Error>; } @@ -77,57 +79,54 @@ pub trait EccInstructions<'a, C: CurveAffine>: Clone + Debug { 'a, C::Scalar, Context = Self::Context, - Integer = Self::Scalar, + AssignedCell = Self::AssignedCell, AssignedInteger = Self::AssignedScalar, >; - type AssignedEcPoint: Clone + Debug; - type Scalar: Clone + Debug; + type AssignedCell: Clone + Debug; type AssignedScalar: Clone + Debug; + type AssignedEcPoint: Clone + Debug; fn scalar_chip(&self) -> &Self::ScalarChip; fn assign_constant( &self, ctx: &mut Self::Context, - point: C, + ec_point: C, ) -> Result; fn assign_point( &self, ctx: &mut Self::Context, - point: Value, + ec_point: Value, ) -> Result; fn sum_with_const( &self, ctx: &mut Self::Context, - values: &[Self::AssignedEcPoint], + values: &[impl Deref], constant: C, ) -> Result; fn fixed_base_msm( &mut self, ctx: &mut Self::Context, - pairs: &[(Self::AssignedScalar, C)], + pairs: &[(impl Deref, C)], ) -> Result; fn variable_base_msm( &mut self, ctx: &mut Self::Context, - pairs: &[(Self::AssignedScalar, Self::AssignedEcPoint)], - ) -> Result; - - fn normalize( - &self, - ctx: &mut Self::Context, - point: &Self::AssignedEcPoint, + pairs: &[( + impl Deref, + impl Deref, + )], ) -> Result; fn assert_equal( &self, ctx: &mut Self::Context, - a: &Self::AssignedEcPoint, - b: &Self::AssignedEcPoint, + lhs: &Self::AssignedEcPoint, + rhs: &Self::AssignedEcPoint, ) -> Result<(), Error>; } @@ -152,7 +151,7 @@ mod halo2_wrong { AssignedPoint, BaseFieldEccChip, }; use rand::rngs::OsRng; - use std::iter; + use std::{iter, ops::Deref}; impl<'a, F: FieldExt> Context for RegionCtx<'a, F> { fn constrain_equal(&mut self, lhs: Cell, rhs: Cell) -> Result<(), Error> { @@ -166,17 +165,13 @@ mod halo2_wrong { impl<'a, F: FieldExt> IntegerInstructions<'a, F> for MainGate { type Context = RegionCtx<'a, F>; - type Integer = F; + type AssignedCell = AssignedCell; type AssignedInteger = AssignedCell; - fn integer(&self, scalar: F) -> Self::Integer { - scalar - } - fn assign_integer( &self, ctx: &mut Self::Context, - integer: Value, + integer: Value, ) -> Result { self.assign_value(ctx, integer) } @@ -192,7 +187,7 @@ mod halo2_wrong { fn sum_with_coeff_and_const( &self, ctx: &mut Self::Context, - values: &[(F, Self::AssignedInteger)], + values: &[(F, impl Deref)], constant: F, ) -> Result { self.compose( @@ -208,7 +203,11 @@ mod halo2_wrong { fn sum_products_with_coeff_and_const( &self, ctx: &mut Self::Context, - values: &[(F, Self::AssignedInteger, Self::AssignedInteger)], + values: &[( + F, + impl Deref, + impl Deref, + )], constant: F, ) -> Result { match values.len() { @@ -289,39 +288,39 @@ mod halo2_wrong { fn sub( &self, ctx: &mut Self::Context, - a: &Self::AssignedInteger, - b: &Self::AssignedInteger, + lhs: &Self::AssignedInteger, + rhs: &Self::AssignedInteger, ) -> Result { - MainGateInstructions::sub(self, ctx, a, b) + MainGateInstructions::sub(self, ctx, lhs, rhs) } fn neg( &self, ctx: &mut Self::Context, - a: &Self::AssignedInteger, + value: &Self::AssignedInteger, ) -> Result { - MainGateInstructions::neg_with_constant(self, ctx, a, F::zero()) + MainGateInstructions::neg_with_constant(self, ctx, value, F::zero()) } fn invert( &self, ctx: &mut Self::Context, - a: &Self::AssignedInteger, + value: &Self::AssignedInteger, ) -> Result { - MainGateInstructions::invert_unsafe(self, ctx, a) + MainGateInstructions::invert_unsafe(self, ctx, value) } fn assert_equal( &self, ctx: &mut Self::Context, - a: &Self::AssignedInteger, - b: &Self::AssignedInteger, + lhs: &Self::AssignedInteger, + rhs: &Self::AssignedInteger, ) -> Result<(), Error> { let mut eq = true; - a.value().zip(b.value()).map(|(lhs, rhs)| { + lhs.value().zip(rhs.value()).map(|(lhs, rhs)| { eq &= lhs == rhs; }); - MainGateInstructions::assert_equal(self, ctx, a, b) + MainGateInstructions::assert_equal(self, ctx, lhs, rhs) .and(eq.then_some(()).ok_or(Error::Synthesis)) } } @@ -331,9 +330,9 @@ mod halo2_wrong { { type Context = RegionCtx<'a, C::Scalar>; type ScalarChip = MainGate; - type AssignedEcPoint = AssignedPoint; - type Scalar = C::Scalar; + type AssignedCell = AssignedCell; type AssignedScalar = AssignedCell; + type AssignedEcPoint = AssignedPoint; fn scalar_chip(&self) -> &Self::ScalarChip { self.main_gate() @@ -342,65 +341,79 @@ mod halo2_wrong { fn assign_constant( &self, ctx: &mut Self::Context, - point: C, + ec_point: C, ) -> Result { - self.assign_constant(ctx, point) + self.assign_constant(ctx, ec_point) } fn assign_point( &self, ctx: &mut Self::Context, - point: Value, + ec_point: Value, ) -> Result { - self.assign_point(ctx, point) + self.assign_point(ctx, ec_point) } fn sum_with_const( &self, ctx: &mut Self::Context, - values: &[Self::AssignedEcPoint], + values: &[impl Deref], constant: C, ) -> Result { if values.is_empty() { return self.assign_constant(ctx, constant); } - iter::empty() - .chain( - (!bool::from(constant.is_identity())) - .then(|| self.assign_constant(ctx, constant)), - ) - .chain(values.iter().cloned().map(Ok)) + let constant = (!bool::from(constant.is_identity())) + .then(|| self.assign_constant(ctx, constant)) + .transpose()?; + let output = iter::empty() + .chain(constant) + .chain(values.iter().map(|value| value.deref().clone())) + .map(Ok) .reduce(|acc, ec_point| self.add(ctx, &acc?, &ec_point?)) - .unwrap() + .unwrap()?; + self.normalize(ctx, &output) } fn fixed_base_msm( &mut self, ctx: &mut Self::Context, - pairs: &[(Self::AssignedScalar, C)], + pairs: &[(impl Deref, C)], ) -> Result { + assert!(!pairs.is_empty()); + // FIXME: Implement fixed base MSM in halo2_wrong let pairs = pairs .iter() + .filter(|(_, base)| !bool::from(base.is_identity())) .map(|(scalar, base)| { - Ok::<_, Error>((scalar.clone(), self.assign_constant(ctx, *base)?)) + Ok::<_, Error>((scalar.deref().clone(), self.assign_constant(ctx, *base)?)) }) .collect::, _>>()?; + let pairs = pairs + .iter() + .map(|(scalar, base)| (scalar, base)) + .collect_vec(); self.variable_base_msm(ctx, &pairs) } fn variable_base_msm( &mut self, ctx: &mut Self::Context, - pairs: &[(Self::AssignedScalar, Self::AssignedEcPoint)], + pairs: &[( + impl Deref, + impl Deref, + )], ) -> Result { + assert!(!pairs.is_empty()); + const WINDOW_SIZE: usize = 3; let pairs = pairs .iter() - .map(|(scalar, base)| (base.clone(), scalar.clone())) + .map(|(scalar, base)| (base.deref().clone(), scalar.deref().clone())) .collect_vec(); - match self.mul_batch_1d_horizontal(ctx, pairs.clone(), WINDOW_SIZE) { + let output = match self.mul_batch_1d_horizontal(ctx, pairs.clone(), WINDOW_SIZE) { Err(_) => { if self.assign_aux(ctx, WINDOW_SIZE, pairs.len()).is_err() { let aux_generator = Value::known(C::Curve::random(OsRng).into()); @@ -410,30 +423,23 @@ mod halo2_wrong { self.mul_batch_1d_horizontal(ctx, pairs, WINDOW_SIZE) } result => result, - } - } - - fn normalize( - &self, - ctx: &mut Self::Context, - point: &Self::AssignedEcPoint, - ) -> Result { - self.normalize(ctx, point) + }?; + self.normalize(ctx, &output) } fn assert_equal( &self, ctx: &mut Self::Context, - a: &Self::AssignedEcPoint, - b: &Self::AssignedEcPoint, + lhs: &Self::AssignedEcPoint, + rhs: &Self::AssignedEcPoint, ) -> Result<(), Error> { let mut eq = true; - [(a.x(), b.x()), (a.y(), b.y())].map(|(lhs, rhs)| { + [(lhs.x(), rhs.x()), (lhs.y(), rhs.y())].map(|(lhs, rhs)| { lhs.integer().zip(rhs.integer()).map(|(lhs, rhs)| { eq &= lhs.value() == rhs.value(); }); }); - self.assert_equal(ctx, a, b) + self.assert_equal(ctx, lhs, rhs) .and(eq.then_some(()).ok_or(Error::Synthesis)) } } diff --git a/src/loader/native.rs b/src/loader/native.rs index 1451ff76..6fce383a 100644 --- a/src/loader/native.rs +++ b/src/loader/native.rs @@ -54,10 +54,11 @@ impl EcPointLoader for NativeLoader { } fn multi_scalar_multiplication( - pairs: &[(>::LoadedScalar, C)], + pairs: &[(&>::LoadedScalar, &C)], ) -> C { pairs .iter() + .cloned() .map(|(scalar, base)| *base * scalar) .reduce(|acc, value| acc + value) .unwrap() diff --git a/src/pcs.rs b/src/pcs.rs index 65804895..23fdda2a 100644 --- a/src/pcs.rs +++ b/src/pcs.rs @@ -123,7 +123,7 @@ where L: Loader, PCS: PolynomialCommitmentScheme, { - fn from_repr(repr: Vec) -> Result; + fn from_repr(repr: &[&L::LoadedScalar]) -> Result; } impl AccumulatorEncoding for () @@ -132,7 +132,7 @@ where L: Loader, PCS: PolynomialCommitmentScheme, { - fn from_repr(_: Vec) -> Result { + fn from_repr(_: &[&L::LoadedScalar]) -> Result { unimplemented!() } } diff --git a/src/pcs/kzg.rs b/src/pcs/kzg.rs index 9f10bd44..056589a8 100644 --- a/src/pcs/kzg.rs +++ b/src/pcs/kzg.rs @@ -15,6 +15,9 @@ pub use accumulator::{KzgAccumulator, LimbsEncoding}; pub use decider::KzgDecidingKey; pub use multiopen::{Bdfg21, Bdfg21Proof, Gwc19, Gwc19Proof}; +#[cfg(feature = "loader_halo2")] +pub use accumulator::LimbsEncodingInstructions; + #[derive(Clone, Debug)] pub struct Kzg(PhantomData<(M, MOS)>); diff --git a/src/pcs/kzg/accumulation.rs b/src/pcs/kzg/accumulation.rs index cd13fd00..4273ce9a 100644 --- a/src/pcs/kzg/accumulation.rs +++ b/src/pcs/kzg/accumulation.rs @@ -44,16 +44,16 @@ where ) -> Result { let (lhs, rhs) = instances .iter() - .cloned() - .map(|accumulator| (accumulator.lhs, accumulator.rhs)) - .chain(proof.blind.clone()) + .map(|accumulator| (&accumulator.lhs, &accumulator.rhs)) + .chain(proof.blind.as_ref().map(|(lhs, rhs)| (lhs, rhs))) .unzip::<_, _, Vec<_>, Vec<_>>(); let powers_of_r = proof.r.powers(lhs.len()); - let [lhs, rhs] = [lhs, rhs].map(|msms| { - msms.into_iter() + let [lhs, rhs] = [lhs, rhs].map(|bases| { + bases + .into_iter() .zip(powers_of_r.iter()) - .map(|(msm, r)| Msm::::base(msm) * r) + .map(|(base, r)| Msm::::base(base) * r) .sum::>() .evaluate(None) }); @@ -184,7 +184,7 @@ where let powers_of_r = r.powers(lhs.len()); let [lhs, rhs] = [lhs, rhs].map(|msms| { - msms.into_iter() + msms.iter() .zip(powers_of_r.iter()) .map(|(msm, power_of_r)| Msm::::base(msm) * power_of_r) .sum::>() diff --git a/src/pcs/kzg/accumulator.rs b/src/pcs/kzg/accumulator.rs index 17c7bf83..50ce6ba8 100644 --- a/src/pcs/kzg/accumulator.rs +++ b/src/pcs/kzg/accumulator.rs @@ -53,13 +53,22 @@ mod native { Accumulator = KzgAccumulator, >, { - fn from_repr(limbs: Vec) -> Result { + fn from_repr(limbs: &[&C::Scalar]) -> Result { assert_eq!(limbs.len(), 4 * LIMBS); let [lhs_x, lhs_y, rhs_x, rhs_y]: [_; 4] = limbs .chunks(LIMBS) .into_iter() - .map(|limbs| fe_from_limbs::<_, _, LIMBS, BITS>(limbs.try_into().unwrap())) + .map(|limbs| { + fe_from_limbs::<_, _, LIMBS, BITS>( + limbs + .iter() + .map(|limb| **limb) + .collect_vec() + .try_into() + .unwrap(), + ) + }) .collect_vec() .try_into() .unwrap(); @@ -100,7 +109,7 @@ mod evm { Accumulator = KzgAccumulator>, >, { - fn from_repr(limbs: Vec) -> Result { + fn from_repr(limbs: &[&Scalar]) -> Result { assert_eq!(limbs.len(), 4 * LIMBS); let loader = limbs[0].loader(); @@ -122,10 +131,13 @@ mod evm { } } +#[cfg(feature = "loader_halo2")] +pub use halo2::LimbsEncodingInstructions; + #[cfg(feature = "loader_halo2")] mod halo2 { use crate::{ - loader::halo2::{Context, EccInstructions, Halo2Loader, Scalar, Valuetools}, + loader::halo2::{EccInstructions, Halo2Loader, Scalar, Valuetools}, pcs::{ kzg::{KzgAccumulator, LimbsEncoding}, AccumulatorEncoding, PolynomialCommitmentScheme, @@ -136,19 +148,18 @@ mod halo2 { }, Error, }; - use halo2_proofs::circuit::Value; - use halo2_wrong_ecc::{maingate::AssignedValue, AssignedPoint}; - use std::{iter, rc::Rc}; + use halo2_proofs::{circuit::Value, plonk}; + use std::{iter, ops::Deref, rc::Rc}; - fn ec_point_from_assigned_limbs( - limbs: &[AssignedValue], + fn ec_point_from_limbs( + limbs: &[Value<&C::Scalar>], ) -> Value { assert_eq!(limbs.len(), 2 * LIMBS); let [x, y] = [&limbs[..LIMBS], &limbs[LIMBS..]].map(|limbs| { limbs .iter() - .map(|assigned| assigned.value()) + .cloned() .fold_zipped(Vec::new(), |mut acc, limb| { acc.push(*limb); acc @@ -159,6 +170,22 @@ mod halo2 { x.zip(y).map(|(x, y)| C::from_xy(x, y).unwrap()) } + pub trait LimbsEncodingInstructions<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize>: + EccInstructions<'a, C> + { + fn assign_ec_point_from_limbs( + &self, + ctx: &mut Self::Context, + limbs: &[impl Deref], + ) -> Result; + + fn assign_ec_point_to_limbs( + &self, + ctx: &mut Self::Context, + ec_point: impl Deref, + ) -> Result, plonk::Error>; + } + impl<'a, C, PCS, EccChip, const LIMBS: usize, const BITS: usize> AccumulatorEncoding>, PCS> for LimbsEncoding where @@ -168,41 +195,72 @@ mod halo2 { Rc>, Accumulator = KzgAccumulator>>, >, - EccChip: EccInstructions< - 'a, - C, - AssignedEcPoint = AssignedPoint<::Base, C::Scalar, LIMBS, BITS>, - AssignedScalar = AssignedValue, - >, + EccChip: LimbsEncodingInstructions<'a, C, LIMBS, BITS>, { - fn from_repr(limbs: Vec>) -> Result { + fn from_repr(limbs: &[&Scalar<'a, C, EccChip>]) -> Result { assert_eq!(limbs.len(), 4 * LIMBS); let loader = limbs[0].loader(); - let assigned_limbs = limbs.iter().map(|limb| limb.assigned()).collect_vec(); - let [lhs, rhs] = [&assigned_limbs[..2 * LIMBS], &assigned_limbs[2 * LIMBS..]].map( - |assigned_limbs| { - let ec_point = ec_point_from_assigned_limbs::<_, LIMBS, BITS>(assigned_limbs); - loader.assign_ec_point(ec_point) - }, - ); - - for (src, dst) in assigned_limbs.iter().zip( - iter::empty() - .chain(lhs.assigned().x().limbs()) - .chain(lhs.assigned().y().limbs()) - .chain(rhs.assigned().x().limbs()) - .chain(rhs.assigned().y().limbs()), - ) { - loader - .ctx_mut() - .constrain_equal(src.cell(), dst.as_ref().cell()) + let [lhs, rhs] = [&limbs[..2 * LIMBS], &limbs[2 * LIMBS..]].map(|limbs| { + let assigned = loader + .ecc_chip() + .assign_ec_point_from_limbs( + &mut loader.ctx_mut(), + &limbs.iter().map(|limb| limb.assigned()).collect_vec(), + ) .unwrap(); + loader.ec_point_from_assigned(assigned) + }); + + Ok(KzgAccumulator::new(lhs, rhs)) + } + } + + mod halo2_wrong { + use super::*; + use halo2_wrong_ecc::BaseFieldEccChip; + + impl<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize> + LimbsEncodingInstructions<'a, C, LIMBS, BITS> for BaseFieldEccChip + { + fn assign_ec_point_from_limbs( + &self, + ctx: &mut Self::Context, + limbs: &[impl Deref], + ) -> Result { + assert_eq!(limbs.len(), 2 * LIMBS); + + let ec_point = self.assign_point( + ctx, + ec_point_from_limbs::<_, LIMBS, BITS>( + &limbs.iter().map(|limb| limb.value()).collect_vec(), + ), + )?; + + for (src, dst) in limbs.iter().zip_eq( + iter::empty() + .chain(ec_point.x().limbs()) + .chain(ec_point.y().limbs()), + ) { + ctx.constrain_equal(src.cell(), dst.as_ref().cell())?; + } + + Ok(ec_point) } - let accumulator = KzgAccumulator::new(lhs, rhs); - Ok(accumulator) + fn assign_ec_point_to_limbs( + &self, + _: &mut Self::Context, + ec_point: impl Deref, + ) -> Result, plonk::Error> { + Ok(iter::empty() + .chain(ec_point.x().limbs()) + .chain(ec_point.y().limbs()) + .map(|limb| limb.as_ref()) + .cloned() + .collect()) + } } } } diff --git a/src/pcs/kzg/decider.rs b/src/pcs/kzg/decider.rs index b6957883..de3e2a06 100644 --- a/src/pcs/kzg/decider.rs +++ b/src/pcs/kzg/decider.rs @@ -144,7 +144,7 @@ mod evm { let powers_of_challenge = LoadedScalar::::powers(&challenge, lhs.len()); let [lhs, rhs] = [lhs, rhs].map(|msms| { - msms.into_iter() + msms.iter() .zip(powers_of_challenge.iter()) .map(|(msm, power_of_challenge)| { Msm::>::base(msm) * power_of_challenge diff --git a/src/pcs/kzg/multiopen/bdfg21.rs b/src/pcs/kzg/multiopen/bdfg21.rs index 7f70ca61..f542f750 100644 --- a/src/pcs/kzg/multiopen/bdfg21.rs +++ b/src/pcs/kzg/multiopen/bdfg21.rs @@ -47,8 +47,8 @@ where queries: &[Query], proof: &Bdfg21Proof, ) -> Result { + let sets = query_sets(queries); let f = { - let sets = query_sets(queries); let coeffs = query_set_coeffs(&sets, z, &proof.z_prime); let powers_of_mu = proof @@ -62,10 +62,10 @@ where msms.zip(proof.gamma.powers(sets.len()).into_iter()) .map(|(msm, power_of_gamma)| msm * &power_of_gamma) .sum::>() - - Msm::base(proof.w.clone()) * &coeffs[0].z_s + - Msm::base(&proof.w) * &coeffs[0].z_s }; - let rhs = Msm::base(proof.w_prime.clone()); + let rhs = Msm::base(&proof.w_prime); let lhs = f + rhs.clone() * &proof.z_prime; Ok(KzgAccumulator::new( @@ -143,7 +143,7 @@ fn query_sets(queries: &[Query]) -> Vec(queries: &[Query]) -> Vec(queries: &[Query]) -> Vec>( - sets: &[QuerySet], +fn query_set_coeffs<'a, F: FieldExt, T: LoadedScalar>( + sets: &[QuerySet<'a, F, T>], z: &T, z_prime: &T, ) -> Vec> { @@ -211,17 +211,17 @@ fn query_set_coeffs>( } #[derive(Clone, Debug)] -struct QuerySet { +struct QuerySet<'a, F, T> { shifts: Vec, polys: Vec, - evals: Vec>, + evals: Vec>, } -impl> QuerySet { +impl<'a, F: FieldExt, T: LoadedScalar> QuerySet<'a, F, T> { fn msm>( &self, coeff: &QuerySetCoeff, - commitments: &[Msm], + commitments: &[Msm<'a, C, L>], powers_of_mu: &[T], ) -> Msm { self.polys @@ -241,7 +241,7 @@ impl> QuerySet { &coeff .eval_coeffs .iter() - .zip(evals.iter()) + .zip(evals.iter().cloned()) .map(|(coeff, eval)| (coeff.evaluated(), eval)) .collect_vec(), ) * coeff.r_eval_coeff.as_ref().unwrap().evaluated(); @@ -288,18 +288,15 @@ where }) .collect_vec(); - let z = &powers_of_z[1].clone(); + let z = &powers_of_z[1]; let z_pow_k_minus_one = { let k_minus_one = shifts.len() - 1; powers_of_z .iter() .enumerate() .skip(1) - .filter_map(|(i, power_of_z)| { - (k_minus_one & (1 << i) == 1).then(|| power_of_z.clone()) - }) - .reduce(|acc, value| acc * value) - .unwrap_or_else(|| loader.load_one()) + .filter_map(|(i, power_of_z)| (k_minus_one & (1 << i) == 1).then(|| power_of_z)) + .fold(loader.load_one(), |acc, value| acc * value) }; let barycentric_weights = shifts @@ -354,7 +351,7 @@ where .map(Fraction::evaluated) .collect_vec(), ); - self.r_eval_coeff = Some(match self.commitment_coeff.clone() { + self.r_eval_coeff = Some(match self.commitment_coeff.as_ref() { Some(coeff) => Fraction::new(coeff.evaluated().clone(), barycentric_weights_sum), None => Fraction::one_over(barycentric_weights_sum), }); diff --git a/src/pcs/kzg/multiopen/gwc19.rs b/src/pcs/kzg/multiopen/gwc19.rs index 121fce8a..6e3f579f 100644 --- a/src/pcs/kzg/multiopen/gwc19.rs +++ b/src/pcs/kzg/multiopen/gwc19.rs @@ -55,15 +55,13 @@ where .map(|(msm, power_of_u)| msm * power_of_u) .sum::>() }; - let z_omegas = sets - .iter() - .map(|set| z.clone() * &z.loader().load_const(&set.shift)); + let z_omegas = sets.iter().map(|set| z.loader().load_const(&set.shift) * z); let rhs = proof .ws .iter() .zip(powers_of_u.iter()) - .map(|(w, power_of_u)| Msm::base(w.clone()) * power_of_u) + .map(|(w, power_of_u)| Msm::base(w) * power_of_u) .collect_vec(); let lhs = f + rhs .iter() @@ -105,25 +103,25 @@ where } } -struct QuerySet { +struct QuerySet<'a, F, T> { shift: F, polys: Vec, - evals: Vec, + evals: Vec<&'a T>, } -impl QuerySet +impl<'a, F, T> QuerySet<'a, F, T> where F: PrimeField, T: Clone, { fn msm>( &self, - commitments: &[Msm], + commitments: &[Msm<'a, C, L>], powers_of_v: &[L::LoadedScalar], ) -> Msm { self.polys .iter() - .zip(self.evals.iter()) + .zip(self.evals.iter().cloned()) .map(|(poly, eval)| { let commitment = commitments[*poly].clone(); commitment - Msm::constant(eval.clone()) @@ -142,12 +140,12 @@ where queries.iter().fold(Vec::new(), |mut sets, query| { if let Some(pos) = sets.iter().position(|set| set.shift == query.shift) { sets[pos].polys.push(query.poly); - sets[pos].evals.push(query.eval.clone()); + sets[pos].evals.push(&query.eval); } else { sets.push(QuerySet { shift: query.shift, polys: vec![query.poly], - evals: vec![query.eval.clone()], + evals: vec![&query.eval], }); } sets diff --git a/src/system/halo2.rs b/src/system/halo2.rs index 3d7cf140..a49fa6ef 100644 --- a/src/system/halo2.rs +++ b/src/system/halo2.rs @@ -601,11 +601,14 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { .zip(permutation_fixeds.chunks(self.permutation_chunk_size)) .enumerate() .map( - |(i, ((((z, z_w, _), (_, z_next_w, _)), polys), permutation_fixeds))| { + |( + i, + ((((z, z_omega, _), (_, z_next_omega, _)), polys), permutation_fixeds), + )| { let left = if self.zk || zs.len() == 1 { - z_w.clone() + z_omega.clone() } else { - z_w + l_last * (z_next_w - z_w) + z_omega + l_last * (z_next_omega - z_omega) } * polys .iter() .zip(permutation_fixeds.iter()) @@ -675,7 +678,10 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { .iter() .zip(polys.iter()) .flat_map( - |(lookup, (z, z_w, permuted_input, permuted_input_w_inv, permuted_table))| { + |( + lookup, + (z, z_omega, permuted_input, permuted_input_omega_inv, permuted_table), + )| { let input = compress(lookup.input_expressions()); let table = compress(lookup.table_expressions()); iter::empty() @@ -683,20 +689,20 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { .chain(self.zk.then(|| l_last * (z * z - z))) .chain(Some(if self.zk { l_active - * (z_w * (permuted_input + beta) * (permuted_table + gamma) + * (z_omega * (permuted_input + beta) * (permuted_table + gamma) - z * (input + beta) * (table + gamma)) } else { - z_w * (permuted_input + beta) * (permuted_table + gamma) + z_omega * (permuted_input + beta) * (permuted_table + gamma) - z * (input + beta) * (table + gamma) })) .chain(self.zk.then(|| l_0 * (permuted_input - permuted_table))) .chain(Some(if self.zk { l_active * (permuted_input - permuted_table) - * (permuted_input - permuted_input_w_inv) + * (permuted_input - permuted_input_omega_inv) } else { (permuted_input - permuted_table) - * (permuted_input - permuted_input_w_inv) + * (permuted_input - permuted_input_omega_inv) })) }, ) diff --git a/src/system/halo2/test/kzg.rs b/src/system/halo2/test/kzg.rs index 3b7e1694..2b267758 100644 --- a/src/system/halo2/test/kzg.rs +++ b/src/system/halo2/test/kzg.rs @@ -27,8 +27,8 @@ pub fn main_gate_with_range_with_mock_kzg_accumulator( let srs = read_or_create_srs(TESTDATA_DIR, 1, setup::); let [g1, s_g1] = [srs.get_g()[0], srs.get_g()[1]].map(|point| point.coordinates().unwrap()); MainGateWithRange::new( - [*s_g1.x(), *s_g1.y(), *g1.x(), *g1.y()] - .iter() + [s_g1.x(), s_g1.y(), g1.x(), g1.y()] + .into_iter() .cloned() .flat_map(fe_to_limbs::<_, _, LIMBS, BITS>) .collect(), diff --git a/src/system/halo2/test/kzg/halo2.rs b/src/system/halo2/test/kzg/halo2.rs index 18767c98..11a6046f 100644 --- a/src/system/halo2/test/kzg/halo2.rs +++ b/src/system/halo2/test/kzg/halo2.rs @@ -7,7 +7,7 @@ use crate::{ pcs::{ kzg::{ Bdfg21, Kzg, KzgAccumulator, KzgAs, KzgAsProvingKey, KzgAsVerifyingKey, - KzgSuccinctVerifyingKey, LimbsEncoding, + KzgSuccinctVerifyingKey, LimbsEncoding, LimbsEncodingInstructions, }, AccumulationScheme, AccumulationSchemeProver, }, @@ -31,7 +31,7 @@ use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ circuit::{floor_planner::V1, Layouter, Value}, plonk, - plonk::Circuit, + plonk::{Circuit, Error}, poly::{ commitment::ParamsProver, kzg::{ @@ -48,7 +48,7 @@ use halo2_wrong_ecc::{ }; use paste::paste; use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; -use std::{iter, rc::Rc}; +use std::rc::Rc; const T: usize = 5; const RATE: usize = 4; @@ -281,14 +281,14 @@ impl Circuit for Accumulation { range_chip.load_table(&mut layouter)?; - let (lhs, rhs) = layouter.assign_region( + let accumulator_limbs = layouter.assign_region( || "", |region| { let ctx = RegionCtx::new(region, 0); let ecc_chip = config.ecc_chip(); let loader = Halo2Loader::new(ecc_chip, ctx); - let KzgAccumulator { lhs, rhs } = accumulate( + let accumulator = accumulate( &self.svk, &loader, &self.snarks, @@ -296,21 +296,26 @@ impl Circuit for Accumulation { self.as_proof(), ); + let accumulator_limbs = [accumulator.lhs, accumulator.rhs] + .iter() + .map(|ec_point| { + loader + .ecc_chip() + .assign_ec_point_to_limbs(&mut loader.ctx_mut(), ec_point.assigned()) + }) + .collect::, Error>>()? + .into_iter() + .flatten(); + loader.print_row_metering(); println!("Total row cost: {}", loader.ctx().offset()); - Ok((lhs.assigned(), rhs.assigned())) + Ok(accumulator_limbs) }, )?; - for (limb, row) in iter::empty() - .chain(lhs.x().limbs()) - .chain(lhs.y().limbs()) - .chain(rhs.x().limbs()) - .chain(rhs.y().limbs()) - .zip(0..) - { - main_gate.expose_public(layouter.namespace(|| ""), limb.into(), row)?; + for (row, limb) in accumulator_limbs.enumerate() { + main_gate.expose_public(layouter.namespace(|| ""), limb, row)?; } Ok(()) diff --git a/src/system/halo2/transcript/halo2.rs b/src/system/halo2/transcript/halo2.rs index bb7e8e23..ab7d548c 100644 --- a/src/system/halo2/transcript/halo2.rs +++ b/src/system/halo2/transcript/halo2.rs @@ -1,60 +1,58 @@ use crate::{ loader::{ - halo2::{EcPoint, EccInstructions, Halo2Loader, IntegerInstructions, Scalar}, + halo2::{EcPoint, EccInstructions, Halo2Loader, Scalar}, native::{self, NativeLoader}, Loader, ScalarLoader, }, util::{ - arithmetic::{fe_to_fe, CurveAffine, FieldExt, PrimeField}, + arithmetic::{fe_to_fe, CurveAffine, PrimeField}, hash::Poseidon, transcript::{Transcript, TranscriptRead, TranscriptWrite}, Itertools, }, Error, }; -use halo2_proofs::{ - circuit::{AssignedCell, Value}, - transcript::EncodedChallenge, -}; +use halo2_proofs::{circuit::Value, transcript::EncodedChallenge}; use std::{ io::{self, Read, Write}, - marker::PhantomData, rc::Rc, }; -pub trait EncodeNative<'a, C: CurveAffine, N: FieldExt>: EccInstructions<'a, C> { - fn encode_native( +/// Encoding that encodes elliptic curve point into native field elements. +pub trait NativeEncoding<'a, C>: EccInstructions<'a, C> +where + C: CurveAffine, +{ + fn encode( &self, ctx: &mut Self::Context, ec_point: &Self::AssignedEcPoint, - ) -> Result>, Error>; + ) -> Result, Error>; } pub struct PoseidonTranscript< - C: CurveAffine, - L: Loader, + C, + L, S, const T: usize, const RATE: usize, const R_F: usize, const R_P: usize, -> { +> where + C: CurveAffine, + L: Loader, +{ loader: L, stream: S, buf: Poseidon>::LoadedScalar, T, RATE>, - _marker: PhantomData, } -impl< - 'a, - C: CurveAffine, - R: Read, - EccChip: EncodeNative<'a, C, C::Scalar, AssignedScalar = AssignedCell>, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > PoseidonTranscript>, Value, T, RATE, R_F, R_P> +impl<'a, C, R, EccChip, const T: usize, const RATE: usize, const R_F: usize, const R_P: usize> + PoseidonTranscript>, Value, T, RATE, R_F, R_P> +where + C: CurveAffine, + R: Read, + EccChip: NativeEncoding<'a, C>, { pub fn new(loader: &Rc>, stream: Value) -> Self { let buf = Poseidon::new(loader, R_F, R_P); @@ -62,22 +60,17 @@ impl< loader: loader.clone(), stream, buf, - _marker: PhantomData, } } } -impl< - 'a, - C: CurveAffine, - R: Read, - EccChip: EncodeNative<'a, C, C::Scalar, AssignedScalar = AssignedCell>, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > Transcript>> +impl<'a, C, R, EccChip, const T: usize, const RATE: usize, const R_F: usize, const R_P: usize> + Transcript>> for PoseidonTranscript>, Value, T, RATE, R_F, R_P> +where + C: CurveAffine, + R: Read, + EccChip: NativeEncoding<'a, C>, { fn loader(&self) -> &Rc> { &self.loader @@ -96,30 +89,31 @@ impl< let encoded = self .loader .ecc_chip() - .encode_native(&mut self.loader.ctx_mut(), &ec_point.assigned()) + .encode(&mut self.loader.ctx_mut(), &ec_point.assigned()) .map(|encoded| { encoded .into_iter() .map(|encoded| self.loader.scalar_from_assigned(encoded)) .collect_vec() }) - .map_err(|_| Error::Transcript(io::ErrorKind::Other, "".to_string()))?; + .map_err(|_| { + Error::Transcript( + io::ErrorKind::Other, + "Failed to encode elliptic curve point into native field elements".to_string(), + ) + })?; self.buf.update(&encoded); Ok(()) } } -impl< - 'a, - C: CurveAffine, - R: Read, - EccChip: EncodeNative<'a, C, C::Scalar, AssignedScalar = AssignedCell>, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > TranscriptRead>> +impl<'a, C, R, EccChip, const T: usize, const RATE: usize, const R_F: usize, const R_P: usize> + TranscriptRead>> for PoseidonTranscript>, Value, T, RATE, R_F, R_P> +where + C: CurveAffine, + R: Read, + EccChip: NativeEncoding<'a, C>, { fn read_scalar(&mut self) -> Result, Error> { let scalar = self.stream.as_mut().and_then(|stream| { @@ -128,7 +122,7 @@ impl< return Value::unknown(); } Option::::from(C::Scalar::from_repr(data)) - .map(|scalar| Value::known(self.loader.scalar_chip().integer(scalar))) + .map(Value::known) .unwrap_or_else(Value::unknown) }); let scalar = self.loader.assign_scalar(scalar); @@ -152,8 +146,6 @@ impl< } } -// - impl PoseidonTranscript { @@ -162,7 +154,6 @@ impl TranscriptRead - for PoseidonTranscript +impl + TranscriptRead for PoseidonTranscript +where + C: CurveAffine, + R: Read, { fn read_scalar(&mut self) -> Result { let mut data = ::Repr::default(); @@ -243,14 +230,11 @@ impl< } } -impl< - C: CurveAffine, - W: Write, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > PoseidonTranscript +impl + PoseidonTranscript +where + C: CurveAffine, + W: Write, { pub fn stream_mut(&mut self) -> &mut W { &mut self.stream @@ -261,14 +245,11 @@ impl< } } -impl< - C: CurveAffine, - W: Write, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > TranscriptWrite for PoseidonTranscript +impl TranscriptWrite + for PoseidonTranscript +where + C: CurveAffine, + W: Write, { fn write_scalar(&mut self, scalar: C::Scalar) -> Result<(), Error> { self.common_scalar(&scalar)?; @@ -332,15 +313,12 @@ impl halo2_proofs::transcript::TranscriptRead> +impl + halo2_proofs::transcript::TranscriptRead> for PoseidonTranscript +where + C: CurveAffine, + R: Read, { fn read_point(&mut self) -> io::Result { match TranscriptRead::read_ec_point(self) { @@ -359,30 +337,24 @@ impl< } } -impl< - C: CurveAffine, - R: Read, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > halo2_proofs::transcript::TranscriptReadBuffer> +impl + halo2_proofs::transcript::TranscriptReadBuffer> for PoseidonTranscript +where + C: CurveAffine, + R: Read, { fn init(reader: R) -> Self { Self::new(reader) } } -impl< - C: CurveAffine, - W: Write, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > halo2_proofs::transcript::TranscriptWrite> +impl + halo2_proofs::transcript::TranscriptWrite> for PoseidonTranscript +where + C: CurveAffine, + W: Write, { fn write_point(&mut self, ec_point: C) -> io::Result<()> { halo2_proofs::transcript::Transcript::>::common_point( @@ -399,15 +371,12 @@ impl< } } -impl< - C: CurveAffine, - W: Write, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - > halo2_proofs::transcript::TranscriptWriterBuffer> +impl + halo2_proofs::transcript::TranscriptWriterBuffer> for PoseidonTranscript +where + C: CurveAffine, + W: Write, { fn init(writer: W) -> Self { Self::new(writer) @@ -419,15 +388,15 @@ impl< } mod halo2_wrong { - use crate::system::halo2::transcript::halo2::EncodeNative; + use crate::system::halo2::transcript::halo2::NativeEncoding; use halo2_curves::CurveAffine; use halo2_proofs::circuit::AssignedCell; use halo2_wrong_ecc::BaseFieldEccChip; - impl<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize> EncodeNative<'a, C, C::Scalar> + impl<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize> NativeEncoding<'a, C> for BaseFieldEccChip { - fn encode_native( + fn encode( &self, _: &mut Self::Context, ec_point: &Self::AssignedEcPoint, diff --git a/src/util/arithmetic.rs b/src/util/arithmetic.rs index b9a5c7c6..02d6da32 100644 --- a/src/util/arithmetic.rs +++ b/src/util/arithmetic.rs @@ -186,14 +186,14 @@ impl Fraction { self.eval = Some( self.numer - .as_ref() - .map(|numer| numer.clone() * &self.denom) + .take() + .map(|numer| numer * &self.denom) .unwrap_or_else(|| self.denom.clone()), ); } pub fn evaluated(&self) -> &T { - assert!(self.inv); + assert!(self.eval.is_some()); self.eval.as_ref().unwrap() } @@ -241,19 +241,12 @@ pub fn fe_to_limbs [F2; LIMBS] { let big = BigUint::from_bytes_le(fe.to_repr().as_ref()); - let mask = (BigUint::one() << BITS) - 1usize; + let mask = &((BigUint::one() << BITS) - 1usize); (0usize..) .step_by(BITS) .take(LIMBS) - .map(move |shift| fe_from_big((&big >> shift) & &mask)) + .map(|shift| fe_from_big((&big >> shift) & mask)) .collect_vec() .try_into() .unwrap() } - -pub fn powers(scalar: F) -> impl Iterator -where - for<'a> F: Mul<&'a F, Output = F> + One + Clone, -{ - iter::successors(Some(F::one()), move |power| Some(scalar.clone() * power)) -} diff --git a/src/util/msm.rs b/src/util/msm.rs index a15eab9d..f35ea197 100644 --- a/src/util/msm.rs +++ b/src/util/msm.rs @@ -9,13 +9,13 @@ use std::{ }; #[derive(Clone, Debug)] -pub struct Msm> { +pub struct Msm<'a, C: CurveAffine, L: Loader> { constant: Option, scalars: Vec, - bases: Vec, + bases: Vec<&'a L::LoadedEcPoint>, } -impl Default for Msm +impl<'a, C, L> Default for Msm<'a, C, L> where C: CurveAffine, L: Loader, @@ -29,7 +29,7 @@ where } } -impl Msm +impl<'a, C, L> Msm<'a, C, L> where C: CurveAffine, L: Loader, @@ -41,7 +41,7 @@ where } } - pub fn base(base: L::LoadedEcPoint) -> Self { + pub fn base<'b: 'a>(base: &'b L::LoadedEcPoint) -> Self { let one = base.loader().load_one(); Msm { scalars: vec![one], @@ -72,8 +72,12 @@ where .ec_point_load_const(&gen) }); let pairs = iter::empty() - .chain(self.constant.map(|constant| (constant, gen.unwrap()))) - .chain(self.scalars.into_iter().zip(self.bases.into_iter())) + .chain( + self.constant + .as_ref() + .map(|constant| (constant, gen.as_ref().unwrap())), + ) + .chain(self.scalars.iter().zip(self.bases.into_iter())) .collect_vec(); L::multi_scalar_multiplication(&pairs) } @@ -87,16 +91,16 @@ where } } - pub fn push(&mut self, scalar: L::LoadedScalar, base: L::LoadedEcPoint) { + pub fn push<'b: 'a>(&mut self, scalar: L::LoadedScalar, base: &'b L::LoadedEcPoint) { if let Some(pos) = self.bases.iter().position(|exist| exist.eq(&base)) { - self.scalars[pos] += scalar; + self.scalars[pos] += &scalar; } else { self.scalars.push(scalar); self.bases.push(base); } } - pub fn extend(&mut self, mut other: Self) { + pub fn extend<'b: 'a>(&mut self, mut other: Msm<'b, C, L>) { match (self.constant.as_mut(), other.constant.as_ref()) { (Some(lhs), Some(rhs)) => *lhs += rhs, (None, Some(_)) => self.constant = other.constant.take(), @@ -108,58 +112,62 @@ where } } -impl Add> for Msm +impl<'a, 'b, C, L> Add> for Msm<'a, C, L> where + 'b: 'a, C: CurveAffine, L: Loader, { - type Output = Msm; + type Output = Msm<'a, C, L>; - fn add(mut self, rhs: Msm) -> Self::Output { + fn add(mut self, rhs: Msm<'b, C, L>) -> Self::Output { self.extend(rhs); self } } -impl AddAssign> for Msm +impl<'a, 'b, C, L> AddAssign> for Msm<'a, C, L> where + 'b: 'a, C: CurveAffine, L: Loader, { - fn add_assign(&mut self, rhs: Msm) { + fn add_assign(&mut self, rhs: Msm<'b, C, L>) { self.extend(rhs); } } -impl Sub> for Msm +impl<'a, 'b, C, L> Sub> for Msm<'a, C, L> where + 'b: 'a, C: CurveAffine, L: Loader, { - type Output = Msm; + type Output = Msm<'a, C, L>; - fn sub(mut self, rhs: Msm) -> Self::Output { + fn sub(mut self, rhs: Msm<'b, C, L>) -> Self::Output { self.extend(-rhs); self } } -impl SubAssign> for Msm +impl<'a, 'b, C, L> SubAssign> for Msm<'a, C, L> where + 'b: 'a, C: CurveAffine, L: Loader, { - fn sub_assign(&mut self, rhs: Msm) { + fn sub_assign(&mut self, rhs: Msm<'b, C, L>) { self.extend(-rhs); } } -impl Mul<&L::LoadedScalar> for Msm +impl<'a, C, L> Mul<&L::LoadedScalar> for Msm<'a, C, L> where C: CurveAffine, L: Loader, { - type Output = Msm; + type Output = Msm<'a, C, L>; fn mul(mut self, rhs: &L::LoadedScalar) -> Self::Output { self.scale(rhs); @@ -167,7 +175,7 @@ where } } -impl MulAssign<&L::LoadedScalar> for Msm +impl<'a, C, L> MulAssign<&L::LoadedScalar> for Msm<'a, C, L> where C: CurveAffine, L: Loader, @@ -177,13 +185,13 @@ where } } -impl Neg for Msm +impl<'a, C, L> Neg for Msm<'a, C, L> where C: CurveAffine, L: Loader, { - type Output = Msm; - fn neg(mut self) -> Msm { + type Output = Msm<'a, C, L>; + fn neg(mut self) -> Msm<'a, C, L> { self.constant = self.constant.map(|constant| -constant); for scalar in self.scalars.iter_mut() { *scalar = -scalar.clone(); @@ -192,7 +200,7 @@ where } } -impl Sum for Msm +impl<'a, C, L> Sum for Msm<'a, C, L> where C: CurveAffine, L: Loader, diff --git a/src/util/protocol.rs b/src/util/protocol.rs index e9ecd9f0..f7747060 100644 --- a/src/util/protocol.rs +++ b/src/util/protocol.rs @@ -41,7 +41,7 @@ where quotient: self.quotient.clone(), transcript_initial_state, instance_committing_key: self.instance_committing_key.clone(), - linearization: self.linearization.clone(), + linearization: self.linearization, accumulator_indices: self.accumulator_indices.clone(), } } @@ -82,11 +82,11 @@ where let langranges = langranges.into_iter().sorted().dedup().collect_vec(); let one = loader.load_one(); - let zn_minus_one = zn.clone() - one; + let zn_minus_one = zn.clone() - &one; let zn_minus_one_inv = Fraction::one_over(zn_minus_one.clone()); let n_inv = loader.load_const(&domain.n_inv); - let numer = zn_minus_one.clone() * n_inv; + let numer = zn_minus_one.clone() * &n_inv; let omegas = langranges .iter() .map(|&i| loader.load_const(&domain.rotate_scalar(C::Scalar::one(), Rotation(i)))) @@ -378,7 +378,7 @@ fn merge_left_right(a: Option>, b: Option>) -> O } } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] pub enum LinearizationStrategy { /// Older linearization strategy of GWC19, which has linearization /// polynomial that doesn't evaluate to 0, and requires prover to send extra diff --git a/src/verifier/plonk.rs b/src/verifier/plonk.rs index c3276af4..df208949 100644 --- a/src/verifier/plonk.rs +++ b/src/verifier/plonk.rs @@ -137,8 +137,8 @@ where instances .iter() .zip(bases.iter()) - .map(|(scalar, base)| Msm::::base(base.clone()) * scalar) - .chain(constant.clone().map(|constant| Msm::base(constant))) + .map(|(scalar, base)| Msm::::base(base) * scalar) + .chain(constant.as_ref().map(Msm::base)) .sum::>() .evaluate(None) }) @@ -190,12 +190,13 @@ where .accumulator_indices .iter() .map(|accumulator_indices| { - accumulator_indices - .iter() - .map(|&(i, j)| instances[i][j].clone()) - .collect() + AE::from_repr( + &accumulator_indices + .iter() + .map(|&(i, j)| &instances[i][j]) + .collect_vec(), + ) }) - .map(AE::from_repr) .collect::, _>>()?; Ok(Self { @@ -241,25 +242,20 @@ where .collect() } - fn commitments( - &self, - protocol: &Protocol, + fn commitments<'a>( + &'a self, + protocol: &'a Protocol, common_poly_eval: &CommonPolynomialEvaluation, evaluations: &mut HashMap, ) -> Result>, Error> { let loader = common_poly_eval.zn().loader(); let mut commitments = iter::empty() - .chain( - protocol - .preprocessed - .iter() - .map(|value| Msm::base(value.clone())), - ) + .chain(protocol.preprocessed.iter().map(Msm::base)) .chain( self.committed_instances - .clone() + .as_ref() .map(|committed_instances| { - committed_instances.into_iter().map(Msm::base).collect_vec() + committed_instances.iter().map(Msm::base).collect_vec() }) .unwrap_or_else(|| { iter::repeat_with(Default::default) @@ -267,7 +263,7 @@ where .collect_vec() }), ) - .chain(self.witnesses.iter().cloned().map(Msm::base)) + .chain(self.witnesses.iter().map(Msm::base)) .collect_vec(); let numerator = protocol.quotient.numerator.evaluate( @@ -314,7 +310,7 @@ where .pow_const(protocol.quotient.chunk_degree as u64) .powers(self.quotients.len()) .into_iter() - .zip(self.quotients.iter().cloned().map(Msm::base)) + .zip(self.quotients.iter().map(Msm::base)) .map(|(coeff, chunk)| chunk * &coeff) .sum::>(); match protocol.linearization { From 5c31088f8530470227c411b5d168b445cb59858b Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 8 Nov 2022 19:58:00 -0800 Subject: [PATCH 04/73] feat: implement ipa pcs and accumulation (#14) --- Cargo.toml | 7 +- src/loader/halo2/test.rs | 21 +- src/pcs.rs | 1 + src/pcs/ipa.rs | 447 ++++++++++++++++++++++++++++ src/pcs/ipa/accumulation.rs | 291 ++++++++++++++++++ src/pcs/ipa/accumulator.rs | 21 ++ src/pcs/ipa/decider.rs | 57 ++++ src/pcs/ipa/multiopen.rs | 3 + src/pcs/ipa/multiopen/bgh19.rs | 417 ++++++++++++++++++++++++++ src/system/halo2.rs | 1 + src/system/halo2/strategy.rs | 53 ++++ src/system/halo2/test.rs | 1 + src/system/halo2/test/ipa.rs | 143 +++++++++ src/system/halo2/test/ipa/native.rs | 59 ++++ src/system/halo2/test/kzg/halo2.rs | 9 +- src/util.rs | 40 +++ src/util/arithmetic.rs | 12 + src/util/msm.rs | 123 +++++++- src/util/poly.rs | 175 +++++++++++ 19 files changed, 1866 insertions(+), 15 deletions(-) create mode 100644 src/pcs/ipa.rs create mode 100644 src/pcs/ipa/accumulation.rs create mode 100644 src/pcs/ipa/accumulator.rs create mode 100644 src/pcs/ipa/decider.rs create mode 100644 src/pcs/ipa/multiopen.rs create mode 100644 src/pcs/ipa/multiopen/bgh19.rs create mode 100644 src/system/halo2/strategy.rs create mode 100644 src/system/halo2/test/ipa.rs create mode 100644 src/system/halo2/test/ipa/native.rs create mode 100644 src/util/poly.rs diff --git a/Cargo.toml b/Cargo.toml index e5bbb0d2..44dcd60b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,9 @@ rand = "0.8" hex = "0.4" halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.0", package = "halo2curves" } +# parallel +rayon = { version = "1.5.3", optional = true } + # system_halo2 halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2022_10_22", optional = true } @@ -41,13 +44,13 @@ tui = { version = "0.19", default-features = false, features = ["crossterm"] } [features] default = ["loader_evm", "loader_halo2", "system_halo2"] +parallel = ["dep:rayon"] + loader_evm = ["dep:ethereum_types", "dep:sha3", "dep:revm", "dep:bytes", "dep:rlp"] loader_halo2 = ["dep:halo2_proofs", "dep:halo2_wrong_ecc", "dep:poseidon"] system_halo2 = ["dep:halo2_proofs"] -sanity_check = [] - [[example]] name = "evm-verifier" required-features = ["loader_evm", "system_halo2"] diff --git a/src/loader/halo2/test.rs b/src/loader/halo2/test.rs index 08551fe0..dd2fccaa 100644 --- a/src/loader/halo2/test.rs +++ b/src/loader/halo2/test.rs @@ -4,6 +4,7 @@ use crate::{ }; use halo2_proofs::circuit::Value; +#[derive(Clone, Debug)] pub struct Snark { pub protocol: Protocol, pub instances: Vec>, @@ -27,6 +28,7 @@ impl Snark { } } +#[derive(Clone, Debug)] pub struct SnarkWitness { pub protocol: Protocol, pub instances: Vec>>, @@ -48,18 +50,23 @@ impl From> for SnarkWitness { } impl SnarkWitness { - pub fn without_witnesses(&self) -> Self { + pub fn new_without_witness(protocol: Protocol) -> Self { + let instances = protocol + .num_instance + .iter() + .map(|num_instance| vec![Value::unknown(); *num_instance]) + .collect(); SnarkWitness { - protocol: self.protocol.clone(), - instances: self - .instances - .iter() - .map(|instances| vec![Value::unknown(); instances.len()]) - .collect(), + protocol, + instances, proof: Value::unknown(), } } + pub fn without_witnesses(&self) -> Self { + SnarkWitness::new_without_witness(self.protocol.clone()) + } + pub fn proof(&self) -> Value<&[u8]> { self.proof.as_ref().map(Vec::as_slice) } diff --git a/src/pcs.rs b/src/pcs.rs index 23fdda2a..bf944a43 100644 --- a/src/pcs.rs +++ b/src/pcs.rs @@ -10,6 +10,7 @@ use crate::{ use rand::Rng; use std::fmt::Debug; +pub mod ipa; pub mod kzg; pub trait PolynomialCommitmentScheme: Clone + Debug diff --git a/src/pcs/ipa.rs b/src/pcs/ipa.rs new file mode 100644 index 00000000..a2b34824 --- /dev/null +++ b/src/pcs/ipa.rs @@ -0,0 +1,447 @@ +use crate::{ + loader::{native::NativeLoader, LoadedScalar, Loader, ScalarLoader}, + pcs::PolynomialCommitmentScheme, + util::{ + arithmetic::{ + inner_product, powers, Curve, CurveAffine, Domain, Field, Fraction, PrimeField, + }, + msm::{multi_scalar_multiplication, Msm}, + parallelize, + poly::Polynomial, + transcript::{TranscriptRead, TranscriptWrite}, + Itertools, + }, + Error, +}; +use rand::Rng; +use std::{fmt::Debug, iter, marker::PhantomData}; + +mod accumulation; +mod accumulator; +mod decider; +mod multiopen; + +pub use accumulation::{IpaAs, IpaAsProof}; +pub use accumulator::IpaAccumulator; +pub use decider::IpaDecidingKey; +pub use multiopen::{Bgh19, Bgh19Proof, Bgh19SuccinctVerifyingKey}; + +#[derive(Clone, Debug)] +pub struct Ipa(PhantomData<(C, MOS)>); + +impl PolynomialCommitmentScheme for Ipa +where + C: CurveAffine, + L: Loader, + MOS: Clone + Debug, +{ + type Accumulator = IpaAccumulator; +} + +impl Ipa +where + C: CurveAffine, +{ + pub fn create_proof( + pk: &IpaProvingKey, + p: &[C::Scalar], + z: &C::Scalar, + omega: Option<&C::Scalar>, + transcript: &mut T, + mut rng: R, + ) -> Result, Error> + where + T: TranscriptWrite, + R: Rng, + { + let mut p_prime = Polynomial::new(p.to_vec()); + if pk.zk() { + let p_bar = { + let mut p_bar = Polynomial::rand(p.len(), &mut rng); + let p_bar_at_z = p_bar.evaluate(*z); + p_bar[0] -= p_bar_at_z; + p_bar + }; + let omega_bar = C::Scalar::random(&mut rng); + let c_bar = pk.commit(&p_bar, Some(omega_bar)); + transcript.write_ec_point(c_bar)?; + + let alpha = transcript.squeeze_challenge(); + let omega_prime = *omega.unwrap() + alpha * omega_bar; + transcript.write_scalar(omega_prime)?; + + p_prime = p_prime + &(p_bar * alpha); + }; + + let xi_0 = transcript.squeeze_challenge(); + let h_prime = pk.h * xi_0; + let mut bases = pk.g.clone(); + let mut coeffs = p_prime.to_vec(); + let mut zs = powers(*z).take(coeffs.len()).collect_vec(); + + let k = pk.domain.k; + let mut xi = Vec::with_capacity(k); + for i in 0..k { + let half = 1 << (k - i - 1); + + let l_i = multi_scalar_multiplication(&coeffs[half..], &bases[..half]) + + h_prime * inner_product(&coeffs[half..], &zs[..half]); + let r_i = multi_scalar_multiplication(&coeffs[..half], &bases[half..]) + + h_prime * inner_product(&coeffs[..half], &zs[half..]); + transcript.write_ec_point(l_i.to_affine())?; + transcript.write_ec_point(r_i.to_affine())?; + + let xi_i = transcript.squeeze_challenge(); + let xi_i_inv = Field::invert(&xi_i).unwrap(); + + let (bases_l, bases_r) = bases.split_at_mut(half); + let (coeffs_l, coeffs_r) = coeffs.split_at_mut(half); + let (zs_l, zs_r) = zs.split_at_mut(half); + parallelize(bases_l, |(bases_l, start)| { + let mut tmp = Vec::with_capacity(bases_l.len()); + for (lhs, rhs) in bases_l.iter().zip(bases_r[start..].iter()) { + tmp.push(lhs.to_curve() + *rhs * xi_i); + } + C::Curve::batch_normalize(&tmp, bases_l); + }); + parallelize(coeffs_l, |(coeffs_l, start)| { + for (lhs, rhs) in coeffs_l.iter_mut().zip(coeffs_r[start..].iter()) { + *lhs += xi_i_inv * rhs; + } + }); + parallelize(zs_l, |(zs_l, start)| { + for (lhs, rhs) in zs_l.iter_mut().zip(zs_r[start..].iter()) { + *lhs += xi_i * rhs; + } + }); + bases = bases_l.to_vec(); + coeffs = coeffs_l.to_vec(); + zs = zs_l.to_vec(); + + xi.push(xi_i); + } + + transcript.write_ec_point(bases[0])?; + transcript.write_scalar(coeffs[0])?; + + Ok(IpaAccumulator::new(xi, bases[0])) + } + + pub fn read_proof>( + svk: &IpaSuccinctVerifyingKey, + transcript: &mut T, + ) -> Result, Error> + where + T: TranscriptRead, + { + IpaProof::read(svk, transcript) + } + + pub fn succinct_verify>( + svk: &IpaSuccinctVerifyingKey, + commitment: &Msm, + z: &L::LoadedScalar, + eval: &L::LoadedScalar, + proof: &IpaProof, + ) -> Result, Error> { + let loader = z.loader(); + let h = loader.ec_point_load_const(&svk.h); + let s = svk.s.as_ref().map(|s| loader.ec_point_load_const(s)); + let h = Msm::::base(&h); + + let h_prime = h * &proof.xi_0; + let lhs = { + let c_prime = match ( + s.as_ref(), + proof.c_bar_alpha.as_ref(), + proof.omega_prime.as_ref(), + ) { + (Some(s), Some((c_bar, alpha)), Some(omega_prime)) => { + let s = Msm::::base(s); + commitment.clone() + Msm::base(c_bar) * alpha - s * omega_prime + } + (None, None, None) => commitment.clone(), + _ => unreachable!(), + }; + let c_0 = c_prime + h_prime.clone() * eval; + let c_k = c_0 + + proof + .rounds + .iter() + .zip(proof.xi_inv().iter()) + .flat_map(|(Round { l, r, xi }, xi_inv)| [(l, xi_inv), (r, xi)]) + .map(|(base, scalar)| Msm::::base(base) * scalar) + .sum::>(); + c_k.evaluate(None) + }; + let rhs = { + let u = Msm::::base(&proof.u); + let v_prime = h_eval(&proof.xi(), z) * &proof.c; + (u * &proof.c + h_prime * &v_prime).evaluate(None) + }; + + loader.ec_point_assert_eq("C_k == c[U] + v'[H']", &lhs, &rhs)?; + + Ok(IpaAccumulator::new(proof.xi(), proof.u.clone())) + } +} + +#[derive(Clone, Debug)] +pub struct IpaProvingKey { + pub domain: Domain, + pub g: Vec, + pub h: C, + pub s: Option, +} + +impl IpaProvingKey { + pub fn new(domain: Domain, g: Vec, h: C, s: Option) -> Self { + Self { domain, g, h, s } + } + + pub fn zk(&self) -> bool { + self.s.is_some() + } + + pub fn svk(&self) -> IpaSuccinctVerifyingKey { + IpaSuccinctVerifyingKey::new(self.domain.clone(), self.h, self.s) + } + + pub fn dk(&self) -> IpaDecidingKey { + IpaDecidingKey::new(self.g.clone()) + } + + pub fn commit(&self, poly: &Polynomial, omega: Option) -> C { + let mut c = multi_scalar_multiplication(&poly[..], &self.g); + match (self.s, omega) { + (Some(s), Some(omega)) => c += s * omega, + (None, None) => {} + _ => unreachable!(), + }; + c.to_affine() + } +} + +impl IpaProvingKey { + #[cfg(test)] + pub fn rand(k: usize, zk: bool, mut rng: R) -> Self { + use crate::util::arithmetic::{root_of_unity, Group}; + + let domain = Domain::new(k, root_of_unity(k)); + let mut g = vec![C::default(); 1 << k]; + C::Curve::batch_normalize( + &iter::repeat_with(|| C::Curve::random(&mut rng)) + .take(1 << k) + .collect_vec(), + &mut g, + ); + let h = C::Curve::random(&mut rng).to_affine(); + let s = zk.then(|| C::Curve::random(&mut rng).to_affine()); + Self { domain, g, h, s } + } +} + +#[derive(Clone, Debug)] +pub struct IpaSuccinctVerifyingKey { + pub domain: Domain, + pub h: C, + pub s: Option, +} + +impl IpaSuccinctVerifyingKey { + pub fn new(domain: Domain, h: C, s: Option) -> Self { + Self { domain, h, s } + } + + pub fn zk(&self) -> bool { + self.s.is_some() + } +} + +#[derive(Clone, Debug)] +pub struct IpaProof +where + C: CurveAffine, + L: Loader, +{ + c_bar_alpha: Option<(L::LoadedEcPoint, L::LoadedScalar)>, + omega_prime: Option, + xi_0: L::LoadedScalar, + rounds: Vec>, + u: L::LoadedEcPoint, + c: L::LoadedScalar, +} + +impl IpaProof +where + C: CurveAffine, + L: Loader, +{ + pub fn new( + c_bar_alpha: Option<(L::LoadedEcPoint, L::LoadedScalar)>, + omega_prime: Option, + xi_0: L::LoadedScalar, + rounds: Vec>, + u: L::LoadedEcPoint, + c: L::LoadedScalar, + ) -> Self { + Self { + c_bar_alpha, + omega_prime, + xi_0, + rounds, + u, + c, + } + } + + pub fn read(svk: &IpaSuccinctVerifyingKey, transcript: &mut T) -> Result + where + T: TranscriptRead, + { + let c_bar_alpha = svk + .zk() + .then(|| { + let c_bar = transcript.read_ec_point()?; + let alpha = transcript.squeeze_challenge(); + Ok((c_bar, alpha)) + }) + .transpose()?; + let omega_prime = svk.zk().then(|| transcript.read_scalar()).transpose()?; + let xi_0 = transcript.squeeze_challenge(); + let rounds = iter::repeat_with(|| { + Ok(Round::new( + transcript.read_ec_point()?, + transcript.read_ec_point()?, + transcript.squeeze_challenge(), + )) + }) + .take(svk.domain.k) + .collect::, _>>()?; + let u = transcript.read_ec_point()?; + let c = transcript.read_scalar()?; + Ok(Self { + c_bar_alpha, + omega_prime, + xi_0, + rounds, + u, + c, + }) + } + + pub fn xi(&self) -> Vec { + self.rounds.iter().map(|round| round.xi.clone()).collect() + } + + pub fn xi_inv(&self) -> Vec { + let mut xi_inv = self.xi().into_iter().map(Fraction::one_over).collect_vec(); + L::batch_invert(xi_inv.iter_mut().filter_map(Fraction::denom_mut)); + xi_inv.iter_mut().for_each(Fraction::evaluate); + xi_inv + .into_iter() + .map(|xi_inv| xi_inv.evaluated().clone()) + .collect() + } +} + +#[derive(Clone, Debug)] +pub struct Round +where + C: CurveAffine, + L: Loader, +{ + l: L::LoadedEcPoint, + r: L::LoadedEcPoint, + xi: L::LoadedScalar, +} + +impl Round +where + C: CurveAffine, + L: Loader, +{ + pub fn new(l: L::LoadedEcPoint, r: L::LoadedEcPoint, xi: L::LoadedScalar) -> Self { + Self { l, r, xi } + } +} + +pub fn h_eval>(xi: &[T], z: &T) -> T { + let loader = z.loader(); + let one = loader.load_one(); + loader.product( + &iter::successors(Some(z.clone()), |z| Some(z.square())) + .zip(xi.iter().rev()) + .map(|(z, xi)| z * xi + &one) + .collect_vec() + .iter() + .collect_vec(), + ) +} + +pub fn h_coeffs(xi: &[F], scalar: F) -> Vec { + assert!(!xi.is_empty()); + + let mut coeffs = vec![F::zero(); 1 << xi.len()]; + coeffs[0] = scalar; + + for (len, xi) in xi.iter().rev().enumerate().map(|(i, xi)| (1 << i, xi)) { + let (left, right) = coeffs.split_at_mut(len); + let right = &mut right[0..len]; + right.copy_from_slice(left); + for coeffs in right { + *coeffs *= xi; + } + } + + coeffs +} + +#[cfg(all(test, feature = "system_halo2"))] +mod test { + use crate::{ + pcs::{ + ipa::{self, IpaProvingKey}, + Decider, + }, + util::{arithmetic::Field, msm::Msm, poly::Polynomial}, + }; + use halo2_curves::pasta::pallas; + use halo2_proofs::transcript::{ + Blake2bRead, Blake2bWrite, TranscriptReadBuffer, TranscriptWriterBuffer, + }; + use rand::rngs::OsRng; + + #[test] + fn test_ipa() { + type Ipa = ipa::Ipa; + + let k = 10; + let mut rng = OsRng; + + for zk in [false, true] { + let pk = IpaProvingKey::::rand(k, zk, &mut rng); + let (c, z, v, proof) = { + let p = Polynomial::::rand(pk.domain.n, &mut rng); + let omega = pk.zk().then(|| pallas::Scalar::random(&mut rng)); + let c = pk.commit(&p, omega); + let z = pallas::Scalar::random(&mut rng); + let v = p.evaluate(z); + let mut transcript = Blake2bWrite::init(Vec::new()); + Ipa::create_proof(&pk, &p[..], &z, omega.as_ref(), &mut transcript, &mut rng) + .unwrap(); + (c, z, v, transcript.finalize()) + }; + + let svk = pk.svk(); + let accumulator = { + let mut transcript = Blake2bRead::init(proof.as_slice()); + let proof = Ipa::read_proof(&svk, &mut transcript).unwrap(); + Ipa::succinct_verify(&svk, &Msm::base(&c), &z, &v, &proof).unwrap() + }; + + let dk = pk.dk(); + assert!(Ipa::decide(&dk, accumulator)); + } + } +} diff --git a/src/pcs/ipa/accumulation.rs b/src/pcs/ipa/accumulation.rs new file mode 100644 index 00000000..eeea9efe --- /dev/null +++ b/src/pcs/ipa/accumulation.rs @@ -0,0 +1,291 @@ +use crate::{ + loader::{native::NativeLoader, LoadedScalar, Loader}, + pcs::{ + ipa::{ + h_coeffs, h_eval, Ipa, IpaAccumulator, IpaProof, IpaProvingKey, IpaSuccinctVerifyingKey, + }, + AccumulationScheme, AccumulationSchemeProver, PolynomialCommitmentScheme, + }, + util::{ + arithmetic::{Curve, CurveAffine, Field}, + msm::Msm, + poly::Polynomial, + transcript::{TranscriptRead, TranscriptWrite}, + Itertools, + }, + Error, +}; +use rand::Rng; +use std::{array, iter, marker::PhantomData}; + +#[derive(Clone, Debug)] +pub struct IpaAs(PhantomData); + +impl AccumulationScheme for IpaAs +where + C: CurveAffine, + L: Loader, + PCS: PolynomialCommitmentScheme>, +{ + type VerifyingKey = IpaSuccinctVerifyingKey; + type Proof = IpaAsProof; + + fn read_proof( + vk: &Self::VerifyingKey, + instances: &[PCS::Accumulator], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + IpaAsProof::read(vk, instances, transcript) + } + + fn verify( + vk: &Self::VerifyingKey, + instances: &[PCS::Accumulator], + proof: &Self::Proof, + ) -> Result { + let loader = proof.z.loader(); + let s = vk.s.as_ref().map(|s| loader.ec_point_load_const(s)); + + let (u, h) = instances + .iter() + .map(|IpaAccumulator { u, xi }| (u.clone(), h_eval(xi, &proof.z))) + .chain( + proof + .a_b_u + .as_ref() + .map(|(a, b, u)| (u.clone(), a.clone() * &proof.z + b)), + ) + .unzip::<_, _, Vec<_>, Vec<_>>(); + let powers_of_alpha = proof.alpha.powers(u.len()); + + let mut c = powers_of_alpha + .iter() + .zip(u.iter()) + .map(|(power_of_alpha, u)| Msm::::base(u) * power_of_alpha) + .sum::>(); + if let Some(omega) = proof.omega.as_ref() { + c += Msm::base(s.as_ref().unwrap()) * omega; + } + let v = loader.sum_products(&powers_of_alpha.iter().zip(h.iter()).collect_vec()); + + Ipa::::succinct_verify(vk, &c, &proof.z, &v, &proof.ipa) + } +} + +#[derive(Clone, Debug)] +pub struct IpaAsProof +where + C: CurveAffine, + L: Loader, + PCS: PolynomialCommitmentScheme>, +{ + a_b_u: Option<(L::LoadedScalar, L::LoadedScalar, L::LoadedEcPoint)>, + omega: Option, + alpha: L::LoadedScalar, + z: L::LoadedScalar, + ipa: IpaProof, + _marker: PhantomData, +} + +impl IpaAsProof +where + C: CurveAffine, + L: Loader, + PCS: PolynomialCommitmentScheme>, +{ + fn read( + vk: &IpaSuccinctVerifyingKey, + instances: &[PCS::Accumulator], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + assert!(instances.len() > 1); + + let a_b_u = vk + .zk() + .then(|| { + let a = transcript.read_scalar()?; + let b = transcript.read_scalar()?; + let u = transcript.read_ec_point()?; + Ok((a, b, u)) + }) + .transpose()?; + let omega = vk + .zk() + .then(|| { + let omega = transcript.read_scalar()?; + Ok(omega) + }) + .transpose()?; + + for accumulator in instances { + for xi in accumulator.xi.iter() { + transcript.common_scalar(xi)?; + } + transcript.common_ec_point(&accumulator.u)?; + } + + let alpha = transcript.squeeze_challenge(); + let z = transcript.squeeze_challenge(); + + let ipa = IpaProof::read(vk, transcript)?; + + Ok(Self { + a_b_u, + omega, + alpha, + z, + ipa, + _marker: PhantomData, + }) + } +} + +impl AccumulationSchemeProver for IpaAs +where + C: CurveAffine, + PCS: PolynomialCommitmentScheme>, +{ + type ProvingKey = IpaProvingKey; + + fn create_proof( + pk: &Self::ProvingKey, + instances: &[PCS::Accumulator], + transcript: &mut T, + mut rng: R, + ) -> Result + where + T: TranscriptWrite, + R: Rng, + { + assert!(instances.len() > 1); + + let a_b_u = pk + .zk() + .then(|| { + let [a, b] = array::from_fn(|_| C::Scalar::random(&mut rng)); + let u = (pk.g[1] * a + pk.g[0] * b).to_affine(); + transcript.write_scalar(a)?; + transcript.write_scalar(b)?; + transcript.write_ec_point(u)?; + Ok((a, b, u)) + }) + .transpose()?; + let omega = pk + .zk() + .then(|| { + let omega = C::Scalar::random(&mut rng); + transcript.write_scalar(omega)?; + Ok(omega) + }) + .transpose()?; + + for accumulator in instances { + for xi in accumulator.xi.iter() { + transcript.common_scalar(xi)?; + } + transcript.common_ec_point(&accumulator.u)?; + } + + let alpha = transcript.squeeze_challenge(); + let z = transcript.squeeze_challenge(); + + let (u, h) = instances + .iter() + .map(|IpaAccumulator { u, xi }| (*u, h_coeffs(xi, C::Scalar::one()))) + .chain(a_b_u.map(|(a, b, u)| { + ( + u, + iter::empty() + .chain([b, a]) + .chain(iter::repeat_with(C::Scalar::zero).take(pk.domain.n - 2)) + .collect(), + ) + })) + .unzip::<_, _, Vec<_>, Vec<_>>(); + let powers_of_alpha = alpha.powers(u.len()); + + let h = powers_of_alpha + .into_iter() + .zip(h.into_iter().map(Polynomial::new)) + .map(|(power_of_alpha, h)| h * power_of_alpha) + .sum::>(); + + Ipa::::create_proof(pk, &h.to_vec(), &z, omega.as_ref(), transcript, &mut rng) + } +} + +#[cfg(test)] +mod test { + use crate::{ + pcs::{ + ipa::{self, IpaProvingKey}, + AccumulationScheme, AccumulationSchemeProver, Decider, + }, + util::{arithmetic::Field, msm::Msm, poly::Polynomial, Itertools}, + }; + use halo2_curves::pasta::pallas; + use halo2_proofs::transcript::{ + Blake2bRead, Blake2bWrite, TranscriptReadBuffer, TranscriptWriterBuffer, + }; + use rand::rngs::OsRng; + use std::iter; + + #[test] + fn test_ipa_as() { + type Ipa = ipa::Ipa; + type IpaAs = ipa::IpaAs; + + let k = 10; + let zk = true; + let mut rng = OsRng; + + let pk = IpaProvingKey::::rand(k, zk, &mut rng); + let accumulators = iter::repeat_with(|| { + let (c, z, v, proof) = { + let p = Polynomial::::rand(pk.domain.n, &mut rng); + let omega = pk.zk().then(|| pallas::Scalar::random(&mut rng)); + let c = pk.commit(&p, omega); + let z = pallas::Scalar::random(&mut rng); + let v = p.evaluate(z); + let mut transcript = Blake2bWrite::init(Vec::new()); + Ipa::create_proof(&pk, &p[..], &z, omega.as_ref(), &mut transcript, &mut rng) + .unwrap(); + (c, z, v, transcript.finalize()) + }; + + let svk = pk.svk(); + let accumulator = { + let mut transcript = Blake2bRead::init(proof.as_slice()); + let proof = Ipa::read_proof(&svk, &mut transcript).unwrap(); + Ipa::succinct_verify(&svk, &Msm::base(&c), &z, &v, &proof).unwrap() + }; + + accumulator + }) + .take(10) + .collect_vec(); + + let proof = { + let apk = pk.clone(); + let mut transcript = Blake2bWrite::init(Vec::new()); + IpaAs::create_proof(&apk, &accumulators, &mut transcript, &mut rng).unwrap(); + transcript.finalize() + }; + + let accumulator = { + let avk = pk.svk(); + let mut transcript = Blake2bRead::init(proof.as_slice()); + let proof = IpaAs::read_proof(&avk, &accumulators, &mut transcript).unwrap(); + IpaAs::verify(&avk, &accumulators, &proof).unwrap() + }; + + let dk = pk.dk(); + assert!(Ipa::decide(&dk, accumulator)); + } +} diff --git a/src/pcs/ipa/accumulator.rs b/src/pcs/ipa/accumulator.rs new file mode 100644 index 00000000..27d9d5c7 --- /dev/null +++ b/src/pcs/ipa/accumulator.rs @@ -0,0 +1,21 @@ +use crate::{loader::Loader, util::arithmetic::CurveAffine}; + +#[derive(Clone, Debug)] +pub struct IpaAccumulator +where + C: CurveAffine, + L: Loader, +{ + pub xi: Vec, + pub u: L::LoadedEcPoint, +} + +impl IpaAccumulator +where + C: CurveAffine, + L: Loader, +{ + pub fn new(xi: Vec, u: L::LoadedEcPoint) -> Self { + Self { xi, u } + } +} diff --git a/src/pcs/ipa/decider.rs b/src/pcs/ipa/decider.rs new file mode 100644 index 00000000..2cf8c6cc --- /dev/null +++ b/src/pcs/ipa/decider.rs @@ -0,0 +1,57 @@ +#[derive(Clone, Debug)] +pub struct IpaDecidingKey { + pub g: Vec, +} + +impl IpaDecidingKey { + pub fn new(g: Vec) -> Self { + Self { g } + } +} + +impl From> for IpaDecidingKey { + fn from(g: Vec) -> IpaDecidingKey { + IpaDecidingKey::new(g) + } +} + +mod native { + use crate::{ + loader::native::NativeLoader, + pcs::{ + ipa::{h_coeffs, Ipa, IpaAccumulator, IpaDecidingKey}, + Decider, + }, + util::{ + arithmetic::{Curve, CurveAffine, Field}, + msm::multi_scalar_multiplication, + }, + }; + use std::fmt::Debug; + + impl Decider for Ipa + where + C: CurveAffine, + MOS: Clone + Debug, + { + type DecidingKey = IpaDecidingKey; + type Output = bool; + + fn decide( + dk: &Self::DecidingKey, + IpaAccumulator { u, xi }: IpaAccumulator, + ) -> bool { + let h = h_coeffs(&xi, C::Scalar::one()); + u == multi_scalar_multiplication(&h, &dk.g).to_affine() + } + + fn decide_all( + dk: &Self::DecidingKey, + accumulators: Vec>, + ) -> bool { + !accumulators + .into_iter() + .any(|accumulator| !Self::decide(dk, accumulator)) + } + } +} diff --git a/src/pcs/ipa/multiopen.rs b/src/pcs/ipa/multiopen.rs new file mode 100644 index 00000000..9f685e76 --- /dev/null +++ b/src/pcs/ipa/multiopen.rs @@ -0,0 +1,3 @@ +mod bgh19; + +pub use bgh19::{Bgh19, Bgh19Proof, Bgh19SuccinctVerifyingKey}; diff --git a/src/pcs/ipa/multiopen/bgh19.rs b/src/pcs/ipa/multiopen/bgh19.rs new file mode 100644 index 00000000..29d291ad --- /dev/null +++ b/src/pcs/ipa/multiopen/bgh19.rs @@ -0,0 +1,417 @@ +use crate::{ + loader::{LoadedScalar, Loader, ScalarLoader}, + pcs::{ + ipa::{Ipa, IpaProof, IpaSuccinctVerifyingKey, Round}, + MultiOpenScheme, Query, + }, + util::{ + arithmetic::{ilog2, CurveAffine, Domain, FieldExt, Fraction}, + msm::Msm, + transcript::TranscriptRead, + Itertools, + }, + Error, +}; +use std::{ + collections::{BTreeMap, BTreeSet}, + iter, + marker::PhantomData, +}; + +#[derive(Clone, Debug)] +pub struct Bgh19; + +impl MultiOpenScheme for Ipa +where + C: CurveAffine, + L: Loader, +{ + type SuccinctVerifyingKey = Bgh19SuccinctVerifyingKey; + type Proof = Bgh19Proof; + + fn read_proof( + svk: &Self::SuccinctVerifyingKey, + queries: &[Query], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + Bgh19Proof::read(svk, queries, transcript) + } + + fn succinct_verify( + svk: &Self::SuccinctVerifyingKey, + commitments: &[Msm], + x: &L::LoadedScalar, + queries: &[Query], + proof: &Self::Proof, + ) -> Result { + let loader = x.loader(); + let g = loader.ec_point_load_const(&svk.g); + + // Multiopen + let sets = query_sets(queries); + let p = { + let coeffs = query_set_coeffs(&sets, x, &proof.x_3); + + let powers_of_x_1 = proof + .x_1 + .powers(sets.iter().map(|set| set.polys.len()).max().unwrap()); + let f_eval = { + let powers_of_x_2 = proof.x_2.powers(sets.len()); + let f_evals = sets + .iter() + .zip(coeffs.iter()) + .zip(proof.q_evals.iter()) + .map(|((set, coeff), q_eval)| set.f_eval(coeff, q_eval, &powers_of_x_1)) + .collect_vec(); + x.loader() + .sum_products(&powers_of_x_2.iter().zip(f_evals.iter().rev()).collect_vec()) + }; + let msms = sets + .iter() + .zip(proof.q_evals.iter()) + .map(|(set, q_eval)| set.msm(commitments, q_eval, &powers_of_x_1)); + + let (mut msm, constant) = iter::once(Msm::base(&proof.f) - Msm::constant(f_eval)) + .chain(msms) + .zip(proof.x_4.powers(sets.len() + 1).into_iter().rev()) + .map(|(msm, power_of_x_4)| msm * &power_of_x_4) + .sum::>() + .split(); + if let Some(constant) = constant { + msm += Msm::base(&g) * &constant; + } + msm + }; + + // IPA + Ipa::::succinct_verify(&svk.ipa, &p, &proof.x_3, &loader.load_zero(), &proof.ipa) + } +} + +#[derive(Clone, Debug)] +pub struct Bgh19SuccinctVerifyingKey { + g: C, + ipa: IpaSuccinctVerifyingKey, +} + +impl Bgh19SuccinctVerifyingKey { + pub fn new(domain: Domain, g: C, w: C, u: C) -> Self { + Self { + g, + ipa: IpaSuccinctVerifyingKey::new(domain, u, Some(w)), + } + } +} + +#[derive(Clone, Debug)] +pub struct Bgh19Proof +where + C: CurveAffine, + L: Loader, +{ + // Multiopen + x_1: L::LoadedScalar, + x_2: L::LoadedScalar, + f: L::LoadedEcPoint, + x_3: L::LoadedScalar, + q_evals: Vec, + x_4: L::LoadedScalar, + // IPA + ipa: IpaProof, +} + +impl Bgh19Proof +where + C: CurveAffine, + L: Loader, +{ + fn read>( + svk: &Bgh19SuccinctVerifyingKey, + queries: &[Query], + transcript: &mut T, + ) -> Result { + // Multiopen + let x_1 = transcript.squeeze_challenge(); + let x_2 = transcript.squeeze_challenge(); + let f = transcript.read_ec_point()?; + let x_3 = transcript.squeeze_challenge(); + let q_evals = transcript.read_n_scalars(query_sets(queries).len())?; + let x_4 = transcript.squeeze_challenge(); + // IPA + let s = transcript.read_ec_point()?; + let xi = transcript.squeeze_challenge(); + let z = transcript.squeeze_challenge(); + let rounds = iter::repeat_with(|| { + Ok(Round::new( + transcript.read_ec_point()?, + transcript.read_ec_point()?, + transcript.squeeze_challenge(), + )) + }) + .take(svk.ipa.domain.k) + .collect::, _>>()?; + let c = transcript.read_scalar()?; + let blind = transcript.read_scalar()?; + let g = transcript.read_ec_point()?; + Ok(Bgh19Proof { + x_1, + x_2, + f, + x_3, + q_evals, + x_4, + ipa: IpaProof::new(Some((s, xi)), Some(blind), z, rounds, g, c), + }) + } +} + +fn query_sets(queries: &[Query]) -> Vec> +where + F: FieldExt, + T: Clone, +{ + let poly_shifts = queries.iter().fold( + Vec::<(usize, Vec, Vec<&T>)>::new(), + |mut poly_shifts, query| { + if let Some(pos) = poly_shifts + .iter() + .position(|(poly, _, _)| *poly == query.poly) + { + let (_, shifts, evals) = &mut poly_shifts[pos]; + if !shifts.contains(&query.shift) { + shifts.push(query.shift); + evals.push(&query.eval); + } + } else { + poly_shifts.push((query.poly, vec![query.shift], vec![&query.eval])); + } + poly_shifts + }, + ); + + poly_shifts.into_iter().fold( + Vec::>::new(), + |mut sets, (poly, shifts, evals)| { + if let Some(pos) = sets.iter().position(|set| { + BTreeSet::from_iter(set.shifts.iter()) == BTreeSet::from_iter(shifts.iter()) + }) { + let set = &mut sets[pos]; + if !set.polys.contains(&poly) { + set.polys.push(poly); + set.evals.push( + set.shifts + .iter() + .map(|lhs| { + let idx = shifts.iter().position(|rhs| lhs == rhs).unwrap(); + evals[idx] + }) + .collect(), + ); + } + } else { + let set = QuerySet { + shifts, + polys: vec![poly], + evals: vec![evals], + }; + sets.push(set); + } + sets + }, + ) +} + +fn query_set_coeffs(sets: &[QuerySet], x: &T, x_3: &T) -> Vec> +where + F: FieldExt, + T: LoadedScalar, +{ + let loader = x.loader(); + let superset = sets + .iter() + .flat_map(|set| set.shifts.clone()) + .sorted() + .dedup(); + + let size = 2.max( + ilog2((sets.iter().map(|set| set.shifts.len()).max().unwrap() - 1).next_power_of_two()) + 1, + ); + let powers_of_x = x.powers(size); + let x_3_minus_x_shift_i = BTreeMap::from_iter( + superset.map(|shift| (shift, x_3.clone() - x.clone() * loader.load_const(&shift))), + ); + + let mut coeffs = sets + .iter() + .map(|set| QuerySetCoeff::new(&set.shifts, &powers_of_x, x_3, &x_3_minus_x_shift_i)) + .collect_vec(); + + T::Loader::batch_invert(coeffs.iter_mut().flat_map(QuerySetCoeff::denoms)); + T::Loader::batch_invert(coeffs.iter_mut().flat_map(QuerySetCoeff::denoms)); + coeffs.iter_mut().for_each(QuerySetCoeff::evaluate); + + coeffs +} + +#[derive(Clone, Debug)] +struct QuerySet<'a, F, T> { + shifts: Vec, + polys: Vec, + evals: Vec>, +} + +impl<'a, F, T> QuerySet<'a, F, T> +where + F: FieldExt, + T: LoadedScalar, +{ + fn msm>( + &self, + commitments: &[Msm<'a, C, L>], + q_eval: &T, + powers_of_x_1: &[T], + ) -> Msm { + self.polys + .iter() + .rev() + .zip(powers_of_x_1) + .map(|(poly, power_of_x_1)| commitments[*poly].clone() * power_of_x_1) + .sum::>() + - Msm::constant(q_eval.clone()) + } + + fn f_eval(&self, coeff: &QuerySetCoeff, q_eval: &T, powers_of_x_1: &[T]) -> T { + let loader = q_eval.loader(); + let r_eval = { + let r_evals = self + .evals + .iter() + .map(|evals| { + loader.sum_products( + &coeff + .eval_coeffs + .iter() + .zip(evals.iter()) + .map(|(coeff, eval)| (coeff.evaluated(), *eval)) + .collect_vec(), + ) * coeff.r_eval_coeff.as_ref().unwrap().evaluated() + }) + .collect_vec(); + loader.sum_products(&r_evals.iter().rev().zip(powers_of_x_1).collect_vec()) + }; + + (q_eval.clone() - r_eval) * coeff.f_eval_coeff.evaluated() + } +} + +#[derive(Clone, Debug)] +struct QuerySetCoeff { + eval_coeffs: Vec>, + r_eval_coeff: Option>, + f_eval_coeff: Fraction, + _marker: PhantomData, +} + +impl QuerySetCoeff +where + F: FieldExt, + T: LoadedScalar, +{ + fn new(shifts: &[F], powers_of_x: &[T], x_3: &T, x_3_minus_x_shift_i: &BTreeMap) -> Self { + let loader = x_3.loader(); + let normalized_ell_primes = shifts + .iter() + .enumerate() + .map(|(j, shift_j)| { + shifts + .iter() + .enumerate() + .filter(|&(i, _)| i != j) + .map(|(_, shift_i)| (*shift_j - shift_i)) + .reduce(|acc, value| acc * value) + .unwrap_or_else(|| F::one()) + }) + .collect_vec(); + + let x = &powers_of_x[1].clone(); + let x_pow_k_minus_one = { + let k_minus_one = shifts.len() - 1; + powers_of_x + .iter() + .enumerate() + .skip(1) + .filter_map(|(i, power_of_x)| { + (k_minus_one & (1 << i) == 1).then(|| power_of_x.clone()) + }) + .reduce(|acc, value| acc * value) + .unwrap_or_else(|| loader.load_one()) + }; + + let barycentric_weights = shifts + .iter() + .zip(normalized_ell_primes.iter()) + .map(|(shift, normalized_ell_prime)| { + loader.sum_products_with_coeff(&[ + (*normalized_ell_prime, &x_pow_k_minus_one, x_3), + (-(*normalized_ell_prime * shift), &x_pow_k_minus_one, x), + ]) + }) + .map(Fraction::one_over) + .collect_vec(); + + let f_eval_coeff = Fraction::one_over( + loader.product( + &shifts + .iter() + .map(|shift| x_3_minus_x_shift_i.get(shift).unwrap()) + .collect_vec(), + ), + ); + + Self { + eval_coeffs: barycentric_weights, + r_eval_coeff: None, + f_eval_coeff, + _marker: PhantomData, + } + } + + fn denoms(&mut self) -> impl IntoIterator { + if self.eval_coeffs.first().unwrap().denom().is_some() { + return self + .eval_coeffs + .iter_mut() + .chain(Some(&mut self.f_eval_coeff)) + .filter_map(Fraction::denom_mut) + .collect_vec(); + } + + if self.r_eval_coeff.is_none() { + self.eval_coeffs + .iter_mut() + .chain(Some(&mut self.f_eval_coeff)) + .for_each(Fraction::evaluate); + + let loader = self.f_eval_coeff.evaluated().loader(); + let barycentric_weights_sum = loader.sum( + &self + .eval_coeffs + .iter() + .map(Fraction::evaluated) + .collect_vec(), + ); + self.r_eval_coeff = Some(Fraction::one_over(barycentric_weights_sum)); + + return vec![self.r_eval_coeff.as_mut().unwrap().denom_mut().unwrap()]; + } + + unreachable!() + } + + fn evaluate(&mut self) { + self.r_eval_coeff.as_mut().unwrap().evaluate(); + } +} diff --git a/src/system/halo2.rs b/src/system/halo2.rs index a49fa6ef..7c26387d 100644 --- a/src/system/halo2.rs +++ b/src/system/halo2.rs @@ -16,6 +16,7 @@ use halo2_proofs::{ use num_integer::Integer; use std::{io, iter, mem::size_of}; +pub mod strategy; pub mod transcript; #[cfg(test)] diff --git a/src/system/halo2/strategy.rs b/src/system/halo2/strategy.rs new file mode 100644 index 00000000..de66f8e3 --- /dev/null +++ b/src/system/halo2/strategy.rs @@ -0,0 +1,53 @@ +pub mod ipa { + use crate::util::arithmetic::CurveAffine; + use halo2_proofs::{ + plonk::Error, + poly::{ + commitment::MSM, + ipa::{ + commitment::{IPACommitmentScheme, ParamsIPA}, + msm::MSMIPA, + multiopen::VerifierIPA, + strategy::GuardIPA, + }, + VerificationStrategy, + }, + }; + + #[derive(Clone, Debug)] + pub struct SingleStrategy<'a, C: CurveAffine> { + msm: MSMIPA<'a, C>, + } + + impl<'a, C: CurveAffine> VerificationStrategy<'a, IPACommitmentScheme, VerifierIPA<'a, C>> + for SingleStrategy<'a, C> + { + type Output = C; + + fn new(params: &'a ParamsIPA) -> Self { + SingleStrategy { + msm: MSMIPA::new(params), + } + } + + fn process( + self, + f: impl FnOnce(MSMIPA<'a, C>) -> Result, Error>, + ) -> Result { + let guard = f(self.msm)?; + + let g = guard.compute_g(); + let (msm, _) = guard.use_g(g); + + if msm.check() { + Ok(g) + } else { + Err(Error::ConstraintSystemFailure) + } + } + + fn finalize(self) -> bool { + unreachable!() + } + } +} diff --git a/src/system/halo2/test.rs b/src/system/halo2/test.rs index 9cd4a2fc..1ec03306 100644 --- a/src/system/halo2/test.rs +++ b/src/system/halo2/test.rs @@ -12,6 +12,7 @@ use rand_chacha::rand_core::RngCore; use std::{fs, io::Cursor}; mod circuit; +mod ipa; mod kzg; pub use circuit::{ diff --git a/src/system/halo2/test/ipa.rs b/src/system/halo2/test/ipa.rs new file mode 100644 index 00000000..07fd6efd --- /dev/null +++ b/src/system/halo2/test/ipa.rs @@ -0,0 +1,143 @@ +use crate::util::arithmetic::CurveAffine; +use halo2_proofs::poly::{ + commitment::{Params, ParamsProver}, + ipa::commitment::ParamsIPA, +}; +use std::mem::size_of; + +mod native; + +pub const TESTDATA_DIR: &str = "./src/system/halo2/test/ipa/testdata"; + +pub fn setup(k: u32) -> ParamsIPA { + ParamsIPA::new(k) +} + +pub fn w_u() -> (C, C) { + let mut buf = Vec::new(); + setup::(1).write(&mut buf).unwrap(); + + let repr = C::Repr::default(); + let repr_len = repr.as_ref().len(); + let offset = size_of::() + 4 * repr_len; + + let [w, u] = [offset, offset + repr_len].map(|offset| { + let mut repr = C::Repr::default(); + repr.as_mut() + .copy_from_slice(&buf[offset..offset + repr_len]); + C::from_bytes(&repr).unwrap() + }); + + (w, u) +} + +macro_rules! halo2_ipa_config { + ($zk:expr, $num_proof:expr) => { + $crate::system::halo2::Config::ipa() + .set_zk($zk) + .with_num_proof($num_proof) + }; + ($zk:expr, $num_proof:expr, $accumulator_indices:expr) => { + $crate::system::halo2::Config::ipa() + .set_zk($zk) + .with_num_proof($num_proof) + .with_accumulator_indices($accumulator_indices) + }; +} + +macro_rules! halo2_ipa_prepare { + ($dir:expr, $curve:path, $k:expr, $config:expr, $create_circuit:expr) => {{ + use $crate::system::halo2::test::{halo2_prepare, ipa::setup}; + + halo2_prepare!($dir, $k, setup::<$curve>, $config, $create_circuit) + }}; + (pallas::Affine, $k:expr, $config:expr, $create_circuit:expr) => {{ + use halo2_curves::pasta::pallas; + use $crate::system::halo2::test::ipa::TESTDATA_DIR; + + halo2_ipa_prepare!( + &format!("{TESTDATA_DIR}/pallas"), + pallas::Affine, + $k, + $config, + $create_circuit + ) + }}; + (vesta::Affine, $k:expr, $config:expr, $create_circuit:expr) => {{ + use halo2_curves::pasta::vesta; + use $crate::system::halo2::test::ipa::TESTDATA_DIR; + + halo2_ipa_prepare!( + &format!("{TESTDATA_DIR}/vesta"), + vesta::Affine, + $k, + $config, + $create_circuit + ) + }}; +} + +macro_rules! halo2_ipa_create_snark { + ( + $prover:ty, + $verifier:ty, + $transcript_read:ty, + $transcript_write:ty, + $encoded_challenge:ty, + $params:expr, + $pk:expr, + $protocol:expr, + $circuits:expr + ) => {{ + use halo2_proofs::poly::ipa::commitment::IPACommitmentScheme; + use $crate::{ + system::halo2::{strategy::ipa::SingleStrategy, test::halo2_create_snark}, + util::arithmetic::GroupEncoding, + }; + + halo2_create_snark!( + IPACommitmentScheme<_>, + $prover, + $verifier, + SingleStrategy<_>, + $transcript_read, + $transcript_write, + $encoded_challenge, + |proof, g| { [proof, g.to_bytes().as_ref().to_vec()].concat() }, + $params, + $pk, + $protocol, + $circuits + ) + }}; +} + +macro_rules! halo2_ipa_native_verify { + ( + $plonk_verifier:ty, + $params:expr, + $protocol:expr, + $instances:expr, + $transcript:expr + ) => {{ + use $crate::{ + pcs::ipa::{Bgh19SuccinctVerifyingKey, IpaDecidingKey}, + system::halo2::test::{halo2_native_verify, ipa::w_u}, + }; + + let (w, u) = w_u(); + halo2_native_verify!( + $plonk_verifier, + $params, + $protocol, + $instances, + $transcript, + &Bgh19SuccinctVerifyingKey::new($protocol.domain.clone(), $params.get_g()[0], w, u), + &IpaDecidingKey::new($params.get_g().to_vec()) + ) + }}; +} + +pub(crate) use { + halo2_ipa_config, halo2_ipa_create_snark, halo2_ipa_native_verify, halo2_ipa_prepare, +}; diff --git a/src/system/halo2/test/ipa/native.rs b/src/system/halo2/test/ipa/native.rs new file mode 100644 index 00000000..7d9e09bb --- /dev/null +++ b/src/system/halo2/test/ipa/native.rs @@ -0,0 +1,59 @@ +use crate::{ + pcs::ipa::{Bgh19, Ipa}, + system::halo2::test::ipa::{ + halo2_ipa_config, halo2_ipa_create_snark, halo2_ipa_native_verify, halo2_ipa_prepare, + }, + system::halo2::test::StandardPlonk, + verifier::Plonk, +}; +use halo2_curves::pasta::pallas; +use halo2_proofs::{ + poly::ipa::multiopen::{ProverIPA, VerifierIPA}, + transcript::{Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer}, +}; +use paste::paste; +use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; + +macro_rules! test { + (@ $name:ident, $k:expr, $config:expr, $create_cirucit:expr, $prover:ty, $verifier:ty, $plonk_verifier:ty) => { + paste! { + #[test] + fn []() { + let (params, pk, protocol, circuits) = halo2_ipa_prepare!( + pallas::Affine, + $k, + $config, + $create_cirucit + ); + let snark = halo2_ipa_create_snark!( + $prover, + $verifier, + Blake2bWrite<_, _, _>, + Blake2bRead<_, _, _>, + Challenge255<_>, + ¶ms, + &pk, + &protocol, + &circuits + ); + halo2_ipa_native_verify!( + $plonk_verifier, + params, + &snark.protocol, + &snark.instances, + &mut Blake2bRead::<_, pallas::Affine, _>::init(snark.proof.as_slice()) + ); + } + } + }; + ($name:ident, $k:expr, $config:expr, $create_cirucit:expr) => { + test!(@ $name, $k, $config, $create_cirucit, ProverIPA, VerifierIPA, Plonk::>); + } +} + +test!( + zk_standard_plonk_rand, + 9, + halo2_ipa_config!(true, 1), + StandardPlonk::rand(ChaCha20Rng::from_seed(Default::default())) +); diff --git a/src/system/halo2/test/kzg/halo2.rs b/src/system/halo2/test/kzg/halo2.rs index 11a6046f..314af5c7 100644 --- a/src/system/halo2/test/kzg/halo2.rs +++ b/src/system/halo2/test/kzg/halo2.rs @@ -1,6 +1,6 @@ use crate::{ - loader, loader::{ + self, halo2::test::{Snark, SnarkWitness}, native::NativeLoader, }, @@ -30,8 +30,7 @@ use crate::{ use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ circuit::{floor_planner::V1, Layouter, Value}, - plonk, - plonk::{Circuit, Error}, + plonk::{Circuit, ConstraintSystem, Error}, poly::{ commitment::ParamsProver, kzg::{ @@ -263,7 +262,7 @@ impl Circuit for Accumulation { } } - fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { + fn configure(meta: &mut ConstraintSystem) -> Self::Config { MainGateWithRangeConfig::configure( meta, vec![BITS / LIMBS], @@ -275,7 +274,7 @@ impl Circuit for Accumulation { &self, config: Self::Config, mut layouter: impl Layouter, - ) -> Result<(), plonk::Error> { + ) -> Result<(), Error> { let main_gate = config.main_gate(); let range_chip = config.range_chip(); diff --git a/src/util.rs b/src/util.rs index 3d5d0d79..b42db61c 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,7 +1,47 @@ pub mod arithmetic; pub mod hash; pub mod msm; +pub mod poly; pub mod protocol; pub mod transcript; pub(crate) use itertools::Itertools; + +#[cfg(feature = "parallel")] +pub(crate) use rayon::current_num_threads; + +pub fn parallelize_iter(iter: I, f: F) +where + I: Send + Iterator, + T: Send, + F: Fn(T) + Send + Sync + Clone, +{ + #[cfg(feature = "parallel")] + rayon::scope(|scope| { + for item in iter { + let f = f.clone(); + scope.spawn(move |_| f(item)); + } + }); + #[cfg(not(feature = "parallel"))] + iter.for_each(f); +} + +pub fn parallelize(v: &mut [T], f: F) +where + T: Send, + F: Fn((&mut [T], usize)) + Send + Sync + Clone, +{ + #[cfg(feature = "parallel")] + { + let num_threads = current_num_threads(); + let chunk_size = v.len() / num_threads; + if chunk_size < num_threads { + f((v, 0)); + } else { + parallelize_iter(v.chunks_mut(chunk_size).zip((0..).step_by(chunk_size)), f); + } + } + #[cfg(not(feature = "parallel"))] + f((v, 0)); +} diff --git a/src/util/arithmetic.rs b/src/util/arithmetic.rs index 02d6da32..dacd2443 100644 --- a/src/util/arithmetic.rs +++ b/src/util/arithmetic.rs @@ -250,3 +250,15 @@ pub fn fe_to_limbs(scalar: F) -> impl Iterator { + iter::successors(Some(F::one()), move |power| Some(scalar * power)) +} + +pub fn inner_product(lhs: &[F], rhs: &[F]) -> F { + lhs.iter() + .zip_eq(rhs.iter()) + .map(|(lhs, rhs)| *lhs * rhs) + .reduce(|acc, product| acc + product) + .unwrap_or_default() +} diff --git a/src/util/msm.rs b/src/util/msm.rs index f35ea197..014a29e8 100644 --- a/src/util/msm.rs +++ b/src/util/msm.rs @@ -1,10 +1,15 @@ use crate::{ loader::{LoadedEcPoint, Loader}, - util::{arithmetic::CurveAffine, Itertools}, + util::{ + arithmetic::{CurveAffine, Group, PrimeField}, + Itertools, + }, }; +use num_integer::Integer; use std::{ default::Default, iter::{self, Sum}, + mem::size_of, ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; @@ -209,3 +214,119 @@ where iter.reduce(|acc, item| acc + item).unwrap_or_default() } } + +#[derive(Clone, Copy)] +enum Bucket { + None, + Affine(C), + Projective(C::Curve), +} + +impl Bucket { + fn add_assign(&mut self, rhs: &C) { + *self = match *self { + Bucket::None => Bucket::Affine(*rhs), + Bucket::Affine(lhs) => Bucket::Projective(lhs + *rhs), + Bucket::Projective(mut lhs) => { + lhs += *rhs; + Bucket::Projective(lhs) + } + } + } + + fn add(self, mut rhs: C::Curve) -> C::Curve { + match self { + Bucket::None => rhs, + Bucket::Affine(lhs) => { + rhs += lhs; + rhs + } + Bucket::Projective(lhs) => lhs + rhs, + } + } +} + +fn multi_scalar_multiplication_serial( + scalars: &[C::Scalar], + bases: &[C], + result: &mut C::Curve, +) { + let scalars = scalars.iter().map(|scalar| scalar.to_repr()).collect_vec(); + let num_bytes = scalars[0].as_ref().len(); + let num_bits = 8 * num_bytes; + + let window_size = (scalars.len() as f64).ln().ceil() as usize + 2; + let num_buckets = (1 << window_size) - 1; + + let windowed_scalar = |idx: usize, bytes: &::Repr| { + let skip_bits = idx * window_size; + let skip_bytes = skip_bits / 8; + + let mut value = [0; size_of::()]; + for (dst, src) in value.iter_mut().zip(bytes.as_ref()[skip_bytes..].iter()) { + *dst = *src; + } + + (usize::from_le_bytes(value) >> (skip_bits - (skip_bytes * 8))) & num_buckets + }; + + let num_window = Integer::div_ceil(&num_bits, &window_size); + for idx in (0..num_window).rev() { + for _ in 0..window_size { + *result = result.double(); + } + + let mut buckets = vec![Bucket::None; num_buckets]; + + for (scalar, base) in scalars.iter().zip(bases.iter()) { + let scalar = windowed_scalar(idx, scalar); + if scalar != 0 { + buckets[scalar - 1].add_assign(base); + } + } + + let mut running_sum = C::Curve::identity(); + for bucket in buckets.into_iter().rev() { + running_sum = bucket.add(running_sum); + *result += &running_sum; + } + } +} + +// Copy from https://github.com/zcash/halo2/blob/main/halo2_proofs/src/arithmetic.rs +pub fn multi_scalar_multiplication(scalars: &[C::Scalar], bases: &[C]) -> C::Curve { + assert_eq!(scalars.len(), bases.len()); + + #[cfg(feature = "parallel")] + { + use crate::util::{current_num_threads, parallelize_iter}; + + let num_threads = current_num_threads(); + if scalars.len() < num_threads { + let mut result = C::Curve::identity(); + multi_scalar_multiplication_serial(scalars, bases, &mut result); + return result; + } + + let chunk_size = Integer::div_ceil(&scalars.len(), &num_threads); + let mut results = vec![C::Curve::identity(); num_threads]; + parallelize_iter( + scalars + .chunks(chunk_size) + .zip(bases.chunks(chunk_size)) + .zip(results.iter_mut()), + |((scalars, bases), result)| { + multi_scalar_multiplication_serial(scalars, bases, result); + }, + ); + results + .iter() + .fold(C::Curve::identity(), |acc, result| acc + result) + } + #[cfg(not(feature = "parallel"))] + { + let mut result = C::Curve::identity(); + multi_scalar_multiplication_serial(scalars, bases, &mut result); + result + } +} diff --git a/src/util/poly.rs b/src/util/poly.rs new file mode 100644 index 00000000..ea120b33 --- /dev/null +++ b/src/util/poly.rs @@ -0,0 +1,175 @@ +use crate::util::{arithmetic::Field, parallelize}; +use rand::Rng; +use std::{ + iter::{self, Sum}, + ops::{ + Add, Index, IndexMut, Mul, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, + RangeToInclusive, Sub, + }, +}; + +#[derive(Clone, Debug)] +pub struct Polynomial(Vec); + +impl Polynomial { + pub fn new(inner: Vec) -> Self { + Self(inner) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + pub fn len(&self) -> usize { + self.0.len() + } + + pub fn iter(&self) -> impl Iterator { + self.0.iter() + } + + pub fn iter_mut(&mut self) -> impl Iterator { + self.0.iter_mut() + } + + pub fn to_vec(self) -> Vec { + self.0 + } +} + +impl Polynomial { + pub fn rand(n: usize, mut rng: R) -> Self { + Self::new(iter::repeat_with(|| F::random(&mut rng)).take(n).collect()) + } + + pub fn evaluate(&self, x: F) -> F { + let evaluate_serial = |coeffs: &[F]| { + coeffs + .iter() + .rev() + .fold(F::zero(), |acc, coeff| acc * x + coeff) + }; + + #[cfg(feature = "parallel")] + { + use crate::util::{arithmetic::powers, current_num_threads, parallelize_iter}; + use num_integer::Integer; + + let num_threads = current_num_threads(); + if self.len() * 2 < num_threads { + return evaluate_serial(&self.0); + } + + let chunk_size = Integer::div_ceil(&self.len(), &num_threads); + let mut results = vec![F::zero(); num_threads]; + parallelize_iter( + results + .iter_mut() + .zip(self.0.chunks(chunk_size)) + .zip(powers(x.pow_vartime(&[chunk_size as u64, 0, 0, 0]))), + |((result, coeffs), scalar)| *result = evaluate_serial(coeffs) * scalar, + ); + results.iter().fold(F::zero(), |acc, result| acc + result) + } + #[cfg(not(feature = "parallel"))] + evaluate_serial(&self.0) + } +} + +impl<'a, F: Field> Add<&'a Polynomial> for Polynomial { + type Output = Polynomial; + + fn add(mut self, rhs: &'a Polynomial) -> Polynomial { + parallelize(&mut self.0, |(lhs, start)| { + for (lhs, rhs) in lhs.iter_mut().zip(rhs.0[start..].iter()) { + *lhs += *rhs; + } + }); + self + } +} + +impl<'a, F: Field> Sub<&'a Polynomial> for Polynomial { + type Output = Polynomial; + + fn sub(mut self, rhs: &'a Polynomial) -> Polynomial { + parallelize(&mut self.0, |(lhs, start)| { + for (lhs, rhs) in lhs.iter_mut().zip(rhs.0[start..].iter()) { + *lhs -= *rhs; + } + }); + self + } +} + +impl Sub for Polynomial { + type Output = Polynomial; + + fn sub(mut self, rhs: F) -> Polynomial { + self.0[0] -= rhs; + self + } +} + +impl Add for Polynomial { + type Output = Polynomial; + + fn add(mut self, rhs: F) -> Polynomial { + self.0[0] += rhs; + self + } +} + +impl Mul for Polynomial { + type Output = Polynomial; + + fn mul(mut self, rhs: F) -> Polynomial { + if rhs == F::zero() { + return Polynomial::new(vec![F::zero(); self.len()]); + } + if rhs == F::one() { + return self; + } + parallelize(&mut self.0, |(lhs, _)| { + for lhs in lhs.iter_mut() { + *lhs *= rhs; + } + }); + self + } +} + +impl Sum for Polynomial { + fn sum>(iter: I) -> Self { + iter.reduce(|acc, item| acc + &item).unwrap() + } +} + +macro_rules! impl_index { + ($($range:ty => $output:ty,)*) => { + $( + impl Index<$range> for Polynomial { + type Output = $output; + + fn index(&self, index: $range) -> &$output { + self.0.index(index) + } + } + impl IndexMut<$range> for Polynomial { + fn index_mut(&mut self, index: $range) -> &mut $output { + self.0.index_mut(index) + } + } + )* + }; +} + +impl_index!( + usize => F, + Range => [F], + RangeFrom => [F], + RangeFull => [F], + RangeInclusive => [F], + RangeTo => [F], + RangeToInclusive => [F], +); From ba167b73ca09d77ab08958d4a4b4e0433222e4db Mon Sep 17 00:00:00 2001 From: Han Date: Mon, 14 Nov 2022 00:21:11 -0800 Subject: [PATCH 05/73] ci: add `svm-rs` and install `solc@0.8.17` in job `test` (#16) --- .github/workflows/ci.yaml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index a50958d0..61c72229 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,6 +23,9 @@ jobs: with: cache-on-failure: true + - name: Install solc + run: (hash svm 2>/dev/null || cargo install svm-rs) && svm install 0.8.17 && solc --version + - name: Run test run: cargo test --all --all-features -- --nocapture From c5645e705edb178e63631a7eb2a4b9c0dec9abbc Mon Sep 17 00:00:00 2001 From: DoHoon Kim <59155248+DoHoonKim8@users.noreply.github.com> Date: Fri, 18 Nov 2022 00:50:24 +0900 Subject: [PATCH 06/73] Update `EvmLoader` to generate Yul code instead of bytecode (#15) * Update `EvmLoader` to generate Yul instead of bytecode * feat: simplify * feat: Add missing end_gas_metering impl Co-authored-by: Han Co-authored-by: Han --- examples/evm-verifier-with-accumulator.rs | 4 +- examples/evm-verifier.rs | 4 +- src/loader/evm.rs | 3 +- src/loader/evm/code.rs | 336 ++--------- src/loader/evm/loader.rs | 689 ++++++++++------------ src/loader/evm/test.rs | 19 +- src/loader/evm/util.rs | 40 +- src/pcs/kzg/decider.rs | 10 +- src/system/halo2/test/kzg/evm.rs | 8 +- src/system/halo2/transcript/evm.rs | 27 +- 10 files changed, 428 insertions(+), 712 deletions(-) diff --git a/examples/evm-verifier-with-accumulator.rs b/examples/evm-verifier-with-accumulator.rs index 10a7b269..8f08883d 100644 --- a/examples/evm-verifier-with-accumulator.rs +++ b/examples/evm-verifier-with-accumulator.rs @@ -17,7 +17,7 @@ use halo2_proofs::{ use itertools::Itertools; use plonk_verifier::{ loader::{ - evm::{encode_calldata, EvmLoader, ExecutorBuilder}, + evm::{self, encode_calldata, EvmLoader, ExecutorBuilder}, native::NativeLoader, }, pcs::kzg::{Gwc19, Kzg, KzgAs, LimbsEncoding}, @@ -570,7 +570,7 @@ fn gen_aggregation_evm_verifier( let proof = Plonk::read_proof(&svk, &protocol, &instances, &mut transcript).unwrap(); Plonk::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); - loader.deployment_code() + evm::compile_yul(&loader.yul_code()) } fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { diff --git a/examples/evm-verifier.rs b/examples/evm-verifier.rs index 4ff5c682..b45bb59d 100644 --- a/examples/evm-verifier.rs +++ b/examples/evm-verifier.rs @@ -20,7 +20,7 @@ use halo2_proofs::{ }; use itertools::Itertools; use plonk_verifier::{ - loader::evm::{encode_calldata, EvmLoader, ExecutorBuilder}, + loader::evm::{self, encode_calldata, EvmLoader, ExecutorBuilder}, pcs::kzg::{Gwc19, Kzg}, system::halo2::{compile, transcript::evm::EvmTranscript, Config}, verifier::{self, PlonkVerifier}, @@ -222,7 +222,7 @@ fn gen_evm_verifier( let proof = Plonk::read_proof(&svk, &protocol, &instances, &mut transcript).unwrap(); Plonk::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); - loader.deployment_code() + evm::compile_yul(&loader.yul_code()) } fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { diff --git a/src/loader/evm.rs b/src/loader/evm.rs index fa80b97e..263da0e2 100644 --- a/src/loader/evm.rs +++ b/src/loader/evm.rs @@ -7,7 +7,8 @@ mod test; pub use loader::{EcPoint, EvmLoader, Scalar}; pub use util::{ - encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, ExecutorBuilder, MemoryChunk, + compile_yul, encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, ExecutorBuilder, + MemoryChunk, }; pub use ethereum_types::U256; diff --git a/src/loader/evm/code.rs b/src/loader/evm/code.rs index 80dd5c71..840d1e67 100644 --- a/src/loader/evm/code.rs +++ b/src/loader/evm/code.rs @@ -1,7 +1,3 @@ -use crate::util::Itertools; -use ethereum_types::U256; -use std::{collections::HashMap, iter}; - pub enum Precompiled { BigModExp = 0x05, Bn254Add = 0x6, @@ -10,286 +6,70 @@ pub enum Precompiled { } #[derive(Clone, Debug)] -pub struct Code { - code: Vec, - constants: HashMap, - stack_len: usize, +pub struct YulCode { + // runtime code area + runtime: String, } -impl Code { - pub fn new(constants: impl IntoIterator) -> Self { - let mut code = Self { - code: Vec::new(), - constants: HashMap::new(), - stack_len: 0, - }; - let constants = constants.into_iter().collect_vec(); - for constant in constants.iter() { - code.push(*constant); - } - code.constants = HashMap::from_iter( - constants - .into_iter() - .enumerate() - .map(|(idx, value)| (value, idx)), - ); - code - } - - pub fn deployment(code: Vec) -> Vec { - let code_len = code.len(); - assert_ne!(code_len, 0); - - iter::empty() - .chain([ - PUSH1 + 1, - (code_len >> 8) as u8, - (code_len & 0xff) as u8, - PUSH1, - 14, - PUSH1, - 0, - CODECOPY, - ]) - .chain([ - PUSH1 + 1, - (code_len >> 8) as u8, - (code_len & 0xff) as u8, - PUSH1, - 0, - RETURN, - ]) - .chain(code) - .collect() - } - - pub fn stack_len(&self) -> usize { - self.stack_len - } - - pub fn len(&self) -> usize { - self.code.len() - } - - pub fn is_empty(&self) -> bool { - self.code.is_empty() - } - - pub fn push>(&mut self, value: T) -> &mut Self { - let value = value.into(); - match self.constants.get(&value) { - Some(idx) if (0..16).contains(&(self.stack_len - idx - 1)) => { - self.dup(self.stack_len - idx - 1); - } - _ => { - let mut bytes = vec![0; 32]; - value.to_big_endian(&mut bytes); - let bytes = bytes - .iter() - .position(|byte| *byte != 0) - .map_or(vec![0], |pos| bytes.drain(pos..).collect()); - self.code.push(PUSH1 - 1 + bytes.len() as u8); - self.code.extend(bytes); - self.stack_len += 1; - } +impl YulCode { + pub fn new() -> Self { + YulCode { + runtime: String::new(), } - self - } - - pub fn dup(&mut self, pos: usize) -> &mut Self { - assert!((0..16).contains(&pos)); - self.code.push(DUP1 + pos as u8); - self.stack_len += 1; - self } - pub fn swap(&mut self, pos: usize) -> &mut Self { - assert!((1..17).contains(&pos)); - self.code.push(SWAP1 - 1 + pos as u8); - self + pub fn code(&self, base_modulus: String, scalar_modulus: String) -> String { + format!( + " + object \"plonk_verifier\" {{ + code {{ + function allocate(size) -> ptr {{ + ptr := mload(0x40) + if eq(ptr, 0) {{ ptr := 0x60 }} + mstore(0x40, add(ptr, size)) + }} + let size := datasize(\"Runtime\") + let offset := allocate(size) + datacopy(offset, dataoffset(\"Runtime\"), size) + return(offset, size) + }} + object \"Runtime\" {{ + code {{ + let success:bool := true + let f_p := {base_modulus} + let f_q := {scalar_modulus} + function validate_ec_point(x, y) -> valid:bool {{ + {{ + let x_lt_p:bool := lt(x, {base_modulus}) + let y_lt_p:bool := lt(y, {base_modulus}) + valid := and(x_lt_p, y_lt_p) + }} + {{ + let x_is_zero:bool := eq(x, 0) + let y_is_zero:bool := eq(y, 0) + let x_or_y_is_zero:bool := or(x_is_zero, y_is_zero) + let x_and_y_is_not_zero:bool := not(x_or_y_is_zero) + valid := and(x_and_y_is_not_zero, valid) + }} + {{ + let y_square := mulmod(y, y, {base_modulus}) + let x_square := mulmod(x, x, {base_modulus}) + let x_cube := mulmod(x_square, x, {base_modulus}) + let x_cube_plus_3 := addmod(x_cube, 3, {base_modulus}) + let y_square_eq_x_cube_plus_3:bool := eq(x_cube_plus_3, y_square) + valid := and(y_square_eq_x_cube_plus_3, valid) + }} + }} + {} + }} + }} + }}", + self.runtime + ) } -} -impl From for Vec { - fn from(code: Code) -> Self { - code.code + pub fn runtime_append(&mut self, mut code: String) { + code.push('\n'); + self.runtime.push_str(&code); } } - -macro_rules! impl_opcodes { - ($($method:ident -> ($opcode:ident, $stack_len_diff:expr))*) => { - $( - #[allow(dead_code)] - impl Code { - pub fn $method(&mut self) -> &mut Self { - self.code.push($opcode); - self.stack_len = ((self.stack_len as isize) + $stack_len_diff) as usize; - self - } - } - )* - }; -} - -impl_opcodes!( - stop -> (STOP, 0) - add -> (ADD, -1) - mul -> (MUL, -1) - sub -> (SUB, -1) - div -> (DIV, -1) - sdiv -> (SDIV, -1) - r#mod -> (MOD, -1) - smod -> (SMOD, -1) - addmod -> (ADDMOD, -2) - mulmod -> (MULMOD, -2) - exp -> (EXP, -1) - signextend -> (SIGNEXTEND, -1) - lt -> (LT, -1) - gt -> (GT, -1) - slt -> (SLT, -1) - sgt -> (SGT, -1) - eq -> (EQ, -1) - iszero -> (ISZERO, 0) - and -> (AND, -1) - or -> (OR, -1) - xor -> (XOR, -1) - not -> (NOT, 0) - byte -> (BYTE, -1) - shl -> (SHL, -1) - shr -> (SHR, -1) - sar -> (SAR, -1) - keccak256 -> (SHA3, -1) - address -> (ADDRESS, 1) - balance -> (BALANCE, 0) - origin -> (ORIGIN, 1) - caller -> (CALLER, 1) - callvalue -> (CALLVALUE, 1) - calldataload -> (CALLDATALOAD, 0) - calldatasize -> (CALLDATASIZE, 1) - calldatacopy -> (CALLDATACOPY, -3) - codesize -> (CODESIZE, 1) - codecopy -> (CODECOPY, -3) - gasprice -> (GASPRICE, 1) - extcodesize -> (EXTCODESIZE, 0) - extcodecopy -> (EXTCODECOPY, -4) - returndatasize -> (RETURNDATASIZE, 1) - returndatacopy -> (RETURNDATACOPY, -3) - extcodehash -> (EXTCODEHASH, 0) - blockhash -> (BLOCKHASH, 0) - coinbase -> (COINBASE, 1) - timestamp -> (TIMESTAMP, 1) - number -> (NUMBER, 1) - difficulty -> (DIFFICULTY, 1) - gaslimit -> (GASLIMIT, 1) - chainid -> (CHAINID, 1) - selfbalance -> (SELFBALANCE, 1) - basefee -> (BASEFEE, 1) - pop -> (POP, -1) - mload -> (MLOAD, 0) - mstore -> (MSTORE, -2) - mstore8 -> (MSTORE8, -2) - sload -> (SLOAD, 0) - sstore -> (SSTORE, -2) - jump -> (JUMP, -1) - jumpi -> (JUMPI, -2) - pc -> (PC, 1) - msize -> (MSIZE, 1) - gas -> (GAS, 1) - jumpdest -> (JUMPDEST, 0) - log0 -> (LOG0, -2) - log1 -> (LOG1, -3) - log2 -> (LOG2, -4) - log3 -> (LOG3, -5) - log4 -> (LOG4, -6) - create -> (CREATE, -2) - call -> (CALL, -6) - callcode -> (CALLCODE, -6) - r#return -> (RETURN, -2) - delegatecall -> (DELEGATECALL, -5) - create2 -> (CREATE2, -3) - staticcall -> (STATICCALL, -5) - revert -> (REVERT, -2) - selfdestruct -> (SELFDESTRUCT, -1) -); - -const STOP: u8 = 0x00; -const ADD: u8 = 0x01; -const MUL: u8 = 0x02; -const SUB: u8 = 0x03; -const DIV: u8 = 0x04; -const SDIV: u8 = 0x05; -const MOD: u8 = 0x06; -const SMOD: u8 = 0x07; -const ADDMOD: u8 = 0x08; -const MULMOD: u8 = 0x09; -const EXP: u8 = 0x0A; -const SIGNEXTEND: u8 = 0x0B; -const LT: u8 = 0x10; -const GT: u8 = 0x11; -const SLT: u8 = 0x12; -const SGT: u8 = 0x13; -const EQ: u8 = 0x14; -const ISZERO: u8 = 0x15; -const AND: u8 = 0x16; -const OR: u8 = 0x17; -const XOR: u8 = 0x18; -const NOT: u8 = 0x19; -const BYTE: u8 = 0x1A; -const SHL: u8 = 0x1B; -const SHR: u8 = 0x1C; -const SAR: u8 = 0x1D; -const SHA3: u8 = 0x20; -const ADDRESS: u8 = 0x30; -const BALANCE: u8 = 0x31; -const ORIGIN: u8 = 0x32; -const CALLER: u8 = 0x33; -const CALLVALUE: u8 = 0x34; -const CALLDATALOAD: u8 = 0x35; -const CALLDATASIZE: u8 = 0x36; -const CALLDATACOPY: u8 = 0x37; -const CODESIZE: u8 = 0x38; -const CODECOPY: u8 = 0x39; -const GASPRICE: u8 = 0x3A; -const EXTCODESIZE: u8 = 0x3B; -const EXTCODECOPY: u8 = 0x3C; -const RETURNDATASIZE: u8 = 0x3D; -const RETURNDATACOPY: u8 = 0x3E; -const EXTCODEHASH: u8 = 0x3F; -const BLOCKHASH: u8 = 0x40; -const COINBASE: u8 = 0x41; -const TIMESTAMP: u8 = 0x42; -const NUMBER: u8 = 0x43; -const DIFFICULTY: u8 = 0x44; -const GASLIMIT: u8 = 0x45; -const CHAINID: u8 = 0x46; -const SELFBALANCE: u8 = 0x47; -const BASEFEE: u8 = 0x48; -const POP: u8 = 0x50; -const MLOAD: u8 = 0x51; -const MSTORE: u8 = 0x52; -const MSTORE8: u8 = 0x53; -const SLOAD: u8 = 0x54; -const SSTORE: u8 = 0x55; -const JUMP: u8 = 0x56; -const JUMPI: u8 = 0x57; -const PC: u8 = 0x58; -const MSIZE: u8 = 0x59; -const GAS: u8 = 0x5A; -const JUMPDEST: u8 = 0x5B; -const PUSH1: u8 = 0x60; -const DUP1: u8 = 0x80; -const SWAP1: u8 = 0x90; -const LOG0: u8 = 0xA0; -const LOG1: u8 = 0xA1; -const LOG2: u8 = 0xA2; -const LOG3: u8 = 0xA3; -const LOG4: u8 = 0xA4; -const CREATE: u8 = 0xF0; -const CALL: u8 = 0xF1; -const CALLCODE: u8 = 0xF2; -const RETURN: u8 = 0xF3; -const DELEGATECALL: u8 = 0xF4; -const CREATE2: u8 = 0xF5; -const STATICCALL: u8 = 0xFA; -const REVERT: u8 = 0xFD; -const SELFDESTRUCT: u8 = 0xFF; diff --git a/src/loader/evm/loader.rs b/src/loader/evm/loader.rs index 9e8b8e2a..c630a468 100644 --- a/src/loader/evm/loader.rs +++ b/src/loader/evm/loader.rs @@ -1,9 +1,11 @@ use crate::{ - loader::evm::{ - code::{Code, Precompiled}, - fe_to_u256, modulus, + loader::{ + evm::{ + code::{Precompiled, YulCode}, + fe_to_u256, modulus, u256_to_fe, + }, + EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader, }, - loader::{evm::u256_to_fe, EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader}, util::{ arithmetic::{CurveAffine, FieldOps, PrimeField}, Itertools, @@ -11,6 +13,7 @@ use crate::{ Error, }; use ethereum_types::{U256, U512}; +use hex; use std::{ cell::RefCell, collections::HashMap, @@ -50,24 +53,29 @@ impl Value { pub struct EvmLoader { base_modulus: U256, scalar_modulus: U256, - code: RefCell, + code: RefCell, ptr: RefCell, cache: RefCell>, #[cfg(test)] gas_metering_ids: RefCell>, } +fn hex_encode_u256(value: &U256) -> String { + let mut bytes = [0; 32]; + value.to_big_endian(&mut bytes); + format!("0x{}", hex::encode(bytes)) +} + impl EvmLoader { pub fn new() -> Rc where - Base: PrimeField, + Base: PrimeField, Scalar: PrimeField, { let base_modulus = modulus::(); let scalar_modulus = modulus::(); - let code = Code::new([1.into(), base_modulus, scalar_modulus - 1, scalar_modulus]) - .push(1) - .to_owned(); + let code = YulCode::new(); + Rc::new(Self { base_modulus, scalar_modulus, @@ -79,22 +87,16 @@ impl EvmLoader { }) } - pub fn deployment_code(self: &Rc) -> Vec { - Code::deployment(self.runtime_code()) - } - - pub fn runtime_code(self: &Rc) -> Vec { - let mut code = self.code.borrow().clone(); - let dst = code.len() + 9; - code.push(dst) - .jumpi() - .push(0) - .push(0) - .revert() - .jumpdest() - .stop() - .to_owned() - .into() + pub fn yul_code(self: &Rc) -> String { + let code = " + if not(success) { revert(0, 0) } + return(0, 0)" + .to_string(); + self.code.borrow_mut().runtime_append(code); + self.code.borrow().code( + hex_encode_u256(&self.base_modulus), + hex_encode_u256(&self.scalar_modulus), + ) } pub fn allocate(self: &Rc, size: usize) -> usize { @@ -103,121 +105,64 @@ impl EvmLoader { ptr } - pub(crate) fn scalar_modulus(&self) -> U256 { - self.scalar_modulus - } - pub(crate) fn ptr(&self) -> usize { *self.ptr.borrow() } - pub(crate) fn code_mut(&self) -> impl DerefMut + '_ { + pub(crate) fn code_mut(&self) -> impl DerefMut + '_ { self.code.borrow_mut() } - pub(crate) fn scalar(self: &Rc, value: Value) -> Scalar { - let value = if matches!( - value, - Value::Constant(_) | Value::Memory(_) | Value::Negated(_) - ) { - value - } else { - let identifier = value.identifier(); - let some_ptr = self.cache.borrow().get(&identifier).cloned(); - let ptr = if let Some(ptr) = some_ptr { - ptr - } else { - self.push(&Scalar { - loader: self.clone(), - value, - }); - let ptr = self.allocate(0x20); - self.code.borrow_mut().push(ptr).mstore(); - self.cache.borrow_mut().insert(identifier, ptr); - ptr - }; - Value::Memory(ptr) - }; - Scalar { - loader: self.clone(), - value, - } - } - - fn ec_point(self: &Rc, value: Value<(U256, U256)>) -> EcPoint { - EcPoint { - loader: self.clone(), - value, - } - } - - fn push(self: &Rc, scalar: &Scalar) { + fn push(self: &Rc, scalar: &Scalar) -> String { match scalar.value.clone() { Value::Constant(constant) => { - self.code.borrow_mut().push(constant); + format!("{constant}") } Value::Memory(ptr) => { - self.code.borrow_mut().push(ptr).mload(); + format!("mload({ptr:#x})") } Value::Negated(value) => { - self.push(&self.scalar(*value)); - self.code.borrow_mut().push(self.scalar_modulus).sub(); + let v = self.push(&self.scalar(*value)); + format!("sub(f_q, {v})") } Value::Sum(lhs, rhs) => { - self.code.borrow_mut().push(self.scalar_modulus); - self.push(&self.scalar(*lhs)); - self.push(&self.scalar(*rhs)); - self.code.borrow_mut().addmod(); + let lhs = self.push(&self.scalar(*lhs)); + let rhs = self.push(&self.scalar(*rhs)); + format!("addmod({lhs}, {rhs}, f_q)") } Value::Product(lhs, rhs) => { - self.code.borrow_mut().push(self.scalar_modulus); - self.push(&self.scalar(*lhs)); - self.push(&self.scalar(*rhs)); - self.code.borrow_mut().mulmod(); + let lhs = self.push(&self.scalar(*lhs)); + let rhs = self.push(&self.scalar(*rhs)); + format!("mulmod({lhs}, {rhs}, f_q)") } } } pub fn calldataload_scalar(self: &Rc, offset: usize) -> Scalar { let ptr = self.allocate(0x20); - self.code - .borrow_mut() - .push(self.scalar_modulus) - .push(offset) - .calldataload() - .r#mod() - .push(ptr) - .mstore(); + let code = format!("mstore({ptr:#x}, mod(calldataload({offset:#x}), f_q))"); + self.code.borrow_mut().runtime_append(code); self.scalar(Value::Memory(ptr)) } pub fn calldataload_ec_point(self: &Rc, offset: usize) -> EcPoint { - let ptr = self.allocate(0x40); - self.code - .borrow_mut() - // [..., success] - .push(offset) - // [..., success, x_cd_ptr] - .calldataload() - // [..., success, x] - .dup(0) - // [..., success, x, x] - .push(ptr) - // [..., success, x, x, x_ptr] - .mstore() - // [..., success, x] - .push(offset + 0x20) - // [..., success, x, y_cd_ptr] - .calldataload() - // [..., success, x, y] - .dup(0) - // [..., success, x, y, y] - .push(ptr + 0x20) - // [..., success, x, y, y, y_ptr] - .mstore(); - // [..., success, x, y] - self.validate_ec_point(); - self.ec_point(Value::Memory(ptr)) + let x_ptr = self.allocate(0x40); + let y_ptr = x_ptr + 0x20; + let x_cd_ptr = offset; + let y_cd_ptr = offset + 0x20; + let validate_code = self.validate_ec_point(); + let code = format!( + " + {{ + let x := calldataload({x_cd_ptr:#x}) + mstore({x_ptr:#x}, x) + let y := calldataload({y_cd_ptr:#x}) + mstore({y_ptr:#x}, y) + {validate_code} + }}" + ); + self.code.borrow_mut().runtime_append(code); + self.ec_point(Value::Memory(x_ptr)) } pub fn ec_point_from_limbs( @@ -226,124 +171,94 @@ impl EvmLoader { y_limbs: [&Scalar; LIMBS], ) -> EcPoint { let ptr = self.allocate(0x40); - for (ptr, limbs) in [(ptr, x_limbs), (ptr + 0x20, y_limbs)] { - for (idx, limb) in limbs.into_iter().enumerate() { - self.push(limb); - // [..., success, acc] - if idx > 0 { - self.code - .borrow_mut() - .push(idx * BITS) - // [..., success, acc, limb_i, shift] - .shl() - // [..., success, acc, limb_i << shift] - .add(); - // [..., success, acc] - } + let mut code = String::new(); + for (idx, limb) in x_limbs.iter().enumerate() { + let limb_i = self.push(limb); + let shift = idx * BITS; + if idx == 0 { + code.push_str(format!("let x := {limb_i}\n").as_str()); + } else { + code.push_str(format!("x := add(x, shl({shift}, {limb_i}))\n").as_str()); + } + } + let x_ptr = ptr; + code.push_str(format!("mstore({x_ptr}, x)\n").as_str()); + for (idx, limb) in y_limbs.iter().enumerate() { + let limb_i = self.push(limb); + let shift = idx * BITS; + if idx == 0 { + code.push_str(format!("let y := {limb_i}\n").as_str()); + } else { + code.push_str(format!("y := add(y, shl({shift}, {limb_i}))\n").as_str()); } - self.code - .borrow_mut() - // [..., success, coordinate] - .dup(0) - // [..., success, coordinate, coordinate] - .push(ptr) - // [..., success, coordinate, coordinate, ptr] - .mstore(); - // [..., success, coordinate] } - // [..., success, x, y] - self.validate_ec_point(); + let y_ptr = ptr + 0x20; + code.push_str(format!("mstore({y_ptr}, y)\n").as_str()); + let validate_code = self.validate_ec_point(); + let code = format!( + "{{ + {code} + {validate_code} + }}" + ); + self.code.borrow_mut().runtime_append(code); self.ec_point(Value::Memory(ptr)) } - fn validate_ec_point(self: &Rc) { - self.code - .borrow_mut() - // [..., success, x, y] - .push(self.base_modulus) - // [..., success, x, y, p] - .dup(2) - // [..., success, x, y, p, x] - .lt() - // [..., success, x, y, x_lt_p] - .push(self.base_modulus) - // [..., success, x, y, x_lt_p, p] - .dup(2) - // [..., success, x, y, x_lt_p, p, y] - .lt() - // [..., success, x, y, x_lt_p, y_lt_p] - .and() - // [..., success, x, y, valid] - .dup(2) - // [..., success, x, y, valid, x] - .iszero() - // [..., success, x, y, valid, x_is_zero] - .dup(2) - // [..., success, x, y, valid, x_is_zero, y] - .iszero() - // [..., success, x, y, valid, x_is_zero, y_is_zero] - .or() - // [..., success, x, y, valid, x_or_y_is_zero] - .not() - // [..., success, x, y, valid, x_and_y_is_not_zero] - .and() - // [..., success, x, y, valid] - .push(self.base_modulus) - // [..., success, x, y, valid, p] - .dup(2) - // [..., success, x, y, valid, p, y] - .dup(0) - // [..., success, x, y, valid, p, y, y] - .mulmod() - // [..., success, x, y, valid, y_square] - .push(self.base_modulus) - // [..., success, x, y, valid, y_square, p] - .push(3) - // [..., success, x, y, valid, y_square, p, 3] - .push(self.base_modulus) - // [..., success, x, y, valid, y_square, p, 3, p] - .dup(6) - // [..., success, x, y, valid, y_square, p, 3, p, x] - .push(self.base_modulus) - // [..., success, x, y, valid, y_square, p, 3, p, x, p] - .dup(1) - // [..., success, x, y, valid, y_square, p, 3, p, x, p, x] - .dup(0) - // [..., success, x, y, valid, y_square, p, 3, p, x, p, x, x] - .mulmod() - // [..., success, x, y, valid, y_square, p, 3, p, x, x_square] - .mulmod() - // [..., success, x, y, valid, y_square, p, 3, x_cube] - .addmod() - // [..., success, x, y, valid, y_square, x_cube_plus_3] - .eq() - // [..., success, x, y, valid, y_square_eq_x_cube_plus_3] - .and() - // [..., success, x, y, valid] - .swap(2) - // [..., success, valid, y, x] - .pop() - // [..., success, valid, y] - .pop() - // [..., success, valid] - .and(); + fn validate_ec_point(self: &Rc) -> String { + "success := and(validate_ec_point(x, y), success)".to_string() + } + + pub(crate) fn scalar(self: &Rc, value: Value) -> Scalar { + let value = if matches!( + value, + Value::Constant(_) | Value::Memory(_) | Value::Negated(_) + ) { + value + } else { + let identifier = value.identifier(); + let some_ptr = self.cache.borrow().get(&identifier).cloned(); + let ptr = if let Some(ptr) = some_ptr { + ptr + } else { + let v = self.push(&Scalar { + loader: self.clone(), + value, + }); + let ptr = self.allocate(0x20); + self.code + .borrow_mut() + .runtime_append(format!("mstore({ptr:#x}, {v})")); + self.cache.borrow_mut().insert(identifier, ptr); + ptr + }; + Value::Memory(ptr) + }; + Scalar { + loader: self.clone(), + value, + } + } + + fn ec_point(self: &Rc, value: Value<(U256, U256)>) -> EcPoint { + EcPoint { + loader: self.clone(), + value, + } } pub fn keccak256(self: &Rc, ptr: usize, len: usize) -> usize { let hash_ptr = self.allocate(0x20); - self.code - .borrow_mut() - .push(len) - .push(ptr) - .keccak256() - .push(hash_ptr) - .mstore(); + let code = format!("mstore({hash_ptr:#x}, keccak256({ptr:#x}, {len}))"); + self.code.borrow_mut().runtime_append(code); hash_ptr } pub fn copy_scalar(self: &Rc, scalar: &Scalar, ptr: usize) { - self.push(scalar); - self.code.borrow_mut().push(ptr).mstore(); + let scalar = self.push(scalar); + self.code + .borrow_mut() + .runtime_append(format!("mstore({ptr:#x}, {scalar})")); } pub fn dup_scalar(self: &Rc, scalar: &Scalar) -> Scalar { @@ -356,26 +271,26 @@ impl EvmLoader { let ptr = self.allocate(0x40); match value.value { Value::Constant((x, y)) => { - self.code - .borrow_mut() - .push(x) - .push(ptr) - .mstore() - .push(y) - .push(ptr + 0x20) - .mstore(); + let x_ptr = ptr; + let y_ptr = ptr + 0x20; + let x = hex_encode_u256(&x); + let y = hex_encode_u256(&y); + let code = format!( + "mstore({x_ptr:#x}, {x}) + mstore({y_ptr:#x}, {y})" + ); + self.code.borrow_mut().runtime_append(code); } Value::Memory(src_ptr) => { - self.code - .borrow_mut() - .push(src_ptr) - .mload() - .push(ptr) - .mstore() - .push(src_ptr + 0x20) - .mload() - .push(ptr + 0x20) - .mstore(); + let x_ptr = ptr; + let y_ptr = ptr + 0x20; + let src_x = src_ptr; + let src_y = src_ptr + 0x20; + let code = format!( + "mstore({x_ptr:#x}, mload({src_x:#x})) + mstore({y_ptr:#x}, mload({src_y:#x}))" + ); + self.code.borrow_mut().runtime_append(code); } Value::Negated(_) | Value::Sum(_, _) | Value::Product(_, _) => { unreachable!() @@ -391,16 +306,9 @@ impl EvmLoader { Precompiled::Bn254ScalarMul => (0x60, 0x40), Precompiled::Bn254Pairing => (0x180, 0x20), }; - self.code - .borrow_mut() - .push(rd_len) - .push(rd_ptr) - .push(cd_len) - .push(cd_ptr) - .push(precompile as usize) - .gas() - .staticcall() - .and(); + let a = precompile as usize; + let code = format!("success := and(eq(staticcall(gas(), {a:#x}, {cd_ptr:#x}, {cd_len:#x}, {rd_ptr:#x}, {rd_len:#x}), 1), success)"); + self.code.borrow_mut().runtime_append(code); } fn invert(self: &Rc, scalar: &Scalar) -> Scalar { @@ -441,38 +349,41 @@ impl EvmLoader { ) { let rd_ptr = self.dup_ec_point(lhs).ptr(); self.allocate(0x80); - self.code - .borrow_mut() - .push(g2.0) - .push(rd_ptr + 0x40) - .mstore() - .push(g2.1) - .push(rd_ptr + 0x60) - .mstore() - .push(g2.2) - .push(rd_ptr + 0x80) - .mstore() - .push(g2.3) - .push(rd_ptr + 0xa0) - .mstore(); + let g2_0 = hex_encode_u256(&g2.0); + let g2_0_ptr = rd_ptr + 0x40; + let g2_1 = hex_encode_u256(&g2.1); + let g2_1_ptr = rd_ptr + 0x60; + let g2_2 = hex_encode_u256(&g2.2); + let g2_2_ptr = rd_ptr + 0x80; + let g2_3 = hex_encode_u256(&g2.3); + let g2_3_ptr = rd_ptr + 0xa0; + let code = format!( + "mstore({g2_0_ptr:#x}, {g2_0}) + mstore({g2_1_ptr:#x}, {g2_1}) + mstore({g2_2_ptr:#x}, {g2_2}) + mstore({g2_3_ptr:#x}, {g2_3})" + ); + self.code.borrow_mut().runtime_append(code); self.dup_ec_point(rhs); self.allocate(0x80); - self.code - .borrow_mut() - .push(minus_s_g2.0) - .push(rd_ptr + 0x100) - .mstore() - .push(minus_s_g2.1) - .push(rd_ptr + 0x120) - .mstore() - .push(minus_s_g2.2) - .push(rd_ptr + 0x140) - .mstore() - .push(minus_s_g2.3) - .push(rd_ptr + 0x160) - .mstore(); + let minus_s_g2_0 = hex_encode_u256(&minus_s_g2.0); + let minus_s_g2_0_ptr = rd_ptr + 0x100; + let minus_s_g2_1 = hex_encode_u256(&minus_s_g2.1); + let minus_s_g2_1_ptr = rd_ptr + 0x120; + let minus_s_g2_2 = hex_encode_u256(&minus_s_g2.2); + let minus_s_g2_2_ptr = rd_ptr + 0x140; + let minus_s_g2_3 = hex_encode_u256(&minus_s_g2.3); + let minus_s_g2_3_ptr = rd_ptr + 0x160; + let code = format!( + "mstore({minus_s_g2_0_ptr:#x}, {minus_s_g2_0}) + mstore({minus_s_g2_1_ptr:#x}, {minus_s_g2_1}) + mstore({minus_s_g2_2_ptr:#x}, {minus_s_g2_2}) + mstore({minus_s_g2_3_ptr:#x}, {minus_s_g2_3})" + ); + self.code.borrow_mut().runtime_append(code); self.staticcall(Precompiled::Bn254Pairing, rd_ptr, rd_ptr); - self.code.borrow_mut().push(rd_ptr).mload().and(); + let code = format!("success := and(eq(mload({rd_ptr:#x}), 1), success)"); + self.code.borrow_mut().runtime_append(code); } fn add(self: &Rc, lhs: &Scalar, rhs: &Scalar) -> Scalar { @@ -525,21 +436,16 @@ impl EvmLoader { self.gas_metering_ids .borrow_mut() .push(identifier.to_string()); - self.code.borrow_mut().gas().swap(1); + let code = format!("let {identifier} := gas()"); + self.code.borrow_mut().runtime_append(code); } fn end_gas_metering(self: &Rc) { - self.code - .borrow_mut() - .swap(1) - .push(9) - .gas() - .swap(2) - .sub() - .sub() - .push(0) - .push(0) - .log1(); + let code = format!( + "log1(0, 0, sub({}, gas()))", + self.gas_metering_ids.borrow().last().unwrap() + ); + self.code.borrow_mut().runtime_append(code); } pub fn print_gas_metering(self: &Rc, costs: Vec) { @@ -745,7 +651,7 @@ impl PartialEq for Scalar { impl> LoadedScalar for Scalar { type Loader = Rc; - fn loader(&self) -> &Rc { + fn loader(&self) -> &Self::Loader { &self.loader } } @@ -753,7 +659,7 @@ impl> LoadedScalar for Scalar { impl EcPointLoader for Rc where C: CurveAffine, - C::ScalarExt: PrimeField, + C::Scalar: PrimeField, { type LoadedEcPoint = EcPoint; @@ -802,48 +708,39 @@ impl> ScalarLoader for Rc { let push_addend = |(coeff, value): &(F, &Scalar)| { assert_ne!(*coeff, F::zero()); match (*coeff == F::one(), &value.value) { - (true, _) => { - self.push(value); - } - (false, Value::Constant(value)) => { - self.push(&self.scalar(Value::Constant(fe_to_u256( - *coeff * u256_to_fe::(*value), - )))); - } + (true, _) => self.push(value), + (false, Value::Constant(value)) => self.push(&self.scalar(Value::Constant( + fe_to_u256(*coeff * u256_to_fe::(*value)), + ))), (false, _) => { - self.code.borrow_mut().push(self.scalar_modulus); - self.push(&self.scalar(Value::Constant(fe_to_u256(*coeff)))); - self.push(value); - self.code.borrow_mut().mulmod(); + let value = self.push(value); + let coeff = self.push(&self.scalar(Value::Constant(fe_to_u256(*coeff)))); + format!("mulmod({value}, {coeff}, f_q)") } } }; let mut values = values.iter(); - if constant == F::zero() { - push_addend(values.next().unwrap()); + let initial_value = if constant == F::zero() { + push_addend(values.next().unwrap()) } else { - self.push(&self.scalar(Value::Constant(fe_to_u256(constant)))); - } - - let chunk_size = 16 - self.code.borrow().stack_len(); - for values in &values.chunks(chunk_size) { - let values = values.into_iter().collect_vec(); - - self.code.borrow_mut().push(self.scalar_modulus); - for _ in 1..chunk_size.min(values.len()) { - self.code.borrow_mut().dup(0); - } - self.code.borrow_mut().swap(chunk_size.min(values.len())); + self.push(&self.scalar(Value::Constant(fe_to_u256(constant)))) + }; - for value in values { - push_addend(value); - self.code.borrow_mut().addmod(); - } + let mut code = format!("let result := {initial_value}\n"); + for value in values { + let v = push_addend(value); + let addend = format!("result := addmod({v}, result, f_q)\n"); + code.push_str(addend.as_str()); } let ptr = self.allocate(0x20); - self.code.borrow_mut().push(ptr).mstore(); + code.push_str(format!("mstore({ptr}, result)").as_str()); + self.code.borrow_mut().runtime_append(format!( + "{{ + {code} + }}" + )); self.scalar(Value::Memory(ptr)) } @@ -863,63 +760,64 @@ impl> ScalarLoader for Rc { (_, Value::Constant(lhs), Value::Constant(rhs)) => { self.push(&self.scalar(Value::Constant(fe_to_u256( *coeff * u256_to_fe::(*lhs) * u256_to_fe::(*rhs), - )))); + )))) } (_, value @ Value::Memory(_), Value::Constant(constant)) | (_, Value::Constant(constant), value @ Value::Memory(_)) => { - self.code.borrow_mut().push(self.scalar_modulus); - self.push(&self.scalar(Value::Constant(fe_to_u256( + let v1 = self.push(&self.scalar(value.clone())); + let v2 = self.push(&self.scalar(Value::Constant(fe_to_u256( *coeff * u256_to_fe::(*constant), )))); - self.push(&self.scalar(value.clone())); - self.code.borrow_mut().mulmod(); + format!("mulmod({v1}, {v2}, f_q)") } (true, _, _) => { - self.code.borrow_mut().push(self.scalar_modulus); - self.push(lhs); - self.push(rhs); - self.code.borrow_mut().mulmod(); + let rhs = self.push(rhs); + let lhs = self.push(lhs); + format!("mulmod({rhs}, {lhs}, f_q)") } (false, _, _) => { - self.code.borrow_mut().push(self.scalar_modulus).dup(0); - self.push(&self.scalar(Value::Constant(fe_to_u256(*coeff)))); - self.push(lhs); - self.code.borrow_mut().mulmod(); - self.push(rhs); - self.code.borrow_mut().mulmod(); + let rhs = self.push(rhs); + let lhs = self.push(lhs); + let value = self.push(&self.scalar(Value::Constant(fe_to_u256(*coeff)))); + format!("mulmod({rhs}, mulmod({lhs}, {value}, f_q), f_q)") } } }; let mut values = values.iter(); - if constant == F::zero() { - push_addend(values.next().unwrap()); + let initial_value = if constant == F::zero() { + push_addend(values.next().unwrap()) } else { - self.push(&self.scalar(Value::Constant(fe_to_u256(constant)))); - } - - let chunk_size = 16 - self.code.borrow().stack_len(); - for values in &values.chunks(chunk_size) { - let values = values.into_iter().collect_vec(); - - self.code.borrow_mut().push(self.scalar_modulus); - for _ in 1..chunk_size.min(values.len()) { - self.code.borrow_mut().dup(0); - } - self.code.borrow_mut().swap(chunk_size.min(values.len())); + self.push(&self.scalar(Value::Constant(fe_to_u256(constant)))) + }; - for value in values { - push_addend(value); - self.code.borrow_mut().addmod(); - } + let mut code = format!("let result := {initial_value}\n"); + for value in values { + let v = push_addend(value); + let addend = format!("result := addmod({v}, result, f_q)\n"); + code.push_str(addend.as_str()); } let ptr = self.allocate(0x20); - self.code.borrow_mut().push(ptr).mstore(); + code.push_str(format!("mstore({ptr}, result)").as_str()); + self.code.borrow_mut().runtime_append(format!( + "{{ + {code} + }}" + )); self.scalar(Value::Memory(ptr)) } + // batch_invert algorithm + // n := values.len() - 1 + // input : values[0], ..., values[n] + // output : values[0]^{-1}, ..., values[n]^{-1} + // 1. products[i] <- values[0] * ... * values[i], i = 1, ..., n + // 2. inv <- (products[n])^{-1} + // 3. v_n <- values[n] + // 4. values[n] <- products[n - 1] * inv (values[n]^{-1}) + // 5. inv <- v_n * inv fn batch_invert<'a>(values: impl IntoIterator) { let values = values.into_iter().collect_vec(); let loader = &values.first().unwrap().loader; @@ -931,29 +829,35 @@ impl> ScalarLoader for Rc { ) .collect_vec(); - loader.code.borrow_mut().push(loader.scalar_modulus); - for _ in 2..values.len() { - loader.code.borrow_mut().dup(0); + let initial_value = loader.push(products.first().unwrap()); + let mut code = format!("let prod := {initial_value}\n"); + for (_, (value, product)) in values.iter().zip(products.iter()).skip(1).enumerate() { + let v = loader.push(value); + let ptr = product.ptr(); + code.push_str( + format!( + " + prod := mulmod({v}, prod, f_q) + mstore({ptr:#x}, prod) + " + ) + .as_str(), + ); } - - loader.push(products.first().unwrap()); - for (idx, (value, product)) in values.iter().zip(products.iter()).skip(1).enumerate() { - loader.push(value); - loader.code.borrow_mut().mulmod(); - if idx < values.len() - 2 { - loader.code.borrow_mut().dup(0); - } - loader.code.borrow_mut().push(product.ptr()).mstore(); - } - - let inv = loader.invert(products.last().unwrap()); - - loader.code.borrow_mut().push(loader.scalar_modulus); - for _ in 2..values.len() { - loader.code.borrow_mut().dup(0); - } - - loader.push(&inv); + loader.code.borrow_mut().runtime_append(format!( + "{{ + {code} + }}" + )); + + let inv = loader.push(&loader.invert(products.last().unwrap())); + + let mut code = format!( + " + let inv := {inv} + let v + " + ); for (value, product) in values.iter().rev().zip( products .iter() @@ -963,22 +867,29 @@ impl> ScalarLoader for Rc { .chain(iter::once(None)), ) { if let Some(product) = product { - loader.push(value); - loader - .code - .borrow_mut() - .dup(2) - .dup(2) - .push(product.ptr()) - .mload() - .mulmod() - .push(value.ptr()) - .mstore() - .mulmod(); + let val_ptr = value.ptr(); + let prod_ptr = product.ptr(); + let v = loader.push(value); + code.push_str( + format!( + " + v := {v} + mstore({val_ptr}, mulmod(mload({prod_ptr:#x}), inv, f_q)) + inv := mulmod(v, inv, f_q) + " + ) + .as_str(), + ); } else { - loader.code.borrow_mut().push(value.ptr()).mstore(); + let ptr = value.ptr(); + code.push_str(format!("mstore({ptr:#x}, inv)\n").as_str()); } } + loader.code.borrow_mut().runtime_append(format!( + "{{ + {code} + }}" + )); } } diff --git a/src/loader/evm/test.rs b/src/loader/evm/test.rs index f81c5f54..e6f3703e 100644 --- a/src/loader/evm/test.rs +++ b/src/loader/evm/test.rs @@ -3,7 +3,6 @@ use crate::{ util::Itertools, }; use ethereum_types::{Address, U256}; -use revm::{AccountInfo, Bytecode}; use std::env::var_os; mod tui; @@ -15,28 +14,26 @@ fn debug() -> bool { ) } -pub fn execute(code: Vec, calldata: Vec) -> (bool, u64, Vec) { +pub fn execute(deployment_code: Vec, calldata: Vec) -> (bool, u64, Vec) { assert!( - code.len() <= 0x6000, + deployment_code.len() <= 0x6000, "Contract size {} exceeds the limit 24576", - code.len() + deployment_code.len() ); let debug = debug(); let caller = Address::from_low_u64_be(0xfe); - let callee = Address::from_low_u64_be(0xff); let mut evm = ExecutorBuilder::default() .with_gas_limit(u64::MAX.into()) .set_debugger(debug) .build(); - evm.db_mut().insert_account_info( - callee, - AccountInfo::new(0.into(), 1, Bytecode::new_raw(code.into())), - ); - - let result = evm.call_raw(caller, callee, calldata.into(), 0.into()); + let contract = evm + .deploy(caller, deployment_code.into(), 0.into()) + .address + .unwrap(); + let result = evm.call_raw(caller, contract, calldata.into(), 0.into()); let costs = result .logs diff --git a/src/loader/evm/util.rs b/src/loader/evm/util.rs index 0a772513..a7df5209 100644 --- a/src/loader/evm/util.rs +++ b/src/loader/evm/util.rs @@ -3,7 +3,11 @@ use crate::{ util::{arithmetic::PrimeField, Itertools}, }; use ethereum_types::U256; -use std::iter; +use std::{ + io::Write, + iter, + process::{Command, Stdio}, +}; pub(crate) mod executor; @@ -94,3 +98,37 @@ pub fn estimate_gas(cost: Cost) -> usize { intrinsic_cost + calldata_cost + ec_operation_cost } + +pub fn compile_yul(code: &str) -> Vec { + let mut cmd = Command::new("solc") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .arg("--bin") + .arg("--yul") + .arg("-") + .spawn() + .unwrap(); + cmd.stdin + .take() + .unwrap() + .write_all(code.as_bytes()) + .unwrap(); + let output = cmd.wait_with_output().unwrap().stdout; + let binary = *split_by_ascii_whitespace(&output).last().unwrap(); + hex::decode(binary).unwrap() +} + +fn split_by_ascii_whitespace(bytes: &[u8]) -> Vec<&[u8]> { + let mut split = Vec::new(); + let mut start = None; + for (idx, byte) in bytes.iter().enumerate() { + if byte.is_ascii_whitespace() { + if let Some(start) = start.take() { + split.push(&bytes[start..idx]); + } + } else if start.is_none() { + start = Some(idx); + } + } + split +} diff --git a/src/pcs/kzg/decider.rs b/src/pcs/kzg/decider.rs index de3e2a06..3a3ba096 100644 --- a/src/pcs/kzg/decider.rs +++ b/src/pcs/kzg/decider.rs @@ -132,14 +132,8 @@ mod evm { let hash_ptr = loader.keccak256(lhs[0].ptr(), lhs.len() * 0x80); let challenge_ptr = loader.allocate(0x20); - loader - .code_mut() - .push(loader.scalar_modulus()) - .push(hash_ptr) - .mload() - .r#mod() - .push(challenge_ptr) - .mstore(); + let code = format!("mstore({challenge_ptr}, mod(mload({hash_ptr}), f_q))"); + loader.code_mut().runtime_append(code); let challenge = loader.scalar(Value::Memory(challenge_ptr)); let powers_of_challenge = LoadedScalar::::powers(&challenge, lhs.len()); diff --git a/src/system/halo2/test/kzg/evm.rs b/src/system/halo2/test/kzg/evm.rs index 4e57d369..1ab52083 100644 --- a/src/system/halo2/test/kzg/evm.rs +++ b/src/system/halo2/test/kzg/evm.rs @@ -24,7 +24,7 @@ macro_rules! halo2_kzg_evm_verify { use halo2_proofs::poly::commitment::ParamsProver; use std::rc::Rc; use $crate::{ - loader::evm::{encode_calldata, execute, EvmLoader}, + loader::evm::{compile_yul, encode_calldata, execute, EvmLoader}, system::halo2::{ test::kzg::{BITS, LIMBS}, transcript::evm::EvmTranscript, @@ -34,7 +34,7 @@ macro_rules! halo2_kzg_evm_verify { }; let loader = EvmLoader::new::(); - let runtime_code = { + let deployment_code = { let svk = $params.get_g()[0].into(); let dk = ($params.g2(), $params.s_g2()).into(); let protocol = $protocol.loaded(&loader); @@ -49,11 +49,11 @@ macro_rules! halo2_kzg_evm_verify { .unwrap(); <$plonk_verifier>::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); - loader.runtime_code() + compile_yul(&loader.yul_code()) }; let (accept, total_cost, costs) = - execute(runtime_code, encode_calldata($instances, &$proof)); + execute(deployment_code, encode_calldata($instances, &$proof)); loader.print_gas_metering(costs); println!("Total gas cost: {}", total_cost); diff --git a/src/system/halo2/transcript/evm.rs b/src/system/halo2/transcript/evm.rs index e461bc05..32d60b8f 100644 --- a/src/system/halo2/transcript/evm.rs +++ b/src/system/halo2/transcript/evm.rs @@ -73,11 +73,9 @@ where fn squeeze_challenge(&mut self) -> Scalar { let len = if self.buf.len() == 0x20 { assert_eq!(self.loader.ptr(), self.buf.end()); - self.loader - .code_mut() - .push(1) - .push(self.buf.end()) - .mstore8(); + let buf_end = self.buf.end(); + let code = format!("mstore8({buf_end}, 1)"); + self.loader.code_mut().runtime_append(code); 0x21 } else { self.buf.len() @@ -86,17 +84,14 @@ where let challenge_ptr = self.loader.allocate(0x20); let dup_hash_ptr = self.loader.allocate(0x20); - self.loader - .code_mut() - .push(hash_ptr) - .mload() - .push(self.loader.scalar_modulus()) - .dup(1) - .r#mod() - .push(challenge_ptr) - .mstore() - .push(dup_hash_ptr) - .mstore(); + let code = format!( + "{{ + let hash := mload({hash_ptr:#x}) + mstore({challenge_ptr:#x}, mod(hash, f_q)) + mstore({dup_hash_ptr:#x}, hash) + }}" + ); + self.loader.code_mut().runtime_append(code); self.buf.reset(dup_hash_ptr); self.buf.extend(0x20); From 5e5de91c5dae319287e1bc30004a430ee74c915f Mon Sep 17 00:00:00 2001 From: Han Date: Wed, 30 Nov 2022 02:18:44 -0800 Subject: [PATCH 07/73] fix: pin all `revm` dependencies (#18) --- Cargo.toml | 10 +++++----- examples/evm-verifier-with-accumulator.rs | 3 +-- examples/evm-verifier.rs | 3 +-- src/loader/evm.rs | 6 ++---- src/loader/evm/loader.rs | 3 +-- src/loader/evm/test.rs | 3 +-- src/loader/evm/test/tui.rs | 6 ++++-- src/loader/evm/util.rs | 3 ++- src/loader/evm/util/executor.rs | 11 +---------- src/pcs/kzg/decider.rs | 3 +-- src/system/halo2/transcript/evm.rs | 3 +-- src/util/protocol.rs | 5 ++++- src/verifier/plonk.rs | 13 +++++++------ 13 files changed, 31 insertions(+), 41 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 44dcd60b..eaea3b94 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,11 +20,11 @@ rayon = { version = "1.5.3", optional = true } halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2022_10_22", optional = true } # loader_evm -ethereum_types = { package = "ethereum-types", version = "0.13", default-features = false, features = ["std"], optional = true } sha3 = { version = "0.10", optional = true } -revm = { version = "2.1.0", optional = true } -bytes = { version = "1.2", optional = true } -rlp = { version = "0.5", default-features = false, features = ["std"], optional = true } +bytes = { version = "1.1.0", default-features = false, optional = true } +primitive-types = { version = "0.12.1", default-features = false, features = ["std"], optional = true } +rlp = { version = "0.5.2", default-features = false, features = ["std"], optional = true } +revm = { version = "= 2.3.1", optional = true } # loader_halo2 halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc", optional = true } @@ -46,7 +46,7 @@ default = ["loader_evm", "loader_halo2", "system_halo2"] parallel = ["dep:rayon"] -loader_evm = ["dep:ethereum_types", "dep:sha3", "dep:revm", "dep:bytes", "dep:rlp"] +loader_evm = ["dep:bytes", "dep:sha3", "dep:primitive-types", "dep:rlp", "dep:revm"] loader_halo2 = ["dep:halo2_proofs", "dep:halo2_wrong_ecc", "dep:poseidon"] system_halo2 = ["dep:halo2_proofs"] diff --git a/examples/evm-verifier-with-accumulator.rs b/examples/evm-verifier-with-accumulator.rs index 8f08883d..95d0f69a 100644 --- a/examples/evm-verifier-with-accumulator.rs +++ b/examples/evm-verifier-with-accumulator.rs @@ -1,4 +1,3 @@ -use ethereum_types::Address; use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ dev::MockProver, @@ -17,7 +16,7 @@ use halo2_proofs::{ use itertools::Itertools; use plonk_verifier::{ loader::{ - evm::{self, encode_calldata, EvmLoader, ExecutorBuilder}, + evm::{self, encode_calldata, Address, EvmLoader, ExecutorBuilder}, native::NativeLoader, }, pcs::kzg::{Gwc19, Kzg, KzgAs, LimbsEncoding}, diff --git a/examples/evm-verifier.rs b/examples/evm-verifier.rs index b45bb59d..a85665a8 100644 --- a/examples/evm-verifier.rs +++ b/examples/evm-verifier.rs @@ -1,4 +1,3 @@ -use ethereum_types::Address; use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, @@ -20,7 +19,7 @@ use halo2_proofs::{ }; use itertools::Itertools; use plonk_verifier::{ - loader::evm::{self, encode_calldata, EvmLoader, ExecutorBuilder}, + loader::evm::{self, encode_calldata, Address, EvmLoader, ExecutorBuilder}, pcs::kzg::{Gwc19, Kzg}, system::halo2::{compile, transcript::evm::EvmTranscript, Config}, verifier::{self, PlonkVerifier}, diff --git a/src/loader/evm.rs b/src/loader/evm.rs index 263da0e2..c11670d8 100644 --- a/src/loader/evm.rs +++ b/src/loader/evm.rs @@ -7,11 +7,9 @@ mod test; pub use loader::{EcPoint, EvmLoader, Scalar}; pub use util::{ - compile_yul, encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, ExecutorBuilder, - MemoryChunk, + compile_yul, encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, Address, + ExecutorBuilder, MemoryChunk, H256, U256, U512, }; -pub use ethereum_types::U256; - #[cfg(test)] pub use test::execute; diff --git a/src/loader/evm/loader.rs b/src/loader/evm/loader.rs index c630a468..fdd0ee9c 100644 --- a/src/loader/evm/loader.rs +++ b/src/loader/evm/loader.rs @@ -2,7 +2,7 @@ use crate::{ loader::{ evm::{ code::{Precompiled, YulCode}, - fe_to_u256, modulus, u256_to_fe, + fe_to_u256, modulus, u256_to_fe, U256, U512, }, EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader, }, @@ -12,7 +12,6 @@ use crate::{ }, Error, }; -use ethereum_types::{U256, U512}; use hex; use std::{ cell::RefCell, diff --git a/src/loader/evm/test.rs b/src/loader/evm/test.rs index e6f3703e..e3467408 100644 --- a/src/loader/evm/test.rs +++ b/src/loader/evm/test.rs @@ -1,8 +1,7 @@ use crate::{ - loader::evm::{test::tui::Tui, util::ExecutorBuilder}, + loader::evm::{test::tui::Tui, Address, ExecutorBuilder, U256}, util::Itertools, }; -use ethereum_types::{Address, U256}; use std::env::var_os; mod tui; diff --git a/src/loader/evm/test/tui.rs b/src/loader/evm/test/tui.rs index c0c4d7f8..455f308b 100644 --- a/src/loader/evm/test/tui.rs +++ b/src/loader/evm/test/tui.rs @@ -1,6 +1,9 @@ //! Copied and modified from https://github.com/foundry-rs/foundry/blob/master/ui/src/lib.rs -use crate::loader::evm::util::executor::{CallKind, DebugStep}; +use crate::loader::evm::{ + util::executor::{CallKind, DebugStep}, + Address, +}; use crossterm::{ event::{ self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers, @@ -9,7 +12,6 @@ use crossterm::{ execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; -use ethereum_types::Address; use revm::opcode; use std::{ cmp::{max, min}, diff --git a/src/loader/evm/util.rs b/src/loader/evm/util.rs index a7df5209..16eaa08d 100644 --- a/src/loader/evm/util.rs +++ b/src/loader/evm/util.rs @@ -2,13 +2,14 @@ use crate::{ cost::Cost, util::{arithmetic::PrimeField, Itertools}, }; -use ethereum_types::U256; use std::{ io::Write, iter, process::{Command, Stdio}, }; +pub use primitive_types::{H160 as Address, H256, U256, U512}; + pub(crate) mod executor; pub use executor::ExecutorBuilder; diff --git a/src/loader/evm/util/executor.rs b/src/loader/evm/util/executor.rs index ec9695e0..47a80658 100644 --- a/src/loader/evm/util/executor.rs +++ b/src/loader/evm/util/executor.rs @@ -1,7 +1,7 @@ //! Copied and modified from https://github.com/foundry-rs/foundry/blob/master/evm/src/executor/mod.rs +use crate::loader::evm::{Address, H256, U256}; use bytes::Bytes; -use ethereum_types::{Address, H256, U256, U64}; use revm::{ evm_inner, opcode, spec_opcode_gas, Account, BlockEnv, CallInputs, CallScheme, CreateInputs, CreateScheme, Database, DatabaseCommit, EVMData, Env, ExecutionResult, Gas, GasInspector, @@ -77,14 +77,6 @@ pub struct Log { pub address: Address, pub topics: Vec, pub data: Bytes, - pub block_hash: Option, - pub block_number: Option, - pub transaction_hash: Option, - pub transaction_index: Option, - pub log_index: Option, - pub transaction_log_index: Option, - pub log_type: Option, - pub removed: Option, } #[derive(Clone, Debug, Default)] @@ -98,7 +90,6 @@ impl Inspector for LogCollector { address: *address, topics: topics.to_vec(), data: data.clone(), - ..Default::default() }); } diff --git a/src/pcs/kzg/decider.rs b/src/pcs/kzg/decider.rs index 3a3ba096..1ec0eb09 100644 --- a/src/pcs/kzg/decider.rs +++ b/src/pcs/kzg/decider.rs @@ -69,7 +69,7 @@ mod native { mod evm { use crate::{ loader::{ - evm::{loader::Value, EvmLoader}, + evm::{loader::Value, EvmLoader, U256}, LoadedScalar, }, pcs::{ @@ -81,7 +81,6 @@ mod evm { msm::Msm, }, }; - use ethereum_types::U256; use std::{fmt::Debug, rc::Rc}; impl Decider> for Kzg diff --git a/src/system/halo2/transcript/evm.rs b/src/system/halo2/transcript/evm.rs index 32d60b8f..68c3ae4a 100644 --- a/src/system/halo2/transcript/evm.rs +++ b/src/system/halo2/transcript/evm.rs @@ -1,6 +1,6 @@ use crate::{ loader::{ - evm::{loader::Value, u256_to_fe, EcPoint, EvmLoader, MemoryChunk, Scalar}, + evm::{loader::Value, u256_to_fe, EcPoint, EvmLoader, MemoryChunk, Scalar, U256}, native::{self, NativeLoader}, Loader, }, @@ -12,7 +12,6 @@ use crate::{ }, Error, }; -use ethereum_types::U256; use halo2_proofs::transcript::EncodedChallenge; use std::{ io::{self, Read, Write}, diff --git a/src/util/protocol.rs b/src/util/protocol.rs index f7747060..2eaf604e 100644 --- a/src/util/protocol.rs +++ b/src/util/protocol.rs @@ -149,7 +149,10 @@ pub struct QuotientPolynomial { impl QuotientPolynomial { pub fn num_chunk(&self) -> usize { - Integer::div_ceil(&(self.numerator.degree() - 1), &self.chunk_degree) + Integer::div_ceil( + &(self.numerator.degree().checked_sub(1).unwrap_or_default()), + &self.chunk_degree, + ) } } diff --git a/src/verifier/plonk.rs b/src/verifier/plonk.rs index df208949..3bfcf9c0 100644 --- a/src/verifier/plonk.rs +++ b/src/verifier/plonk.rs @@ -1,6 +1,6 @@ use crate::{ cost::{Cost, CostEstimation}, - loader::{native::NativeLoader, LoadedScalar, Loader}, + loader::{LoadedScalar, Loader}, pcs::{self, AccumulatorEncoding, MultiOpenScheme}, util::{ arithmetic::{CurveAffine, Field, Rotation}, @@ -394,14 +394,15 @@ where } } -impl CostEstimation<(C, MOS)> for Plonk +impl CostEstimation<(C, L, MOS)> for Plonk where C: CurveAffine, - MOS: MultiOpenScheme + CostEstimation>>, + L: Loader, + MOS: MultiOpenScheme + CostEstimation>>, { - type Input = Protocol; + type Input = Protocol; - fn estimate_cost(protocol: &Protocol) -> Cost { + fn estimate_cost(protocol: &Protocol) -> Cost { let plonk_cost = { let num_accumulator = protocol.accumulator_indices.len(); let num_instance = protocol.num_instance.iter().sum(); @@ -412,7 +413,7 @@ where Cost::new(num_instance, num_commitment, num_evaluation, num_msm) }; let pcs_cost = { - let queries = PlonkProof::::empty_queries(protocol); + let queries = PlonkProof::::empty_queries(protocol); MOS::estimate_cost(&queries) }; plonk_cost + pcs_cost From 50d69c18f66f9d0b6917ab8e9cb33be3b5a4f468 Mon Sep 17 00:00:00 2001 From: Han Date: Sat, 17 Dec 2022 12:44:08 +0800 Subject: [PATCH 08/73] fix: looser trait bound on impl `CostEstimation` for `Plonk` (#20) --- src/verifier/plonk.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/verifier/plonk.rs b/src/verifier/plonk.rs index 3bfcf9c0..e29410d3 100644 --- a/src/verifier/plonk.rs +++ b/src/verifier/plonk.rs @@ -394,7 +394,7 @@ where } } -impl CostEstimation<(C, L, MOS)> for Plonk +impl CostEstimation<(C, L)> for Plonk where C: CurveAffine, L: Loader, From dda742375cf87a268cba416b85a1d1b4e3383378 Mon Sep 17 00:00:00 2001 From: Han Date: Fri, 23 Dec 2022 15:31:23 +0800 Subject: [PATCH 09/73] Restructure for more kind of verifier (#21) * feat: restructure to monorepo and expand the project scope to be generic (s)nark verifier * feat: reorganize mods and traits for further new features * refactor: simplify trait bounds * chore: use hyphen case for crate name (`snark_verifier` -> `snark-verifier`) --- Cargo.toml | 64 +-- README.md | 4 +- snark-verifier/Cargo.toml | 60 +++ .../evm-verifier-with-accumulator.rs | 59 +- .../examples}/evm-verifier.rs | 17 +- snark-verifier/src/cost.rs | 29 + snark-verifier/src/lib.rs | 18 + {src => snark-verifier/src}/loader.rs | 0 {src => snark-verifier/src}/loader/evm.rs | 0 .../src}/loader/evm/code.rs | 0 .../src}/loader/evm/loader.rs | 0 .../src}/loader/evm/test.rs | 0 .../src}/loader/evm/test/tui.rs | 0 .../src}/loader/evm/util.rs | 2 +- .../src}/loader/evm/util/executor.rs | 0 snark-verifier/src/loader/halo2.rs | 29 + .../src}/loader/halo2/loader.rs | 0 .../src}/loader/halo2/shim.rs | 0 .../src}/loader/halo2/test.rs | 10 +- {src => snark-verifier/src}/loader/native.rs | 0 {src => snark-verifier/src}/pcs.rs | 81 ++- {src => snark-verifier/src}/pcs/ipa.rs | 32 +- .../src}/pcs/ipa/accumulation.rs | 49 +- .../src}/pcs/ipa/accumulator.rs | 0 snark-verifier/src/pcs/ipa/decider.rs | 65 +++ snark-verifier/src/pcs/ipa/multiopen.rs | 3 + .../src}/pcs/ipa/multiopen/bgh19.rs | 40 +- {src => snark-verifier/src}/pcs/kzg.rs | 19 +- .../src}/pcs/kzg/accumulation.rs | 65 +-- .../src}/pcs/kzg/accumulator.rs | 41 +- .../src}/pcs/kzg/decider.rs | 75 ++- .../src}/pcs/kzg/multiopen.rs | 0 .../src}/pcs/kzg/multiopen/bdfg21.rs | 21 +- .../src}/pcs/kzg/multiopen/gwc19.rs | 25 +- {src => snark-verifier/src}/system.rs | 0 {src => snark-verifier/src}/system/halo2.rs | 12 +- .../src}/system/halo2/strategy.rs | 0 .../src}/system/halo2/test.rs | 10 +- .../src}/system/halo2/test/circuit.rs | 0 .../system/halo2/test/circuit/maingate.rs | 0 .../system/halo2/test/circuit/standard.rs | 0 .../src}/system/halo2/test/ipa.rs | 13 +- .../src}/system/halo2/test/ipa/native.rs | 6 +- .../src}/system/halo2/test/kzg.rs | 3 +- .../src}/system/halo2/test/kzg/evm.rs | 21 +- .../src}/system/halo2/test/kzg/halo2.rs | 31 +- .../src}/system/halo2/test/kzg/native.rs | 8 +- .../src}/system/halo2/transcript.rs | 0 .../src}/system/halo2/transcript/evm.rs | 0 .../src}/system/halo2/transcript/halo2.rs | 0 {src => snark-verifier/src}/util.rs | 1 - .../src}/util/arithmetic.rs | 0 {src => snark-verifier/src}/util/hash.rs | 0 .../src}/util/hash/poseidon.rs | 0 {src => snark-verifier/src}/util/msm.rs | 0 {src => snark-verifier/src}/util/poly.rs | 0 {src => snark-verifier/src}/util/protocol.rs | 32 -- .../src}/util/transcript.rs | 0 snark-verifier/src/verifier.rs | 35 ++ snark-verifier/src/verifier/plonk.rs | 173 ++++++ .../src/verifier/plonk/proof.rs | 192 ++----- snark-verifier/src/verifier/plonk/protocol.rs | 503 ++++++++++++++++++ src/cost.rs | 44 -- src/lib.rs | 42 -- src/loader/halo2.rs | 69 --- src/pcs/ipa/decider.rs | 57 -- src/pcs/ipa/multiopen.rs | 3 - src/verifier.rs | 51 -- 68 files changed, 1268 insertions(+), 846 deletions(-) create mode 100644 snark-verifier/Cargo.toml rename {examples => snark-verifier/examples}/evm-verifier-with-accumulator.rs (92%) rename {examples => snark-verifier/examples}/evm-verifier.rs (94%) create mode 100644 snark-verifier/src/cost.rs create mode 100644 snark-verifier/src/lib.rs rename {src => snark-verifier/src}/loader.rs (100%) rename {src => snark-verifier/src}/loader/evm.rs (100%) rename {src => snark-verifier/src}/loader/evm/code.rs (100%) rename {src => snark-verifier/src}/loader/evm/loader.rs (100%) rename {src => snark-verifier/src}/loader/evm/test.rs (100%) rename {src => snark-verifier/src}/loader/evm/test/tui.rs (100%) rename {src => snark-verifier/src}/loader/evm/util.rs (97%) rename {src => snark-verifier/src}/loader/evm/util/executor.rs (100%) create mode 100644 snark-verifier/src/loader/halo2.rs rename {src => snark-verifier/src}/loader/halo2/loader.rs (100%) rename {src => snark-verifier/src}/loader/halo2/shim.rs (100%) rename {src => snark-verifier/src}/loader/halo2/test.rs (85%) rename {src => snark-verifier/src}/loader/native.rs (100%) rename {src => snark-verifier/src}/pcs.rs (62%) rename {src => snark-verifier/src}/pcs/ipa.rs (94%) rename {src => snark-verifier/src}/pcs/ipa/accumulation.rs (84%) rename {src => snark-verifier/src}/pcs/ipa/accumulator.rs (100%) create mode 100644 snark-verifier/src/pcs/ipa/decider.rs create mode 100644 snark-verifier/src/pcs/ipa/multiopen.rs rename {src => snark-verifier/src}/pcs/ipa/multiopen/bgh19.rs (92%) rename {src => snark-verifier/src}/pcs/kzg.rs (61%) rename {src => snark-verifier/src}/pcs/kzg/accumulation.rs (70%) rename {src => snark-verifier/src}/pcs/kzg/accumulator.rs (85%) rename {src => snark-verifier/src}/pcs/kzg/decider.rs (66%) rename {src => snark-verifier/src}/pcs/kzg/multiopen.rs (100%) rename {src => snark-verifier/src}/pcs/kzg/multiopen/bdfg21.rs (95%) rename {src => snark-verifier/src}/pcs/kzg/multiopen/gwc19.rs (87%) rename {src => snark-verifier/src}/system.rs (100%) rename {src => snark-verifier/src}/system/halo2.rs (99%) rename {src => snark-verifier/src}/system/halo2/strategy.rs (100%) rename {src => snark-verifier/src}/system/halo2/test.rs (95%) rename {src => snark-verifier/src}/system/halo2/test/circuit.rs (100%) rename {src => snark-verifier/src}/system/halo2/test/circuit/maingate.rs (100%) rename {src => snark-verifier/src}/system/halo2/test/circuit/standard.rs (100%) rename {src => snark-verifier/src}/system/halo2/test/ipa.rs (91%) rename {src => snark-verifier/src}/system/halo2/test/ipa/native.rs (92%) rename {src => snark-verifier/src}/system/halo2/test/kzg.rs (97%) rename {src => snark-verifier/src}/system/halo2/test/kzg/evm.rs (85%) rename {src => snark-verifier/src}/system/halo2/test/kzg/halo2.rs (92%) rename {src => snark-verifier/src}/system/halo2/test/kzg/native.rs (88%) rename {src => snark-verifier/src}/system/halo2/transcript.rs (100%) rename {src => snark-verifier/src}/system/halo2/transcript/evm.rs (100%) rename {src => snark-verifier/src}/system/halo2/transcript/halo2.rs (100%) rename {src => snark-verifier/src}/util.rs (98%) rename {src => snark-verifier/src}/util/arithmetic.rs (100%) rename {src => snark-verifier/src}/util/hash.rs (100%) rename {src => snark-verifier/src}/util/hash/poseidon.rs (100%) rename {src => snark-verifier/src}/util/msm.rs (100%) rename {src => snark-verifier/src}/util/poly.rs (100%) rename {src => snark-verifier/src}/util/protocol.rs (90%) rename {src => snark-verifier/src}/util/transcript.rs (100%) create mode 100644 snark-verifier/src/verifier.rs create mode 100644 snark-verifier/src/verifier/plonk.rs rename src/verifier/plonk.rs => snark-verifier/src/verifier/plonk/proof.rs (65%) create mode 100644 snark-verifier/src/verifier/plonk/protocol.rs delete mode 100644 src/cost.rs delete mode 100644 src/lib.rs delete mode 100644 src/loader/halo2.rs delete mode 100644 src/pcs/ipa/decider.rs delete mode 100644 src/pcs/ipa/multiopen.rs delete mode 100644 src/verifier.rs diff --git a/Cargo.toml b/Cargo.toml index eaea3b94..180136fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,60 +1,4 @@ -[package] -name = "plonk_verifier" -version = "0.1.0" -edition = "2021" - -[dependencies] -itertools = "0.10.3" -lazy_static = "1.4.0" -num-bigint = "0.4.3" -num-integer = "0.1.45" -num-traits = "0.2.15" -rand = "0.8" -hex = "0.4" -halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.0", package = "halo2curves" } - -# parallel -rayon = { version = "1.5.3", optional = true } - -# system_halo2 -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2022_10_22", optional = true } - -# loader_evm -sha3 = { version = "0.10", optional = true } -bytes = { version = "1.1.0", default-features = false, optional = true } -primitive-types = { version = "0.12.1", default-features = false, features = ["std"], optional = true } -rlp = { version = "0.5.2", default-features = false, features = ["std"], optional = true } -revm = { version = "= 2.3.1", optional = true } - -# loader_halo2 -halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc", optional = true } -poseidon = { git = "https://github.com/privacy-scaling-explorations/poseidon", tag = "v2022_10_22", optional = true } - -[dev-dependencies] -rand_chacha = "0.3.1" -paste = "1.0.7" - -# system_halo2 -halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc" } - -# loader_evm -crossterm = { version = "0.25" } -tui = { version = "0.19", default-features = false, features = ["crossterm"] } - -[features] -default = ["loader_evm", "loader_halo2", "system_halo2"] - -parallel = ["dep:rayon"] - -loader_evm = ["dep:bytes", "dep:sha3", "dep:primitive-types", "dep:rlp", "dep:revm"] -loader_halo2 = ["dep:halo2_proofs", "dep:halo2_wrong_ecc", "dep:poseidon"] - -system_halo2 = ["dep:halo2_proofs"] - -[[example]] -name = "evm-verifier" -required-features = ["loader_evm", "system_halo2"] - -[[example]] -name = "evm-verifier-with-accumulator" -required-features = ["loader_halo2", "loader_evm", "system_halo2"] +[workspace] +members = [ + "snark-verifier", +] diff --git a/README.md b/README.md index bcd16c74..db401c9f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,3 @@ -# PLONK Verifier +# SNARK Verifier -Generic PLONK verifier. +Generic (S)NARK verifier. diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml new file mode 100644 index 00000000..0d32d22f --- /dev/null +++ b/snark-verifier/Cargo.toml @@ -0,0 +1,60 @@ +[package] +name = "snark-verifier" +version = "0.1.0" +edition = "2021" + +[dependencies] +itertools = "0.10.3" +lazy_static = "1.4.0" +num-bigint = "0.4.3" +num-integer = "0.1.45" +num-traits = "0.2.15" +rand = "0.8" +hex = "0.4" +halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.0", package = "halo2curves" } + +# parallel +rayon = { version = "1.5.3", optional = true } + +# system_halo2 +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2022_10_22", optional = true } + +# loader_evm +sha3 = { version = "0.10", optional = true } +bytes = { version = "1.1.0", default-features = false, optional = true } +primitive-types = { version = "0.12.1", default-features = false, features = ["std"], optional = true } +rlp = { version = "0.5.2", default-features = false, features = ["std"], optional = true } +revm = { version = "= 2.3.1", optional = true } + +# loader_halo2 +halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc", optional = true } +poseidon = { git = "https://github.com/privacy-scaling-explorations/poseidon", tag = "v2022_10_22", optional = true } + +[dev-dependencies] +rand_chacha = "0.3.1" +paste = "1.0.7" + +# system_halo2 +halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc" } + +# loader_evm +crossterm = { version = "0.25" } +tui = { version = "0.19", default-features = false, features = ["crossterm"] } + +[features] +default = ["loader_evm", "loader_halo2", "system_halo2"] + +parallel = ["dep:rayon"] + +loader_evm = ["dep:bytes", "dep:sha3", "dep:primitive-types", "dep:rlp", "dep:revm"] +loader_halo2 = ["dep:halo2_proofs", "dep:halo2_wrong_ecc", "dep:poseidon"] + +system_halo2 = ["dep:halo2_proofs"] + +[[example]] +name = "evm-verifier" +required-features = ["loader_evm", "system_halo2"] + +[[example]] +name = "evm-verifier-with-accumulator" +required-features = ["loader_halo2", "loader_evm", "system_halo2"] diff --git a/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs similarity index 92% rename from examples/evm-verifier-with-accumulator.rs rename to snark-verifier/examples/evm-verifier-with-accumulator.rs index 95d0f69a..ba23e352 100644 --- a/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -14,24 +14,24 @@ use halo2_proofs::{ transcript::{EncodedChallenge, TranscriptReadBuffer, TranscriptWriterBuffer}, }; use itertools::Itertools; -use plonk_verifier::{ +use rand::rngs::OsRng; +use snark_verifier::{ loader::{ evm::{self, encode_calldata, Address, EvmLoader, ExecutorBuilder}, native::NativeLoader, }, - pcs::kzg::{Gwc19, Kzg, KzgAs, LimbsEncoding}, + pcs::kzg::{Gwc19, KzgAs, LimbsEncoding}, system::halo2::{compile, transcript::evm::EvmTranscript, Config}, - verifier::{self, PlonkVerifier}, + verifier::{self, SnarkVerifier}, }; -use rand::rngs::OsRng; use std::{io::Cursor, rc::Rc}; const LIMBS: usize = 4; const BITS: usize = 68; -type Pcs = Kzg; -type As = KzgAs; -type Plonk = verifier::Plonk>; +type As = KzgAs; +type PlonkSuccinctVerifier = verifier::plonk::PlonkSuccinctVerifier>; +type PlonkVerifier = verifier::plonk::PlonkVerifier>; mod application { use halo2_curves::bn256::Fr; @@ -161,7 +161,7 @@ mod application { } mod aggregation { - use super::{As, Plonk, BITS, LIMBS}; + use super::{As, PlonkSuccinctVerifier, BITS, LIMBS}; use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, @@ -177,7 +177,8 @@ mod aggregation { EccConfig, }; use itertools::Itertools; - use plonk_verifier::{ + use rand::rngs::OsRng; + use snark_verifier::{ loader::{self, native::NativeLoader}, pcs::{ kzg::{KzgAccumulator, KzgSuccinctVerifyingKey, LimbsEncodingInstructions}, @@ -185,10 +186,8 @@ mod aggregation { }, system, util::arithmetic::{fe_to_limbs, FieldExt}, - verifier::PlonkVerifier, - Protocol, + verifier::{plonk::PlonkProtocol, SnarkVerifier}, }; - use rand::rngs::OsRng; use std::rc::Rc; const T: usize = 5; @@ -203,13 +202,17 @@ mod aggregation { system::halo2::transcript::halo2::PoseidonTranscript; pub struct Snark { - protocol: Protocol, + protocol: PlonkProtocol, instances: Vec>, proof: Vec, } impl Snark { - pub fn new(protocol: Protocol, instances: Vec>, proof: Vec) -> Self { + pub fn new( + protocol: PlonkProtocol, + instances: Vec>, + proof: Vec, + ) -> Self { Self { protocol, instances, @@ -234,7 +237,7 @@ mod aggregation { #[derive(Clone)] pub struct SnarkWitness { - protocol: Protocol, + protocol: PlonkProtocol, instances: Vec>>, proof: Value>, } @@ -282,8 +285,10 @@ mod aggregation { let instances = assign_instances(&snark.instances); let mut transcript = PoseidonTranscript::, _>::new(loader, snark.proof()); - let proof = Plonk::read_proof(svk, &protocol, &instances, &mut transcript).unwrap(); - Plonk::succinct_verify(svk, &protocol, &instances, &proof).unwrap() + let proof = + PlonkSuccinctVerifier::read_proof(svk, &protocol, &instances, &mut transcript) + .unwrap(); + PlonkSuccinctVerifier::verify(svk, &protocol, &instances, &proof).unwrap() }) .collect_vec(); @@ -352,10 +357,15 @@ mod aggregation { .flat_map(|snark| { let mut transcript = PoseidonTranscript::::new(snark.proof.as_slice()); - let proof = - Plonk::read_proof(&svk, &snark.protocol, &snark.instances, &mut transcript) - .unwrap(); - Plonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof).unwrap() + let proof = PlonkSuccinctVerifier::read_proof( + &svk, + &snark.protocol, + &snark.instances, + &mut transcript, + ) + .unwrap(); + PlonkSuccinctVerifier::verify(&svk, &snark.protocol, &snark.instances, &proof) + .unwrap() }) .collect_vec(); @@ -551,8 +561,6 @@ fn gen_aggregation_evm_verifier( num_instance: Vec, accumulator_indices: Vec<(usize, usize)>, ) -> Vec { - let svk = params.get_g()[0].into(); - let dk = (params.g2(), params.s_g2()).into(); let protocol = compile( params, vk, @@ -560,14 +568,15 @@ fn gen_aggregation_evm_verifier( .with_num_instance(num_instance.clone()) .with_accumulator_indices(Some(accumulator_indices)), ); + let vk = (params.get_g()[0], params.g2(), params.s_g2()).into(); let loader = EvmLoader::new::(); let protocol = protocol.loaded(&loader); let mut transcript = EvmTranscript::<_, Rc, _, _>::new(&loader); let instances = transcript.load_instances(num_instance); - let proof = Plonk::read_proof(&svk, &protocol, &instances, &mut transcript).unwrap(); - Plonk::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); + let proof = PlonkVerifier::read_proof(&vk, &protocol, &instances, &mut transcript).unwrap(); + PlonkVerifier::verify(&vk, &protocol, &instances, &proof).unwrap(); evm::compile_yul(&loader.yul_code()) } diff --git a/examples/evm-verifier.rs b/snark-verifier/examples/evm-verifier.rs similarity index 94% rename from examples/evm-verifier.rs rename to snark-verifier/examples/evm-verifier.rs index a85665a8..58b08074 100644 --- a/examples/evm-verifier.rs +++ b/snark-verifier/examples/evm-verifier.rs @@ -18,16 +18,16 @@ use halo2_proofs::{ transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, }; use itertools::Itertools; -use plonk_verifier::{ +use rand::{rngs::OsRng, RngCore}; +use snark_verifier::{ loader::evm::{self, encode_calldata, Address, EvmLoader, ExecutorBuilder}, - pcs::kzg::{Gwc19, Kzg}, + pcs::kzg::{Gwc19, KzgAs}, system::halo2::{compile, transcript::evm::EvmTranscript, Config}, - verifier::{self, PlonkVerifier}, + verifier::{self, SnarkVerifier}, }; -use rand::{rngs::OsRng, RngCore}; use std::rc::Rc; -type Plonk = verifier::Plonk>; +type PlonkVerifier = verifier::plonk::PlonkVerifier>; #[derive(Clone, Copy)] struct StandardPlonkConfig { @@ -205,21 +205,20 @@ fn gen_evm_verifier( vk: &VerifyingKey, num_instance: Vec, ) -> Vec { - let svk = params.get_g()[0].into(); - let dk = (params.g2(), params.s_g2()).into(); let protocol = compile( params, vk, Config::kzg().with_num_instance(num_instance.clone()), ); + let vk = (params.get_g()[0], params.g2(), params.s_g2()).into(); let loader = EvmLoader::new::(); let protocol = protocol.loaded(&loader); let mut transcript = EvmTranscript::<_, Rc, _, _>::new(&loader); let instances = transcript.load_instances(num_instance); - let proof = Plonk::read_proof(&svk, &protocol, &instances, &mut transcript).unwrap(); - Plonk::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); + let proof = PlonkVerifier::read_proof(&vk, &protocol, &instances, &mut transcript).unwrap(); + PlonkVerifier::verify(&vk, &protocol, &instances, &proof).unwrap(); evm::compile_yul(&loader.yul_code()) } diff --git a/snark-verifier/src/cost.rs b/snark-verifier/src/cost.rs new file mode 100644 index 00000000..a85d6af4 --- /dev/null +++ b/snark-verifier/src/cost.rs @@ -0,0 +1,29 @@ +use std::ops::Add; + +#[derive(Debug, Default, Clone, PartialEq, Eq)] +pub struct Cost { + pub num_instance: usize, + pub num_commitment: usize, + pub num_evaluation: usize, + pub num_msm: usize, + pub num_pairing: usize, +} + +impl Add for Cost { + type Output = Cost; + + fn add(mut self, rhs: Cost) -> Self::Output { + self.num_instance += rhs.num_instance; + self.num_commitment += rhs.num_commitment; + self.num_evaluation += rhs.num_evaluation; + self.num_msm += rhs.num_msm; + self.num_pairing += rhs.num_pairing; + self + } +} + +pub trait CostEstimation { + type Input; + + fn estimate_cost(input: &Self::Input) -> Cost; +} diff --git a/snark-verifier/src/lib.rs b/snark-verifier/src/lib.rs new file mode 100644 index 00000000..c2b9350a --- /dev/null +++ b/snark-verifier/src/lib.rs @@ -0,0 +1,18 @@ +#![allow(clippy::type_complexity)] +#![allow(clippy::too_many_arguments)] +#![allow(clippy::upper_case_acronyms)] + +pub mod cost; +pub mod loader; +pub mod pcs; +pub mod system; +pub mod util; +pub mod verifier; + +#[derive(Clone, Debug)] +pub enum Error { + InvalidInstances, + InvalidProtocol(String), + AssertionFailure(String), + Transcript(std::io::ErrorKind, String), +} diff --git a/src/loader.rs b/snark-verifier/src/loader.rs similarity index 100% rename from src/loader.rs rename to snark-verifier/src/loader.rs diff --git a/src/loader/evm.rs b/snark-verifier/src/loader/evm.rs similarity index 100% rename from src/loader/evm.rs rename to snark-verifier/src/loader/evm.rs diff --git a/src/loader/evm/code.rs b/snark-verifier/src/loader/evm/code.rs similarity index 100% rename from src/loader/evm/code.rs rename to snark-verifier/src/loader/evm/code.rs diff --git a/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs similarity index 100% rename from src/loader/evm/loader.rs rename to snark-verifier/src/loader/evm/loader.rs diff --git a/src/loader/evm/test.rs b/snark-verifier/src/loader/evm/test.rs similarity index 100% rename from src/loader/evm/test.rs rename to snark-verifier/src/loader/evm/test.rs diff --git a/src/loader/evm/test/tui.rs b/snark-verifier/src/loader/evm/test/tui.rs similarity index 100% rename from src/loader/evm/test/tui.rs rename to snark-verifier/src/loader/evm/test/tui.rs diff --git a/src/loader/evm/util.rs b/snark-verifier/src/loader/evm/util.rs similarity index 97% rename from src/loader/evm/util.rs rename to snark-verifier/src/loader/evm/util.rs index 16eaa08d..2c74731a 100644 --- a/src/loader/evm/util.rs +++ b/snark-verifier/src/loader/evm/util.rs @@ -95,7 +95,7 @@ pub fn estimate_gas(cost: Cost) -> usize { let intrinsic_cost = 21000; let calldata_cost = (proof_size as f64 * 15.25).ceil() as usize; - let ec_operation_cost = 113100 + (cost.num_msm - 2) * 6350; + let ec_operation_cost = (45100 + cost.num_pairing * 34000) + (cost.num_msm - 2) * 6350; intrinsic_cost + calldata_cost + ec_operation_cost } diff --git a/src/loader/evm/util/executor.rs b/snark-verifier/src/loader/evm/util/executor.rs similarity index 100% rename from src/loader/evm/util/executor.rs rename to snark-verifier/src/loader/evm/util/executor.rs diff --git a/snark-verifier/src/loader/halo2.rs b/snark-verifier/src/loader/halo2.rs new file mode 100644 index 00000000..ce75b00c --- /dev/null +++ b/snark-verifier/src/loader/halo2.rs @@ -0,0 +1,29 @@ +pub(crate) mod loader; +mod shim; + +#[cfg(test)] +pub(crate) mod test; + +pub use loader::{EcPoint, Halo2Loader, Scalar}; +pub use shim::{Context, EccInstructions, IntegerInstructions}; +pub use util::Valuetools; + +pub use halo2_wrong_ecc; + +mod util { + use halo2_proofs::circuit::Value; + + pub trait Valuetools: Iterator> { + fn fold_zipped(self, init: B, mut f: F) -> Value + where + Self: Sized, + F: FnMut(B, V) -> B, + { + self.fold(Value::known(init), |acc, value| { + acc.zip(value).map(|(acc, value)| f(acc, value)) + }) + } + } + + impl>> Valuetools for I {} +} diff --git a/src/loader/halo2/loader.rs b/snark-verifier/src/loader/halo2/loader.rs similarity index 100% rename from src/loader/halo2/loader.rs rename to snark-verifier/src/loader/halo2/loader.rs diff --git a/src/loader/halo2/shim.rs b/snark-verifier/src/loader/halo2/shim.rs similarity index 100% rename from src/loader/halo2/shim.rs rename to snark-verifier/src/loader/halo2/shim.rs diff --git a/src/loader/halo2/test.rs b/snark-verifier/src/loader/halo2/test.rs similarity index 85% rename from src/loader/halo2/test.rs rename to snark-verifier/src/loader/halo2/test.rs index dd2fccaa..2de9d287 100644 --- a/src/loader/halo2/test.rs +++ b/snark-verifier/src/loader/halo2/test.rs @@ -1,18 +1,18 @@ use crate::{ util::{arithmetic::CurveAffine, Itertools}, - Protocol, + verifier::plonk::PlonkProtocol, }; use halo2_proofs::circuit::Value; #[derive(Clone, Debug)] pub struct Snark { - pub protocol: Protocol, + pub protocol: PlonkProtocol, pub instances: Vec>, pub proof: Vec, } impl Snark { - pub fn new(protocol: Protocol, instances: Vec>, proof: Vec) -> Self { + pub fn new(protocol: PlonkProtocol, instances: Vec>, proof: Vec) -> Self { assert_eq!( protocol.num_instance, instances @@ -30,7 +30,7 @@ impl Snark { #[derive(Clone, Debug)] pub struct SnarkWitness { - pub protocol: Protocol, + pub protocol: PlonkProtocol, pub instances: Vec>>, pub proof: Value>, } @@ -50,7 +50,7 @@ impl From> for SnarkWitness { } impl SnarkWitness { - pub fn new_without_witness(protocol: Protocol) -> Self { + pub fn new_without_witness(protocol: PlonkProtocol) -> Self { let instances = protocol .num_instance .iter() diff --git a/src/loader/native.rs b/snark-verifier/src/loader/native.rs similarity index 100% rename from src/loader/native.rs rename to snark-verifier/src/loader/native.rs diff --git a/src/pcs.rs b/snark-verifier/src/pcs.rs similarity index 62% rename from src/pcs.rs rename to snark-verifier/src/pcs.rs index bf944a43..45444a07 100644 --- a/src/pcs.rs +++ b/snark-verifier/src/pcs.rs @@ -8,19 +8,11 @@ use crate::{ Error, }; use rand::Rng; -use std::fmt::Debug; +use std::{fmt::Debug, marker::PhantomData}; pub mod ipa; pub mod kzg; -pub trait PolynomialCommitmentScheme: Clone + Debug -where - C: CurveAffine, - L: Loader, -{ - type Accumulator: Clone + Debug; -} - #[derive(Clone, Debug)] pub struct Query { pub poly: usize, @@ -38,56 +30,44 @@ impl Query { } } -pub trait MultiOpenScheme: PolynomialCommitmentScheme +pub trait PolynomialCommitmentScheme: Clone + Debug where C: CurveAffine, L: Loader, { - type SuccinctVerifyingKey: Clone + Debug; + type VerifyingKey: Clone + Debug; type Proof: Clone + Debug; + type Output: Clone + Debug; fn read_proof( - svk: &Self::SuccinctVerifyingKey, + vk: &Self::VerifyingKey, queries: &[Query], transcript: &mut T, ) -> Result where T: TranscriptRead; - fn succinct_verify( - svk: &Self::SuccinctVerifyingKey, + fn verify( + vk: &Self::VerifyingKey, commitments: &[Msm], point: &L::LoadedScalar, queries: &[Query], proof: &Self::Proof, - ) -> Result; + ) -> Result; } -pub trait Decider: PolynomialCommitmentScheme +pub trait AccumulationScheme where C: CurveAffine, L: Loader, { - type DecidingKey: Clone + Debug; - type Output: Clone + Debug; - - fn decide(dk: &Self::DecidingKey, accumulator: Self::Accumulator) -> Self::Output; - - fn decide_all(dk: &Self::DecidingKey, accumulators: Vec) -> Self::Output; -} - -pub trait AccumulationScheme: Clone + Debug -where - C: CurveAffine, - L: Loader, - PCS: PolynomialCommitmentScheme, -{ + type Accumulator: Clone + Debug; type VerifyingKey: Clone + Debug; type Proof: Clone + Debug; fn read_proof( vk: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], transcript: &mut T, ) -> Result where @@ -95,45 +75,62 @@ where fn verify( vk: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], proof: &Self::Proof, - ) -> Result; + ) -> Result; +} + +pub trait AccumulationDecider: AccumulationScheme +where + C: CurveAffine, + L: Loader, +{ + type DecidingKey: Clone + Debug; + + fn decide(dk: &Self::DecidingKey, accumulator: Self::Accumulator) -> Result<(), Error>; + + fn decide_all( + dk: &Self::DecidingKey, + accumulators: Vec, + ) -> Result<(), Error>; } -pub trait AccumulationSchemeProver: AccumulationScheme +pub trait AccumulationSchemeProver: AccumulationScheme where C: CurveAffine, - PCS: PolynomialCommitmentScheme, { type ProvingKey: Clone + Debug; fn create_proof( pk: &Self::ProvingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], transcript: &mut T, rng: R, - ) -> Result + ) -> Result where T: TranscriptWrite, R: Rng; } -pub trait AccumulatorEncoding: Clone + Debug +pub trait AccumulatorEncoding: Clone + Debug where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme, { - fn from_repr(repr: &[&L::LoadedScalar]) -> Result; + type Accumulator: Clone + Debug; + + fn from_repr(repr: &[&L::LoadedScalar]) -> Result; } -impl AccumulatorEncoding for () +impl AccumulatorEncoding for PhantomData where C: CurveAffine, L: Loader, PCS: PolynomialCommitmentScheme, { - fn from_repr(_: &[&L::LoadedScalar]) -> Result { + type Accumulator = PCS::Output; + + fn from_repr(_: &[&L::LoadedScalar]) -> Result { unimplemented!() } } diff --git a/src/pcs/ipa.rs b/snark-verifier/src/pcs/ipa.rs similarity index 94% rename from src/pcs/ipa.rs rename to snark-verifier/src/pcs/ipa.rs index a2b34824..249e0f0d 100644 --- a/src/pcs/ipa.rs +++ b/snark-verifier/src/pcs/ipa.rs @@ -1,6 +1,5 @@ use crate::{ loader::{native::NativeLoader, LoadedScalar, Loader, ScalarLoader}, - pcs::PolynomialCommitmentScheme, util::{ arithmetic::{ inner_product, powers, Curve, CurveAffine, Domain, Field, Fraction, PrimeField, @@ -24,21 +23,12 @@ mod multiopen; pub use accumulation::{IpaAs, IpaAsProof}; pub use accumulator::IpaAccumulator; pub use decider::IpaDecidingKey; -pub use multiopen::{Bgh19, Bgh19Proof, Bgh19SuccinctVerifyingKey}; +pub use multiopen::{Bgh19, Bgh19Proof}; #[derive(Clone, Debug)] -pub struct Ipa(PhantomData<(C, MOS)>); +pub struct Ipa(PhantomData); -impl PolynomialCommitmentScheme for Ipa -where - C: CurveAffine, - L: Loader, - MOS: Clone + Debug, -{ - type Accumulator = IpaAccumulator; -} - -impl Ipa +impl Ipa where C: CurveAffine, { @@ -204,11 +194,11 @@ impl IpaProvingKey { } pub fn svk(&self) -> IpaSuccinctVerifyingKey { - IpaSuccinctVerifyingKey::new(self.domain.clone(), self.h, self.s) + IpaSuccinctVerifyingKey::new(self.domain.clone(), self.g[0], self.h, self.s) } pub fn dk(&self) -> IpaDecidingKey { - IpaDecidingKey::new(self.g.clone()) + IpaDecidingKey::new(self.svk(), self.g.clone()) } pub fn commit(&self, poly: &Polynomial, omega: Option) -> C { @@ -244,13 +234,14 @@ impl IpaProvingKey { #[derive(Clone, Debug)] pub struct IpaSuccinctVerifyingKey { pub domain: Domain, + pub g: C, pub h: C, pub s: Option, } impl IpaSuccinctVerifyingKey { - pub fn new(domain: Domain, h: C, s: Option) -> Self { - Self { domain, h, s } + pub fn new(domain: Domain, g: C, h: C, s: Option) -> Self { + Self { domain, g, h, s } } pub fn zk(&self) -> bool { @@ -402,7 +393,7 @@ mod test { use crate::{ pcs::{ ipa::{self, IpaProvingKey}, - Decider, + AccumulationDecider, }, util::{arithmetic::Field, msm::Msm, poly::Polynomial}, }; @@ -414,7 +405,8 @@ mod test { #[test] fn test_ipa() { - type Ipa = ipa::Ipa; + type Ipa = ipa::Ipa; + type IpaAs = ipa::IpaAs; let k = 10; let mut rng = OsRng; @@ -441,7 +433,7 @@ mod test { }; let dk = pk.dk(); - assert!(Ipa::decide(&dk, accumulator)); + assert!(IpaAs::decide(&dk, accumulator).is_ok()); } } } diff --git a/src/pcs/ipa/accumulation.rs b/snark-verifier/src/pcs/ipa/accumulation.rs similarity index 84% rename from src/pcs/ipa/accumulation.rs rename to snark-verifier/src/pcs/ipa/accumulation.rs index eeea9efe..888e11aa 100644 --- a/src/pcs/ipa/accumulation.rs +++ b/snark-verifier/src/pcs/ipa/accumulation.rs @@ -4,7 +4,7 @@ use crate::{ ipa::{ h_coeffs, h_eval, Ipa, IpaAccumulator, IpaProof, IpaProvingKey, IpaSuccinctVerifyingKey, }, - AccumulationScheme, AccumulationSchemeProver, PolynomialCommitmentScheme, + AccumulationScheme, AccumulationSchemeProver, }, util::{ arithmetic::{Curve, CurveAffine, Field}, @@ -16,23 +16,24 @@ use crate::{ Error, }; use rand::Rng; -use std::{array, iter, marker::PhantomData}; +use std::{array, fmt::Debug, iter, marker::PhantomData}; #[derive(Clone, Debug)] -pub struct IpaAs(PhantomData); +pub struct IpaAs(PhantomData<(C, MOS)>); -impl AccumulationScheme for IpaAs +impl AccumulationScheme for IpaAs where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme>, + MOS: Clone + Debug, { + type Accumulator = IpaAccumulator; type VerifyingKey = IpaSuccinctVerifyingKey; - type Proof = IpaAsProof; + type Proof = IpaAsProof; fn read_proof( vk: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], transcript: &mut T, ) -> Result where @@ -43,9 +44,9 @@ where fn verify( vk: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], proof: &Self::Proof, - ) -> Result { + ) -> Result { let loader = proof.z.loader(); let s = vk.s.as_ref().map(|s| loader.ec_point_load_const(s)); @@ -71,34 +72,31 @@ where } let v = loader.sum_products(&powers_of_alpha.iter().zip(h.iter()).collect_vec()); - Ipa::::succinct_verify(vk, &c, &proof.z, &v, &proof.ipa) + Ipa::succinct_verify(vk, &c, &proof.z, &v, &proof.ipa) } } #[derive(Clone, Debug)] -pub struct IpaAsProof +pub struct IpaAsProof where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme>, { a_b_u: Option<(L::LoadedScalar, L::LoadedScalar, L::LoadedEcPoint)>, omega: Option, alpha: L::LoadedScalar, z: L::LoadedScalar, ipa: IpaProof, - _marker: PhantomData, } -impl IpaAsProof +impl IpaAsProof where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme>, { fn read( vk: &IpaSuccinctVerifyingKey, - instances: &[PCS::Accumulator], + instances: &[IpaAccumulator], transcript: &mut T, ) -> Result where @@ -141,24 +139,23 @@ where alpha, z, ipa, - _marker: PhantomData, }) } } -impl AccumulationSchemeProver for IpaAs +impl AccumulationSchemeProver for IpaAs where C: CurveAffine, - PCS: PolynomialCommitmentScheme>, + MOS: Clone + Debug, { type ProvingKey = IpaProvingKey; fn create_proof( pk: &Self::ProvingKey, - instances: &[PCS::Accumulator], + instances: &[IpaAccumulator], transcript: &mut T, mut rng: R, - ) -> Result + ) -> Result, Error> where T: TranscriptWrite, R: Rng, @@ -216,7 +213,7 @@ where .map(|(power_of_alpha, h)| h * power_of_alpha) .sum::>(); - Ipa::::create_proof(pk, &h.to_vec(), &z, omega.as_ref(), transcript, &mut rng) + Ipa::create_proof(pk, &h.to_vec(), &z, omega.as_ref(), transcript, &mut rng) } } @@ -225,7 +222,7 @@ mod test { use crate::{ pcs::{ ipa::{self, IpaProvingKey}, - AccumulationScheme, AccumulationSchemeProver, Decider, + AccumulationDecider, AccumulationScheme, AccumulationSchemeProver, }, util::{arithmetic::Field, msm::Msm, poly::Polynomial, Itertools}, }; @@ -238,8 +235,8 @@ mod test { #[test] fn test_ipa_as() { - type Ipa = ipa::Ipa; - type IpaAs = ipa::IpaAs; + type Ipa = ipa::Ipa; + type IpaAs = ipa::IpaAs; let k = 10; let zk = true; @@ -286,6 +283,6 @@ mod test { }; let dk = pk.dk(); - assert!(Ipa::decide(&dk, accumulator)); + assert!(IpaAs::decide(&dk, accumulator).is_ok()); } } diff --git a/src/pcs/ipa/accumulator.rs b/snark-verifier/src/pcs/ipa/accumulator.rs similarity index 100% rename from src/pcs/ipa/accumulator.rs rename to snark-verifier/src/pcs/ipa/accumulator.rs diff --git a/snark-verifier/src/pcs/ipa/decider.rs b/snark-verifier/src/pcs/ipa/decider.rs new file mode 100644 index 00000000..db7b42fb --- /dev/null +++ b/snark-verifier/src/pcs/ipa/decider.rs @@ -0,0 +1,65 @@ +use crate::{pcs::ipa::IpaSuccinctVerifyingKey, util::arithmetic::CurveAffine}; + +#[derive(Clone, Debug)] +pub struct IpaDecidingKey { + svk: IpaSuccinctVerifyingKey, + g: Vec, +} + +impl IpaDecidingKey { + pub fn new(svk: IpaSuccinctVerifyingKey, g: Vec) -> Self { + Self { svk, g } + } +} + +impl AsRef> for IpaDecidingKey { + fn as_ref(&self) -> &IpaSuccinctVerifyingKey { + &self.svk + } +} + +mod native { + use crate::{ + loader::native::NativeLoader, + pcs::{ + ipa::{h_coeffs, IpaAccumulator, IpaAs, IpaDecidingKey}, + AccumulationDecider, + }, + util::{ + arithmetic::{Curve, CurveAffine, Field}, + msm::multi_scalar_multiplication, + Itertools, + }, + Error, + }; + use std::fmt::Debug; + + impl AccumulationDecider for IpaAs + where + C: CurveAffine, + MOS: Clone + Debug, + { + type DecidingKey = IpaDecidingKey; + + fn decide( + dk: &Self::DecidingKey, + IpaAccumulator { u, xi }: IpaAccumulator, + ) -> Result<(), Error> { + let h = h_coeffs(&xi, C::Scalar::one()); + (u == multi_scalar_multiplication(&h, &dk.g).to_affine()) + .then_some(()) + .ok_or_else(|| Error::AssertionFailure("U == commit(G, h)".to_string())) + } + + fn decide_all( + dk: &Self::DecidingKey, + accumulators: Vec>, + ) -> Result<(), Error> { + accumulators + .into_iter() + .map(|accumulator| Self::decide(dk, accumulator)) + .try_collect::<_, Vec<_>, _>()?; + Ok(()) + } + } +} diff --git a/snark-verifier/src/pcs/ipa/multiopen.rs b/snark-verifier/src/pcs/ipa/multiopen.rs new file mode 100644 index 00000000..99b0a565 --- /dev/null +++ b/snark-verifier/src/pcs/ipa/multiopen.rs @@ -0,0 +1,3 @@ +mod bgh19; + +pub use bgh19::{Bgh19, Bgh19Proof}; diff --git a/src/pcs/ipa/multiopen/bgh19.rs b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs similarity index 92% rename from src/pcs/ipa/multiopen/bgh19.rs rename to snark-verifier/src/pcs/ipa/multiopen/bgh19.rs index 29d291ad..6f19a44a 100644 --- a/src/pcs/ipa/multiopen/bgh19.rs +++ b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs @@ -1,11 +1,11 @@ use crate::{ loader::{LoadedScalar, Loader, ScalarLoader}, pcs::{ - ipa::{Ipa, IpaProof, IpaSuccinctVerifyingKey, Round}, - MultiOpenScheme, Query, + ipa::{Ipa, IpaAccumulator, IpaAs, IpaProof, IpaSuccinctVerifyingKey, Round}, + PolynomialCommitmentScheme, Query, }, util::{ - arithmetic::{ilog2, CurveAffine, Domain, FieldExt, Fraction}, + arithmetic::{ilog2, CurveAffine, FieldExt, Fraction}, msm::Msm, transcript::TranscriptRead, Itertools, @@ -21,16 +21,17 @@ use std::{ #[derive(Clone, Debug)] pub struct Bgh19; -impl MultiOpenScheme for Ipa +impl PolynomialCommitmentScheme for IpaAs where C: CurveAffine, L: Loader, { - type SuccinctVerifyingKey = Bgh19SuccinctVerifyingKey; + type VerifyingKey = IpaSuccinctVerifyingKey; type Proof = Bgh19Proof; + type Output = IpaAccumulator; fn read_proof( - svk: &Self::SuccinctVerifyingKey, + svk: &Self::VerifyingKey, queries: &[Query], transcript: &mut T, ) -> Result @@ -40,13 +41,13 @@ where Bgh19Proof::read(svk, queries, transcript) } - fn succinct_verify( - svk: &Self::SuccinctVerifyingKey, + fn verify( + svk: &Self::VerifyingKey, commitments: &[Msm], x: &L::LoadedScalar, queries: &[Query], proof: &Self::Proof, - ) -> Result { + ) -> Result { let loader = x.loader(); let g = loader.ec_point_load_const(&svk.g); @@ -87,22 +88,7 @@ where }; // IPA - Ipa::::succinct_verify(&svk.ipa, &p, &proof.x_3, &loader.load_zero(), &proof.ipa) - } -} - -#[derive(Clone, Debug)] -pub struct Bgh19SuccinctVerifyingKey { - g: C, - ipa: IpaSuccinctVerifyingKey, -} - -impl Bgh19SuccinctVerifyingKey { - pub fn new(domain: Domain, g: C, w: C, u: C) -> Self { - Self { - g, - ipa: IpaSuccinctVerifyingKey::new(domain, u, Some(w)), - } + Ipa::succinct_verify(svk, &p, &proof.x_3, &loader.load_zero(), &proof.ipa) } } @@ -129,7 +115,7 @@ where L: Loader, { fn read>( - svk: &Bgh19SuccinctVerifyingKey, + svk: &IpaSuccinctVerifyingKey, queries: &[Query], transcript: &mut T, ) -> Result { @@ -151,7 +137,7 @@ where transcript.squeeze_challenge(), )) }) - .take(svk.ipa.domain.k) + .take(svk.domain.k) .collect::, _>>()?; let c = transcript.read_scalar()?; let blind = transcript.read_scalar()?; diff --git a/src/pcs/kzg.rs b/snark-verifier/src/pcs/kzg.rs similarity index 61% rename from src/pcs/kzg.rs rename to snark-verifier/src/pcs/kzg.rs index 056589a8..80d7ab63 100644 --- a/src/pcs/kzg.rs +++ b/snark-verifier/src/pcs/kzg.rs @@ -1,9 +1,4 @@ -use crate::{ - loader::Loader, - pcs::PolynomialCommitmentScheme, - util::arithmetic::{CurveAffine, MultiMillerLoop}, -}; -use std::{fmt::Debug, marker::PhantomData}; +use crate::util::arithmetic::CurveAffine; mod accumulation; mod accumulator; @@ -18,18 +13,6 @@ pub use multiopen::{Bdfg21, Bdfg21Proof, Gwc19, Gwc19Proof}; #[cfg(feature = "loader_halo2")] pub use accumulator::LimbsEncodingInstructions; -#[derive(Clone, Debug)] -pub struct Kzg(PhantomData<(M, MOS)>); - -impl PolynomialCommitmentScheme for Kzg -where - M: MultiMillerLoop, - L: Loader, - MOS: Clone + Debug, -{ - type Accumulator = KzgAccumulator; -} - #[derive(Clone, Copy, Debug)] pub struct KzgSuccinctVerifyingKey { pub g: C, diff --git a/src/pcs/kzg/accumulation.rs b/snark-verifier/src/pcs/kzg/accumulation.rs similarity index 70% rename from src/pcs/kzg/accumulation.rs rename to snark-verifier/src/pcs/kzg/accumulation.rs index 4273ce9a..202a8ce1 100644 --- a/src/pcs/kzg/accumulation.rs +++ b/snark-verifier/src/pcs/kzg/accumulation.rs @@ -1,47 +1,45 @@ use crate::{ loader::{native::NativeLoader, LoadedScalar, Loader}, - pcs::{ - kzg::KzgAccumulator, AccumulationScheme, AccumulationSchemeProver, - PolynomialCommitmentScheme, - }, + pcs::{kzg::KzgAccumulator, AccumulationScheme, AccumulationSchemeProver}, util::{ - arithmetic::{Curve, CurveAffine, Field}, + arithmetic::{Curve, CurveAffine, Field, MultiMillerLoop}, msm::Msm, transcript::{TranscriptRead, TranscriptWrite}, }, Error, }; use rand::Rng; -use std::marker::PhantomData; +use std::{fmt::Debug, marker::PhantomData}; #[derive(Clone, Debug)] -pub struct KzgAs(PhantomData); +pub struct KzgAs(PhantomData<(M, MOS)>); -impl AccumulationScheme for KzgAs +impl AccumulationScheme for KzgAs where - C: CurveAffine, - L: Loader, - PCS: PolynomialCommitmentScheme>, + M: MultiMillerLoop, + L: Loader, + MOS: Clone + Debug, { + type Accumulator = KzgAccumulator; type VerifyingKey = KzgAsVerifyingKey; - type Proof = KzgAsProof; + type Proof = KzgAsProof; fn read_proof( vk: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], transcript: &mut T, ) -> Result where - T: TranscriptRead, + T: TranscriptRead, { KzgAsProof::read(vk, instances, transcript) } fn verify( _: &Self::VerifyingKey, - instances: &[PCS::Accumulator], + instances: &[Self::Accumulator], proof: &Self::Proof, - ) -> Result { + ) -> Result { let (lhs, rhs) = instances .iter() .map(|accumulator| (&accumulator.lhs, &accumulator.rhs)) @@ -53,7 +51,7 @@ where bases .into_iter() .zip(powers_of_r.iter()) - .map(|(base, r)| Msm::::base(base) * r) + .map(|(base, r)| Msm::::base(base) * r) .sum::>() .evaluate(None) }); @@ -89,26 +87,23 @@ impl KzgAsVerifyingKey { } #[derive(Clone, Debug)] -pub struct KzgAsProof +pub struct KzgAsProof where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme>, { blind: Option<(L::LoadedEcPoint, L::LoadedEcPoint)>, r: L::LoadedScalar, - _marker: PhantomData, } -impl KzgAsProof +impl KzgAsProof where C: CurveAffine, L: Loader, - PCS: PolynomialCommitmentScheme>, { fn read( vk: &KzgAsVerifyingKey, - instances: &[PCS::Accumulator], + instances: &[KzgAccumulator], transcript: &mut T, ) -> Result where @@ -128,29 +123,25 @@ where let r = transcript.squeeze_challenge(); - Ok(Self { - blind, - r, - _marker: PhantomData, - }) + Ok(Self { blind, r }) } } -impl AccumulationSchemeProver for KzgAs +impl AccumulationSchemeProver for KzgAs where - C: CurveAffine, - PCS: PolynomialCommitmentScheme>, + M: MultiMillerLoop, + MOS: Clone + Debug, { - type ProvingKey = KzgAsProvingKey; + type ProvingKey = KzgAsProvingKey; fn create_proof( pk: &Self::ProvingKey, - instances: &[PCS::Accumulator], + instances: &[KzgAccumulator], transcript: &mut T, rng: R, - ) -> Result + ) -> Result, Error> where - T: TranscriptWrite, + T: TranscriptWrite, R: Rng, { assert!(!instances.is_empty()); @@ -163,7 +154,7 @@ where let blind = pk .zk() .then(|| { - let s = C::Scalar::random(rng); + let s = M::Scalar::random(rng); let (g, s_g) = pk.0.unwrap(); let lhs = (s_g * s).to_affine(); let rhs = (g * s).to_affine(); @@ -186,7 +177,7 @@ where let [lhs, rhs] = [lhs, rhs].map(|msms| { msms.iter() .zip(powers_of_r.iter()) - .map(|(msm, power_of_r)| Msm::::base(msm) * power_of_r) + .map(|(msm, power_of_r)| Msm::::base(msm) * power_of_r) .sum::>() .evaluate(None) }); diff --git a/src/pcs/kzg/accumulator.rs b/snark-verifier/src/pcs/kzg/accumulator.rs similarity index 85% rename from src/pcs/kzg/accumulator.rs rename to snark-verifier/src/pcs/kzg/accumulator.rs index 50ce6ba8..b76ab80a 100644 --- a/src/pcs/kzg/accumulator.rs +++ b/snark-verifier/src/pcs/kzg/accumulator.rs @@ -34,7 +34,7 @@ mod native { loader::native::NativeLoader, pcs::{ kzg::{KzgAccumulator, LimbsEncoding}, - AccumulatorEncoding, PolynomialCommitmentScheme, + AccumulatorEncoding, }, util::{ arithmetic::{fe_from_limbs, CurveAffine}, @@ -43,17 +43,14 @@ mod native { Error, }; - impl AccumulatorEncoding + impl AccumulatorEncoding for LimbsEncoding where C: CurveAffine, - PCS: PolynomialCommitmentScheme< - C, - NativeLoader, - Accumulator = KzgAccumulator, - >, { - fn from_repr(limbs: &[&C::Scalar]) -> Result { + type Accumulator = KzgAccumulator; + + fn from_repr(limbs: &[&C::Scalar]) -> Result { assert_eq!(limbs.len(), 4 * LIMBS); let [lhs_x, lhs_y, rhs_x, rhs_y]: [_; 4] = limbs @@ -88,7 +85,7 @@ mod evm { loader::evm::{EvmLoader, Scalar}, pcs::{ kzg::{KzgAccumulator, LimbsEncoding}, - AccumulatorEncoding, PolynomialCommitmentScheme, + AccumulatorEncoding, }, util::{ arithmetic::{CurveAffine, PrimeField}, @@ -98,18 +95,15 @@ mod evm { }; use std::rc::Rc; - impl AccumulatorEncoding, PCS> + impl AccumulatorEncoding> for LimbsEncoding where C: CurveAffine, C::Scalar: PrimeField, - PCS: PolynomialCommitmentScheme< - C, - Rc, - Accumulator = KzgAccumulator>, - >, { - fn from_repr(limbs: &[&Scalar]) -> Result { + type Accumulator = KzgAccumulator>; + + fn from_repr(limbs: &[&Scalar]) -> Result { assert_eq!(limbs.len(), 4 * LIMBS); let loader = limbs[0].loader(); @@ -140,7 +134,7 @@ mod halo2 { loader::halo2::{EccInstructions, Halo2Loader, Scalar, Valuetools}, pcs::{ kzg::{KzgAccumulator, LimbsEncoding}, - AccumulatorEncoding, PolynomialCommitmentScheme, + AccumulatorEncoding, }, util::{ arithmetic::{fe_from_limbs, CurveAffine}, @@ -186,18 +180,15 @@ mod halo2 { ) -> Result, plonk::Error>; } - impl<'a, C, PCS, EccChip, const LIMBS: usize, const BITS: usize> - AccumulatorEncoding>, PCS> for LimbsEncoding + impl<'a, C, EccChip, const LIMBS: usize, const BITS: usize> + AccumulatorEncoding>> for LimbsEncoding where C: CurveAffine, - PCS: PolynomialCommitmentScheme< - C, - Rc>, - Accumulator = KzgAccumulator>>, - >, EccChip: LimbsEncodingInstructions<'a, C, LIMBS, BITS>, { - fn from_repr(limbs: &[&Scalar<'a, C, EccChip>]) -> Result { + type Accumulator = KzgAccumulator>>; + + fn from_repr(limbs: &[&Scalar<'a, C, EccChip>]) -> Result { assert_eq!(limbs.len(), 4 * LIMBS); let loader = limbs[0].loader(); diff --git a/src/pcs/kzg/decider.rs b/snark-verifier/src/pcs/kzg/decider.rs similarity index 66% rename from src/pcs/kzg/decider.rs rename to snark-verifier/src/pcs/kzg/decider.rs index 1ec0eb09..53cbd601 100644 --- a/src/pcs/kzg/decider.rs +++ b/snark-verifier/src/pcs/kzg/decider.rs @@ -1,16 +1,22 @@ -use crate::util::arithmetic::MultiMillerLoop; +use crate::{pcs::kzg::KzgSuccinctVerifyingKey, util::arithmetic::MultiMillerLoop}; use std::marker::PhantomData; #[derive(Debug, Clone, Copy)] pub struct KzgDecidingKey { - pub g2: M::G2Affine, - pub s_g2: M::G2Affine, + svk: KzgSuccinctVerifyingKey, + g2: M::G2Affine, + s_g2: M::G2Affine, _marker: PhantomData, } impl KzgDecidingKey { - pub fn new(g2: M::G2Affine, s_g2: M::G2Affine) -> Self { + pub fn new( + svk: impl Into>, + g2: M::G2Affine, + s_g2: M::G2Affine, + ) -> Self { Self { + svk: svk.into(), g2, s_g2, _marker: PhantomData, @@ -18,9 +24,15 @@ impl KzgDecidingKey { } } -impl From<(M::G2Affine, M::G2Affine)> for KzgDecidingKey { - fn from((g2, s_g2): (M::G2Affine, M::G2Affine)) -> KzgDecidingKey { - KzgDecidingKey::new(g2, s_g2) +impl From<(M::G1Affine, M::G2Affine, M::G2Affine)> for KzgDecidingKey { + fn from((g1, g2, s_g2): (M::G1Affine, M::G2Affine, M::G2Affine)) -> KzgDecidingKey { + KzgDecidingKey::new(g1, g2, s_g2) + } +} + +impl AsRef> for KzgDecidingKey { + fn as_ref(&self) -> &KzgSuccinctVerifyingKey { + &self.svk } } @@ -28,39 +40,47 @@ mod native { use crate::{ loader::native::NativeLoader, pcs::{ - kzg::{Kzg, KzgAccumulator, KzgDecidingKey}, - Decider, + kzg::{KzgAccumulator, KzgAs, KzgDecidingKey}, + AccumulationDecider, + }, + util::{ + arithmetic::{Group, MillerLoopResult, MultiMillerLoop}, + Itertools, }, - util::arithmetic::{Group, MillerLoopResult, MultiMillerLoop}, + Error, }; use std::fmt::Debug; - impl Decider for Kzg + impl AccumulationDecider for KzgAs where M: MultiMillerLoop, MOS: Clone + Debug, { type DecidingKey = KzgDecidingKey; - type Output = bool; fn decide( dk: &Self::DecidingKey, KzgAccumulator { lhs, rhs }: KzgAccumulator, - ) -> bool { + ) -> Result<(), Error> { let terms = [(&lhs, &dk.g2.into()), (&rhs, &(-dk.s_g2).into())]; - M::multi_miller_loop(&terms) - .final_exponentiation() - .is_identity() - .into() + bool::from( + M::multi_miller_loop(&terms) + .final_exponentiation() + .is_identity(), + ) + .then_some(()) + .ok_or_else(|| Error::AssertionFailure("e(lhs, g2)·e(rhs, -s_g2) == O".to_string())) } fn decide_all( dk: &Self::DecidingKey, accumulators: Vec>, - ) -> bool { - !accumulators + ) -> Result<(), Error> { + accumulators .into_iter() - .any(|accumulator| !Self::decide(dk, accumulator)) + .map(|accumulator| Self::decide(dk, accumulator)) + .try_collect::<_, Vec<_>, _>()?; + Ok(()) } } } @@ -73,29 +93,29 @@ mod evm { LoadedScalar, }, pcs::{ - kzg::{Kzg, KzgAccumulator, KzgDecidingKey}, - Decider, + kzg::{KzgAccumulator, KzgAs, KzgDecidingKey}, + AccumulationDecider, }, util::{ arithmetic::{CurveAffine, MultiMillerLoop, PrimeField}, msm::Msm, }, + Error, }; use std::{fmt::Debug, rc::Rc}; - impl Decider> for Kzg + impl AccumulationDecider> for KzgAs where M: MultiMillerLoop, M::Scalar: PrimeField, MOS: Clone + Debug, { type DecidingKey = KzgDecidingKey; - type Output = (); fn decide( dk: &Self::DecidingKey, KzgAccumulator { lhs, rhs }: KzgAccumulator>, - ) { + ) -> Result<(), Error> { let loader = lhs.loader(); let [g2, minus_s_g2] = [dk.g2, -dk.s_g2].map(|ec_point| { let coordinates = ec_point.coordinates().unwrap(); @@ -109,12 +129,13 @@ mod evm { ) }); loader.pairing(&lhs, g2, &rhs, minus_s_g2); + Ok(()) } fn decide_all( dk: &Self::DecidingKey, mut accumulators: Vec>>, - ) { + ) -> Result<(), Error> { assert!(!accumulators.is_empty()); let accumulator = if accumulators.len() == 1 { @@ -149,7 +170,7 @@ mod evm { KzgAccumulator::new(lhs, rhs) }; - Self::decide(dk, accumulator) + >>::decide(dk, accumulator) } } } diff --git a/src/pcs/kzg/multiopen.rs b/snark-verifier/src/pcs/kzg/multiopen.rs similarity index 100% rename from src/pcs/kzg/multiopen.rs rename to snark-verifier/src/pcs/kzg/multiopen.rs diff --git a/src/pcs/kzg/multiopen/bdfg21.rs b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs similarity index 95% rename from src/pcs/kzg/multiopen/bdfg21.rs rename to snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs index f542f750..b532f684 100644 --- a/src/pcs/kzg/multiopen/bdfg21.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs @@ -2,8 +2,8 @@ use crate::{ cost::{Cost, CostEstimation}, loader::{LoadedScalar, Loader, ScalarLoader}, pcs::{ - kzg::{Kzg, KzgAccumulator, KzgSuccinctVerifyingKey}, - MultiOpenScheme, Query, + kzg::{KzgAccumulator, KzgAs, KzgSuccinctVerifyingKey}, + PolynomialCommitmentScheme, Query, }, util::{ arithmetic::{ilog2, CurveAffine, FieldExt, Fraction, MultiMillerLoop}, @@ -21,13 +21,14 @@ use std::{ #[derive(Clone, Debug)] pub struct Bdfg21; -impl MultiOpenScheme for Kzg +impl PolynomialCommitmentScheme for KzgAs where M: MultiMillerLoop, L: Loader, { - type SuccinctVerifyingKey = KzgSuccinctVerifyingKey; + type VerifyingKey = KzgSuccinctVerifyingKey; type Proof = Bdfg21Proof; + type Output = KzgAccumulator; fn read_proof( _: &KzgSuccinctVerifyingKey, @@ -40,13 +41,13 @@ where Bdfg21Proof::read(transcript) } - fn succinct_verify( + fn verify( svk: &KzgSuccinctVerifyingKey, commitments: &[Msm], z: &L::LoadedScalar, queries: &[Query], proof: &Bdfg21Proof, - ) -> Result { + ) -> Result { let sets = query_sets(queries); let f = { let coeffs = query_set_coeffs(&sets, z, &proof.z_prime); @@ -366,13 +367,17 @@ where } } -impl CostEstimation for Kzg +impl CostEstimation for KzgAs where M: MultiMillerLoop, { type Input = Vec>; fn estimate_cost(_: &Vec>) -> Cost { - Cost::new(0, 2, 0, 2) + Cost { + num_commitment: 2, + num_msm: 2, + ..Default::default() + } } } diff --git a/src/pcs/kzg/multiopen/gwc19.rs b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs similarity index 87% rename from src/pcs/kzg/multiopen/gwc19.rs rename to snark-verifier/src/pcs/kzg/multiopen/gwc19.rs index 6e3f579f..31786e7d 100644 --- a/src/pcs/kzg/multiopen/gwc19.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs @@ -2,8 +2,8 @@ use crate::{ cost::{Cost, CostEstimation}, loader::{LoadedScalar, Loader}, pcs::{ - kzg::{Kzg, KzgAccumulator, KzgSuccinctVerifyingKey}, - MultiOpenScheme, Query, + kzg::{KzgAccumulator, KzgAs, KzgSuccinctVerifyingKey}, + PolynomialCommitmentScheme, Query, }, util::{ arithmetic::{CurveAffine, MultiMillerLoop, PrimeField}, @@ -17,16 +17,17 @@ use crate::{ #[derive(Clone, Debug)] pub struct Gwc19; -impl MultiOpenScheme for Kzg +impl PolynomialCommitmentScheme for KzgAs where M: MultiMillerLoop, L: Loader, { - type SuccinctVerifyingKey = KzgSuccinctVerifyingKey; + type VerifyingKey = KzgSuccinctVerifyingKey; type Proof = Gwc19Proof; + type Output = KzgAccumulator; fn read_proof( - _: &Self::SuccinctVerifyingKey, + _: &Self::VerifyingKey, queries: &[Query], transcript: &mut T, ) -> Result @@ -36,13 +37,13 @@ where Gwc19Proof::read(queries, transcript) } - fn succinct_verify( - svk: &Self::SuccinctVerifyingKey, + fn verify( + svk: &Self::VerifyingKey, commitments: &[Msm], z: &L::LoadedScalar, queries: &[Query], proof: &Self::Proof, - ) -> Result { + ) -> Result { let sets = query_sets(queries); let powers_of_u = &proof.u.powers(sets.len()); let f = { @@ -152,7 +153,7 @@ where }) } -impl CostEstimation for Kzg +impl CostEstimation for KzgAs where M: MultiMillerLoop, { @@ -160,6 +161,10 @@ where fn estimate_cost(queries: &Vec>) -> Cost { let num_w = query_sets(queries).len(); - Cost::new(0, num_w, 0, num_w) + Cost { + num_commitment: num_w, + num_msm: num_w, + ..Default::default() + } } } diff --git a/src/system.rs b/snark-verifier/src/system.rs similarity index 100% rename from src/system.rs rename to snark-verifier/src/system.rs diff --git a/src/system/halo2.rs b/snark-verifier/src/system/halo2.rs similarity index 99% rename from src/system/halo2.rs rename to snark-verifier/src/system/halo2.rs index 7c26387d..bb7b1bb9 100644 --- a/src/system/halo2.rs +++ b/snark-verifier/src/system/halo2.rs @@ -1,12 +1,12 @@ use crate::{ util::{ arithmetic::{root_of_unity, CurveAffine, Domain, FieldExt, Rotation}, - protocol::{ - CommonPolynomial, Expression, InstanceCommittingKey, Query, QuotientPolynomial, - }, Itertools, }, - Protocol, + verifier::plonk::protocol::{ + CommonPolynomial, Expression, InstanceCommittingKey, PlonkProtocol, Query, + QuotientPolynomial, + }, }; use halo2_proofs::{ plonk::{self, Any, ConstraintSystem, FirstPhase, SecondPhase, ThirdPhase, VerifyingKey}, @@ -84,7 +84,7 @@ pub fn compile<'a, C: CurveAffine, P: Params<'a, C>>( params: &P, vk: &VerifyingKey, config: Config, -) -> Protocol { +) -> PlonkProtocol { assert_eq!(vk.get_domain().k(), params.k()); let cs = vk.cs(); @@ -150,7 +150,7 @@ pub fn compile<'a, C: CurveAffine, P: Params<'a, C>>( .map(|accumulator_indices| polynomials.accumulator_indices(accumulator_indices)) .unwrap_or_default(); - Protocol { + PlonkProtocol { domain, preprocessed, num_instance: polynomials.num_instance(), diff --git a/src/system/halo2/strategy.rs b/snark-verifier/src/system/halo2/strategy.rs similarity index 100% rename from src/system/halo2/strategy.rs rename to snark-verifier/src/system/halo2/strategy.rs diff --git a/src/system/halo2/test.rs b/snark-verifier/src/system/halo2/test.rs similarity index 95% rename from src/system/halo2/test.rs rename to snark-verifier/src/system/halo2/test.rs index 1ec03306..03e5503a 100644 --- a/src/system/halo2/test.rs +++ b/snark-verifier/src/system/halo2/test.rs @@ -207,15 +207,13 @@ macro_rules! halo2_native_verify { $protocol:expr, $instances:expr, $transcript:expr, - $svk:expr, - $dk:expr + $vk:expr ) => {{ use halo2_proofs::poly::commitment::ParamsProver; - use $crate::verifier::PlonkVerifier; + use $crate::verifier::SnarkVerifier; - let proof = - <$plonk_verifier>::read_proof($svk, $protocol, $instances, $transcript).unwrap(); - assert!(<$plonk_verifier>::verify($svk, $dk, $protocol, $instances, &proof).unwrap()) + let proof = <$plonk_verifier>::read_proof($vk, $protocol, $instances, $transcript).unwrap(); + assert!(<$plonk_verifier>::verify($vk, $protocol, $instances, &proof).is_ok()) }}; } diff --git a/src/system/halo2/test/circuit.rs b/snark-verifier/src/system/halo2/test/circuit.rs similarity index 100% rename from src/system/halo2/test/circuit.rs rename to snark-verifier/src/system/halo2/test/circuit.rs diff --git a/src/system/halo2/test/circuit/maingate.rs b/snark-verifier/src/system/halo2/test/circuit/maingate.rs similarity index 100% rename from src/system/halo2/test/circuit/maingate.rs rename to snark-verifier/src/system/halo2/test/circuit/maingate.rs diff --git a/src/system/halo2/test/circuit/standard.rs b/snark-verifier/src/system/halo2/test/circuit/standard.rs similarity index 100% rename from src/system/halo2/test/circuit/standard.rs rename to snark-verifier/src/system/halo2/test/circuit/standard.rs diff --git a/src/system/halo2/test/ipa.rs b/snark-verifier/src/system/halo2/test/ipa.rs similarity index 91% rename from src/system/halo2/test/ipa.rs rename to snark-verifier/src/system/halo2/test/ipa.rs index 07fd6efd..b85666d8 100644 --- a/src/system/halo2/test/ipa.rs +++ b/snark-verifier/src/system/halo2/test/ipa.rs @@ -121,7 +121,7 @@ macro_rules! halo2_ipa_native_verify { $transcript:expr ) => {{ use $crate::{ - pcs::ipa::{Bgh19SuccinctVerifyingKey, IpaDecidingKey}, + pcs::ipa::{IpaDecidingKey, IpaSuccinctVerifyingKey}, system::halo2::test::{halo2_native_verify, ipa::w_u}, }; @@ -132,8 +132,15 @@ macro_rules! halo2_ipa_native_verify { $protocol, $instances, $transcript, - &Bgh19SuccinctVerifyingKey::new($protocol.domain.clone(), $params.get_g()[0], w, u), - &IpaDecidingKey::new($params.get_g().to_vec()) + &IpaDecidingKey::new( + IpaSuccinctVerifyingKey::new( + $protocol.domain.clone(), + $params.get_g()[0], + u, + Some(w) + ), + $params.get_g().to_vec() + ) ) }}; } diff --git a/src/system/halo2/test/ipa/native.rs b/snark-verifier/src/system/halo2/test/ipa/native.rs similarity index 92% rename from src/system/halo2/test/ipa/native.rs rename to snark-verifier/src/system/halo2/test/ipa/native.rs index 7d9e09bb..07621771 100644 --- a/src/system/halo2/test/ipa/native.rs +++ b/snark-verifier/src/system/halo2/test/ipa/native.rs @@ -1,10 +1,10 @@ use crate::{ - pcs::ipa::{Bgh19, Ipa}, + pcs::ipa::{Bgh19, IpaAs}, system::halo2::test::ipa::{ halo2_ipa_config, halo2_ipa_create_snark, halo2_ipa_native_verify, halo2_ipa_prepare, }, system::halo2::test::StandardPlonk, - verifier::Plonk, + verifier::plonk::PlonkVerifier, }; use halo2_curves::pasta::pallas; use halo2_proofs::{ @@ -47,7 +47,7 @@ macro_rules! test { } }; ($name:ident, $k:expr, $config:expr, $create_cirucit:expr) => { - test!(@ $name, $k, $config, $create_cirucit, ProverIPA, VerifierIPA, Plonk::>); + test!(@ $name, $k, $config, $create_cirucit, ProverIPA, VerifierIPA, PlonkVerifier::>); } } diff --git a/src/system/halo2/test/kzg.rs b/snark-verifier/src/system/halo2/test/kzg.rs similarity index 97% rename from src/system/halo2/test/kzg.rs rename to snark-verifier/src/system/halo2/test/kzg.rs index 2b267758..77c26964 100644 --- a/src/system/halo2/test/kzg.rs +++ b/snark-verifier/src/system/halo2/test/kzg.rs @@ -109,8 +109,7 @@ macro_rules! halo2_kzg_native_verify { $protocol, $instances, $transcript, - &$params.get_g()[0].into(), - &($params.g2(), $params.s_g2()).into() + &($params.get_g()[0], $params.g2(), $params.s_g2()).into() ) }}; } diff --git a/src/system/halo2/test/kzg/evm.rs b/snark-verifier/src/system/halo2/test/kzg/evm.rs similarity index 85% rename from src/system/halo2/test/kzg/evm.rs rename to snark-verifier/src/system/halo2/test/kzg/evm.rs index 1ab52083..8c44ced2 100644 --- a/src/system/halo2/test/kzg/evm.rs +++ b/snark-verifier/src/system/halo2/test/kzg/evm.rs @@ -1,6 +1,6 @@ use crate::{ loader::native::NativeLoader, - pcs::kzg::{Bdfg21, Gwc19, Kzg, LimbsEncoding}, + pcs::kzg::{Bdfg21, Gwc19, KzgAs, LimbsEncoding}, system::halo2::{ test::{ kzg::{ @@ -11,7 +11,7 @@ use crate::{ }, transcript::evm::{ChallengeEvm, EvmTranscript}, }, - verifier::Plonk, + verifier::plonk::PlonkVerifier, }; use halo2_curves::bn256::{Bn256, G1Affine}; use halo2_proofs::poly::kzg::multiopen::{ProverGWC, ProverSHPLONK, VerifierGWC, VerifierSHPLONK}; @@ -30,13 +30,12 @@ macro_rules! halo2_kzg_evm_verify { transcript::evm::EvmTranscript, }, util::Itertools, - verifier::PlonkVerifier, + verifier::SnarkVerifier, }; let loader = EvmLoader::new::(); let deployment_code = { - let svk = $params.get_g()[0].into(); - let dk = ($params.g2(), $params.s_g2()).into(); + let vk = ($params.get_g()[0].into(), $params.g2(), $params.s_g2()).into(); let protocol = $protocol.loaded(&loader); let mut transcript = EvmTranscript::<_, Rc, _, _>::new(&loader); let instances = transcript.load_instances( @@ -45,9 +44,9 @@ macro_rules! halo2_kzg_evm_verify { .map(|instances| instances.len()) .collect_vec(), ); - let proof = <$plonk_verifier>::read_proof(&svk, &protocol, &instances, &mut transcript) - .unwrap(); - <$plonk_verifier>::verify(&svk, &dk, &protocol, &instances, &proof).unwrap(); + let proof = + <$plonk_verifier>::read_proof(&vk, &protocol, &instances, &mut transcript).unwrap(); + <$plonk_verifier>::verify(&vk, &protocol, &instances, &proof).unwrap(); compile_yul(&loader.yul_code()) }; @@ -101,11 +100,11 @@ macro_rules! test { } }; ($name:ident, $k:expr, $config:expr, $create_circuit:expr) => { - test!(@ #[test], shplonk, $name, $k, $config, $create_circuit, ProverSHPLONK<_>, VerifierSHPLONK<_>, Plonk, LimbsEncoding>); - test!(@ #[test], plonk, $name, $k, $config, $create_circuit, ProverGWC<_>, VerifierGWC<_>, Plonk, LimbsEncoding>); + test!(@ #[test], shplonk, $name, $k, $config, $create_circuit, ProverSHPLONK<_>, VerifierSHPLONK<_>, PlonkVerifier, LimbsEncoding>); + test!(@ #[test], plonk, $name, $k, $config, $create_circuit, ProverGWC<_>, VerifierGWC<_>, PlonkVerifier, LimbsEncoding>); }; ($(#[$attr:meta],)* $name:ident, $k:expr, $config:expr, $create_circuit:expr) => { - test!(@ #[test] $(,#[$attr])*, plonk, $name, $k, $config, $create_circuit, ProverGWC<_>, VerifierGWC<_>, Plonk, LimbsEncoding>); + test!(@ #[test] $(,#[$attr])*, plonk, $name, $k, $config, $create_circuit, ProverGWC<_>, VerifierGWC<_>, PlonkVerifier, LimbsEncoding>); }; } diff --git a/src/system/halo2/test/kzg/halo2.rs b/snark-verifier/src/system/halo2/test/kzg/halo2.rs similarity index 92% rename from src/system/halo2/test/kzg/halo2.rs rename to snark-verifier/src/system/halo2/test/kzg/halo2.rs index 314af5c7..1fd461da 100644 --- a/src/system/halo2/test/kzg/halo2.rs +++ b/snark-verifier/src/system/halo2/test/kzg/halo2.rs @@ -6,7 +6,7 @@ use crate::{ }, pcs::{ kzg::{ - Bdfg21, Kzg, KzgAccumulator, KzgAs, KzgAsProvingKey, KzgAsVerifyingKey, + Bdfg21, KzgAccumulator, KzgAs, KzgAsProvingKey, KzgAsVerifyingKey, KzgSuccinctVerifyingKey, LimbsEncoding, LimbsEncodingInstructions, }, AccumulationScheme, AccumulationSchemeProver, @@ -25,7 +25,7 @@ use crate::{ }, }, util::{arithmetic::fe_to_limbs, Itertools}, - verifier::{self, PlonkVerifier}, + verifier::{self, SnarkVerifier}, }; use halo2_curves::bn256::{Bn256, Fq, Fr, G1Affine}; use halo2_proofs::{ @@ -59,12 +59,12 @@ type Halo2Loader<'a> = loader::halo2::Halo2Loader<'a, G1Affine, BaseFieldEccChip type PoseidonTranscript = system::halo2::transcript::halo2::PoseidonTranscript; -type Pcs = Kzg; type Svk = KzgSuccinctVerifyingKey; -type As = KzgAs; +type As = KzgAs; type AsPk = KzgAsProvingKey; type AsVk = KzgAsVerifyingKey; -type Plonk = verifier::Plonk>; +type PlonkSuccinctVerifier = verifier::plonk::PlonkSuccinctVerifier>; +type PlonkVerifier = verifier::plonk::PlonkVerifier>; pub fn accumulate<'a>( svk: &Svk, @@ -92,8 +92,10 @@ pub fn accumulate<'a>( let instances = assign_instances(&snark.instances); let mut transcript = PoseidonTranscript::, _>::new(loader, snark.proof()); - let proof = Plonk::read_proof(svk, &protocol, &instances, &mut transcript).unwrap(); - Plonk::succinct_verify(svk, &protocol, &instances, &proof).unwrap() + let proof = + PlonkSuccinctVerifier::read_proof(svk, &protocol, &instances, &mut transcript) + .unwrap(); + PlonkSuccinctVerifier::verify(svk, &protocol, &instances, &proof).unwrap() }) .collect_vec(); @@ -133,10 +135,15 @@ impl Accumulation { .flat_map(|snark| { let mut transcript = PoseidonTranscript::::new(snark.proof.as_slice()); - let proof = - Plonk::read_proof(&svk, &snark.protocol, &snark.instances, &mut transcript) - .unwrap(); - Plonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof).unwrap() + let proof = PlonkSuccinctVerifier::read_proof( + &svk, + &snark.protocol, + &snark.instances, + &mut transcript, + ) + .unwrap(); + PlonkSuccinctVerifier::verify(&svk, &snark.protocol, &snark.instances, &proof) + .unwrap() }) .collect_vec(); @@ -343,7 +350,7 @@ macro_rules! test { &circuits ); halo2_kzg_native_verify!( - Plonk, + PlonkVerifier, params, &snark.protocol, &snark.instances, diff --git a/src/system/halo2/test/kzg/native.rs b/snark-verifier/src/system/halo2/test/kzg/native.rs similarity index 88% rename from src/system/halo2/test/kzg/native.rs rename to snark-verifier/src/system/halo2/test/kzg/native.rs index e52ceb38..b1d38e06 100644 --- a/src/system/halo2/test/kzg/native.rs +++ b/snark-verifier/src/system/halo2/test/kzg/native.rs @@ -1,5 +1,5 @@ use crate::{ - pcs::kzg::{Bdfg21, Gwc19, Kzg, LimbsEncoding}, + pcs::kzg::{Bdfg21, Gwc19, KzgAs, LimbsEncoding}, system::halo2::test::{ kzg::{ halo2_kzg_config, halo2_kzg_create_snark, halo2_kzg_native_verify, halo2_kzg_prepare, @@ -7,7 +7,7 @@ use crate::{ }, StandardPlonk, }, - verifier::Plonk, + verifier::plonk::PlonkVerifier, }; use halo2_curves::bn256::{Bn256, G1Affine}; use halo2_proofs::{ @@ -49,8 +49,8 @@ macro_rules! test { } }; ($name:ident, $k:expr, $config:expr, $create_cirucit:expr) => { - test!(@ shplonk, $name, $k, $config, $create_cirucit, ProverSHPLONK<_>, VerifierSHPLONK<_>, Plonk, LimbsEncoding>); - test!(@ plonk, $name, $k, $config, $create_cirucit, ProverGWC<_>, VerifierGWC<_>, Plonk, LimbsEncoding>); + test!(@ shplonk, $name, $k, $config, $create_cirucit, ProverSHPLONK<_>, VerifierSHPLONK<_>, PlonkVerifier, LimbsEncoding>); + test!(@ plonk, $name, $k, $config, $create_cirucit, ProverGWC<_>, VerifierGWC<_>, PlonkVerifier, LimbsEncoding>); } } diff --git a/src/system/halo2/transcript.rs b/snark-verifier/src/system/halo2/transcript.rs similarity index 100% rename from src/system/halo2/transcript.rs rename to snark-verifier/src/system/halo2/transcript.rs diff --git a/src/system/halo2/transcript/evm.rs b/snark-verifier/src/system/halo2/transcript/evm.rs similarity index 100% rename from src/system/halo2/transcript/evm.rs rename to snark-verifier/src/system/halo2/transcript/evm.rs diff --git a/src/system/halo2/transcript/halo2.rs b/snark-verifier/src/system/halo2/transcript/halo2.rs similarity index 100% rename from src/system/halo2/transcript/halo2.rs rename to snark-verifier/src/system/halo2/transcript/halo2.rs diff --git a/src/util.rs b/snark-verifier/src/util.rs similarity index 98% rename from src/util.rs rename to snark-verifier/src/util.rs index b42db61c..bbfa8c89 100644 --- a/src/util.rs +++ b/snark-verifier/src/util.rs @@ -2,7 +2,6 @@ pub mod arithmetic; pub mod hash; pub mod msm; pub mod poly; -pub mod protocol; pub mod transcript; pub(crate) use itertools::Itertools; diff --git a/src/util/arithmetic.rs b/snark-verifier/src/util/arithmetic.rs similarity index 100% rename from src/util/arithmetic.rs rename to snark-verifier/src/util/arithmetic.rs diff --git a/src/util/hash.rs b/snark-verifier/src/util/hash.rs similarity index 100% rename from src/util/hash.rs rename to snark-verifier/src/util/hash.rs diff --git a/src/util/hash/poseidon.rs b/snark-verifier/src/util/hash/poseidon.rs similarity index 100% rename from src/util/hash/poseidon.rs rename to snark-verifier/src/util/hash/poseidon.rs diff --git a/src/util/msm.rs b/snark-verifier/src/util/msm.rs similarity index 100% rename from src/util/msm.rs rename to snark-verifier/src/util/msm.rs diff --git a/src/util/poly.rs b/snark-verifier/src/util/poly.rs similarity index 100% rename from src/util/poly.rs rename to snark-verifier/src/util/poly.rs diff --git a/src/util/protocol.rs b/snark-verifier/src/util/protocol.rs similarity index 90% rename from src/util/protocol.rs rename to snark-verifier/src/util/protocol.rs index 2eaf604e..6ae361db 100644 --- a/src/util/protocol.rs +++ b/snark-verifier/src/util/protocol.rs @@ -4,7 +4,6 @@ use crate::{ arithmetic::{CurveAffine, Domain, Field, Fraction, Rotation}, Itertools, }, - Protocol, }; use num_integer::Integer; use num_traits::One; @@ -16,37 +15,6 @@ use std::{ ops::{Add, Mul, Neg, Sub}, }; -impl Protocol -where - C: CurveAffine, -{ - pub fn loaded>(&self, loader: &L) -> Protocol { - let preprocessed = self - .preprocessed - .iter() - .map(|preprocessed| loader.ec_point_load_const(preprocessed)) - .collect(); - let transcript_initial_state = self - .transcript_initial_state - .as_ref() - .map(|transcript_initial_state| loader.load_const(transcript_initial_state)); - Protocol { - domain: self.domain.clone(), - preprocessed, - num_instance: self.num_instance.clone(), - num_witness: self.num_witness.clone(), - num_challenge: self.num_challenge.clone(), - evaluations: self.evaluations.clone(), - queries: self.queries.clone(), - quotient: self.quotient.clone(), - transcript_initial_state, - instance_committing_key: self.instance_committing_key.clone(), - linearization: self.linearization, - accumulator_indices: self.accumulator_indices.clone(), - } - } -} - #[derive(Clone, Copy, Debug)] pub enum CommonPolynomial { Identity, diff --git a/src/util/transcript.rs b/snark-verifier/src/util/transcript.rs similarity index 100% rename from src/util/transcript.rs rename to snark-verifier/src/util/transcript.rs diff --git a/snark-verifier/src/verifier.rs b/snark-verifier/src/verifier.rs new file mode 100644 index 00000000..c492fe55 --- /dev/null +++ b/snark-verifier/src/verifier.rs @@ -0,0 +1,35 @@ +use crate::{ + loader::Loader, + util::{arithmetic::CurveAffine, transcript::TranscriptRead}, + Error, +}; +use std::fmt::Debug; + +pub mod plonk; + +pub trait SnarkVerifier +where + C: CurveAffine, + L: Loader, +{ + type VerifyingKey: Clone + Debug; + type Protocol: Clone + Debug; + type Proof: Clone + Debug; + type Output: Clone + Debug; + + fn read_proof( + vk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead; + + fn verify( + vk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + proof: &Self::Proof, + ) -> Result; +} diff --git a/snark-verifier/src/verifier/plonk.rs b/snark-verifier/src/verifier/plonk.rs new file mode 100644 index 00000000..08bf5dc9 --- /dev/null +++ b/snark-verifier/src/verifier/plonk.rs @@ -0,0 +1,173 @@ +use crate::{ + cost::{Cost, CostEstimation}, + loader::Loader, + pcs::{ + AccumulationDecider, AccumulationScheme, AccumulatorEncoding, PolynomialCommitmentScheme, + Query, + }, + util::{arithmetic::CurveAffine, transcript::TranscriptRead}, + verifier::{plonk::protocol::CommonPolynomialEvaluation, SnarkVerifier}, + Error, +}; +use std::{iter, marker::PhantomData}; + +mod proof; +pub(crate) mod protocol; + +pub use proof::PlonkProof; +pub use protocol::PlonkProtocol; + +pub struct PlonkSuccinctVerifier>(PhantomData<(AS, AE)>); + +impl SnarkVerifier for PlonkSuccinctVerifier +where + C: CurveAffine, + L: Loader, + AS: AccumulationScheme + PolynomialCommitmentScheme, + AE: AccumulatorEncoding, +{ + type VerifyingKey = >::VerifyingKey; + type Protocol = PlonkProtocol; + type Proof = PlonkProof; + type Output = Vec; + + fn read_proof( + svk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + PlonkProof::read::(svk, protocol, instances, transcript) + } + + fn verify( + svk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + proof: &Self::Proof, + ) -> Result { + let common_poly_eval = { + let mut common_poly_eval = + CommonPolynomialEvaluation::new(&protocol.domain, protocol.langranges(), &proof.z); + + L::batch_invert(common_poly_eval.denoms()); + common_poly_eval.evaluate(); + + common_poly_eval + }; + + let mut evaluations = proof.evaluations(protocol, instances, &common_poly_eval)?; + let commitments = proof.commitments(protocol, &common_poly_eval, &mut evaluations)?; + let queries = proof.queries(protocol, evaluations); + + let accumulator = >::verify( + svk, + &commitments, + &proof.z, + &queries, + &proof.pcs, + )?; + + let accumulators = iter::empty() + .chain(Some(accumulator)) + .chain(proof.old_accumulators.iter().cloned()) + .collect(); + + Ok(accumulators) + } +} + +pub struct PlonkVerifier>(PhantomData<(AS, AE)>); + +impl SnarkVerifier for PlonkVerifier +where + C: CurveAffine, + L: Loader, + AS: AccumulationDecider + PolynomialCommitmentScheme, + AS::DecidingKey: AsRef<>::VerifyingKey>, + AE: AccumulatorEncoding, +{ + type VerifyingKey = AS::DecidingKey; + type Protocol = PlonkProtocol; + type Proof = PlonkProof; + type Output = (); + + fn read_proof( + vk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + transcript: &mut T, + ) -> Result + where + T: TranscriptRead, + { + PlonkProof::read::(vk.as_ref(), protocol, instances, transcript) + } + + fn verify( + vk: &Self::VerifyingKey, + protocol: &Self::Protocol, + instances: &[Vec], + proof: &Self::Proof, + ) -> Result { + let accumulators = + PlonkSuccinctVerifier::::verify(vk.as_ref(), protocol, instances, proof)?; + AS::decide_all(vk, accumulators) + } +} + +impl CostEstimation<(C, L)> for PlonkSuccinctVerifier +where + C: CurveAffine, + L: Loader, + AS: AccumulationScheme + + PolynomialCommitmentScheme + + CostEstimation>>, +{ + type Input = PlonkProtocol; + + fn estimate_cost(protocol: &PlonkProtocol) -> Cost { + let plonk_cost = { + let num_accumulator = protocol.accumulator_indices.len(); + let num_instance = protocol.num_instance.iter().sum(); + let num_commitment = + protocol.num_witness.iter().sum::() + protocol.quotient.num_chunk(); + let num_evaluation = protocol.evaluations.len(); + let num_msm = protocol.preprocessed.len() + num_commitment + 1 + 2 * num_accumulator; + Cost { + num_instance, + num_commitment, + num_evaluation, + num_msm, + ..Default::default() + } + }; + let pcs_cost = { + let queries = PlonkProof::::empty_queries(protocol); + AS::estimate_cost(&queries) + }; + plonk_cost + pcs_cost + } +} + +impl CostEstimation<(C, L)> for PlonkVerifier +where + C: CurveAffine, + L: Loader, + AS: AccumulationScheme + + PolynomialCommitmentScheme + + CostEstimation>>, +{ + type Input = PlonkProtocol; + + fn estimate_cost(protocol: &PlonkProtocol) -> Cost { + PlonkSuccinctVerifier::::estimate_cost(protocol) + + Cost { + num_pairing: 2, + ..Default::default() + } + } +} diff --git a/src/verifier/plonk.rs b/snark-verifier/src/verifier/plonk/proof.rs similarity index 65% rename from src/verifier/plonk.rs rename to snark-verifier/src/verifier/plonk/proof.rs index e29410d3..fb12aed6 100644 --- a/src/verifier/plonk.rs +++ b/snark-verifier/src/verifier/plonk/proof.rs @@ -1,84 +1,26 @@ use crate::{ - cost::{Cost, CostEstimation}, loader::{LoadedScalar, Loader}, - pcs::{self, AccumulatorEncoding, MultiOpenScheme}, + pcs::{self, AccumulationScheme, AccumulatorEncoding, PolynomialCommitmentScheme}, util::{ arithmetic::{CurveAffine, Field, Rotation}, msm::Msm, - protocol::{ - CommonPolynomial::Lagrange, CommonPolynomialEvaluation, LinearizationStrategy, Query, - }, transcript::TranscriptRead, Itertools, }, - verifier::PlonkVerifier, - Error, Protocol, + verifier::plonk::protocol::{ + CommonPolynomial::Lagrange, CommonPolynomialEvaluation, LinearizationStrategy, + PlonkProtocol, Query, + }, + Error, }; -use std::{collections::HashMap, iter, marker::PhantomData}; - -pub struct Plonk(PhantomData<(MOS, AE)>); - -impl PlonkVerifier for Plonk -where - C: CurveAffine, - L: Loader, - MOS: MultiOpenScheme, - AE: AccumulatorEncoding, -{ - type Proof = PlonkProof; - - fn read_proof( - svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, - instances: &[Vec], - transcript: &mut T, - ) -> Result - where - T: TranscriptRead, - { - PlonkProof::read::(svk, protocol, instances, transcript) - } - - fn succinct_verify( - svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, - instances: &[Vec], - proof: &Self::Proof, - ) -> Result, Error> { - let common_poly_eval = { - let mut common_poly_eval = CommonPolynomialEvaluation::new( - &protocol.domain, - langranges(protocol, instances), - &proof.z, - ); - - L::batch_invert(common_poly_eval.denoms()); - common_poly_eval.evaluate(); - - common_poly_eval - }; - - let mut evaluations = proof.evaluations(protocol, instances, &common_poly_eval)?; - let commitments = proof.commitments(protocol, &common_poly_eval, &mut evaluations)?; - let queries = proof.queries(protocol, evaluations); - - let accumulator = MOS::succinct_verify(svk, &commitments, &proof.z, &queries, &proof.pcs)?; - - let accumulators = iter::empty() - .chain(Some(accumulator)) - .chain(proof.old_accumulators.iter().cloned()) - .collect(); - - Ok(accumulators) - } -} +use std::{collections::HashMap, iter}; #[derive(Clone, Debug)] -pub struct PlonkProof +pub struct PlonkProof where C: CurveAffine, L: Loader, - MOS: MultiOpenScheme, + AS: AccumulationScheme + PolynomialCommitmentScheme, { pub committed_instances: Option>, pub witnesses: Vec, @@ -86,25 +28,25 @@ where pub quotients: Vec, pub z: L::LoadedScalar, pub evaluations: Vec, - pub pcs: MOS::Proof, - pub old_accumulators: Vec, + pub pcs: >::Proof, + pub old_accumulators: Vec, } -impl PlonkProof +impl PlonkProof where C: CurveAffine, L: Loader, - MOS: MultiOpenScheme, + AS: AccumulationScheme + PolynomialCommitmentScheme, { pub fn read( - svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, + svk: &>::VerifyingKey, + protocol: &PlonkProtocol, instances: &[Vec], transcript: &mut T, ) -> Result where T: TranscriptRead, - AE: AccumulatorEncoding, + AE: AccumulatorEncoding, { if let Some(transcript_initial_state) = &protocol.transcript_initial_state { transcript.common_scalar(transcript_initial_state)?; @@ -184,7 +126,11 @@ where let z = transcript.squeeze_challenge(); let evaluations = transcript.read_n_scalars(protocol.evaluations.len())?; - let pcs = MOS::read_proof(svk, &Self::empty_queries(protocol), transcript)?; + let pcs = >::read_proof( + svk, + &Self::empty_queries(protocol), + transcript, + )?; let old_accumulators = protocol .accumulator_indices @@ -211,7 +157,7 @@ where }) } - pub fn empty_queries(protocol: &Protocol) -> Vec> { + pub fn empty_queries(protocol: &PlonkProtocol) -> Vec> { protocol .queries .iter() @@ -225,9 +171,9 @@ where .collect() } - fn queries( + pub(super) fn queries( &self, - protocol: &Protocol, + protocol: &PlonkProtocol, mut evaluations: HashMap, ) -> Vec> { Self::empty_queries(protocol) @@ -242,9 +188,9 @@ where .collect() } - fn commitments<'a>( + pub(super) fn commitments<'a>( &'a self, - protocol: &'a Protocol, + protocol: &'a PlonkProtocol, common_poly_eval: &CommonPolynomialEvaluation, evaluations: &mut HashMap, ) -> Result>, Error> { @@ -279,14 +225,14 @@ where .then(|| commitments.get(query.poly).cloned()) .flatten() }) - .ok_or(Error::InvalidQuery(query)) + .ok_or_else(|| Error::InvalidProtocol(format!("Missing query {query:?}"))) }, &|index| { self.challenges .get(index) .cloned() .map(Msm::constant) - .ok_or(Error::InvalidChallenge(index)) + .ok_or_else(|| Error::InvalidProtocol(format!("Missing challenge {index}"))) }, &|a| Ok(-a?), &|a, b| Ok(a? + b?), @@ -295,7 +241,7 @@ where match (a.size(), b.size()) { (0, _) => Ok(b * &a.try_into_constant().unwrap()), (_, 0) => Ok(a * &b.try_into_constant().unwrap()), - (_, _) => Err(Error::InvalidLinearization), + (_, _) => Err(Error::InvalidProtocol("Invalid linearization".to_string())), } }, &|a, scalar| Ok(a? * &loader.load_const(&scalar)), @@ -339,10 +285,9 @@ where commitments.push(quotient); evaluations.insert( quotient_query, - numerator - .try_into_constant() - .ok_or(Error::InvalidLinearization)? - * common_poly_eval.zn_minus_one_inv(), + numerator.try_into_constant().ok_or_else(|| { + Error::InvalidProtocol("Invalid linearization".to_string()) + })? * common_poly_eval.zn_minus_one_inv(), ); } } @@ -350,9 +295,9 @@ where Ok(commitments) } - fn evaluations( + pub(super) fn evaluations( &self, - protocol: &Protocol, + protocol: &PlonkProtocol, instances: &[Vec], common_poly_eval: &CommonPolynomialEvaluation, ) -> Result, Error> { @@ -393,72 +338,3 @@ where Ok(evals) } } - -impl CostEstimation<(C, L)> for Plonk -where - C: CurveAffine, - L: Loader, - MOS: MultiOpenScheme + CostEstimation>>, -{ - type Input = Protocol; - - fn estimate_cost(protocol: &Protocol) -> Cost { - let plonk_cost = { - let num_accumulator = protocol.accumulator_indices.len(); - let num_instance = protocol.num_instance.iter().sum(); - let num_commitment = - protocol.num_witness.iter().sum::() + protocol.quotient.num_chunk(); - let num_evaluation = protocol.evaluations.len(); - let num_msm = protocol.preprocessed.len() + num_commitment + 1 + 2 * num_accumulator; - Cost::new(num_instance, num_commitment, num_evaluation, num_msm) - }; - let pcs_cost = { - let queries = PlonkProof::::empty_queries(protocol); - MOS::estimate_cost(&queries) - }; - plonk_cost + pcs_cost - } -} - -fn langranges( - protocol: &Protocol, - instances: &[Vec], -) -> impl IntoIterator -where - C: CurveAffine, - L: Loader, -{ - let instance_eval_lagrange = protocol.instance_committing_key.is_none().then(|| { - let queries = { - let offset = protocol.preprocessed.len(); - let range = offset..offset + protocol.num_instance.len(); - protocol - .quotient - .numerator - .used_query() - .into_iter() - .filter(move |query| range.contains(&query.poly)) - }; - let (min_rotation, max_rotation) = queries.fold((0, 0), |(min, max), query| { - if query.rotation.0 < min { - (query.rotation.0, max) - } else if query.rotation.0 > max { - (min, query.rotation.0) - } else { - (min, max) - } - }); - let max_instance_len = instances - .iter() - .map(|instance| instance.len()) - .max() - .unwrap_or_default(); - -max_rotation..max_instance_len as i32 + min_rotation.abs() - }); - protocol - .quotient - .numerator - .used_langrange() - .into_iter() - .chain(instance_eval_lagrange.into_iter().flatten()) -} diff --git a/snark-verifier/src/verifier/plonk/protocol.rs b/snark-verifier/src/verifier/plonk/protocol.rs new file mode 100644 index 00000000..daaa58a9 --- /dev/null +++ b/snark-verifier/src/verifier/plonk/protocol.rs @@ -0,0 +1,503 @@ +use crate::{ + loader::{native::NativeLoader, LoadedScalar, Loader}, + util::{ + arithmetic::{CurveAffine, Domain, Field, Fraction, Rotation}, + Itertools, + }, +}; +use num_integer::Integer; +use num_traits::One; +use std::{ + cmp::max, + collections::{BTreeMap, BTreeSet}, + fmt::Debug, + iter::{self, Sum}, + ops::{Add, Mul, Neg, Sub}, +}; + +#[derive(Clone, Debug)] +pub struct PlonkProtocol +where + C: CurveAffine, + L: Loader, +{ + // Common description + pub domain: Domain, + pub preprocessed: Vec, + pub num_instance: Vec, + pub num_witness: Vec, + pub num_challenge: Vec, + pub evaluations: Vec, + pub queries: Vec, + pub quotient: QuotientPolynomial, + // Minor customization + pub transcript_initial_state: Option, + pub instance_committing_key: Option>, + pub linearization: Option, + pub accumulator_indices: Vec>, +} + +impl PlonkProtocol +where + C: CurveAffine, + L: Loader, +{ + pub(super) fn langranges(&self) -> impl IntoIterator { + let instance_eval_lagrange = self.instance_committing_key.is_none().then(|| { + let queries = { + let offset = self.preprocessed.len(); + let range = offset..offset + self.num_instance.len(); + self.quotient + .numerator + .used_query() + .into_iter() + .filter(move |query| range.contains(&query.poly)) + }; + let (min_rotation, max_rotation) = queries.fold((0, 0), |(min, max), query| { + if query.rotation.0 < min { + (query.rotation.0, max) + } else if query.rotation.0 > max { + (min, query.rotation.0) + } else { + (min, max) + } + }); + let max_instance_len = self.num_instance.iter().max().copied().unwrap_or_default(); + -max_rotation..max_instance_len as i32 + min_rotation.abs() + }); + self.quotient + .numerator + .used_langrange() + .into_iter() + .chain(instance_eval_lagrange.into_iter().flatten()) + } +} +impl PlonkProtocol +where + C: CurveAffine, +{ + pub fn loaded>(&self, loader: &L) -> PlonkProtocol { + let preprocessed = self + .preprocessed + .iter() + .map(|preprocessed| loader.ec_point_load_const(preprocessed)) + .collect(); + let transcript_initial_state = self + .transcript_initial_state + .as_ref() + .map(|transcript_initial_state| loader.load_const(transcript_initial_state)); + PlonkProtocol { + domain: self.domain.clone(), + preprocessed, + num_instance: self.num_instance.clone(), + num_witness: self.num_witness.clone(), + num_challenge: self.num_challenge.clone(), + evaluations: self.evaluations.clone(), + queries: self.queries.clone(), + quotient: self.quotient.clone(), + transcript_initial_state, + instance_committing_key: self.instance_committing_key.clone(), + linearization: self.linearization, + accumulator_indices: self.accumulator_indices.clone(), + } + } +} + +#[cfg(feature = "loader_halo2")] +mod halo2 { + use crate::{ + loader::halo2::{EccInstructions, Halo2Loader}, + util::arithmetic::CurveAffine, + verifier::plonk::PlonkProtocol, + }; + use halo2_proofs::circuit; + use std::rc::Rc; + + impl PlonkProtocol + where + C: CurveAffine, + { + pub fn loaded_preprocessed_as_witness<'a, EccChip: EccInstructions<'a, C>>( + &self, + loader: &Rc>, + ) -> PlonkProtocol>> { + let preprocessed = self + .preprocessed + .iter() + .map(|preprocessed| loader.assign_ec_point(circuit::Value::known(*preprocessed))) + .collect(); + let transcript_initial_state = + self.transcript_initial_state + .as_ref() + .map(|transcript_initial_state| { + loader.assign_scalar(circuit::Value::known(*transcript_initial_state)) + }); + PlonkProtocol { + domain: self.domain.clone(), + preprocessed, + num_instance: self.num_instance.clone(), + num_witness: self.num_witness.clone(), + num_challenge: self.num_challenge.clone(), + evaluations: self.evaluations.clone(), + queries: self.queries.clone(), + quotient: self.quotient.clone(), + transcript_initial_state, + instance_committing_key: self.instance_committing_key.clone(), + linearization: self.linearization, + accumulator_indices: self.accumulator_indices.clone(), + } + } + } +} + +#[derive(Clone, Copy, Debug)] +pub enum CommonPolynomial { + Identity, + Lagrange(i32), +} + +#[derive(Clone, Debug)] +pub struct CommonPolynomialEvaluation +where + C: CurveAffine, + L: Loader, +{ + zn: L::LoadedScalar, + zn_minus_one: L::LoadedScalar, + zn_minus_one_inv: Fraction, + identity: L::LoadedScalar, + lagrange: BTreeMap>, +} + +impl CommonPolynomialEvaluation +where + C: CurveAffine, + L: Loader, +{ + pub fn new( + domain: &Domain, + langranges: impl IntoIterator, + z: &L::LoadedScalar, + ) -> Self { + let loader = z.loader(); + + let zn = z.pow_const(domain.n as u64); + let langranges = langranges.into_iter().sorted().dedup().collect_vec(); + + let one = loader.load_one(); + let zn_minus_one = zn.clone() - &one; + let zn_minus_one_inv = Fraction::one_over(zn_minus_one.clone()); + + let n_inv = loader.load_const(&domain.n_inv); + let numer = zn_minus_one.clone() * &n_inv; + let omegas = langranges + .iter() + .map(|&i| loader.load_const(&domain.rotate_scalar(C::Scalar::one(), Rotation(i)))) + .collect_vec(); + let lagrange_evals = omegas + .iter() + .map(|omega| Fraction::new(numer.clone() * omega, z.clone() - omega)) + .collect_vec(); + + Self { + zn, + zn_minus_one, + zn_minus_one_inv, + identity: z.clone(), + lagrange: langranges.into_iter().zip(lagrange_evals).collect(), + } + } + + pub fn zn(&self) -> &L::LoadedScalar { + &self.zn + } + + pub fn zn_minus_one(&self) -> &L::LoadedScalar { + &self.zn_minus_one + } + + pub fn zn_minus_one_inv(&self) -> &L::LoadedScalar { + self.zn_minus_one_inv.evaluated() + } + + pub fn get(&self, poly: CommonPolynomial) -> &L::LoadedScalar { + match poly { + CommonPolynomial::Identity => &self.identity, + CommonPolynomial::Lagrange(i) => self.lagrange.get(&i).unwrap().evaluated(), + } + } + + pub fn denoms(&mut self) -> impl IntoIterator { + self.lagrange + .iter_mut() + .map(|(_, value)| value.denom_mut()) + .chain(iter::once(self.zn_minus_one_inv.denom_mut())) + .flatten() + } + + pub fn evaluate(&mut self) { + self.lagrange + .iter_mut() + .map(|(_, value)| value) + .chain(iter::once(&mut self.zn_minus_one_inv)) + .for_each(Fraction::evaluate) + } +} + +#[derive(Clone, Debug)] +pub struct QuotientPolynomial { + pub chunk_degree: usize, + pub numerator: Expression, +} + +impl QuotientPolynomial { + pub fn num_chunk(&self) -> usize { + Integer::div_ceil( + &(self.numerator.degree().checked_sub(1).unwrap_or_default()), + &self.chunk_degree, + ) + } +} + +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Query { + pub poly: usize, + pub rotation: Rotation, +} + +impl Query { + pub fn new>(poly: usize, rotation: R) -> Self { + Self { + poly, + rotation: rotation.into(), + } + } +} + +#[derive(Clone, Debug)] +pub enum Expression { + Constant(F), + CommonPolynomial(CommonPolynomial), + Polynomial(Query), + Challenge(usize), + Negated(Box>), + Sum(Box>, Box>), + Product(Box>, Box>), + Scaled(Box>, F), + DistributePowers(Vec>, Box>), +} + +impl Expression { + pub fn evaluate( + &self, + constant: &impl Fn(F) -> T, + common_poly: &impl Fn(CommonPolynomial) -> T, + poly: &impl Fn(Query) -> T, + challenge: &impl Fn(usize) -> T, + negated: &impl Fn(T) -> T, + sum: &impl Fn(T, T) -> T, + product: &impl Fn(T, T) -> T, + scaled: &impl Fn(T, F) -> T, + ) -> T { + let evaluate = |expr: &Expression| { + expr.evaluate( + constant, + common_poly, + poly, + challenge, + negated, + sum, + product, + scaled, + ) + }; + match self { + Expression::Constant(scalar) => constant(scalar.clone()), + Expression::CommonPolynomial(poly) => common_poly(*poly), + Expression::Polynomial(query) => poly(*query), + Expression::Challenge(index) => challenge(*index), + Expression::Negated(a) => { + let a = evaluate(a); + negated(a) + } + Expression::Sum(a, b) => { + let a = evaluate(a); + let b = evaluate(b); + sum(a, b) + } + Expression::Product(a, b) => { + let a = evaluate(a); + let b = evaluate(b); + product(a, b) + } + Expression::Scaled(a, scalar) => { + let a = evaluate(a); + scaled(a, scalar.clone()) + } + Expression::DistributePowers(exprs, scalar) => { + assert!(!exprs.is_empty()); + if exprs.len() == 1 { + return evaluate(exprs.first().unwrap()); + } + let mut exprs = exprs.iter(); + let first = evaluate(exprs.next().unwrap()); + let scalar = evaluate(scalar); + exprs.fold(first, |acc, expr| { + sum(product(acc, scalar.clone()), evaluate(expr)) + }) + } + } + } + + pub fn degree(&self) -> usize { + match self { + Expression::Constant(_) => 0, + Expression::CommonPolynomial(_) => 1, + Expression::Polynomial { .. } => 1, + Expression::Challenge { .. } => 0, + Expression::Negated(a) => a.degree(), + Expression::Sum(a, b) => max(a.degree(), b.degree()), + Expression::Product(a, b) => a.degree() + b.degree(), + Expression::Scaled(a, _) => a.degree(), + Expression::DistributePowers(a, b) => a + .iter() + .chain(Some(b.as_ref())) + .map(Self::degree) + .max() + .unwrap_or_default(), + } + } + + pub fn used_langrange(&self) -> BTreeSet { + self.evaluate( + &|_| None, + &|poly| match poly { + CommonPolynomial::Lagrange(i) => Some(BTreeSet::from_iter([i])), + _ => None, + }, + &|_| None, + &|_| None, + &|a| a, + &merge_left_right, + &merge_left_right, + &|a, _| a, + ) + .unwrap_or_default() + } + + pub fn used_query(&self) -> BTreeSet { + self.evaluate( + &|_| None, + &|_| None, + &|query| Some(BTreeSet::from_iter([query])), + &|_| None, + &|a| a, + &merge_left_right, + &merge_left_right, + &|a, _| a, + ) + .unwrap_or_default() + } +} + +impl From for Expression { + fn from(query: Query) -> Self { + Self::Polynomial(query) + } +} + +impl From for Expression { + fn from(common_poly: CommonPolynomial) -> Self { + Self::CommonPolynomial(common_poly) + } +} + +macro_rules! impl_expression_ops { + ($trait:ident, $op:ident, $variant:ident, $rhs:ty, $rhs_expr:expr) => { + impl $trait<$rhs> for Expression { + type Output = Expression; + fn $op(self, rhs: $rhs) -> Self::Output { + Expression::$variant((self).into(), $rhs_expr(rhs).into()) + } + } + impl $trait<$rhs> for &Expression { + type Output = Expression; + fn $op(self, rhs: $rhs) -> Self::Output { + Expression::$variant((self.clone()).into(), $rhs_expr(rhs).into()) + } + } + impl $trait<&$rhs> for Expression { + type Output = Expression; + fn $op(self, rhs: &$rhs) -> Self::Output { + Expression::$variant((self).into(), $rhs_expr(rhs.clone()).into()) + } + } + impl $trait<&$rhs> for &Expression { + type Output = Expression; + fn $op(self, rhs: &$rhs) -> Self::Output { + Expression::$variant((self.clone()).into(), $rhs_expr(rhs.clone()).into()) + } + } + }; +} + +impl_expression_ops!(Mul, mul, Product, Expression, std::convert::identity); +impl_expression_ops!(Mul, mul, Scaled, F, std::convert::identity); +impl_expression_ops!(Add, add, Sum, Expression, std::convert::identity); +impl_expression_ops!(Sub, sub, Sum, Expression, Neg::neg); + +impl Neg for Expression { + type Output = Expression; + fn neg(self) -> Self::Output { + Expression::Negated(Box::new(self)) + } +} + +impl Neg for &Expression { + type Output = Expression; + fn neg(self) -> Self::Output { + Expression::Negated(Box::new(self.clone())) + } +} + +impl Sum for Expression { + fn sum>(iter: I) -> Self { + iter.reduce(|acc, item| acc + item) + .unwrap_or_else(|| Expression::Constant(F::default())) + } +} + +impl One for Expression { + fn one() -> Self { + Expression::Constant(F::one()) + } +} + +fn merge_left_right(a: Option>, b: Option>) -> Option> { + match (a, b) { + (Some(a), None) | (None, Some(a)) => Some(a), + (Some(mut a), Some(b)) => { + a.extend(b); + Some(a) + } + _ => None, + } +} + +#[derive(Clone, Copy, Debug)] +pub enum LinearizationStrategy { + /// Older linearization strategy of GWC19, which has linearization + /// polynomial that doesn't evaluate to 0, and requires prover to send extra + /// evaluation of it to verifier. + WithoutConstant, + /// Current linearization strategy of GWC19, which has linearization + /// polynomial that evaluate to 0 by subtracting product of vanishing and + /// quotient polynomials. + MinusVanishingTimesQuotient, +} + +#[derive(Clone, Debug, Default)] +pub struct InstanceCommittingKey { + pub bases: Vec, + pub constant: Option, +} diff --git a/src/cost.rs b/src/cost.rs deleted file mode 100644 index b085aed8..00000000 --- a/src/cost.rs +++ /dev/null @@ -1,44 +0,0 @@ -use std::ops::Add; - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Cost { - pub num_instance: usize, - pub num_commitment: usize, - pub num_evaluation: usize, - pub num_msm: usize, -} - -impl Cost { - pub fn new( - num_instance: usize, - num_commitment: usize, - num_evaluation: usize, - num_msm: usize, - ) -> Self { - Self { - num_instance, - num_commitment, - num_evaluation, - num_msm, - } - } -} - -impl Add for Cost { - type Output = Cost; - - fn add(self, rhs: Cost) -> Self::Output { - Cost::new( - self.num_instance + rhs.num_instance, - self.num_commitment + rhs.num_commitment, - self.num_evaluation + rhs.num_evaluation, - self.num_msm + rhs.num_msm, - ) - } -} - -pub trait CostEstimation { - type Input; - - fn estimate_cost(input: &Self::Input) -> Cost; -} diff --git a/src/lib.rs b/src/lib.rs deleted file mode 100644 index 9749924d..00000000 --- a/src/lib.rs +++ /dev/null @@ -1,42 +0,0 @@ -#![allow(clippy::type_complexity)] -#![allow(clippy::too_many_arguments)] -#![allow(clippy::upper_case_acronyms)] - -pub mod cost; -pub mod loader; -pub mod pcs; -pub mod system; -pub mod util; -pub mod verifier; - -#[derive(Clone, Debug)] -pub enum Error { - InvalidInstances, - InvalidLinearization, - InvalidQuery(util::protocol::Query), - InvalidChallenge(usize), - AssertionFailure(String), - Transcript(std::io::ErrorKind, String), -} - -#[derive(Clone, Debug)] -pub struct Protocol -where - C: util::arithmetic::CurveAffine, - L: loader::Loader, -{ - // Common description - pub domain: util::arithmetic::Domain, - pub preprocessed: Vec, - pub num_instance: Vec, - pub num_witness: Vec, - pub num_challenge: Vec, - pub evaluations: Vec, - pub queries: Vec, - pub quotient: util::protocol::QuotientPolynomial, - // Minor customization - pub transcript_initial_state: Option, - pub instance_committing_key: Option>, - pub linearization: Option, - pub accumulator_indices: Vec>, -} diff --git a/src/loader/halo2.rs b/src/loader/halo2.rs deleted file mode 100644 index 5b3361fa..00000000 --- a/src/loader/halo2.rs +++ /dev/null @@ -1,69 +0,0 @@ -use crate::{util::arithmetic::CurveAffine, Protocol}; -use halo2_proofs::circuit; -use std::rc::Rc; - -pub(crate) mod loader; -mod shim; - -#[cfg(test)] -pub(crate) mod test; - -pub use loader::{EcPoint, Halo2Loader, Scalar}; -pub use shim::{Context, EccInstructions, IntegerInstructions}; -pub use util::Valuetools; - -pub use halo2_wrong_ecc; - -mod util { - use halo2_proofs::circuit::Value; - - pub trait Valuetools: Iterator> { - fn fold_zipped(self, init: B, mut f: F) -> Value - where - Self: Sized, - F: FnMut(B, V) -> B, - { - self.fold(Value::known(init), |acc, value| { - acc.zip(value).map(|(acc, value)| f(acc, value)) - }) - } - } - - impl>> Valuetools for I {} -} - -impl Protocol -where - C: CurveAffine, -{ - pub fn loaded_preprocessed_as_witness<'a, EccChip: EccInstructions<'a, C>>( - &self, - loader: &Rc>, - ) -> Protocol>> { - let preprocessed = self - .preprocessed - .iter() - .map(|preprocessed| loader.assign_ec_point(circuit::Value::known(*preprocessed))) - .collect(); - let transcript_initial_state = - self.transcript_initial_state - .as_ref() - .map(|transcript_initial_state| { - loader.assign_scalar(circuit::Value::known(*transcript_initial_state)) - }); - Protocol { - domain: self.domain.clone(), - preprocessed, - num_instance: self.num_instance.clone(), - num_witness: self.num_witness.clone(), - num_challenge: self.num_challenge.clone(), - evaluations: self.evaluations.clone(), - queries: self.queries.clone(), - quotient: self.quotient.clone(), - transcript_initial_state, - instance_committing_key: self.instance_committing_key.clone(), - linearization: self.linearization, - accumulator_indices: self.accumulator_indices.clone(), - } - } -} diff --git a/src/pcs/ipa/decider.rs b/src/pcs/ipa/decider.rs deleted file mode 100644 index 2cf8c6cc..00000000 --- a/src/pcs/ipa/decider.rs +++ /dev/null @@ -1,57 +0,0 @@ -#[derive(Clone, Debug)] -pub struct IpaDecidingKey { - pub g: Vec, -} - -impl IpaDecidingKey { - pub fn new(g: Vec) -> Self { - Self { g } - } -} - -impl From> for IpaDecidingKey { - fn from(g: Vec) -> IpaDecidingKey { - IpaDecidingKey::new(g) - } -} - -mod native { - use crate::{ - loader::native::NativeLoader, - pcs::{ - ipa::{h_coeffs, Ipa, IpaAccumulator, IpaDecidingKey}, - Decider, - }, - util::{ - arithmetic::{Curve, CurveAffine, Field}, - msm::multi_scalar_multiplication, - }, - }; - use std::fmt::Debug; - - impl Decider for Ipa - where - C: CurveAffine, - MOS: Clone + Debug, - { - type DecidingKey = IpaDecidingKey; - type Output = bool; - - fn decide( - dk: &Self::DecidingKey, - IpaAccumulator { u, xi }: IpaAccumulator, - ) -> bool { - let h = h_coeffs(&xi, C::Scalar::one()); - u == multi_scalar_multiplication(&h, &dk.g).to_affine() - } - - fn decide_all( - dk: &Self::DecidingKey, - accumulators: Vec>, - ) -> bool { - !accumulators - .into_iter() - .any(|accumulator| !Self::decide(dk, accumulator)) - } - } -} diff --git a/src/pcs/ipa/multiopen.rs b/src/pcs/ipa/multiopen.rs deleted file mode 100644 index 9f685e76..00000000 --- a/src/pcs/ipa/multiopen.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod bgh19; - -pub use bgh19::{Bgh19, Bgh19Proof, Bgh19SuccinctVerifyingKey}; diff --git a/src/verifier.rs b/src/verifier.rs deleted file mode 100644 index 0eef23d2..00000000 --- a/src/verifier.rs +++ /dev/null @@ -1,51 +0,0 @@ -use crate::{ - loader::Loader, - pcs::{Decider, MultiOpenScheme}, - util::{arithmetic::CurveAffine, transcript::TranscriptRead}, - Error, Protocol, -}; -use std::fmt::Debug; - -mod plonk; - -pub use plonk::{Plonk, PlonkProof}; - -pub trait PlonkVerifier -where - C: CurveAffine, - L: Loader, - MOS: MultiOpenScheme, -{ - type Proof: Clone + Debug; - - fn read_proof( - svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, - instances: &[Vec], - transcript: &mut T, - ) -> Result - where - T: TranscriptRead; - - fn succinct_verify( - svk: &MOS::SuccinctVerifyingKey, - protocol: &Protocol, - instances: &[Vec], - proof: &Self::Proof, - ) -> Result, Error>; - - fn verify( - svk: &MOS::SuccinctVerifyingKey, - dk: &MOS::DecidingKey, - protocol: &Protocol, - instances: &[Vec], - proof: &Self::Proof, - ) -> Result - where - MOS: Decider, - { - let accumulators = Self::succinct_verify(svk, protocol, instances, proof)?; - let output = MOS::decide_all(dk, accumulators); - Ok(output) - } -} From 6a518c94ce680a432caa8cc294005ce6a24edb8b Mon Sep 17 00:00:00 2001 From: han0110 Date: Fri, 6 Jan 2023 14:35:47 +0800 Subject: [PATCH 10/73] docs: add `#![deny(missing_docs)]` and simple documents --- snark-verifier/src/cost.rs | 11 + snark-verifier/src/lib.rs | 16 +- snark-verifier/src/loader.rs | 41 +- snark-verifier/src/loader/evm.rs | 6 +- snark-verifier/src/loader/evm/loader.rs | 15 + snark-verifier/src/loader/evm/util.rs | 27 +- .../src/loader/evm/util/executor.rs | 17 +- snark-verifier/src/loader/halo2.rs | 5 + snark-verifier/src/loader/halo2/loader.rs | 18 + snark-verifier/src/loader/halo2/shim.rs | 28 ++ snark-verifier/src/loader/native.rs | 5 + snark-verifier/src/pcs.rs | 44 +++ snark-verifier/src/pcs/ipa.rs | 40 +- snark-verifier/src/pcs/ipa/accumulation.rs | 2 + snark-verifier/src/pcs/ipa/accumulator.rs | 4 + snark-verifier/src/pcs/ipa/decider.rs | 2 + snark-verifier/src/pcs/ipa/multiopen/bgh19.rs | 31 +- snark-verifier/src/pcs/kzg.rs | 5 + snark-verifier/src/pcs/kzg/accumulation.rs | 8 + snark-verifier/src/pcs/kzg/accumulator.rs | 7 + snark-verifier/src/pcs/kzg/decider.rs | 2 + .../src/pcs/kzg/multiopen/bdfg21.rs | 29 +- snark-verifier/src/pcs/kzg/multiopen/gwc19.rs | 4 + snark-verifier/src/system.rs | 2 + snark-verifier/src/system/halo2.rs | 22 +- snark-verifier/src/system/halo2/strategy.rs | 6 + snark-verifier/src/system/halo2/transcript.rs | 2 + .../src/system/halo2/transcript/evm.rs | 19 +- .../src/system/halo2/transcript/halo2.rs | 18 +- snark-verifier/src/util.rs | 4 + snark-verifier/src/util/arithmetic.rs | 73 +++- snark-verifier/src/util/hash.rs | 2 + snark-verifier/src/util/hash/poseidon.rs | 7 + snark-verifier/src/util/msm.rs | 19 +- snark-verifier/src/util/poly.rs | 12 +- snark-verifier/src/util/protocol.rs | 368 ------------------ snark-verifier/src/util/transcript.rs | 16 + snark-verifier/src/verifier.rs | 9 + snark-verifier/src/verifier/plonk.rs | 15 + snark-verifier/src/verifier/plonk/proof.rs | 22 +- snark-verifier/src/verifier/plonk/protocol.rs | 21 +- 41 files changed, 546 insertions(+), 458 deletions(-) delete mode 100644 snark-verifier/src/util/protocol.rs diff --git a/snark-verifier/src/cost.rs b/snark-verifier/src/cost.rs index a85d6af4..46bc6145 100644 --- a/snark-verifier/src/cost.rs +++ b/snark-verifier/src/cost.rs @@ -1,11 +1,19 @@ +//! Cost estimation. + use std::ops::Add; +/// Cost of verification. #[derive(Debug, Default, Clone, PartialEq, Eq)] pub struct Cost { + /// Number of instances. pub num_instance: usize, + /// Number of commitments in proof. pub num_commitment: usize, + /// Number of evaluations in proof. pub num_evaluation: usize, + /// Number of scalar multiplications to perform. pub num_msm: usize, + /// Number of pairings to perform. pub num_pairing: usize, } @@ -22,8 +30,11 @@ impl Add for Cost { } } +/// For estimating cost of a verifier. pub trait CostEstimation { + /// Input for [`CostEstimation::estimate_cost`]. type Input; + /// Estimate cost of verifier given the input. fn estimate_cost(input: &Self::Input) -> Cost; } diff --git a/snark-verifier/src/lib.rs b/snark-verifier/src/lib.rs index c2b9350a..87e18700 100644 --- a/snark-verifier/src/lib.rs +++ b/snark-verifier/src/lib.rs @@ -1,6 +1,11 @@ -#![allow(clippy::type_complexity)] -#![allow(clippy::too_many_arguments)] -#![allow(clippy::upper_case_acronyms)] +//! Generic (S)NARK verifier. + +#![allow( + clippy::type_complexity, + clippy::too_many_arguments, + clippy::upper_case_acronyms +)] +#![deny(missing_debug_implementations, missing_docs, unsafe_code)] pub mod cost; pub mod loader; @@ -9,10 +14,15 @@ pub mod system; pub mod util; pub mod verifier; +/// Error that could happen while verification. #[derive(Clone, Debug)] pub enum Error { + /// Instances that don't match the amount specified in protocol. InvalidInstances, + /// Protocol that is unreasonable for a verifier. InvalidProtocol(String), + /// Assertion failure while verification. AssertionFailure(String), + /// Transcript error. Transcript(std::io::ErrorKind, String), } diff --git a/snark-verifier/src/loader.rs b/snark-verifier/src/loader.rs index 297390d0..36ea54e9 100644 --- a/snark-verifier/src/loader.rs +++ b/snark-verifier/src/loader.rs @@ -1,3 +1,6 @@ +//! Abstraction of field element and elliptic curve point for generic verifier +//! implementation. + use crate::{ util::{ arithmetic::{CurveAffine, FieldOps, PrimeField}, @@ -15,25 +18,34 @@ pub mod evm; #[cfg(feature = "loader_halo2")] pub mod halo2; +/// Loaded elliptic curve point. pub trait LoadedEcPoint: Clone + Debug + PartialEq { + /// [`Loader`]. type Loader: Loader; + /// Returns [`Loader`]. fn loader(&self) -> &Self::Loader; } +/// Loaded field element. pub trait LoadedScalar: Clone + Debug + PartialEq + FieldOps { + /// [`Loader`]. type Loader: ScalarLoader; + /// Returns [`Loader`]. fn loader(&self) -> &Self::Loader; + /// Returns square. fn square(&self) -> Self { self.clone() * self } + /// Returns inverse if any. fn invert(&self) -> Option { FieldOps::invert(self) } + /// Returns power to exponent. fn pow_const(&self, mut exp: u64) -> Self { assert!(exp > 0); @@ -55,6 +67,7 @@ pub trait LoadedScalar: Clone + Debug + PartialEq + FieldOps { acc } + /// Returns powers up to exponent `n-1`. fn powers(&self, n: usize) -> Vec { iter::once(self.loader().load_one()) .chain( @@ -65,19 +78,25 @@ pub trait LoadedScalar: Clone + Debug + PartialEq + FieldOps { } } +/// Elliptic curve point loader. pub trait EcPointLoader { + /// [`LoadedEcPoint`]. type LoadedEcPoint: LoadedEcPoint; + /// Load a constant elliptic curve point. fn ec_point_load_const(&self, value: &C) -> Self::LoadedEcPoint; + /// Load `identity` as constant. fn ec_point_load_zero(&self) -> Self::LoadedEcPoint { self.ec_point_load_const(&C::identity()) } + /// Load `generator` as constant. fn ec_point_load_one(&self) -> Self::LoadedEcPoint { self.ec_point_load_const(&C::generator()) } + /// Assert lhs and rhs elliptic curve points are equal. fn ec_point_assert_eq( &self, annotation: &str, @@ -85,6 +104,7 @@ pub trait EcPointLoader { rhs: &Self::LoadedEcPoint, ) -> Result<(), Error>; + /// Perform multi-scalar multiplication. fn multi_scalar_multiplication( pairs: &[(&Self::LoadedScalar, &Self::LoadedEcPoint)], ) -> Self::LoadedEcPoint @@ -92,19 +112,25 @@ pub trait EcPointLoader { Self: ScalarLoader; } +/// Field element loader. pub trait ScalarLoader { + /// [`LoadedScalar`]. type LoadedScalar: LoadedScalar; + /// Load a constant field element. fn load_const(&self, value: &F) -> Self::LoadedScalar; + /// Load `zero` as constant. fn load_zero(&self) -> Self::LoadedScalar { self.load_const(&F::zero()) } + /// Load `one` as constant. fn load_one(&self) -> Self::LoadedScalar { self.load_const(&F::one()) } + /// Assert lhs and rhs field elements are equal. fn assert_eq( &self, annotation: &str, @@ -112,6 +138,7 @@ pub trait ScalarLoader { rhs: &Self::LoadedScalar, ) -> Result<(), Error>; + /// Sum field elements with coefficients and constant. fn sum_with_coeff_and_const( &self, values: &[(F, &Self::LoadedScalar)], @@ -140,6 +167,7 @@ pub trait ScalarLoader { .into_owned() } + /// Sum product of field elements with coefficients and constant. fn sum_products_with_coeff_and_const( &self, values: &[(F, &Self::LoadedScalar, &Self::LoadedScalar)], @@ -167,10 +195,12 @@ pub trait ScalarLoader { .unwrap() } + /// Sum field elements with coefficients. fn sum_with_coeff(&self, values: &[(F, &Self::LoadedScalar)]) -> Self::LoadedScalar { self.sum_with_coeff_and_const(values, F::zero()) } + /// Sum field elements and constant. fn sum_with_const(&self, values: &[&Self::LoadedScalar], constant: F) -> Self::LoadedScalar { self.sum_with_coeff_and_const( &values.iter().map(|&value| (F::one(), value)).collect_vec(), @@ -178,10 +208,12 @@ pub trait ScalarLoader { ) } + /// Sum field elements. fn sum(&self, values: &[&Self::LoadedScalar]) -> Self::LoadedScalar { self.sum_with_const(values, F::zero()) } + /// Sum product of field elements with coefficients. fn sum_products_with_coeff( &self, values: &[(F, &Self::LoadedScalar, &Self::LoadedScalar)], @@ -189,6 +221,7 @@ pub trait ScalarLoader { self.sum_products_with_coeff_and_const(values, F::zero()) } + /// Sum product of field elements and constant. fn sum_products_with_const( &self, values: &[(&Self::LoadedScalar, &Self::LoadedScalar)], @@ -203,6 +236,7 @@ pub trait ScalarLoader { ) } + /// Sum product of field elements. fn sum_products( &self, values: &[(&Self::LoadedScalar, &Self::LoadedScalar)], @@ -210,12 +244,14 @@ pub trait ScalarLoader { self.sum_products_with_const(values, F::zero()) } + /// Product of field elements. fn product(&self, values: &[&Self::LoadedScalar]) -> Self::LoadedScalar { values .iter() .fold(self.load_one(), |acc, value| acc * *value) } + /// Batch invert field elements. fn batch_invert<'a>(values: impl IntoIterator) where Self::LoadedScalar: 'a, @@ -226,10 +262,13 @@ pub trait ScalarLoader { } } +/// [`EcPointLoader`] and [`ScalarLoader`] with some helper methods. pub trait Loader: EcPointLoader + ScalarLoader + Clone + Debug { - fn start_cost_metering(&self, _: &str) {} + /// Start cost metering with an `identifier`. + fn start_cost_metering(&self, _identifier: &str) {} + /// End lastest started cost metering. fn end_cost_metering(&self) {} } diff --git a/snark-verifier/src/loader/evm.rs b/snark-verifier/src/loader/evm.rs index c11670d8..e942b4a3 100644 --- a/snark-verifier/src/loader/evm.rs +++ b/snark-verifier/src/loader/evm.rs @@ -1,6 +1,8 @@ +//! `Loader` implementation for generating yul code as EVM verifier. + mod code; pub(crate) mod loader; -mod util; +pub(crate) mod util; #[cfg(test)] mod test; @@ -8,7 +10,7 @@ mod test; pub use loader::{EcPoint, EvmLoader, Scalar}; pub use util::{ compile_yul, encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, Address, - ExecutorBuilder, MemoryChunk, H256, U256, U512, + ExecutorBuilder, H256, U256, U512, }; #[cfg(test)] diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index fdd0ee9c..04ca6709 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -48,6 +48,7 @@ impl Value { } } +/// `Loader` implementation for generating yul code as EVM verifier. #[derive(Clone, Debug)] pub struct EvmLoader { base_modulus: U256, @@ -66,6 +67,7 @@ fn hex_encode_u256(value: &U256) -> String { } impl EvmLoader { + /// Initialize a [`EvmLoader`] with base and scalar field. pub fn new() -> Rc where Base: PrimeField, @@ -86,6 +88,7 @@ impl EvmLoader { }) } + /// Returns generated yul code. pub fn yul_code(self: &Rc) -> String { let code = " if not(success) { revert(0, 0) } @@ -98,6 +101,7 @@ impl EvmLoader { ) } + /// Allocates memory chunk with given `size` and returns pointer. pub fn allocate(self: &Rc, size: usize) -> usize { let ptr = *self.ptr.borrow(); *self.ptr.borrow_mut() += size; @@ -137,6 +141,7 @@ impl EvmLoader { } } + /// Calldata load a field element. pub fn calldataload_scalar(self: &Rc, offset: usize) -> Scalar { let ptr = self.allocate(0x20); let code = format!("mstore({ptr:#x}, mod(calldataload({offset:#x}), f_q))"); @@ -144,6 +149,7 @@ impl EvmLoader { self.scalar(Value::Memory(ptr)) } + /// Calldata load an elliptic curve point and validate it's on curve. pub fn calldataload_ec_point(self: &Rc, offset: usize) -> EcPoint { let x_ptr = self.allocate(0x40); let y_ptr = x_ptr + 0x20; @@ -164,6 +170,7 @@ impl EvmLoader { self.ec_point(Value::Memory(x_ptr)) } + /// Decode an elliptic curve point from limbs. pub fn ec_point_from_limbs( self: &Rc, x_limbs: [&Scalar; LIMBS], @@ -246,6 +253,8 @@ impl EvmLoader { } } + /// Performs `KECCAK256` on `memory[ptr..ptr+len]` and returns pointer of + /// hash. pub fn keccak256(self: &Rc, ptr: usize, len: usize) -> usize { let hash_ptr = self.allocate(0x20); let code = format!("mstore({hash_ptr:#x}, keccak256({ptr:#x}, {len}))"); @@ -253,6 +262,7 @@ impl EvmLoader { hash_ptr } + /// Copies a field element into given `ptr`. pub fn copy_scalar(self: &Rc, scalar: &Scalar, ptr: usize) { let scalar = self.push(scalar); self.code @@ -260,12 +270,14 @@ impl EvmLoader { .runtime_append(format!("mstore({ptr:#x}, {scalar})")); } + /// Allocates a new field element and copies the given value into it. pub fn dup_scalar(self: &Rc, scalar: &Scalar) -> Scalar { let ptr = self.allocate(0x20); self.copy_scalar(scalar, ptr); self.scalar(Value::Memory(ptr)) } + /// Allocates a new elliptic curve point and copies the given value into it. pub fn dup_ec_point(self: &Rc, value: &EcPoint) -> EcPoint { let ptr = self.allocate(0x40); match value.value { @@ -339,6 +351,7 @@ impl EvmLoader { self.ec_point(Value::Memory(rd_ptr)) } + /// Performs pairing. pub fn pairing( self: &Rc, lhs: &EcPoint, @@ -454,6 +467,7 @@ impl EvmLoader { } } +/// Elliptic curve point. #[derive(Clone)] pub struct EcPoint { loader: Rc, @@ -503,6 +517,7 @@ where } } +/// Field element. #[derive(Clone)] pub struct Scalar { loader: Rc, diff --git a/snark-verifier/src/loader/evm/util.rs b/snark-verifier/src/loader/evm/util.rs index 2c74731a..db3cb672 100644 --- a/snark-verifier/src/loader/evm/util.rs +++ b/snark-verifier/src/loader/evm/util.rs @@ -14,43 +14,43 @@ pub(crate) mod executor; pub use executor::ExecutorBuilder; +/// Memory chunk in EVM. +#[derive(Debug)] pub struct MemoryChunk { ptr: usize, len: usize, } impl MemoryChunk { - pub fn new(ptr: usize) -> Self { + pub(crate) fn new(ptr: usize) -> Self { Self { ptr, len: 0 } } - pub fn ptr(&self) -> usize { + pub(crate) fn ptr(&self) -> usize { self.ptr } - pub fn len(&self) -> usize { + pub(crate) fn len(&self) -> usize { self.len } - pub fn is_empty(&self) -> bool { - self.len == 0 - } - - pub fn end(&self) -> usize { + pub(crate) fn end(&self) -> usize { self.ptr + self.len } - pub fn reset(&mut self, ptr: usize) { + pub(crate) fn reset(&mut self, ptr: usize) { self.ptr = ptr; self.len = 0; } - pub fn extend(&mut self, size: usize) { + pub(crate) fn extend(&mut self, size: usize) { self.len += size; } } -// Assume fields implements traits in crate `ff` always have little-endian representation. +/// Convert a [`PrimeField`] into a [`U256`]. +/// Assuming fields implements traits in crate `ff` always have little-endian +/// representation. pub fn fe_to_u256(f: F) -> U256 where F: PrimeField, @@ -58,6 +58,7 @@ where U256::from_little_endian(f.to_repr().as_ref()) } +/// Convert a [`U256`] into a [`PrimeField`]. pub fn u256_to_fe(value: U256) -> F where F: PrimeField, @@ -68,6 +69,7 @@ where F::from_repr(repr).unwrap() } +/// Returns modulus of [`PrimeField`] as [`U256`]. pub fn modulus() -> U256 where F: PrimeField, @@ -75,6 +77,7 @@ where U256::from_little_endian((-F::one()).to_repr().as_ref()) + 1 } +/// Encode instances and proof into calldata. pub fn encode_calldata(instances: &[Vec], proof: &[u8]) -> Vec where F: PrimeField, @@ -90,6 +93,7 @@ where .collect() } +/// Estimate gas cost with given [`Cost`]. pub fn estimate_gas(cost: Cost) -> usize { let proof_size = cost.num_commitment * 64 + (cost.num_evaluation + cost.num_instance) * 32; @@ -100,6 +104,7 @@ pub fn estimate_gas(cost: Cost) -> usize { intrinsic_cost + calldata_cost + ec_operation_cost } +/// Compile given yul `code` into deployment bytecode. pub fn compile_yul(code: &str) -> Vec { let mut cmd = Command::new("solc") .stdin(Stdio::piped()) diff --git a/snark-verifier/src/loader/evm/util/executor.rs b/snark-verifier/src/loader/evm/util/executor.rs index 47a80658..ab7c170f 100644 --- a/snark-verifier/src/loader/evm/util/executor.rs +++ b/snark-verifier/src/loader/evm/util/executor.rs @@ -416,7 +416,6 @@ impl Inspector for Debugger { } } -#[macro_export] macro_rules! call_inspectors { ($id:ident, [ $($inspector:expr),+ ], $call:block) => { $({ @@ -669,16 +668,28 @@ impl Inspector for InspectorStack { } } +/// Call result. +#[derive(Debug)] pub struct RawCallResult { + /// Exit reason pub exit_reason: Return, + /// If the call is reverted or not. pub reverted: bool, + /// Returndata pub result: Bytes, + /// Gas used pub gas_used: u64, + /// Gas refunded pub gas_refunded: u64, + /// Logs emitted during the call pub logs: Vec, + /// Debug information if any pub debug: Option, + /// State changes if any pub state_changeset: Option>, + /// Environment pub env: Env, + /// Output pub out: TransactOut, } @@ -694,6 +705,7 @@ pub struct DeployResult { pub env: Env, } +/// Executor builder. #[derive(Debug, Default)] pub struct ExecutorBuilder { debugger: bool, @@ -701,16 +713,19 @@ pub struct ExecutorBuilder { } impl ExecutorBuilder { + /// Set `debugger`. pub fn set_debugger(mut self, enable: bool) -> Self { self.debugger = enable; self } + /// Set `gas_limit`. pub fn with_gas_limit(mut self, gas_limit: U256) -> Self { self.gas_limit = Some(gas_limit); self } + /// Initialize an [`Executor`]. pub fn build(self) -> Executor { Executor::new(self.debugger, self.gas_limit.unwrap_or(U256::MAX)) } diff --git a/snark-verifier/src/loader/halo2.rs b/snark-verifier/src/loader/halo2.rs index ce75b00c..93a31a26 100644 --- a/snark-verifier/src/loader/halo2.rs +++ b/snark-verifier/src/loader/halo2.rs @@ -1,3 +1,5 @@ +//! `Loader` implementation for generating verifier in [`halo2_proofs`] circuit. + pub(crate) mod loader; mod shim; @@ -13,7 +15,10 @@ pub use halo2_wrong_ecc; mod util { use halo2_proofs::circuit::Value; + /// Helper methods when dealing with iterator of [`Value`]. pub trait Valuetools: Iterator> { + /// Fold zipped values into accumulator, returns `Value::unknown()` if + /// any is `Value::unknown()`. fn fold_zipped(self, init: B, mut f: F) -> Value where Self: Sized, diff --git a/snark-verifier/src/loader/halo2/loader.rs b/snark-verifier/src/loader/halo2/loader.rs index 67c2b12d..17a51183 100644 --- a/snark-verifier/src/loader/halo2/loader.rs +++ b/snark-verifier/src/loader/halo2/loader.rs @@ -17,6 +17,7 @@ use std::{ rc::Rc, }; +/// `Loader` implementation for generating verifier in [`halo2_proofs`] circuit. #[derive(Debug)] pub struct Halo2Loader<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { ecc_chip: RefCell, @@ -29,6 +30,8 @@ pub struct Halo2Loader<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { } impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, EccChip> { + /// Initialize a [`Halo2Loader`] with given [`EccInstructions`] and + /// [`EccInstructions::Context`]. pub fn new(ecc_chip: EccChip, ctx: EccChip::Context) -> Rc { Rc::new(Self { ecc_chip: RefCell::new(ecc_chip), @@ -41,22 +44,27 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc }) } + /// Into [`EccInstructions::Context`]. pub fn into_ctx(self) -> EccChip::Context { self.ctx.into_inner() } + /// Returns reference of [`EccInstructions`]. pub fn ecc_chip(&self) -> Ref { self.ecc_chip.borrow() } + /// Returns reference of [`EccInstructions::ScalarChip`]. pub fn scalar_chip(&self) -> Ref { Ref::map(self.ecc_chip(), |ecc_chip| ecc_chip.scalar_chip()) } + /// Returns reference of [`EccInstructions::Context`]. pub fn ctx(&self) -> Ref { self.ctx.borrow() } + /// Returns mutable reference of [`EccInstructions::Context`]. pub fn ctx_mut(&self) -> RefMut<'_, EccChip::Context> { self.ctx.borrow_mut() } @@ -67,6 +75,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc .unwrap() } + /// Assign a field element witness. pub fn assign_scalar( self: &Rc, scalar: circuit::Value, @@ -78,6 +87,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc self.scalar_from_assigned(assigned) } + /// Returns [`Scalar`] with assigned field element. pub fn scalar_from_assigned( self: &Rc, assigned: EccChip::AssignedScalar, @@ -104,6 +114,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc .unwrap() } + /// Assign an elliptic curve point witness. pub fn assign_ec_point( self: &Rc, ec_point: circuit::Value, @@ -115,6 +126,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc self.ec_point_from_assigned(assigned) } + /// Returns [`EcPoint`] with assigned elliptic curve point. pub fn ec_point_from_assigned( self: &Rc, assigned: EccChip::AssignedEcPoint, @@ -307,6 +319,7 @@ impl Value { } } +/// Field element #[derive(Clone)] pub struct Scalar<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { loader: Rc>, @@ -315,10 +328,12 @@ pub struct Scalar<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { } impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Scalar<'a, C, EccChip> { + /// Returns reference of [`Rc`] pub fn loader(&self) -> &Rc> { &self.loader } + /// Returns reference of [`EccInstructions::AssignedScalar`]. pub fn assigned(&self) -> Ref { if let Some(constant) = self.maybe_const() { *self.value.borrow_mut() = Value::Assigned(self.loader.assign_const_scalar(constant)) @@ -469,6 +484,7 @@ impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> MulAssign<&'b Self } } +/// Elliptic curve point #[derive(Clone)] pub struct EcPoint<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { loader: Rc>, @@ -477,6 +493,7 @@ pub struct EcPoint<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { } impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPoint<'a, C, EccChip> { + /// Into [`EccInstructions::AssignedEcPoint`]. pub fn into_assigned(self) -> EccChip::AssignedEcPoint { match self.value.into_inner() { Value::Constant(constant) => self.loader.assign_const_ec_point(constant), @@ -484,6 +501,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPoint<'a, C, EccChip } } + /// Returns reference of [`EccInstructions::AssignedEcPoint`]. pub fn assigned(&self) -> Ref { if let Some(constant) = self.maybe_const() { *self.value.borrow_mut() = Value::Assigned(self.loader.assign_const_ec_point(constant)) diff --git a/snark-verifier/src/loader/halo2/shim.rs b/snark-verifier/src/loader/halo2/shim.rs index 1d7b6258..7ae65496 100644 --- a/snark-verifier/src/loader/halo2/shim.rs +++ b/snark-verifier/src/loader/halo2/shim.rs @@ -5,29 +5,39 @@ use halo2_proofs::{ }; use std::{fmt::Debug, ops::Deref}; +/// Context for instructions. pub trait Context: Debug { + /// Enforce equality constraint on lhs and rhs. fn constrain_equal(&mut self, lhs: Cell, rhs: Cell) -> Result<(), Error>; + /// Returns current region offset. fn offset(&self) -> usize; } +/// Instructions to handle field element operations. pub trait IntegerInstructions<'a, F: FieldExt>: Clone + Debug { + /// Context. type Context: Context; + /// Assigned cell. type AssignedCell: Clone + Debug; + /// Assigned integer. type AssignedInteger: Clone + Debug; + /// Assign an integer witness. fn assign_integer( &self, ctx: &mut Self::Context, integer: Value, ) -> Result; + /// Assign an integer constant. fn assign_constant( &self, ctx: &mut Self::Context, integer: F, ) -> Result; + /// Sum integers with coefficients and constant. fn sum_with_coeff_and_const( &self, ctx: &mut Self::Context, @@ -35,6 +45,7 @@ pub trait IntegerInstructions<'a, F: FieldExt>: Clone + Debug { constant: F::Scalar, ) -> Result; + /// Sum product of integers with coefficients and constant. fn sum_products_with_coeff_and_const( &self, ctx: &mut Self::Context, @@ -46,6 +57,7 @@ pub trait IntegerInstructions<'a, F: FieldExt>: Clone + Debug { constant: F::Scalar, ) -> Result; + /// Returns `lhs - rhs`. fn sub( &self, ctx: &mut Self::Context, @@ -53,18 +65,21 @@ pub trait IntegerInstructions<'a, F: FieldExt>: Clone + Debug { rhs: &Self::AssignedInteger, ) -> Result; + /// Returns `-value`. fn neg( &self, ctx: &mut Self::Context, value: &Self::AssignedInteger, ) -> Result; + /// Returns `1/value`. fn invert( &self, ctx: &mut Self::Context, value: &Self::AssignedInteger, ) -> Result; + /// Enforce `lhs` and `rhs` are equal. fn assert_equal( &self, ctx: &mut Self::Context, @@ -73,8 +88,11 @@ pub trait IntegerInstructions<'a, F: FieldExt>: Clone + Debug { ) -> Result<(), Error>; } +/// Instructions to handle elliptic curve point operations. pub trait EccInstructions<'a, C: CurveAffine>: Clone + Debug { + /// Context type Context: Context; + /// [`IntegerInstructions`] to handle scalar field operation. type ScalarChip: IntegerInstructions< 'a, C::Scalar, @@ -82,24 +100,31 @@ pub trait EccInstructions<'a, C: CurveAffine>: Clone + Debug { AssignedCell = Self::AssignedCell, AssignedInteger = Self::AssignedScalar, >; + /// Assigned cell. type AssignedCell: Clone + Debug; + /// Assigned scalar field element. type AssignedScalar: Clone + Debug; + /// Assigned elliptic curve point. type AssignedEcPoint: Clone + Debug; + /// Returns reference of [`EccInstructions::ScalarChip`]. fn scalar_chip(&self) -> &Self::ScalarChip; + /// Assign a elliptic curve point constant. fn assign_constant( &self, ctx: &mut Self::Context, ec_point: C, ) -> Result; + /// Assign a elliptic curve point witness. fn assign_point( &self, ctx: &mut Self::Context, ec_point: Value, ) -> Result; + /// Sum elliptic curve points and constant. fn sum_with_const( &self, ctx: &mut Self::Context, @@ -107,12 +132,14 @@ pub trait EccInstructions<'a, C: CurveAffine>: Clone + Debug { constant: C, ) -> Result; + /// Perform fixed base multi-scalar multiplication. fn fixed_base_msm( &mut self, ctx: &mut Self::Context, pairs: &[(impl Deref, C)], ) -> Result; + /// Perform variable base multi-scalar multiplication. fn variable_base_msm( &mut self, ctx: &mut Self::Context, @@ -122,6 +149,7 @@ pub trait EccInstructions<'a, C: CurveAffine>: Clone + Debug { )], ) -> Result; + /// Enforce `lhs` and `rhs` are equal. fn assert_equal( &self, ctx: &mut Self::Context, diff --git a/snark-verifier/src/loader/native.rs b/snark-verifier/src/loader/native.rs index 6fce383a..18d27c50 100644 --- a/snark-verifier/src/loader/native.rs +++ b/snark-verifier/src/loader/native.rs @@ -1,3 +1,5 @@ +//! `Loader` implementation in native rust. + use crate::{ loader::{EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader}, util::arithmetic::{Curve, CurveAffine, FieldOps, PrimeField}, @@ -7,9 +9,12 @@ use lazy_static::lazy_static; use std::fmt::Debug; lazy_static! { + /// NativeLoader instance for [`LoadedEcPoint::loader`] and + /// [`LoadedScalar::loader`] referencing. pub static ref LOADER: NativeLoader = NativeLoader; } +/// `Loader` implementation in native rust. #[derive(Clone, Debug)] pub struct NativeLoader; diff --git a/snark-verifier/src/pcs.rs b/snark-verifier/src/pcs.rs index 45444a07..b7802df7 100644 --- a/snark-verifier/src/pcs.rs +++ b/snark-verifier/src/pcs.rs @@ -1,3 +1,5 @@ +//! Verfieirs for polynomial commitment schemes. + use crate::{ loader::{native::NativeLoader, Loader}, util::{ @@ -13,14 +15,29 @@ use std::{fmt::Debug, marker::PhantomData}; pub mod ipa; pub mod kzg; +/// Query to a oracle. +/// It assumes all queries are based on the same point, but with some `shift`. #[derive(Clone, Debug)] pub struct Query { + /// Index of polynomial to query pub poly: usize, + /// Shift of the query point. pub shift: F, + /// Evaluation read from transcript. pub eval: T, } impl Query { + /// Initialize [`Query`] without evaluation. + pub fn new(poly: usize, shift: F) -> Self { + Self { + poly, + shift, + eval: (), + } + } + + /// Returns [`Query`] with evaluation. pub fn with_evaluation(self, eval: T) -> Query { Query { poly: self.poly, @@ -30,15 +47,20 @@ impl Query { } } +/// Polynomial commitment scheme verifier. pub trait PolynomialCommitmentScheme: Clone + Debug where C: CurveAffine, L: Loader, { + /// Verifying key. type VerifyingKey: Clone + Debug; + /// Structured proof read from transcript. type Proof: Clone + Debug; + /// Output of verification. type Output: Clone + Debug; + /// Read [`PolynomialCommitmentScheme::Proof`] from transcript. fn read_proof( vk: &Self::VerifyingKey, queries: &[Query], @@ -47,6 +69,7 @@ where where T: TranscriptRead; + /// Verify [`PolynomialCommitmentScheme::Proof`] and output [`PolynomialCommitmentScheme::Output`]. fn verify( vk: &Self::VerifyingKey, commitments: &[Msm], @@ -56,15 +79,20 @@ where ) -> Result; } +/// Accumulation scheme verifier. pub trait AccumulationScheme where C: CurveAffine, L: Loader, { + /// Accumulator to be accumulated. type Accumulator: Clone + Debug; + /// Verifying key. type VerifyingKey: Clone + Debug; + /// Structured proof read from transcript. type Proof: Clone + Debug; + /// Read a [`AccumulationScheme::Proof`] from transcript. fn read_proof( vk: &Self::VerifyingKey, instances: &[Self::Accumulator], @@ -73,6 +101,9 @@ where where T: TranscriptRead; + /// Verify old [`AccumulationScheme::Accumulator`]s are accumulated properly + /// into a new one with the [`AccumulationScheme::Proof`], and returns the + /// new one as output. fn verify( vk: &Self::VerifyingKey, instances: &[Self::Accumulator], @@ -80,27 +111,36 @@ where ) -> Result; } +/// Accumulation scheme decider. pub trait AccumulationDecider: AccumulationScheme where C: CurveAffine, L: Loader, { + /// Deciding key. type DecidingKey: Clone + Debug; + /// Decide if a [`AccumulationScheme::Accumulator`] is valid. fn decide(dk: &Self::DecidingKey, accumulator: Self::Accumulator) -> Result<(), Error>; + /// Decide if all [`AccumulationScheme::Accumulator`]s are valid. fn decide_all( dk: &Self::DecidingKey, accumulators: Vec, ) -> Result<(), Error>; } +/// Accumulation scheme prover. pub trait AccumulationSchemeProver: AccumulationScheme where C: CurveAffine, { + /// Proving key. type ProvingKey: Clone + Debug; + /// Create a proof that argues old [`AccumulationScheme::Accumulator`]s are + /// properly accumulated into the new one, and returns the new one as + /// output. fn create_proof( pk: &Self::ProvingKey, instances: &[Self::Accumulator], @@ -112,13 +152,17 @@ where R: Rng; } +/// Accumulator encoding. pub trait AccumulatorEncoding: Clone + Debug where C: CurveAffine, L: Loader, { + /// Accumulator to be encoded. type Accumulator: Clone + Debug; + /// Decode an [`AccumulatorEncoding::Accumulator`] from serveral + /// [`Loader::LoadedScalar`]s. fn from_repr(repr: &[&L::LoadedScalar]) -> Result; } diff --git a/snark-verifier/src/pcs/ipa.rs b/snark-verifier/src/pcs/ipa.rs index 249e0f0d..f07f56cf 100644 --- a/snark-verifier/src/pcs/ipa.rs +++ b/snark-verifier/src/pcs/ipa.rs @@ -1,3 +1,6 @@ +//! Inner product argument polynomial commitment scheme and accumulation scheme. +//! The notations are following https://eprint.iacr.org/2020/499.pdf. + use crate::{ loader::{native::NativeLoader, LoadedScalar, Loader, ScalarLoader}, util::{ @@ -25,6 +28,7 @@ pub use accumulator::IpaAccumulator; pub use decider::IpaDecidingKey; pub use multiopen::{Bgh19, Bgh19Proof}; +/// Inner product argument polynomial commitment scheme. #[derive(Clone, Debug)] pub struct Ipa(PhantomData); @@ -32,6 +36,7 @@ impl Ipa where C: CurveAffine, { + /// Create an inner product argument. pub fn create_proof( pk: &IpaProvingKey, p: &[C::Scalar], @@ -117,6 +122,7 @@ where Ok(IpaAccumulator::new(xi, bases[0])) } + /// Read [`IpaProof`] from transcript. pub fn read_proof>( svk: &IpaSuccinctVerifyingKey, transcript: &mut T, @@ -127,6 +133,7 @@ where IpaProof::read(svk, transcript) } + /// Perform the succinct check of the proof and returns [`IpaAccumulator`]. pub fn succinct_verify>( svk: &IpaSuccinctVerifyingKey, commitment: &Msm, @@ -176,31 +183,41 @@ where } } +/// Inner product argument proving key. #[derive(Clone, Debug)] pub struct IpaProvingKey { + /// Working domain. pub domain: Domain, + /// $\mathbb{G}$ pub g: Vec, + /// $H$ pub h: C, + /// $S$ pub s: Option, } impl IpaProvingKey { + /// Initialize an [`IpaProvingKey`]. pub fn new(domain: Domain, g: Vec, h: C, s: Option) -> Self { Self { domain, g, h, s } } + /// Returns if it supports zero-knowledge. pub fn zk(&self) -> bool { self.s.is_some() } + /// Returns [`IpaSuccinctVerifyingKey`]. pub fn svk(&self) -> IpaSuccinctVerifyingKey { IpaSuccinctVerifyingKey::new(self.domain.clone(), self.g[0], self.h, self.s) } + /// Returns [`IpaDecidingKey`]. pub fn dk(&self) -> IpaDecidingKey { IpaDecidingKey::new(self.svk(), self.g.clone()) } + /// Commit a polynomial into with a randomizer if any. pub fn commit(&self, poly: &Polynomial, omega: Option) -> C { let mut c = multi_scalar_multiplication(&poly[..], &self.g); match (self.s, omega) { @@ -214,7 +231,7 @@ impl IpaProvingKey { impl IpaProvingKey { #[cfg(test)] - pub fn rand(k: usize, zk: bool, mut rng: R) -> Self { + pub(crate) fn rand(k: usize, zk: bool, mut rng: R) -> Self { use crate::util::arithmetic::{root_of_unity, Group}; let domain = Domain::new(k, root_of_unity(k)); @@ -231,24 +248,32 @@ impl IpaProvingKey { } } +/// Inner product argument succinct verifying key. #[derive(Clone, Debug)] pub struct IpaSuccinctVerifyingKey { + /// Working domain. pub domain: Domain, + /// $G_0$ pub g: C, + /// $H$ pub h: C, + /// $S$ pub s: Option, } impl IpaSuccinctVerifyingKey { + /// Initialize an [`IpaSuccinctVerifyingKey`]. pub fn new(domain: Domain, g: C, h: C, s: Option) -> Self { Self { domain, g, h, s } } + /// Returns if it supports zero-knowledge. pub fn zk(&self) -> bool { self.s.is_some() } } +/// Inner product argument #[derive(Clone, Debug)] pub struct IpaProof where @@ -268,7 +293,7 @@ where C: CurveAffine, L: Loader, { - pub fn new( + fn new( c_bar_alpha: Option<(L::LoadedEcPoint, L::LoadedScalar)>, omega_prime: Option, xi_0: L::LoadedScalar, @@ -286,6 +311,7 @@ where } } + /// Read [`AccumulationScheme::Proof`] from transcript. pub fn read(svk: &IpaSuccinctVerifyingKey, transcript: &mut T) -> Result where T: TranscriptRead, @@ -321,10 +347,12 @@ where }) } + /// Returns $\{\xi_0, \xi_1, ...\}$. pub fn xi(&self) -> Vec { self.rounds.iter().map(|round| round.xi.clone()).collect() } + /// Returns $\{\xi_0^{-1}, \xi_1^{-1}, ...\}$. pub fn xi_inv(&self) -> Vec { let mut xi_inv = self.xi().into_iter().map(Fraction::one_over).collect_vec(); L::batch_invert(xi_inv.iter_mut().filter_map(Fraction::denom_mut)); @@ -337,7 +365,7 @@ where } #[derive(Clone, Debug)] -pub struct Round +struct Round where C: CurveAffine, L: Loader, @@ -352,12 +380,12 @@ where C: CurveAffine, L: Loader, { - pub fn new(l: L::LoadedEcPoint, r: L::LoadedEcPoint, xi: L::LoadedScalar) -> Self { + fn new(l: L::LoadedEcPoint, r: L::LoadedEcPoint, xi: L::LoadedScalar) -> Self { Self { l, r, xi } } } -pub fn h_eval>(xi: &[T], z: &T) -> T { +fn h_eval>(xi: &[T], z: &T) -> T { let loader = z.loader(); let one = loader.load_one(); loader.product( @@ -370,7 +398,7 @@ pub fn h_eval>(xi: &[T], z: &T) -> T { ) } -pub fn h_coeffs(xi: &[F], scalar: F) -> Vec { +fn h_coeffs(xi: &[F], scalar: F) -> Vec { assert!(!xi.is_empty()); let mut coeffs = vec![F::zero(); 1 << xi.len()]; diff --git a/snark-verifier/src/pcs/ipa/accumulation.rs b/snark-verifier/src/pcs/ipa/accumulation.rs index 888e11aa..021287d2 100644 --- a/snark-verifier/src/pcs/ipa/accumulation.rs +++ b/snark-verifier/src/pcs/ipa/accumulation.rs @@ -18,6 +18,7 @@ use crate::{ use rand::Rng; use std::{array, fmt::Debug, iter, marker::PhantomData}; +/// Inner product argument accumulation scheme. #[derive(Clone, Debug)] pub struct IpaAs(PhantomData<(C, MOS)>); @@ -76,6 +77,7 @@ where } } +/// Inner product argument accumulation scheme proof. #[derive(Clone, Debug)] pub struct IpaAsProof where diff --git a/snark-verifier/src/pcs/ipa/accumulator.rs b/snark-verifier/src/pcs/ipa/accumulator.rs index 27d9d5c7..fc8d9fd7 100644 --- a/snark-verifier/src/pcs/ipa/accumulator.rs +++ b/snark-verifier/src/pcs/ipa/accumulator.rs @@ -1,12 +1,15 @@ use crate::{loader::Loader, util::arithmetic::CurveAffine}; +/// Inner product argument accumulator. #[derive(Clone, Debug)] pub struct IpaAccumulator where C: CurveAffine, L: Loader, { + /// $\xi$. pub xi: Vec, + /// $U$. pub u: L::LoadedEcPoint, } @@ -15,6 +18,7 @@ where C: CurveAffine, L: Loader, { + /// Initialize a [`IpaAccumulator`]. pub fn new(xi: Vec, u: L::LoadedEcPoint) -> Self { Self { xi, u } } diff --git a/snark-verifier/src/pcs/ipa/decider.rs b/snark-verifier/src/pcs/ipa/decider.rs index db7b42fb..7aefcf81 100644 --- a/snark-verifier/src/pcs/ipa/decider.rs +++ b/snark-verifier/src/pcs/ipa/decider.rs @@ -1,5 +1,6 @@ use crate::{pcs::ipa::IpaSuccinctVerifyingKey, util::arithmetic::CurveAffine}; +/// Inner product argument deciding key. #[derive(Clone, Debug)] pub struct IpaDecidingKey { svk: IpaSuccinctVerifyingKey, @@ -7,6 +8,7 @@ pub struct IpaDecidingKey { } impl IpaDecidingKey { + /// Initialize an [`IpaDecidingKey`]. pub fn new(svk: IpaSuccinctVerifyingKey, g: Vec) -> Self { Self { svk, g } } diff --git a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs index 6f19a44a..2ecb4b8d 100644 --- a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs +++ b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs @@ -5,7 +5,7 @@ use crate::{ PolynomialCommitmentScheme, Query, }, util::{ - arithmetic::{ilog2, CurveAffine, FieldExt, Fraction}, + arithmetic::{CurveAffine, FieldExt, Fraction}, msm::Msm, transcript::TranscriptRead, Itertools, @@ -18,6 +18,8 @@ use std::{ marker::PhantomData, }; +/// Verifier of multi-open inner product argument. It is for the implementation +/// in [`halo2_proofs`]. #[derive(Clone, Debug)] pub struct Bgh19; @@ -92,6 +94,7 @@ where } } +/// Structured proof of [`Bgh19`]. #[derive(Clone, Debug)] pub struct Bgh19Proof where @@ -222,9 +225,12 @@ where .sorted() .dedup(); - let size = 2.max( - ilog2((sets.iter().map(|set| set.shifts.len()).max().unwrap() - 1).next_power_of_two()) + 1, - ); + let size = sets + .iter() + .map(|set| set.shifts.len()) + .chain(Some(2)) + .max() + .unwrap(); let powers_of_x = x.powers(size); let x_3_minus_x_shift_i = BTreeMap::from_iter( superset.map(|shift| (shift, x_3.clone() - x.clone() * loader.load_const(&shift))), @@ -323,26 +329,15 @@ where .collect_vec(); let x = &powers_of_x[1].clone(); - let x_pow_k_minus_one = { - let k_minus_one = shifts.len() - 1; - powers_of_x - .iter() - .enumerate() - .skip(1) - .filter_map(|(i, power_of_x)| { - (k_minus_one & (1 << i) == 1).then(|| power_of_x.clone()) - }) - .reduce(|acc, value| acc * value) - .unwrap_or_else(|| loader.load_one()) - }; + let x_pow_k_minus_one = &powers_of_x[shifts.len() - 1]; let barycentric_weights = shifts .iter() .zip(normalized_ell_primes.iter()) .map(|(shift, normalized_ell_prime)| { loader.sum_products_with_coeff(&[ - (*normalized_ell_prime, &x_pow_k_minus_one, x_3), - (-(*normalized_ell_prime * shift), &x_pow_k_minus_one, x), + (*normalized_ell_prime, x_pow_k_minus_one, x_3), + (-(*normalized_ell_prime * shift), x_pow_k_minus_one, x), ]) }) .map(Fraction::one_over) diff --git a/snark-verifier/src/pcs/kzg.rs b/snark-verifier/src/pcs/kzg.rs index 80d7ab63..8b032a1d 100644 --- a/snark-verifier/src/pcs/kzg.rs +++ b/snark-verifier/src/pcs/kzg.rs @@ -1,3 +1,5 @@ +//! KZG polynomial commitment scheme and accumulation scheme. + use crate::util::arithmetic::CurveAffine; mod accumulation; @@ -13,12 +15,15 @@ pub use multiopen::{Bdfg21, Bdfg21Proof, Gwc19, Gwc19Proof}; #[cfg(feature = "loader_halo2")] pub use accumulator::LimbsEncodingInstructions; +/// KZG succinct verifying key. #[derive(Clone, Copy, Debug)] pub struct KzgSuccinctVerifyingKey { + /// Generator. pub g: C, } impl KzgSuccinctVerifyingKey { + /// Initialize a [`KzgSuccinctVerifyingKey`]. pub fn new(g: C) -> Self { Self { g } } diff --git a/snark-verifier/src/pcs/kzg/accumulation.rs b/snark-verifier/src/pcs/kzg/accumulation.rs index 202a8ce1..572708c3 100644 --- a/snark-verifier/src/pcs/kzg/accumulation.rs +++ b/snark-verifier/src/pcs/kzg/accumulation.rs @@ -11,6 +11,7 @@ use crate::{ use rand::Rng; use std::{fmt::Debug, marker::PhantomData}; +/// KZG accumulation scheme. #[derive(Clone, Debug)] pub struct KzgAs(PhantomData<(M, MOS)>); @@ -60,32 +61,39 @@ where } } +/// KZG accumulation scheme proving key. #[derive(Clone, Copy, Debug, Default)] pub struct KzgAsProvingKey(pub Option<(C, C)>); impl KzgAsProvingKey { + /// Initialize a [`KzgAsProvingKey`]. pub fn new(g: Option<(C, C)>) -> Self { Self(g) } + /// Returns if it supports zero-knowledge or not. pub fn zk(&self) -> bool { self.0.is_some() } + /// Returns [`KzgAsVerifyingKey`]. pub fn vk(&self) -> KzgAsVerifyingKey { KzgAsVerifyingKey(self.zk()) } } +/// KZG accumulation scheme verifying key. #[derive(Clone, Copy, Debug, Default)] pub struct KzgAsVerifyingKey(bool); impl KzgAsVerifyingKey { + /// Returns if it supports zero-knowledge or not. pub fn zk(&self) -> bool { self.0 } } +/// KZG accumulation scheme proof. #[derive(Clone, Debug)] pub struct KzgAsProof where diff --git a/snark-verifier/src/pcs/kzg/accumulator.rs b/snark-verifier/src/pcs/kzg/accumulator.rs index b76ab80a..3ae2aa76 100644 --- a/snark-verifier/src/pcs/kzg/accumulator.rs +++ b/snark-verifier/src/pcs/kzg/accumulator.rs @@ -1,13 +1,16 @@ use crate::{loader::Loader, util::arithmetic::CurveAffine}; use std::fmt::Debug; +/// KZG accumulator, containing lhs G1 and rhs G1 of pairing. #[derive(Clone, Debug)] pub struct KzgAccumulator where C: CurveAffine, L: Loader, { + /// lhs G1 of pairing. pub lhs: L::LoadedEcPoint, + /// rhs G1 of pairing. pub rhs: L::LoadedEcPoint, } @@ -16,6 +19,7 @@ where C: CurveAffine, L: Loader, { + /// Initialize a [`KzgAccumulator`]. pub fn new(lhs: L::LoadedEcPoint, rhs: L::LoadedEcPoint) -> Self { Self { lhs, rhs } } @@ -164,15 +168,18 @@ mod halo2 { x.zip(y).map(|(x, y)| C::from_xy(x, y).unwrap()) } + /// Instructions to encode/decode a elliptic curve point into/from limbs. pub trait LimbsEncodingInstructions<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize>: EccInstructions<'a, C> { + /// Decode and assign an elliptic curve point from limbs. fn assign_ec_point_from_limbs( &self, ctx: &mut Self::Context, limbs: &[impl Deref], ) -> Result; + /// Encode an elliptic curve point into limbs. fn assign_ec_point_to_limbs( &self, ctx: &mut Self::Context, diff --git a/snark-verifier/src/pcs/kzg/decider.rs b/snark-verifier/src/pcs/kzg/decider.rs index 53cbd601..2310b454 100644 --- a/snark-verifier/src/pcs/kzg/decider.rs +++ b/snark-verifier/src/pcs/kzg/decider.rs @@ -1,6 +1,7 @@ use crate::{pcs::kzg::KzgSuccinctVerifyingKey, util::arithmetic::MultiMillerLoop}; use std::marker::PhantomData; +/// KZG deciding key. #[derive(Debug, Clone, Copy)] pub struct KzgDecidingKey { svk: KzgSuccinctVerifyingKey, @@ -10,6 +11,7 @@ pub struct KzgDecidingKey { } impl KzgDecidingKey { + /// Initialize a [`KzgDecidingKey`] pub fn new( svk: impl Into>, g2: M::G2Affine, diff --git a/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs index b532f684..e618549d 100644 --- a/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs @@ -6,7 +6,7 @@ use crate::{ PolynomialCommitmentScheme, Query, }, util::{ - arithmetic::{ilog2, CurveAffine, FieldExt, Fraction, MultiMillerLoop}, + arithmetic::{CurveAffine, FieldExt, Fraction, MultiMillerLoop}, msm::Msm, transcript::TranscriptRead, Itertools, @@ -18,6 +18,9 @@ use std::{ marker::PhantomData, }; +/// Verifier of multi-open KZG. It is for the SHPLONK implementation +/// in [`halo2_proofs`]. +/// Notations are following https://eprint.iacr.org/2020/081. #[derive(Clone, Debug)] pub struct Bdfg21; @@ -76,6 +79,7 @@ where } } +/// Structured proof of [`Bdfg21`]. #[derive(Clone, Debug)] pub struct Bdfg21Proof where @@ -175,9 +179,12 @@ fn query_set_coeffs<'a, F: FieldExt, T: LoadedScalar>( .sorted() .dedup(); - let size = 2.max( - ilog2((sets.iter().map(|set| set.shifts.len()).max().unwrap() - 1).next_power_of_two()) + 1, - ); + let size = sets + .iter() + .map(|set| set.shifts.len()) + .chain(Some(2)) + .max() + .unwrap(); let powers_of_z = z.powers(size); let z_prime_minus_z_shift_i = BTreeMap::from_iter(superset.map(|shift| { ( @@ -290,23 +297,15 @@ where .collect_vec(); let z = &powers_of_z[1]; - let z_pow_k_minus_one = { - let k_minus_one = shifts.len() - 1; - powers_of_z - .iter() - .enumerate() - .skip(1) - .filter_map(|(i, power_of_z)| (k_minus_one & (1 << i) == 1).then(|| power_of_z)) - .fold(loader.load_one(), |acc, value| acc * value) - }; + let z_pow_k_minus_one = &powers_of_z[shifts.len() - 1]; let barycentric_weights = shifts .iter() .zip(normalized_ell_primes.iter()) .map(|(shift, normalized_ell_prime)| { loader.sum_products_with_coeff(&[ - (*normalized_ell_prime, &z_pow_k_minus_one, z_prime), - (-(*normalized_ell_prime * shift), &z_pow_k_minus_one, z), + (*normalized_ell_prime, z_pow_k_minus_one, z_prime), + (-(*normalized_ell_prime * shift), z_pow_k_minus_one, z), ]) }) .map(Fraction::one_over) diff --git a/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs index 31786e7d..358360fa 100644 --- a/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs @@ -14,6 +14,9 @@ use crate::{ Error, }; +/// Verifier of multi-open KZG. It is for the GWC implementation +/// in [`halo2_proofs`]. +/// Notations are following https://eprint.iacr.org/2019/953.pdf. #[derive(Clone, Debug)] pub struct Gwc19; @@ -77,6 +80,7 @@ where } } +/// Structured proof of [`Gwc19`]. #[derive(Clone, Debug)] pub struct Gwc19Proof where diff --git a/snark-verifier/src/system.rs b/snark-verifier/src/system.rs index 5d5aa99c..0ebe4311 100644 --- a/snark-verifier/src/system.rs +++ b/snark-verifier/src/system.rs @@ -1,2 +1,4 @@ +//! Proof systems `snark-verifier` supports + #[cfg(feature = "system_halo2")] pub mod halo2; diff --git a/snark-verifier/src/system/halo2.rs b/snark-verifier/src/system/halo2.rs index bb7b1bb9..a271a17c 100644 --- a/snark-verifier/src/system/halo2.rs +++ b/snark-verifier/src/system/halo2.rs @@ -1,3 +1,5 @@ +//! [`halo2_proofs`] proof system + use crate::{ util::{ arithmetic::{root_of_unity, CurveAffine, Domain, FieldExt, Rotation}, @@ -22,16 +24,19 @@ pub mod transcript; #[cfg(test)] pub(crate) mod test; +/// Configuration for converting a [`VerifyingKey`] of [`halo2_proofs`] into +/// [`PlonkProtocol`]. #[derive(Clone, Debug, Default)] pub struct Config { - pub zk: bool, - pub query_instance: bool, - pub num_proof: usize, - pub num_instance: Vec, - pub accumulator_indices: Option>, + zk: bool, + query_instance: bool, + num_proof: usize, + num_instance: Vec, + accumulator_indices: Option>, } impl Config { + /// Returns [`Config`] with `query_instance` set to `false`. pub fn kzg() -> Self { Self { zk: true, @@ -41,6 +46,7 @@ impl Config { } } + /// Returns [`Config`] with `query_instance` set to `true`. pub fn ipa() -> Self { Self { zk: true, @@ -50,27 +56,32 @@ impl Config { } } + /// Set `zk` pub fn set_zk(mut self, zk: bool) -> Self { self.zk = zk; self } + /// Set `query_instance` pub fn set_query_instance(mut self, query_instance: bool) -> Self { self.query_instance = query_instance; self } + /// Set `num_proof` pub fn with_num_proof(mut self, num_proof: usize) -> Self { assert!(num_proof > 0); self.num_proof = num_proof; self } + /// Set `num_instance` pub fn with_num_instance(mut self, num_instance: Vec) -> Self { self.num_instance = num_instance; self } + /// Set `accumulator_indices` pub fn with_accumulator_indices( mut self, accumulator_indices: Option>, @@ -80,6 +91,7 @@ impl Config { } } +/// Convert a [`VerifyingKey`] of [`halo2_proofs`] into [`PlonkProtocol`]. pub fn compile<'a, C: CurveAffine, P: Params<'a, C>>( params: &P, vk: &VerifyingKey, diff --git a/snark-verifier/src/system/halo2/strategy.rs b/snark-verifier/src/system/halo2/strategy.rs index de66f8e3..0be5c0b0 100644 --- a/snark-verifier/src/system/halo2/strategy.rs +++ b/snark-verifier/src/system/halo2/strategy.rs @@ -1,4 +1,8 @@ +//! Verifier strategy + pub mod ipa { + //! IPA verifier strategy + use crate::util::arithmetic::CurveAffine; use halo2_proofs::{ plonk::Error, @@ -14,6 +18,8 @@ pub mod ipa { }, }; + /// Strategy that handles single proof and decide immediately, but also + /// returns `g` if the proof is valid. #[derive(Clone, Debug)] pub struct SingleStrategy<'a, C: CurveAffine> { msm: MSMIPA<'a, C>, diff --git a/snark-verifier/src/system/halo2/transcript.rs b/snark-verifier/src/system/halo2/transcript.rs index 2200bbf4..6de1b739 100644 --- a/snark-verifier/src/system/halo2/transcript.rs +++ b/snark-verifier/src/system/halo2/transcript.rs @@ -1,3 +1,5 @@ +//! Transcripts implemented with both `halo2_proofs::transcript` and +//! `crate::util::transcript`. use crate::{ loader::native::{self, NativeLoader}, util::{ diff --git a/snark-verifier/src/system/halo2/transcript/evm.rs b/snark-verifier/src/system/halo2/transcript/evm.rs index 68c3ae4a..b7e81c81 100644 --- a/snark-verifier/src/system/halo2/transcript/evm.rs +++ b/snark-verifier/src/system/halo2/transcript/evm.rs @@ -1,6 +1,8 @@ +//! Transcript for verifier on EVM. + use crate::{ loader::{ - evm::{loader::Value, u256_to_fe, EcPoint, EvmLoader, MemoryChunk, Scalar, U256}, + evm::{loader::Value, u256_to_fe, util::MemoryChunk, EcPoint, EvmLoader, Scalar, U256}, native::{self, NativeLoader}, Loader, }, @@ -19,6 +21,9 @@ use std::{ marker::PhantomData, rc::Rc, }; + +/// Transcript for verifier on EVM using keccak256 as hasher. +#[derive(Debug)] pub struct EvmTranscript, S, B> { loader: L, stream: S, @@ -31,6 +36,8 @@ where C: CurveAffine, C::Scalar: PrimeField, { + /// Initialize [`EvmTranscript`] given [`Rc`] and pre-allocate an + /// u256 for `transcript_initial_state`. pub fn new(loader: &Rc) -> Self { let ptr = loader.allocate(0x20); assert_eq!(ptr, 0); @@ -44,6 +51,7 @@ where } } + /// Load `num_instance` instances from calldata to memory. pub fn load_instances(&mut self, num_instance: Vec) -> Vec> { num_instance .into_iter() @@ -147,6 +155,8 @@ impl EvmTranscript> where C: CurveAffine, { + /// Initialize [`EvmTranscript`] given readable or writeable stream for + /// verifying or proving with [`NativeLoader`]. pub fn new(stream: S) -> Self { Self { loader: NativeLoader, @@ -187,7 +197,7 @@ where Option::>::from(ec_point.coordinates()).ok_or_else(|| { Error::Transcript( io::ErrorKind::Other, - "Cannot write points at infinity to the transcript".to_string(), + "Invalid elliptic curve point".to_string(), ) })?; @@ -257,15 +267,20 @@ where C: CurveAffine, S: Write, { + /// Returns mutable `stream`. pub fn stream_mut(&mut self) -> &mut S { &mut self.stream } + /// Finalize transcript and returns `stream`. pub fn finalize(self) -> S { self.stream } } +/// [`EncodedChallenge`] implemented for verifier on EVM, which use input in +/// big-endian as the challenge. +#[derive(Debug)] pub struct ChallengeEvm(C::Scalar) where C: CurveAffine, diff --git a/snark-verifier/src/system/halo2/transcript/halo2.rs b/snark-verifier/src/system/halo2/transcript/halo2.rs index ab7d548c..ef458434 100644 --- a/snark-verifier/src/system/halo2/transcript/halo2.rs +++ b/snark-verifier/src/system/halo2/transcript/halo2.rs @@ -1,3 +1,5 @@ +//! Transcript for verifier in [`halo2_proofs`] circuit. + use crate::{ loader::{ halo2::{EcPoint, EccInstructions, Halo2Loader, Scalar}, @@ -23,6 +25,7 @@ pub trait NativeEncoding<'a, C>: EccInstructions<'a, C> where C: CurveAffine, { + /// Encode an elliptic curve point into field elements. fn encode( &self, ctx: &mut Self::Context, @@ -30,6 +33,10 @@ where ) -> Result, Error>; } +/// Transcript for verifier in [`halo2_proofs`] circuit using poseidon hasher. +/// Currently It assumes the elliptic curve scalar field is same as native +/// field. +#[derive(Debug)] pub struct PoseidonTranscript< C, L, @@ -54,6 +61,7 @@ where R: Read, EccChip: NativeEncoding<'a, C>, { + /// Initialize [`EvmTranscript`] given [`Rc`]. pub fn new(loader: &Rc>, stream: Value) -> Self { let buf = Poseidon::new(loader, R_F, R_P); Self { @@ -99,7 +107,7 @@ where .map_err(|_| { Error::Transcript( io::ErrorKind::Other, - "Failed to encode elliptic curve point into native field elements".to_string(), + "Invalid elliptic curve point".to_string(), ) })?; self.buf.update(&encoded); @@ -149,6 +157,8 @@ where impl PoseidonTranscript { + /// Initialize [`EvmTranscript`] given readable or writeable stream for + /// verifying or proving with [`NativeLoader`]. pub fn new(stream: S) -> Self { Self { loader: NativeLoader, @@ -236,10 +246,12 @@ where C: CurveAffine, W: Write, { + /// Returns mutable `stream`. pub fn stream_mut(&mut self) -> &mut W { &mut self.stream } + /// Finalize transcript and returns `stream`. pub fn finalize(self) -> W { self.stream } @@ -274,6 +286,10 @@ where } } +/// [`EncodedChallenge`] implemented for verifier in [`halo2_proofs`] circuit. +/// Currently It assumes the elliptic curve scalar field is same as native +/// field. +#[derive(Debug)] pub struct ChallengeScalar(C::Scalar); impl EncodedChallenge for ChallengeScalar { diff --git a/snark-verifier/src/util.rs b/snark-verifier/src/util.rs index bbfa8c89..508c0eeb 100644 --- a/snark-verifier/src/util.rs +++ b/snark-verifier/src/util.rs @@ -1,3 +1,5 @@ +//! Utilities. + pub mod arithmetic; pub mod hash; pub mod msm; @@ -9,6 +11,7 @@ pub(crate) use itertools::Itertools; #[cfg(feature = "parallel")] pub(crate) use rayon::current_num_threads; +/// Parallelly executing the function on the items of the given iterator. pub fn parallelize_iter(iter: I, f: F) where I: Send + Iterator, @@ -26,6 +29,7 @@ where iter.for_each(f); } +/// Parallelly executing the function on the given mutable slice. pub fn parallelize(v: &mut [T], f: F) where T: Send, diff --git a/snark-verifier/src/util/arithmetic.rs b/snark-verifier/src/util/arithmetic.rs index dacd2443..af32ded0 100644 --- a/snark-verifier/src/util/arithmetic.rs +++ b/snark-verifier/src/util/arithmetic.rs @@ -1,3 +1,5 @@ +//! Arithmetic related re-exported traits and utilities. + use crate::util::Itertools; use num_bigint::BigUint; use num_traits::One; @@ -18,10 +20,12 @@ pub use halo2_curves::{ Coordinates, CurveAffine, CurveExt, FieldExt, }; +/// [`halo2_curves::pairing::MultiMillerLoop`] with [`std::fmt::Debug`]. pub trait MultiMillerLoop: halo2_curves::pairing::MultiMillerLoop + Debug {} impl MultiMillerLoop for M {} +/// Operations that could be done with field elements. pub trait FieldOps: Sized + Neg @@ -38,9 +42,11 @@ pub trait FieldOps: + for<'a> SubAssign<&'a Self> + for<'a> MulAssign<&'a Self> { + /// Returns multiplicative inversion if any. fn invert(&self) -> Option; } +/// Batch invert [`PrimeField`] elements and multiply all with given coefficient. pub fn batch_invert_and_mul(values: &mut [F], coeff: &F) { let products = values .iter() @@ -65,10 +71,18 @@ pub fn batch_invert_and_mul(values: &mut [F], coeff: &F) { } } +/// Batch invert [`PrimeField`] elements. pub fn batch_invert(values: &mut [F]) { batch_invert_and_mul(values, &F::one()) } +/// Root of unity of 2^k-sized multiplicative subgroup of [`PrimeField`] by +/// repeatedly squaring the root of unity of the largest multiplicative +/// subgroup. +/// +/// # Panic +/// +/// If given `k` is greater than [`PrimeField::S`]. pub fn root_of_unity(k: usize) -> F { assert!(k <= F::S as usize); @@ -78,18 +92,22 @@ pub fn root_of_unity(k: usize) -> F { .unwrap() } +/// Rotation on a group. #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Rotation(pub i32); impl Rotation { + /// No rotation pub fn cur() -> Self { Rotation(0) } + /// To previous element pub fn prev() -> Self { Rotation(-1) } + /// To next element pub fn next() -> Self { Rotation(1) } @@ -101,16 +119,23 @@ impl From for Rotation { } } +/// 2-adicity multiplicative domain #[derive(Clone, Debug)] pub struct Domain { + /// Log size of the domain. pub k: usize, + /// Size of the domain. pub n: usize, + /// Inverse of `n`. pub n_inv: F, + /// Generator of the domain. pub gen: F, + /// Inverse of `gen`. pub gen_inv: F, } impl Domain { + /// Initialize a domain with specified generator. pub fn new(k: usize, gen: F) -> Self { let n = 1 << k; let n_inv = F::from(n as u64).invert().unwrap(); @@ -125,6 +150,7 @@ impl Domain { } } + /// Rotate an element to given `rotation`. pub fn rotate_scalar(&self, scalar: F, rotation: Rotation) -> F { match rotation.0.cmp(&0) { Ordering::Equal => scalar, @@ -134,6 +160,7 @@ impl Domain { } } +/// Contains numerator and denominator for deferred evaluation. #[derive(Clone, Debug)] pub struct Fraction { numer: Option, @@ -143,6 +170,7 @@ pub struct Fraction { } impl Fraction { + /// Initialize an unevaluated fraction. pub fn new(numer: T, denom: T) -> Self { Self { numer: Some(numer), @@ -152,6 +180,7 @@ impl Fraction { } } + /// Initialize an unevaluated fraction without numerator. pub fn one_over(denom: T) -> Self { Self { numer: None, @@ -161,6 +190,7 @@ impl Fraction { } } + /// Returns denominator. pub fn denom(&self) -> Option<&T> { if !self.inv { Some(&self.denom) @@ -169,6 +199,8 @@ impl Fraction { } } + #[must_use = "To be inverted"] + /// Returns mutable denominator for doing inversion. pub fn denom_mut(&mut self) -> Option<&mut T> { if !self.inv { self.inv = true; @@ -180,18 +212,29 @@ impl Fraction { } impl Fraction { + /// Evaluate the fraction and cache the result. + /// + /// # Panic + /// + /// If `denom_mut` is not called before. pub fn evaluate(&mut self) { assert!(self.inv); - assert!(self.eval.is_none()); - - self.eval = Some( - self.numer - .take() - .map(|numer| numer * &self.denom) - .unwrap_or_else(|| self.denom.clone()), - ); + + if self.eval.is_none() { + self.eval = Some( + self.numer + .take() + .map(|numer| numer * &self.denom) + .unwrap_or_else(|| self.denom.clone()), + ); + } } + /// Returns cached fraction evaluation. + /// + /// # Panic + /// + /// If `evaluate` is not called before. pub fn evaluated(&self) -> &T { assert!(self.eval.is_some()); @@ -199,14 +242,12 @@ impl Fraction { } } -pub fn ilog2(value: usize) -> usize { - (usize::BITS - value.leading_zeros() - 1) as usize -} - +/// Modulus of a [`PrimeField`] pub fn modulus() -> BigUint { fe_to_big(-F::one()) + 1usize } +/// Convert a [`BigUint`] into a [`PrimeField`] . pub fn fe_from_big(big: BigUint) -> F { let bytes = big.to_bytes_le(); let mut repr = F::Repr::default(); @@ -215,14 +256,18 @@ pub fn fe_from_big(big: BigUint) -> F { F::from_repr(repr).unwrap() } +/// Convert a [`PrimeField`] into a [`BigUint`]. pub fn fe_to_big(fe: F) -> BigUint { BigUint::from_bytes_le(fe.to_repr().as_ref()) } +/// Convert a [`PrimeField`] into another [`PrimeField`]. pub fn fe_to_fe(fe: F1) -> F2 { fe_from_big(fe_to_big(fe) % modulus::()) } +/// Convert `LIMBS` limbs into a [`PrimeField`], assuming each limb contains at +/// most `BITS`. pub fn fe_from_limbs( limbs: [F1; LIMBS], ) -> F2 { @@ -237,6 +282,8 @@ pub fn fe_from_limbs( fe: F1, ) -> [F2; LIMBS] { @@ -251,10 +298,12 @@ pub fn fe_to_limbs(scalar: F) -> impl Iterator { iter::successors(Some(F::one()), move |power| Some(scalar * power)) } +/// Compute inner product of 2 slice of [`Field`]. pub fn inner_product(lhs: &[F], rhs: &[F]) -> F { lhs.iter() .zip_eq(rhs.iter()) diff --git a/snark-verifier/src/util/hash.rs b/snark-verifier/src/util/hash.rs index 17ede0b3..758e26d5 100644 --- a/snark-verifier/src/util/hash.rs +++ b/snark-verifier/src/util/hash.rs @@ -1,3 +1,5 @@ +//! Hash algorithms. + mod poseidon; pub use crate::util::hash::poseidon::Poseidon; diff --git a/snark-verifier/src/util/hash/poseidon.rs b/snark-verifier/src/util/hash/poseidon.rs index c0fc03a6..60d55d9f 100644 --- a/snark-verifier/src/util/hash/poseidon.rs +++ b/snark-verifier/src/util/hash/poseidon.rs @@ -5,6 +5,7 @@ use crate::{ use poseidon::{self, SparseMDSMatrix, Spec}; use std::{iter, marker::PhantomData, mem}; +#[derive(Debug)] struct State { inner: [L; T], _marker: PhantomData, @@ -106,6 +107,8 @@ impl, const T: usize, const RATE: usize> State { spec: Spec, state: State, @@ -113,6 +116,7 @@ pub struct Poseidon { } impl, const T: usize, const RATE: usize> Poseidon { + /// Initialize a poseidon hasher. pub fn new(loader: &L::Loader, r_f: usize, r_p: usize) -> Self { Self { spec: Spec::new(r_f, r_p), @@ -125,10 +129,13 @@ impl, const T: usize, const RATE: usize> Poseido } } + /// Store given `elements` into buffer. pub fn update(&mut self, elements: &[L]) { self.buf.extend_from_slice(elements); } + /// Consume buffer and perform permutation, then output second element of + /// state. pub fn squeeze(&mut self) -> L { let buf = mem::take(&mut self.buf); let exact = buf.len() % RATE == 0; diff --git a/snark-verifier/src/util/msm.rs b/snark-verifier/src/util/msm.rs index 014a29e8..8fec380a 100644 --- a/snark-verifier/src/util/msm.rs +++ b/snark-verifier/src/util/msm.rs @@ -1,3 +1,5 @@ +//! Multi-scalar multiplication algorithm. + use crate::{ loader::{LoadedEcPoint, Loader}, util::{ @@ -14,6 +16,7 @@ use std::{ }; #[derive(Clone, Debug)] +/// Contains unevaluated multi-scalar multiplication. pub struct Msm<'a, C: CurveAffine, L: Loader> { constant: Option, scalars: Vec, @@ -39,6 +42,7 @@ where C: CurveAffine, L: Loader, { + /// Initialize with a constant. pub fn constant(constant: L::LoadedScalar) -> Self { Msm { constant: Some(constant), @@ -46,6 +50,7 @@ where } } + /// Initialize with a base. pub fn base<'b: 'a>(base: &'b L::LoadedEcPoint) -> Self { let one = base.loader().load_one(); Msm { @@ -68,6 +73,11 @@ where self.bases.is_empty().then(|| self.constant.unwrap()) } + /// Evaluate multi-scalar multiplication. + /// + /// # Panic + /// + /// If given `gen` is `None` but there `constant` has some value. pub fn evaluate(self, gen: Option) -> L::LoadedEcPoint { let gen = gen.map(|gen| { self.bases @@ -87,7 +97,7 @@ where L::multi_scalar_multiplication(&pairs) } - pub fn scale(&mut self, factor: &L::LoadedScalar) { + fn scale(&mut self, factor: &L::LoadedScalar) { if let Some(constant) = self.constant.as_mut() { *constant *= factor; } @@ -96,7 +106,7 @@ where } } - pub fn push<'b: 'a>(&mut self, scalar: L::LoadedScalar, base: &'b L::LoadedEcPoint) { + fn push<'b: 'a>(&mut self, scalar: L::LoadedScalar, base: &'b L::LoadedEcPoint) { if let Some(pos) = self.bases.iter().position(|exist| exist.eq(&base)) { self.scalars[pos] += &scalar; } else { @@ -105,7 +115,7 @@ where } } - pub fn extend<'b: 'a>(&mut self, mut other: Msm<'b, C, L>) { + fn extend<'b: 'a>(&mut self, mut other: Msm<'b, C, L>) { match (self.constant.as_mut(), other.constant.as_ref()) { (Some(lhs), Some(rhs)) => *lhs += rhs, (None, Some(_)) => self.constant = other.constant.take(), @@ -293,7 +303,8 @@ fn multi_scalar_multiplication_serial( } } -// Copy from https://github.com/zcash/halo2/blob/main/halo2_proofs/src/arithmetic.rs +/// Multi-scalar multiplication algorithm copied from +/// https://github.com/zcash/halo2/blob/main/halo2_proofs/src/arithmetic.rs. pub fn multi_scalar_multiplication(scalars: &[C::Scalar], bases: &[C]) -> C::Curve { assert_eq!(scalars.len(), bases.len()); diff --git a/snark-verifier/src/util/poly.rs b/snark-verifier/src/util/poly.rs index ea120b33..eef2f593 100644 --- a/snark-verifier/src/util/poly.rs +++ b/snark-verifier/src/util/poly.rs @@ -1,3 +1,5 @@ +//! Polynomial. + use crate::util::{arithmetic::Field, parallelize}; use rand::Rng; use std::{ @@ -9,39 +11,47 @@ use std::{ }; #[derive(Clone, Debug)] +/// Univariate polynomial. pub struct Polynomial(Vec); impl Polynomial { + /// Initialize an univariate polynomial. pub fn new(inner: Vec) -> Self { Self(inner) } + /// Returns `true` if the `Polynomial` contains no elements. pub fn is_empty(&self) -> bool { self.0.is_empty() } + /// Returns the length of the `Polynomial`. pub fn len(&self) -> usize { self.0.len() } + /// Returns an iterator of the `Polynomial`. pub fn iter(&self) -> impl Iterator { self.0.iter() } + /// Returns a mutable iterator of the `Polynomial`. pub fn iter_mut(&mut self) -> impl Iterator { self.0.iter_mut() } + /// Into vector of coefficients. pub fn to_vec(self) -> Vec { self.0 } } impl Polynomial { - pub fn rand(n: usize, mut rng: R) -> Self { + pub(crate) fn rand(n: usize, mut rng: R) -> Self { Self::new(iter::repeat_with(|| F::random(&mut rng)).take(n).collect()) } + /// Returns evaluation at given `x`. pub fn evaluate(&self, x: F) -> F { let evaluate_serial = |coeffs: &[F]| { coeffs diff --git a/snark-verifier/src/util/protocol.rs b/snark-verifier/src/util/protocol.rs deleted file mode 100644 index 6ae361db..00000000 --- a/snark-verifier/src/util/protocol.rs +++ /dev/null @@ -1,368 +0,0 @@ -use crate::{ - loader::{LoadedScalar, Loader}, - util::{ - arithmetic::{CurveAffine, Domain, Field, Fraction, Rotation}, - Itertools, - }, -}; -use num_integer::Integer; -use num_traits::One; -use std::{ - cmp::max, - collections::{BTreeMap, BTreeSet}, - fmt::Debug, - iter::{self, Sum}, - ops::{Add, Mul, Neg, Sub}, -}; - -#[derive(Clone, Copy, Debug)] -pub enum CommonPolynomial { - Identity, - Lagrange(i32), -} - -#[derive(Clone, Debug)] -pub struct CommonPolynomialEvaluation -where - C: CurveAffine, - L: Loader, -{ - zn: L::LoadedScalar, - zn_minus_one: L::LoadedScalar, - zn_minus_one_inv: Fraction, - identity: L::LoadedScalar, - lagrange: BTreeMap>, -} - -impl CommonPolynomialEvaluation -where - C: CurveAffine, - L: Loader, -{ - pub fn new( - domain: &Domain, - langranges: impl IntoIterator, - z: &L::LoadedScalar, - ) -> Self { - let loader = z.loader(); - - let zn = z.pow_const(domain.n as u64); - let langranges = langranges.into_iter().sorted().dedup().collect_vec(); - - let one = loader.load_one(); - let zn_minus_one = zn.clone() - &one; - let zn_minus_one_inv = Fraction::one_over(zn_minus_one.clone()); - - let n_inv = loader.load_const(&domain.n_inv); - let numer = zn_minus_one.clone() * &n_inv; - let omegas = langranges - .iter() - .map(|&i| loader.load_const(&domain.rotate_scalar(C::Scalar::one(), Rotation(i)))) - .collect_vec(); - let lagrange_evals = omegas - .iter() - .map(|omega| Fraction::new(numer.clone() * omega, z.clone() - omega)) - .collect_vec(); - - Self { - zn, - zn_minus_one, - zn_minus_one_inv, - identity: z.clone(), - lagrange: langranges.into_iter().zip(lagrange_evals).collect(), - } - } - - pub fn zn(&self) -> &L::LoadedScalar { - &self.zn - } - - pub fn zn_minus_one(&self) -> &L::LoadedScalar { - &self.zn_minus_one - } - - pub fn zn_minus_one_inv(&self) -> &L::LoadedScalar { - self.zn_minus_one_inv.evaluated() - } - - pub fn get(&self, poly: CommonPolynomial) -> &L::LoadedScalar { - match poly { - CommonPolynomial::Identity => &self.identity, - CommonPolynomial::Lagrange(i) => self.lagrange.get(&i).unwrap().evaluated(), - } - } - - pub fn denoms(&mut self) -> impl IntoIterator { - self.lagrange - .iter_mut() - .map(|(_, value)| value.denom_mut()) - .chain(iter::once(self.zn_minus_one_inv.denom_mut())) - .flatten() - } - - pub fn evaluate(&mut self) { - self.lagrange - .iter_mut() - .map(|(_, value)| value) - .chain(iter::once(&mut self.zn_minus_one_inv)) - .for_each(Fraction::evaluate) - } -} - -#[derive(Clone, Debug)] -pub struct QuotientPolynomial { - pub chunk_degree: usize, - pub numerator: Expression, -} - -impl QuotientPolynomial { - pub fn num_chunk(&self) -> usize { - Integer::div_ceil( - &(self.numerator.degree().checked_sub(1).unwrap_or_default()), - &self.chunk_degree, - ) - } -} - -#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Query { - pub poly: usize, - pub rotation: Rotation, -} - -impl Query { - pub fn new>(poly: usize, rotation: R) -> Self { - Self { - poly, - rotation: rotation.into(), - } - } -} - -#[derive(Clone, Debug)] -pub enum Expression { - Constant(F), - CommonPolynomial(CommonPolynomial), - Polynomial(Query), - Challenge(usize), - Negated(Box>), - Sum(Box>, Box>), - Product(Box>, Box>), - Scaled(Box>, F), - DistributePowers(Vec>, Box>), -} - -impl Expression { - pub fn evaluate( - &self, - constant: &impl Fn(F) -> T, - common_poly: &impl Fn(CommonPolynomial) -> T, - poly: &impl Fn(Query) -> T, - challenge: &impl Fn(usize) -> T, - negated: &impl Fn(T) -> T, - sum: &impl Fn(T, T) -> T, - product: &impl Fn(T, T) -> T, - scaled: &impl Fn(T, F) -> T, - ) -> T { - let evaluate = |expr: &Expression| { - expr.evaluate( - constant, - common_poly, - poly, - challenge, - negated, - sum, - product, - scaled, - ) - }; - match self { - Expression::Constant(scalar) => constant(scalar.clone()), - Expression::CommonPolynomial(poly) => common_poly(*poly), - Expression::Polynomial(query) => poly(*query), - Expression::Challenge(index) => challenge(*index), - Expression::Negated(a) => { - let a = evaluate(a); - negated(a) - } - Expression::Sum(a, b) => { - let a = evaluate(a); - let b = evaluate(b); - sum(a, b) - } - Expression::Product(a, b) => { - let a = evaluate(a); - let b = evaluate(b); - product(a, b) - } - Expression::Scaled(a, scalar) => { - let a = evaluate(a); - scaled(a, scalar.clone()) - } - Expression::DistributePowers(exprs, scalar) => { - assert!(!exprs.is_empty()); - if exprs.len() == 1 { - return evaluate(exprs.first().unwrap()); - } - let mut exprs = exprs.iter(); - let first = evaluate(exprs.next().unwrap()); - let scalar = evaluate(scalar); - exprs.fold(first, |acc, expr| { - sum(product(acc, scalar.clone()), evaluate(expr)) - }) - } - } - } - - pub fn degree(&self) -> usize { - match self { - Expression::Constant(_) => 0, - Expression::CommonPolynomial(_) => 1, - Expression::Polynomial { .. } => 1, - Expression::Challenge { .. } => 0, - Expression::Negated(a) => a.degree(), - Expression::Sum(a, b) => max(a.degree(), b.degree()), - Expression::Product(a, b) => a.degree() + b.degree(), - Expression::Scaled(a, _) => a.degree(), - Expression::DistributePowers(a, b) => a - .iter() - .chain(Some(b.as_ref())) - .map(Self::degree) - .max() - .unwrap_or_default(), - } - } - - pub fn used_langrange(&self) -> BTreeSet { - self.evaluate( - &|_| None, - &|poly| match poly { - CommonPolynomial::Lagrange(i) => Some(BTreeSet::from_iter([i])), - _ => None, - }, - &|_| None, - &|_| None, - &|a| a, - &merge_left_right, - &merge_left_right, - &|a, _| a, - ) - .unwrap_or_default() - } - - pub fn used_query(&self) -> BTreeSet { - self.evaluate( - &|_| None, - &|_| None, - &|query| Some(BTreeSet::from_iter([query])), - &|_| None, - &|a| a, - &merge_left_right, - &merge_left_right, - &|a, _| a, - ) - .unwrap_or_default() - } -} - -impl From for Expression { - fn from(query: Query) -> Self { - Self::Polynomial(query) - } -} - -impl From for Expression { - fn from(common_poly: CommonPolynomial) -> Self { - Self::CommonPolynomial(common_poly) - } -} - -macro_rules! impl_expression_ops { - ($trait:ident, $op:ident, $variant:ident, $rhs:ty, $rhs_expr:expr) => { - impl $trait<$rhs> for Expression { - type Output = Expression; - fn $op(self, rhs: $rhs) -> Self::Output { - Expression::$variant((self).into(), $rhs_expr(rhs).into()) - } - } - impl $trait<$rhs> for &Expression { - type Output = Expression; - fn $op(self, rhs: $rhs) -> Self::Output { - Expression::$variant((self.clone()).into(), $rhs_expr(rhs).into()) - } - } - impl $trait<&$rhs> for Expression { - type Output = Expression; - fn $op(self, rhs: &$rhs) -> Self::Output { - Expression::$variant((self).into(), $rhs_expr(rhs.clone()).into()) - } - } - impl $trait<&$rhs> for &Expression { - type Output = Expression; - fn $op(self, rhs: &$rhs) -> Self::Output { - Expression::$variant((self.clone()).into(), $rhs_expr(rhs.clone()).into()) - } - } - }; -} - -impl_expression_ops!(Mul, mul, Product, Expression, std::convert::identity); -impl_expression_ops!(Mul, mul, Scaled, F, std::convert::identity); -impl_expression_ops!(Add, add, Sum, Expression, std::convert::identity); -impl_expression_ops!(Sub, sub, Sum, Expression, Neg::neg); - -impl Neg for Expression { - type Output = Expression; - fn neg(self) -> Self::Output { - Expression::Negated(Box::new(self)) - } -} - -impl Neg for &Expression { - type Output = Expression; - fn neg(self) -> Self::Output { - Expression::Negated(Box::new(self.clone())) - } -} - -impl Sum for Expression { - fn sum>(iter: I) -> Self { - iter.reduce(|acc, item| acc + item) - .unwrap_or_else(|| Expression::Constant(F::default())) - } -} - -impl One for Expression { - fn one() -> Self { - Expression::Constant(F::one()) - } -} - -fn merge_left_right(a: Option>, b: Option>) -> Option> { - match (a, b) { - (Some(a), None) | (None, Some(a)) => Some(a), - (Some(mut a), Some(b)) => { - a.extend(b); - Some(a) - } - _ => None, - } -} - -#[derive(Clone, Copy, Debug)] -pub enum LinearizationStrategy { - /// Older linearization strategy of GWC19, which has linearization - /// polynomial that doesn't evaluate to 0, and requires prover to send extra - /// evaluation of it to verifier. - WithoutConstant, - /// Current linearization strategy of GWC19, which has linearization - /// polynomial that evaluate to 0 by subtracting product of vanishing and - /// quotient polynomials. - MinusVanishingTimesQuotient, -} - -#[derive(Clone, Debug, Default)] -pub struct InstanceCommittingKey { - pub bases: Vec, - pub constant: Option, -} diff --git a/snark-verifier/src/util/transcript.rs b/snark-verifier/src/util/transcript.rs index 3337324d..b871b083 100644 --- a/snark-verifier/src/util/transcript.rs +++ b/snark-verifier/src/util/transcript.rs @@ -1,46 +1,62 @@ +//! Transcript traits. + use crate::{ loader::{native::NativeLoader, Loader}, {util::arithmetic::CurveAffine, Error}, }; +/// Common methods for prover and verifier. pub trait Transcript where C: CurveAffine, L: Loader, { + /// Returns [`Loader`]. fn loader(&self) -> &L; + /// Squeeze a challenge. fn squeeze_challenge(&mut self) -> L::LoadedScalar; + /// Squeeze `n` challenges. fn squeeze_n_challenges(&mut self, n: usize) -> Vec { (0..n).map(|_| self.squeeze_challenge()).collect() } + /// Update with an elliptic curve point. fn common_ec_point(&mut self, ec_point: &L::LoadedEcPoint) -> Result<(), Error>; + /// Update with a scalar. fn common_scalar(&mut self, scalar: &L::LoadedScalar) -> Result<(), Error>; } +/// Transcript for verifier. pub trait TranscriptRead: Transcript where C: CurveAffine, L: Loader, { + /// Read a scalar. fn read_scalar(&mut self) -> Result; + /// Read `n` scalar. fn read_n_scalars(&mut self, n: usize) -> Result, Error> { (0..n).map(|_| self.read_scalar()).collect() } + /// Read a elliptic curve point. fn read_ec_point(&mut self) -> Result; + /// Read `n` elliptic curve point. fn read_n_ec_points(&mut self, n: usize) -> Result, Error> { (0..n).map(|_| self.read_ec_point()).collect() } } +/// Transcript for prover. pub trait TranscriptWrite: Transcript { + /// Write a scalar. fn write_scalar(&mut self, scalar: C::Scalar) -> Result<(), Error>; + /// Write a elliptic curve point. fn write_ec_point(&mut self, ec_point: C) -> Result<(), Error>; } diff --git a/snark-verifier/src/verifier.rs b/snark-verifier/src/verifier.rs index c492fe55..813065db 100644 --- a/snark-verifier/src/verifier.rs +++ b/snark-verifier/src/verifier.rs @@ -1,3 +1,5 @@ +//! Verifiers for (S)NARK. + use crate::{ loader::Loader, util::{arithmetic::CurveAffine, transcript::TranscriptRead}, @@ -7,16 +9,22 @@ use std::fmt::Debug; pub mod plonk; +/// (S)NARK verifier for verifying a (S)NARK. pub trait SnarkVerifier where C: CurveAffine, L: Loader, { + /// Verifying key for subroutines if any. type VerifyingKey: Clone + Debug; + /// Protocol specifying configuration of a (S)NARK. type Protocol: Clone + Debug; + /// Structured proof read from transcript. type Proof: Clone + Debug; + /// Output of verification. type Output: Clone + Debug; + /// Read [`SnarkVerifier::Proof`] from transcript. fn read_proof( vk: &Self::VerifyingKey, protocol: &Self::Protocol, @@ -26,6 +34,7 @@ where where T: TranscriptRead; + /// Verify [`SnarkVerifier::Proof`] and output [`SnarkVerifier::Output`]. fn verify( vk: &Self::VerifyingKey, protocol: &Self::Protocol, diff --git a/snark-verifier/src/verifier/plonk.rs b/snark-verifier/src/verifier/plonk.rs index 08bf5dc9..e2f6f940 100644 --- a/snark-verifier/src/verifier/plonk.rs +++ b/snark-verifier/src/verifier/plonk.rs @@ -1,3 +1,13 @@ +//! Verifiers for [PLONK], currently there are [`PlonkSuccinctVerifier`] and +//! [`PlonkVerifier`] implemented and both are implemented assuming the used +//! [`PolynomialCommitmentScheme`] has [atomic] or [split] accumulation scheme +//! ([`PlonkVerifier`] is just [`PlonkSuccinctVerifier`] plus doing accumulator +//! deciding then returns accept/reject as ouput). +//! +//! [PLONK]: https://eprint.iacr.org/2019/953 +//! [atomic]: https://eprint.iacr.org/2020/499 +//! [split]: https://eprint.iacr.org/2020/1618 + use crate::{ cost::{Cost, CostEstimation}, loader::Loader, @@ -17,6 +27,8 @@ pub(crate) mod protocol; pub use proof::PlonkProof; pub use protocol::PlonkProtocol; +/// Verifier that verifies the cheap part of PLONK and ouput the accumulator. +#[derive(Debug)] pub struct PlonkSuccinctVerifier>(PhantomData<(AS, AE)>); impl SnarkVerifier for PlonkSuccinctVerifier @@ -80,6 +92,9 @@ where } } +/// Verifier that first verifies the cheap part of PLONK, then decides +/// accumulator and returns accept/reject as ouput. +#[derive(Debug)] pub struct PlonkVerifier>(PhantomData<(AS, AE)>); impl SnarkVerifier for PlonkVerifier diff --git a/snark-verifier/src/verifier/plonk/proof.rs b/snark-verifier/src/verifier/plonk/proof.rs index fb12aed6..962417ec 100644 --- a/snark-verifier/src/verifier/plonk/proof.rs +++ b/snark-verifier/src/verifier/plonk/proof.rs @@ -15,6 +15,8 @@ use crate::{ }; use std::{collections::HashMap, iter}; +/// Proof of PLONK with [`PolynomialCommitmentScheme`] that has +/// [`AccumulationScheme`]. #[derive(Clone, Debug)] pub struct PlonkProof where @@ -22,13 +24,21 @@ where L: Loader, AS: AccumulationScheme + PolynomialCommitmentScheme, { + /// Computed commitments of instance polynomials. pub committed_instances: Option>, + /// Commitments of witness polynomials read from transcript. pub witnesses: Vec, + /// Challenges squeezed from transcript. pub challenges: Vec, + /// Quotient commitments read from transcript. pub quotients: Vec, + /// Query point squeezed from transcript. pub z: L::LoadedScalar, + /// Evaluations read from transcript. pub evaluations: Vec, + /// Proof of [`PolynomialCommitmentScheme`]. pub pcs: >::Proof, + /// Old [`AccumulationScheme::Accumulator`]s read from instnaces. pub old_accumulators: Vec, } @@ -38,6 +48,7 @@ where L: Loader, AS: AccumulationScheme + PolynomialCommitmentScheme, { + /// Reads each part from transcript as [`PlonkProof`]. pub fn read( svk: &>::VerifyingKey, protocol: &PlonkProtocol, @@ -157,16 +168,15 @@ where }) } - pub fn empty_queries(protocol: &PlonkProtocol) -> Vec> { + pub(super) fn empty_queries(protocol: &PlonkProtocol) -> Vec> { protocol .queries .iter() - .map(|query| pcs::Query { - poly: query.poly, - shift: protocol + .map(|query| { + let shift = protocol .domain - .rotate_scalar(C::Scalar::one(), query.rotation), - eval: (), + .rotate_scalar(C::Scalar::one(), query.rotation); + pcs::Query::new(query.poly, shift) }) .collect() } diff --git a/snark-verifier/src/verifier/plonk/protocol.rs b/snark-verifier/src/verifier/plonk/protocol.rs index daaa58a9..94f97201 100644 --- a/snark-verifier/src/verifier/plonk/protocol.rs +++ b/snark-verifier/src/verifier/plonk/protocol.rs @@ -15,25 +15,37 @@ use std::{ ops::{Add, Mul, Neg, Sub}, }; +/// Protocol specifying configuration of a PLONK. #[derive(Clone, Debug)] pub struct PlonkProtocol where C: CurveAffine, L: Loader, { - // Common description + /// Working domain. pub domain: Domain, + /// Commitments of preprocessed polynomials. pub preprocessed: Vec, + /// Number of instances in each instance polynomial. pub num_instance: Vec, + /// Number of witness polynomials in each phase. pub num_witness: Vec, + /// Number of challenges to squeeze from transcript after each phase. pub num_challenge: Vec, + /// Evaluations to read from transcript. pub evaluations: Vec, + /// [`crate::pcs::PolynomialCommitmentScheme`] queries to verify. pub queries: Vec, + /// Structure of quotient polynomial. pub quotient: QuotientPolynomial, - // Minor customization + /// Prover and verifier common initial state to write to transcript if any. pub transcript_initial_state: Option, + /// Instance polynomials commiting key if any. pub instance_committing_key: Option>, + /// Linearization strategy. pub linearization: Option, + /// Indices (instance polynomial index, row) of encoded + /// [`crate::pcs::AccumulationScheme::Accumulator`]s. pub accumulator_indices: Vec>, } @@ -76,6 +88,8 @@ impl PlonkProtocol where C: CurveAffine, { + /// Loaded `PlonkProtocol` with `preprocessed` and + /// `transcript_initial_state` loaded as constant. pub fn loaded>(&self, loader: &L) -> PlonkProtocol { let preprocessed = self .preprocessed @@ -117,6 +131,9 @@ mod halo2 { where C: CurveAffine, { + /// Loaded `PlonkProtocol` with `preprocessed` and + /// `transcript_initial_state` loaded as witness, which is useful when + /// doing recursion. pub fn loaded_preprocessed_as_witness<'a, EccChip: EccInstructions<'a, C>>( &self, loader: &Rc>, From 3f3da272f4f9eae797add42238fc0510d8cf0598 Mon Sep 17 00:00:00 2001 From: han0110 Date: Fri, 6 Jan 2023 15:36:39 +0800 Subject: [PATCH 11/73] refactor: remove redudant check `validate_ec_point` (still doesn not support identity) --- snark-verifier/src/loader/evm/code.rs | 11 ++--------- snark-verifier/src/loader/evm/loader.rs | 3 ++- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/snark-verifier/src/loader/evm/code.rs b/snark-verifier/src/loader/evm/code.rs index 840d1e67..2fec71d2 100644 --- a/snark-verifier/src/loader/evm/code.rs +++ b/snark-verifier/src/loader/evm/code.rs @@ -44,20 +44,13 @@ impl YulCode { let y_lt_p:bool := lt(y, {base_modulus}) valid := and(x_lt_p, y_lt_p) }} - {{ - let x_is_zero:bool := eq(x, 0) - let y_is_zero:bool := eq(y, 0) - let x_or_y_is_zero:bool := or(x_is_zero, y_is_zero) - let x_and_y_is_not_zero:bool := not(x_or_y_is_zero) - valid := and(x_and_y_is_not_zero, valid) - }} {{ let y_square := mulmod(y, y, {base_modulus}) let x_square := mulmod(x, x, {base_modulus}) let x_cube := mulmod(x_square, x, {base_modulus}) let x_cube_plus_3 := addmod(x_cube, 3, {base_modulus}) - let y_square_eq_x_cube_plus_3:bool := eq(x_cube_plus_3, y_square) - valid := and(y_square_eq_x_cube_plus_3, valid) + let is_affine:bool := eq(x_cube_plus_3, y_square) + valid := and(valid, is_affine) }} }} {} diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index 04ca6709..911625b6 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -149,7 +149,8 @@ impl EvmLoader { self.scalar(Value::Memory(ptr)) } - /// Calldata load an elliptic curve point and validate it's on curve. + /// Calldata load an elliptic curve point and validate it's on affine plane. + /// Note that identity will cause the verification to fail. pub fn calldataload_ec_point(self: &Rc, offset: usize) -> EcPoint { let x_ptr = self.allocate(0x40); let y_ptr = x_ptr + 0x20; From 50232938fb8795abc6044cf054bdea752d24bc20 Mon Sep 17 00:00:00 2001 From: han0110 Date: Fri, 20 Jan 2023 12:19:31 +0800 Subject: [PATCH 12/73] feat: expand more things and fix typos MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Chih Cheng Liang Co-authored-by: Carlos Pérez <37264926+CPerezz@users.noreply.github.com> --- snark-verifier/src/loader.rs | 2 +- snark-verifier/src/loader/evm/util.rs | 4 ++-- snark-verifier/src/pcs.rs | 12 ++++++++---- snark-verifier/src/pcs/ipa.rs | 2 +- snark-verifier/src/pcs/ipa/accumulation.rs | 7 ++++--- snark-verifier/src/pcs/ipa/decider.rs | 1 + snark-verifier/src/pcs/ipa/multiopen/bgh19.rs | 2 +- snark-verifier/src/pcs/kzg.rs | 3 ++- snark-verifier/src/pcs/kzg/accumulation.rs | 5 +++-- snark-verifier/src/pcs/kzg/accumulator.rs | 4 ++-- snark-verifier/src/pcs/kzg/decider.rs | 2 ++ 11 files changed, 27 insertions(+), 17 deletions(-) diff --git a/snark-verifier/src/loader.rs b/snark-verifier/src/loader.rs index 36ea54e9..897890b1 100644 --- a/snark-verifier/src/loader.rs +++ b/snark-verifier/src/loader.rs @@ -269,6 +269,6 @@ pub trait Loader: /// Start cost metering with an `identifier`. fn start_cost_metering(&self, _identifier: &str) {} - /// End lastest started cost metering. + /// End latest started cost metering. fn end_cost_metering(&self) {} } diff --git a/snark-verifier/src/loader/evm/util.rs b/snark-verifier/src/loader/evm/util.rs index db3cb672..62792ee8 100644 --- a/snark-verifier/src/loader/evm/util.rs +++ b/snark-verifier/src/loader/evm/util.rs @@ -49,8 +49,8 @@ impl MemoryChunk { } /// Convert a [`PrimeField`] into a [`U256`]. -/// Assuming fields implements traits in crate `ff` always have little-endian -/// representation. +/// Assuming fields that implement traits in crate `ff` always have +/// little-endian representation. pub fn fe_to_u256(f: F) -> U256 where F: PrimeField, diff --git a/snark-verifier/src/pcs.rs b/snark-verifier/src/pcs.rs index b7802df7..cdd098c8 100644 --- a/snark-verifier/src/pcs.rs +++ b/snark-verifier/src/pcs.rs @@ -15,7 +15,7 @@ use std::{fmt::Debug, marker::PhantomData}; pub mod ipa; pub mod kzg; -/// Query to a oracle. +/// Query to an oracle. /// It assumes all queries are based on the same point, but with some `shift`. #[derive(Clone, Debug)] pub struct Query { @@ -112,12 +112,16 @@ where } /// Accumulation scheme decider. +/// When accumulation is going to end, the decider will perform the check if the +/// final accumulator is valid or not, where the check is usually much more +/// expensive than accumulation verification. pub trait AccumulationDecider: AccumulationScheme where C: CurveAffine, L: Loader, { - /// Deciding key. + /// Deciding key. The key for decider for perform the final accumulator + /// check. type DecidingKey: Clone + Debug; /// Decide if a [`AccumulationScheme::Accumulator`] is valid. @@ -138,8 +142,8 @@ where /// Proving key. type ProvingKey: Clone + Debug; - /// Create a proof that argues old [`AccumulationScheme::Accumulator`]s are - /// properly accumulated into the new one, and returns the new one as + /// Create a proof that argues if old [`AccumulationScheme::Accumulator`]s + /// are properly accumulated into the new one, and returns the new one as /// output. fn create_proof( pk: &Self::ProvingKey, diff --git a/snark-verifier/src/pcs/ipa.rs b/snark-verifier/src/pcs/ipa.rs index f07f56cf..4d870f1e 100644 --- a/snark-verifier/src/pcs/ipa.rs +++ b/snark-verifier/src/pcs/ipa.rs @@ -434,7 +434,7 @@ mod test { #[test] fn test_ipa() { type Ipa = ipa::Ipa; - type IpaAs = ipa::IpaAs; + type IpaAs = ipa::IpaAs; let k = 10; let mut rng = OsRng; diff --git a/snark-verifier/src/pcs/ipa/accumulation.rs b/snark-verifier/src/pcs/ipa/accumulation.rs index 021287d2..7da4197a 100644 --- a/snark-verifier/src/pcs/ipa/accumulation.rs +++ b/snark-verifier/src/pcs/ipa/accumulation.rs @@ -18,9 +18,10 @@ use crate::{ use rand::Rng; use std::{array, fmt::Debug, iter, marker::PhantomData}; -/// Inner product argument accumulation scheme. +/// Inner product argument accumulation scheme. The second generic `MOS` stands +/// for different kind of multi-open scheme. #[derive(Clone, Debug)] -pub struct IpaAs(PhantomData<(C, MOS)>); +pub struct IpaAs(PhantomData<(C, MOS)>); impl AccumulationScheme for IpaAs where @@ -238,7 +239,7 @@ mod test { #[test] fn test_ipa_as() { type Ipa = ipa::Ipa; - type IpaAs = ipa::IpaAs; + type IpaAs = ipa::IpaAs; let k = 10; let zk = true; diff --git a/snark-verifier/src/pcs/ipa/decider.rs b/snark-verifier/src/pcs/ipa/decider.rs index 7aefcf81..933480f3 100644 --- a/snark-verifier/src/pcs/ipa/decider.rs +++ b/snark-verifier/src/pcs/ipa/decider.rs @@ -4,6 +4,7 @@ use crate::{pcs::ipa::IpaSuccinctVerifyingKey, util::arithmetic::CurveAffine}; #[derive(Clone, Debug)] pub struct IpaDecidingKey { svk: IpaSuccinctVerifyingKey, + /// Committing key. g: Vec, } diff --git a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs index 2ecb4b8d..c8723dd0 100644 --- a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs +++ b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs @@ -19,7 +19,7 @@ use std::{ }; /// Verifier of multi-open inner product argument. It is for the implementation -/// in [`halo2_proofs`]. +/// in [`halo2_proofs`], which is previously https://eprint.iacr.org/2019/1021. #[derive(Clone, Debug)] pub struct Bgh19; diff --git a/snark-verifier/src/pcs/kzg.rs b/snark-verifier/src/pcs/kzg.rs index 8b032a1d..8f416ee3 100644 --- a/snark-verifier/src/pcs/kzg.rs +++ b/snark-verifier/src/pcs/kzg.rs @@ -1,4 +1,5 @@ -//! KZG polynomial commitment scheme and accumulation scheme. +//! [KZG]() +//! polynomial commitment scheme and accumulation scheme. use crate::util::arithmetic::CurveAffine; diff --git a/snark-verifier/src/pcs/kzg/accumulation.rs b/snark-verifier/src/pcs/kzg/accumulation.rs index 572708c3..1f901568 100644 --- a/snark-verifier/src/pcs/kzg/accumulation.rs +++ b/snark-verifier/src/pcs/kzg/accumulation.rs @@ -11,9 +11,10 @@ use crate::{ use rand::Rng; use std::{fmt::Debug, marker::PhantomData}; -/// KZG accumulation scheme. +/// KZG accumulation scheme. The second generic `MOS` stands for different kind +/// of multi-open scheme. #[derive(Clone, Debug)] -pub struct KzgAs(PhantomData<(M, MOS)>); +pub struct KzgAs(PhantomData<(M, MOS)>); impl AccumulationScheme for KzgAs where diff --git a/snark-verifier/src/pcs/kzg/accumulator.rs b/snark-verifier/src/pcs/kzg/accumulator.rs index 3ae2aa76..a3fd8e42 100644 --- a/snark-verifier/src/pcs/kzg/accumulator.rs +++ b/snark-verifier/src/pcs/kzg/accumulator.rs @@ -8,9 +8,9 @@ where C: CurveAffine, L: Loader, { - /// lhs G1 of pairing. + /// Left-hand side G1 of pairing. pub lhs: L::LoadedEcPoint, - /// rhs G1 of pairing. + /// Right-hand side G1 of pairing. pub rhs: L::LoadedEcPoint, } diff --git a/snark-verifier/src/pcs/kzg/decider.rs b/snark-verifier/src/pcs/kzg/decider.rs index 2310b454..417a39dc 100644 --- a/snark-verifier/src/pcs/kzg/decider.rs +++ b/snark-verifier/src/pcs/kzg/decider.rs @@ -5,7 +5,9 @@ use std::marker::PhantomData; #[derive(Debug, Clone, Copy)] pub struct KzgDecidingKey { svk: KzgSuccinctVerifyingKey, + /// Generator on G2. g2: M::G2Affine, + /// Generator to the trusted-setup secret on G2. s_g2: M::G2Affine, _marker: PhantomData, } From 8cc0b1503be7bc4804e9909750d8efdfd25b7b0a Mon Sep 17 00:00:00 2001 From: han0110 Date: Fri, 20 Jan 2023 12:28:05 +0800 Subject: [PATCH 13/73] fix: rustdoc warnings --- snark-verifier/src/lib.rs | 2 +- snark-verifier/src/loader/evm/util/executor.rs | 5 +++-- snark-verifier/src/pcs.rs | 2 +- snark-verifier/src/pcs/ipa.rs | 4 ++-- snark-verifier/src/pcs/ipa/multiopen/bgh19.rs | 3 ++- snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs | 2 +- snark-verifier/src/pcs/kzg/multiopen/gwc19.rs | 2 +- snark-verifier/src/system/halo2/transcript/halo2.rs | 4 ++-- snark-verifier/src/util/msm.rs | 2 +- 9 files changed, 14 insertions(+), 12 deletions(-) diff --git a/snark-verifier/src/lib.rs b/snark-verifier/src/lib.rs index 87e18700..11187659 100644 --- a/snark-verifier/src/lib.rs +++ b/snark-verifier/src/lib.rs @@ -5,7 +5,7 @@ clippy::too_many_arguments, clippy::upper_case_acronyms )] -#![deny(missing_debug_implementations, missing_docs, unsafe_code)] +#![deny(missing_debug_implementations, missing_docs, unsafe_code, rustdoc::all)] pub mod cost; pub mod loader; diff --git a/snark-verifier/src/loader/evm/util/executor.rs b/snark-verifier/src/loader/evm/util/executor.rs index ab7c170f..de466c08 100644 --- a/snark-verifier/src/loader/evm/util/executor.rs +++ b/snark-verifier/src/loader/evm/util/executor.rs @@ -1,4 +1,5 @@ -//! Copied and modified from https://github.com/foundry-rs/foundry/blob/master/evm/src/executor/mod.rs +//! Copied and modified from +//! use crate::loader::evm::{Address, H256, U256}; use bytes::Bytes; @@ -725,7 +726,7 @@ impl ExecutorBuilder { self } - /// Initialize an [`Executor`]. + /// Initialize an `Executor`. pub fn build(self) -> Executor { Executor::new(self.debugger, self.gas_limit.unwrap_or(U256::MAX)) } diff --git a/snark-verifier/src/pcs.rs b/snark-verifier/src/pcs.rs index cdd098c8..535ebedf 100644 --- a/snark-verifier/src/pcs.rs +++ b/snark-verifier/src/pcs.rs @@ -166,7 +166,7 @@ where type Accumulator: Clone + Debug; /// Decode an [`AccumulatorEncoding::Accumulator`] from serveral - /// [`Loader::LoadedScalar`]s. + /// [`crate::loader::ScalarLoader::LoadedScalar`]s. fn from_repr(repr: &[&L::LoadedScalar]) -> Result; } diff --git a/snark-verifier/src/pcs/ipa.rs b/snark-verifier/src/pcs/ipa.rs index 4d870f1e..c782c65f 100644 --- a/snark-verifier/src/pcs/ipa.rs +++ b/snark-verifier/src/pcs/ipa.rs @@ -1,5 +1,5 @@ //! Inner product argument polynomial commitment scheme and accumulation scheme. -//! The notations are following https://eprint.iacr.org/2020/499.pdf. +//! The notations are following . use crate::{ loader::{native::NativeLoader, LoadedScalar, Loader, ScalarLoader}, @@ -311,7 +311,7 @@ where } } - /// Read [`AccumulationScheme::Proof`] from transcript. + /// Read [`crate::pcs::AccumulationScheme::Proof`] from transcript. pub fn read(svk: &IpaSuccinctVerifyingKey, transcript: &mut T) -> Result where T: TranscriptRead, diff --git a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs index c8723dd0..a852267a 100644 --- a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs +++ b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs @@ -19,7 +19,8 @@ use std::{ }; /// Verifier of multi-open inner product argument. It is for the implementation -/// in [`halo2_proofs`], which is previously https://eprint.iacr.org/2019/1021. +/// in [`halo2_proofs`], which is previously +/// . #[derive(Clone, Debug)] pub struct Bgh19; diff --git a/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs index e618549d..3a448056 100644 --- a/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs @@ -20,7 +20,7 @@ use std::{ /// Verifier of multi-open KZG. It is for the SHPLONK implementation /// in [`halo2_proofs`]. -/// Notations are following https://eprint.iacr.org/2020/081. +/// Notations are following . #[derive(Clone, Debug)] pub struct Bdfg21; diff --git a/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs index 358360fa..e5741163 100644 --- a/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs @@ -16,7 +16,7 @@ use crate::{ /// Verifier of multi-open KZG. It is for the GWC implementation /// in [`halo2_proofs`]. -/// Notations are following https://eprint.iacr.org/2019/953.pdf. +/// Notations are following . #[derive(Clone, Debug)] pub struct Gwc19; diff --git a/snark-verifier/src/system/halo2/transcript/halo2.rs b/snark-verifier/src/system/halo2/transcript/halo2.rs index ef458434..8519a8ca 100644 --- a/snark-verifier/src/system/halo2/transcript/halo2.rs +++ b/snark-verifier/src/system/halo2/transcript/halo2.rs @@ -61,7 +61,7 @@ where R: Read, EccChip: NativeEncoding<'a, C>, { - /// Initialize [`EvmTranscript`] given [`Rc`]. + /// Initialize [`PoseidonTranscript`] given [`Rc`]. pub fn new(loader: &Rc>, stream: Value) -> Self { let buf = Poseidon::new(loader, R_F, R_P); Self { @@ -157,7 +157,7 @@ where impl PoseidonTranscript { - /// Initialize [`EvmTranscript`] given readable or writeable stream for + /// Initialize [`PoseidonTranscript`] given readable or writeable stream for /// verifying or proving with [`NativeLoader`]. pub fn new(stream: S) -> Self { Self { diff --git a/snark-verifier/src/util/msm.rs b/snark-verifier/src/util/msm.rs index 8fec380a..f68ce6f4 100644 --- a/snark-verifier/src/util/msm.rs +++ b/snark-verifier/src/util/msm.rs @@ -304,7 +304,7 @@ fn multi_scalar_multiplication_serial( } /// Multi-scalar multiplication algorithm copied from -/// https://github.com/zcash/halo2/blob/main/halo2_proofs/src/arithmetic.rs. +/// . pub fn multi_scalar_multiplication(scalars: &[C::Scalar], bases: &[C]) -> C::Curve { assert_eq!(scalars.len(), bases.len()); From 2d5ef6b4cb7e4ac9504f188167a8a2dcfcb377be Mon Sep 17 00:00:00 2001 From: dante <45801863+alexander-camuto@users.noreply.github.com> Date: Wed, 1 Feb 2023 04:39:14 +0000 Subject: [PATCH 14/73] chore: update dependencies (#24) --- snark-verifier/Cargo.toml | 8 ++++---- snark-verifier/src/system/halo2/test/kzg.rs | 7 ++++++- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 0d32d22f..1c92a059 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -11,13 +11,13 @@ num-integer = "0.1.45" num-traits = "0.2.15" rand = "0.8" hex = "0.4" -halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.0", package = "halo2curves" } +halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2curves", tag = "0.3.1", package = "halo2curves" } # parallel rayon = { version = "1.5.3", optional = true } # system_halo2 -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2022_10_22", optional = true } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2023_01_20", optional = true } # loader_evm sha3 = { version = "0.10", optional = true } @@ -27,7 +27,7 @@ rlp = { version = "0.5.2", default-features = false, features = ["std"], optiona revm = { version = "= 2.3.1", optional = true } # loader_halo2 -halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc", optional = true } +halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_01_20", package = "ecc", optional = true } poseidon = { git = "https://github.com/privacy-scaling-explorations/poseidon", tag = "v2022_10_22", optional = true } [dev-dependencies] @@ -35,7 +35,7 @@ rand_chacha = "0.3.1" paste = "1.0.7" # system_halo2 -halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22", package = "ecc" } +halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_01_20", package = "ecc" } # loader_evm crossterm = { version = "0.25" } diff --git a/snark-verifier/src/system/halo2/test/kzg.rs b/snark-verifier/src/system/halo2/test/kzg.rs index 77c26964..c8b4fc77 100644 --- a/snark-verifier/src/system/halo2/test/kzg.rs +++ b/snark-verifier/src/system/halo2/test/kzg.rs @@ -2,6 +2,7 @@ use crate::{ system::halo2::test::{read_or_create_srs, MainGateWithRange}, util::arithmetic::{fe_to_limbs, CurveAffine, MultiMillerLoop}, }; +use halo2_curves::serde::SerdeObject; use halo2_proofs::poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG}; use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; @@ -23,7 +24,11 @@ pub fn setup(k: u32) -> ParamsKZG { } pub fn main_gate_with_range_with_mock_kzg_accumulator( -) -> MainGateWithRange { +) -> MainGateWithRange +where + M::G1Affine: SerdeObject, + M::G2Affine: SerdeObject, +{ let srs = read_or_create_srs(TESTDATA_DIR, 1, setup::); let [g1, s_g1] = [srs.get_g()[0], srs.get_g()[1]].map(|point| point.coordinates().unwrap()); MainGateWithRange::new( From df03d898b841f71cbc36c2fb9fa07b8196f9623e Mon Sep 17 00:00:00 2001 From: Han Date: Fri, 3 Feb 2023 15:30:34 +0800 Subject: [PATCH 15/73] chore: update `halo2` and `halo2wrong` version (#25) --- snark-verifier/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 1c92a059..5ce80f0d 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -17,7 +17,7 @@ halo2_curves = { git = "https://github.com/privacy-scaling-explorations/halo2cur rayon = { version = "1.5.3", optional = true } # system_halo2 -halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2023_01_20", optional = true } +halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2", tag = "v2023_02_02", optional = true } # loader_evm sha3 = { version = "0.10", optional = true } @@ -27,7 +27,7 @@ rlp = { version = "0.5.2", default-features = false, features = ["std"], optiona revm = { version = "= 2.3.1", optional = true } # loader_halo2 -halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_01_20", package = "ecc", optional = true } +halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_02_02", package = "ecc", optional = true } poseidon = { git = "https://github.com/privacy-scaling-explorations/poseidon", tag = "v2022_10_22", optional = true } [dev-dependencies] @@ -35,7 +35,7 @@ rand_chacha = "0.3.1" paste = "1.0.7" # system_halo2 -halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_01_20", package = "ecc" } +halo2_wrong_ecc = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2023_02_02", package = "ecc" } # loader_evm crossterm = { version = "0.25" } From f1265f503f56ac640984532e1b7af4f06755f632 Mon Sep 17 00:00:00 2001 From: Han Date: Tue, 14 Feb 2023 21:15:36 +0800 Subject: [PATCH 16/73] fix: enable `util::hash::poseidon` only when `feature = loader_halo2` (#27) --- snark-verifier/src/util/hash.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/snark-verifier/src/util/hash.rs b/snark-verifier/src/util/hash.rs index 758e26d5..69d50499 100644 --- a/snark-verifier/src/util/hash.rs +++ b/snark-verifier/src/util/hash.rs @@ -1,7 +1,9 @@ //! Hash algorithms. +#[cfg(feature = "loader_halo2")] mod poseidon; +#[cfg(feature = "loader_halo2")] pub use crate::util::hash::poseidon::Poseidon; #[cfg(feature = "loader_evm")] From 4ad803a3523c1b2d6e2e365ddcf677f09c50f7cb Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Sun, 19 Feb 2023 11:47:07 -0800 Subject: [PATCH 17/73] feat: working update to halo2-lib v0.3.0 --- Cargo.toml | 4 - snark-verifier-sdk/Cargo.toml | 6 +- snark-verifier-sdk/benches/standard_plonk.rs | 78 ++- snark-verifier-sdk/benches/zkevm.rs | 145 ++-- .../benches/zkevm_plus_state.rs | 21 +- snark-verifier-sdk/configs/bench_zkevm.config | 1 - .../configs/example_evm_accumulator.config | 1 - snark-verifier-sdk/src/evm.rs | 18 +- snark-verifier-sdk/src/halo2.rs | 37 +- snark-verifier-sdk/src/halo2/aggregation.rs | 663 +++++++++--------- snark-verifier-sdk/src/lib.rs | 57 +- snark-verifier/Cargo.toml | 8 +- .../configs/example_evm_accumulator.config | 1 - .../configs/example_evm_accumulator.json | 7 + snark-verifier/configs/verify_circuit.config | 1 - .../examples/evm-verifier-with-accumulator.rs | 422 +++++------ snark-verifier/examples/evm-verifier.rs | 6 +- snark-verifier/src/loader.rs | 33 +- snark-verifier/src/loader/evm/loader.rs | 103 +-- snark-verifier/src/loader/halo2.rs | 19 +- snark-verifier/src/loader/halo2/loader.rs | 362 ++++------ snark-verifier/src/loader/halo2/shim.rs | 565 +++------------ snark-verifier/src/loader/native.rs | 13 +- snark-verifier/src/pcs/ipa.rs | 35 +- snark-verifier/src/pcs/kzg/accumulator.rs | 127 +--- snark-verifier/src/system/halo2.rs | 6 +- snark-verifier/src/system/halo2/test.rs | 1 + .../src/system/halo2/test/kzg/halo2.rs | 26 +- .../src/system/halo2/transcript/halo2.rs | 101 +-- snark-verifier/src/util/arithmetic.rs | 3 +- 30 files changed, 1111 insertions(+), 1759 deletions(-) delete mode 100644 snark-verifier-sdk/configs/bench_zkevm.config delete mode 100644 snark-verifier-sdk/configs/example_evm_accumulator.config delete mode 100644 snark-verifier/configs/example_evm_accumulator.config create mode 100644 snark-verifier/configs/example_evm_accumulator.json delete mode 100644 snark-verifier/configs/verify_circuit.config diff --git a/Cargo.toml b/Cargo.toml index 7b3ec409..552212b3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,3 @@ incremental = false [profile.flamegraph] inherits = "release" debug = true - -# patch until PR https://github.com/privacy-scaling-explorations/halo2/pull/111 is merged -[patch."https://github.com/privacy-scaling-explorations/halo2.git"] -halo2_proofs = { git = "https://github.com/axiom-crypto/halo2.git", branch = "feat/serde-raw" } \ No newline at end of file diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 222e6eb9..515c4546 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -14,9 +14,9 @@ rand_chacha = "0.3.1" hex = "0.4" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } - halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", tag = "v0.2.2", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } @@ -44,13 +44,13 @@ crossterm = { version = "0.25" } tui = { version = "0.19", default-features = false, features = ["crossterm"] } [features] -default = ["loader_halo2", "loader_evm", "halo2-axiom", "halo2-base/jemallocator"] +default = ["loader_halo2", "loader_evm", "halo2-pse", "halo2-base/jemallocator", "display"] display = ["snark-verifier/display", "dep:ark-std"] loader_evm = ["snark-verifier/loader_evm", "dep:ethereum-types"] loader_halo2 = ["snark-verifier/loader_halo2"] parallel = ["snark-verifier/parallel"] # EXACTLY one of halo2-pse / halo2-axiom should always be turned on; not sure how to enforce this with Cargo -halo2-pse = ["snark-verifier/halo2-pse"] +halo2-pse = ["snark-verifier/halo2-pse", "dep:serde_with"] halo2-axiom = ["snark-verifier/halo2-axiom"] zkevm = ["dep:zkevm-circuits", "dep:bus-mapping", "dep:mock", "dep:eth-types"] diff --git a/snark-verifier-sdk/benches/standard_plonk.rs b/snark-verifier-sdk/benches/standard_plonk.rs index e19776e9..5ff1279e 100644 --- a/snark-verifier-sdk/benches/standard_plonk.rs +++ b/snark-verifier-sdk/benches/standard_plonk.rs @@ -1,6 +1,10 @@ use criterion::{criterion_group, criterion_main}; use criterion::{BenchmarkId, Criterion}; +use halo2_base::gates::builder::CircuitBuilderStage; +use halo2_base::utils::fs::gen_srs; use pprof::criterion::{Output, PProfProfiler}; +use rand::rngs::OsRng; +use std::env::set_var; use ark_std::{end_timer, start_timer}; use halo2_base::halo2_proofs; @@ -9,15 +13,14 @@ use halo2_proofs::{ halo2curves::bn256::Bn256, poly::{commitment::Params, kzg::commitment::ParamsKZG}, }; -use rand::rngs::OsRng; -use rand::SeedableRng; -use rand_chacha::ChaCha20Rng; -use snark_verifier_sdk::CircuitExt; +use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; +use snark_verifier_sdk::halo2::aggregation::AggregationConfigParams; use snark_verifier_sdk::{ gen_pk, halo2::{aggregation::AggregationCircuit, gen_proof_shplonk, gen_snark_shplonk}, Snark, }; +use snark_verifier_sdk::{CircuitExt, SHPLONK}; mod application { use super::halo2_curves::bn256::Fr; @@ -145,9 +148,9 @@ mod application { } #[cfg(feature = "halo2-axiom")] { - region.assign_advice(config.a, 0, Value::known(self.0))?; + region.assign_advice(config.a, 0, Value::known(self.0)); region.assign_fixed(config.q_a, 0, -Fr::one()); - region.assign_advice(config.a, 1, Value::known(-Fr::from(5u64)))?; + region.assign_advice(config.a, 1, Value::known(-Fr::from(5u64))); for (idx, column) in (1..).zip([ config.q_a, config.q_b, @@ -158,7 +161,7 @@ mod application { region.assign_fixed(column, 1, Fr::from(idx as u64)); } - let a = region.assign_advice(config.a, 2, Value::known(Fr::one()))?; + let a = region.assign_advice(config.a, 2, Value::known(Fr::one())); a.copy_advice(&mut region, config.b, 3); a.copy_advice(&mut region, config.c, 4); } @@ -174,41 +177,68 @@ fn gen_application_snark(params: &ParamsKZG) -> Snark { let circuit = application::StandardPlonk::rand(OsRng); let pk = gen_pk(params, &circuit, None); - gen_snark_shplonk(params, &pk, circuit, &mut OsRng, None::<&str>) + gen_snark_shplonk(params, &pk, circuit, None::<&str>) } fn bench(c: &mut Criterion) { - std::env::set_var("VERIFY_CONFIG", "./configs/example_evm_accumulator.config"); - let k = 21; - let params = halo2_base::utils::fs::gen_srs(k); - let params_app = { - let mut params = params.clone(); - params.downsize(8); - params - }; + let path = "./configs/example_evm_accumulator.json"; + let params_app = gen_srs(8); let snarks = [(); 3].map(|_| gen_application_snark(¶ms_app)); + let agg_config = AggregationConfigParams::from_path(path); + let params = gen_srs(agg_config.degree); + let lookup_bits = params.k() as usize - 1; - let start1 = start_timer!(|| "Create aggregation circuit"); - let mut rng = ChaCha20Rng::from_entropy(); - let agg_circuit = AggregationCircuit::new(¶ms, snarks, &mut rng); - end_timer!(start1); + let agg_circuit = AggregationCircuit::keygen::(¶ms, snarks.clone()); + let start0 = start_timer!(|| "gen vk & pk"); let pk = gen_pk(¶ms, &agg_circuit, None); + end_timer!(start0); + let break_points = agg_circuit.break_points(); let mut group = c.benchmark_group("plonk-prover"); group.sample_size(10); group.bench_with_input( - BenchmarkId::new("standard-plonk-agg", k), - &(¶ms, &pk, &agg_circuit), - |b, &(params, pk, agg_circuit)| { + BenchmarkId::new("standard-plonk-agg", params.k()), + &(¶ms, &pk, &break_points, &snarks), + |b, &(params, pk, break_points, snarks)| { b.iter(|| { + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + Some(break_points.clone()), + lookup_bits, + params, + snarks.clone(), + ); let instances = agg_circuit.instances(); - gen_proof_shplonk(params, pk, agg_circuit.clone(), instances, &mut rng, None) + gen_proof_shplonk(params, pk, agg_circuit, instances, None) }) }, ); group.finish(); + + #[cfg(feature = "loader_evm")] + { + // do one more time to verify + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + Some(break_points), + lookup_bits, + ¶ms, + snarks.clone(), + ); + let num_instances = agg_circuit.num_instance(); + let instances = agg_circuit.instances(); + let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); + + let deployment_code = gen_evm_verifier_shplonk::( + ¶ms, + pk.get_vk(), + num_instances, + None, + ); + evm_verify(deployment_code, instances, proof); + } } criterion_group! { diff --git a/snark-verifier-sdk/benches/zkevm.rs b/snark-verifier-sdk/benches/zkevm.rs index f4c3f3fc..e6b4c4e7 100644 --- a/snark-verifier-sdk/benches/zkevm.rs +++ b/snark-verifier-sdk/benches/zkevm.rs @@ -13,10 +13,12 @@ use snark_verifier_sdk::{ }, gen_pk, halo2::{ - aggregation::load_verify_circuit_degree, aggregation::AggregationCircuit, gen_proof_gwc, - gen_proof_shplonk, gen_snark_gwc, gen_snark_shplonk, PoseidonTranscript, POSEIDON_SPEC, + aggregation::load_verify_circuit_degree, + aggregation::{AggregationCircuit, AggregationConfigParams}, + gen_proof_gwc, gen_proof_shplonk, gen_snark_gwc, gen_snark_shplonk, PoseidonTranscript, + POSEIDON_SPEC, }, - CircuitExt, + CircuitExt, GWC, SHPLONK, }; use std::env::{set_var, var}; use std::path::Path; @@ -66,45 +68,88 @@ fn bench(c: &mut Criterion) { let circuit = zkevm::test_circuit(); let params_app = gen_srs(k); let pk = gen_pk(¶ms_app, &circuit, Some(Path::new("data/zkevm_evm.pkey"))); - let snark = gen_snark_gwc( - ¶ms_app, - &pk, - circuit, - &mut transcript, - &mut rng, - Some(Path::new("data/zkevm_evm.snark")), - ); + let snark = + gen_snark_shplonk(¶ms_app, &pk, circuit, Some(Path::new("data/zkevm_evm.snark"))); let snarks = [snark]; // === finished zkevm evm circuit === // === now to do aggregation === - set_var("VERIFY_CONFIG", "./configs/bench_zkevm.config"); - let k = load_verify_circuit_degree(); + let path = "./configs/bench_zkevm.config"; + let agg_config = AggregationConfigParams::from_path(path); + let k = agg_config.degree; + let lookup_bits = k as usize - 1; let params = gen_srs(k); - let start1 = start_timer!(|| "Create aggregation circuit"); - let agg_circuit = AggregationCircuit::new(¶ms, snarks, &mut transcript, &mut rng); - end_timer!(start1); + let agg_circuit = AggregationCircuit::keygen::(¶ms, snarks.clone()); + let start1 = start_timer!(|| "gen vk & pk"); let pk = gen_pk(¶ms, &agg_circuit, None); + end_timer!(start1); + let break_points = agg_circuit.break_points(); + + #[cfg(feature = "loader_evm")] + { + let start2 = start_timer!(|| "Create EVM SHPLONK proof"); + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + Some(break_points.clone()), + lookup_bits, + ¶ms, + snarks.clone(), + ); + let instances = agg_circuit.instances(); + let num_instances = agg_circuit.num_instance(); + + let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); + end_timer!(start2); + + let deployment_code = gen_evm_verifier_shplonk::( + ¶ms, + pk.get_vk(), + num_instances, + None::<&str>, + ); + + evm_verify(deployment_code, instances.clone(), proof); + + let start2 = start_timer!(|| "Create EVM GWC proof"); + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + Some(break_points.clone()), + lookup_bits, + ¶ms, + snarks.clone(), + ); + let proof = gen_evm_proof_gwc(¶ms, &pk, agg_circuit, instances.clone()); + end_timer!(start2); + + let deployment_code = gen_evm_verifier_shplonk::( + ¶ms, + pk.get_vk(), + num_instances, + None::<&str>, + ); + + evm_verify(deployment_code, instances, proof); + } + // run benches let mut group = c.benchmark_group("shplonk-proof"); group.sample_size(10); group.bench_with_input( BenchmarkId::new("zkevm-evm-agg", k), - &(¶ms, &pk, &agg_circuit), - |b, &(params, pk, agg_circuit)| { + &(¶ms, &pk, &break_points, &snarks), + |b, &(params, pk, break_points, snarks)| { b.iter(|| { - let instances = agg_circuit.instances(); - gen_proof_shplonk( + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + Some(break_points.clone()), + lookup_bits, params, - pk, - agg_circuit.clone(), - instances, - &mut transcript, - &mut rng, - None, + snarks.clone(), ); + let instances = agg_circuit.instances(); + gen_proof_shplonk(params, pk, agg_circuit, instances, None) }) }, ); @@ -114,51 +159,23 @@ fn bench(c: &mut Criterion) { group.sample_size(10); group.bench_with_input( BenchmarkId::new("zkevm-evm-agg", k), - &(¶ms, &pk, &agg_circuit), - |b, &(params, pk, agg_circuit)| { + &(¶ms, &pk, &break_points, &snarks), + |b, &(params, pk, break_points, snarks)| { b.iter(|| { - let instances = agg_circuit.instances(); - gen_proof_gwc( + // note that the generic here remains SHPLONK because it reflects the multi-open scheme for the previous snark (= the zkevm snark) + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + Some(break_points.clone()), + lookup_bits, params, - pk, - agg_circuit.clone(), - instances, - &mut transcript, - &mut rng, - None, + snarks.clone(), ); + let instances = agg_circuit.instances(); + gen_proof_gwc(params, pk, agg_circuit, instances, None) }) }, ); group.finish(); - - #[cfg(feature = "loader_evm")] - { - let deployment_code = - gen_evm_verifier_shplonk::(¶ms, pk.get_vk(), &(), None::<&str>); - - let start2 = start_timer!(|| "Create EVM SHPLONK proof"); - let proof = gen_evm_proof_shplonk( - ¶ms, - &pk, - agg_circuit.clone(), - agg_circuit.instances(), - &mut rng, - ); - end_timer!(start2); - - evm_verify(deployment_code, agg_circuit.instances(), proof); - - let deployment_code = - gen_evm_verifier_shplonk::(¶ms, pk.get_vk(), &(), None::<&str>); - - let start2 = start_timer!(|| "Create EVM GWC proof"); - let proof = - gen_evm_proof_gwc(¶ms, &pk, agg_circuit.clone(), agg_circuit.instances(), &mut rng); - end_timer!(start2); - - evm_verify(deployment_code, agg_circuit.instances(), proof); - } } criterion_group!(benches, bench); diff --git a/snark-verifier-sdk/benches/zkevm_plus_state.rs b/snark-verifier-sdk/benches/zkevm_plus_state.rs index 840f8581..8ab021f2 100644 --- a/snark-verifier-sdk/benches/zkevm_plus_state.rs +++ b/snark-verifier-sdk/benches/zkevm_plus_state.rs @@ -76,14 +76,7 @@ fn bench(c: &mut Criterion) { let params_app = gen_srs(k); let evm_snark = { let pk = gen_pk(¶ms_app, &evm_circuit, Some(Path::new("data/zkevm_evm.pkey"))); - gen_snark_gwc( - ¶ms_app, - &pk, - evm_circuit, - &mut transcript, - &mut rng, - Some(Path::new("data/zkevm_evm.snark")), - ) + gen_snark_shplonk(¶ms_app, &pk, evm_circuit, Some(Path::new("data/zkevm_evm.snark"))) }; let state_snark = { let pk = gen_pk(¶ms_app, &state_circuit, Some(Path::new("data/zkevm_state.pkey"))); @@ -91,8 +84,6 @@ fn bench(c: &mut Criterion) { ¶ms_app, &pk, state_circuit, - &mut transcript, - &mut rng, Some(Path::new("data/zkevm_state.snark")), ) }; @@ -118,15 +109,7 @@ fn bench(c: &mut Criterion) { |b, &(params, pk, agg_circuit)| { b.iter(|| { let instances = agg_circuit.instances(); - gen_proof_shplonk( - params, - pk, - agg_circuit.clone(), - instances, - &mut transcript, - &mut rng, - None, - ); + gen_proof_shplonk(params, pk, agg_circuit.clone(), instances, None); }) }, ); diff --git a/snark-verifier-sdk/configs/bench_zkevm.config b/snark-verifier-sdk/configs/bench_zkevm.config deleted file mode 100644 index 5156de4f..00000000 --- a/snark-verifier-sdk/configs/bench_zkevm.config +++ /dev/null @@ -1 +0,0 @@ -{"strategy":"Simple","degree":23,"num_advice":[5],"num_lookup_advice":[1],"num_fixed":1,"lookup_bits":22,"limb_bits":88,"num_limbs":3} diff --git a/snark-verifier-sdk/configs/example_evm_accumulator.config b/snark-verifier-sdk/configs/example_evm_accumulator.config deleted file mode 100644 index 156c402a..00000000 --- a/snark-verifier-sdk/configs/example_evm_accumulator.config +++ /dev/null @@ -1 +0,0 @@ -{"strategy":"Simple","degree":21,"num_advice":[5],"num_lookup_advice":[1],"num_fixed":1,"lookup_bits":20,"limb_bits":88,"num_limbs":3} diff --git a/snark-verifier-sdk/src/evm.rs b/snark-verifier-sdk/src/evm.rs index 456a9bb4..3490e65f 100644 --- a/snark-verifier-sdk/src/evm.rs +++ b/snark-verifier-sdk/src/evm.rs @@ -3,11 +3,10 @@ use super::{CircuitExt, Plonk}; use ark_std::{end_timer, start_timer}; use ethereum_types::Address; use halo2_base::halo2_proofs::{ - dev::MockProver, halo2curves::bn256::{Bn256, Fq, Fr, G1Affine}, plonk::{create_proof, verify_proof, Circuit, ProvingKey, VerifyingKey}, poly::{ - commitment::{Params, ParamsProver, Prover, Verifier}, + commitment::{ParamsProver, Prover, Verifier}, kzg::{ commitment::{KZGCommitmentScheme, ParamsKZG}, msm::DualMSM, @@ -19,7 +18,7 @@ use halo2_base::halo2_proofs::{ transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, }; use itertools::Itertools; -use rand::Rng; +use rand::{rngs::StdRng, SeedableRng}; pub use snark_verifier::loader::evm::encode_calldata; use snark_verifier::{ loader::evm::{compile_yul, EvmLoader, ExecutorBuilder}, @@ -38,7 +37,6 @@ pub fn gen_evm_proof<'params, C, P, V>( pk: &'params ProvingKey, circuit: C, instances: Vec>, - rng: &mut (impl Rng + Send), ) -> Vec where C: Circuit, @@ -50,15 +48,11 @@ where MSMAccumulator = DualMSM<'params, Bn256>, >, { - #[cfg(debug_assertions)] - { - MockProver::run(params.k(), &circuit, instances.clone()).unwrap().assert_satisfied(); - } - let instances = instances.iter().map(|instances| instances.as_slice()).collect_vec(); #[cfg(feature = "display")] let proof_time = start_timer!(|| "Create EVM proof"); + let rng = StdRng::from_entropy(); let proof = { let mut transcript = TranscriptWriterBuffer::<_, G1Affine, _>::init(Vec::new()); create_proof::, P, _, _, EvmTranscript<_, _, _, _>, _>( @@ -98,9 +92,8 @@ pub fn gen_evm_proof_gwc<'params, C: Circuit>( pk: &'params ProvingKey, circuit: C, instances: Vec>, - rng: &mut (impl Rng + Send), ) -> Vec { - gen_evm_proof::, VerifierGWC<_>>(params, pk, circuit, instances, rng) + gen_evm_proof::, VerifierGWC<_>>(params, pk, circuit, instances) } pub fn gen_evm_proof_shplonk<'params, C: Circuit>( @@ -108,9 +101,8 @@ pub fn gen_evm_proof_shplonk<'params, C: Circuit>( pk: &'params ProvingKey, circuit: C, instances: Vec>, - rng: &mut (impl Rng + Send), ) -> Vec { - gen_evm_proof::, VerifierSHPLONK<_>>(params, pk, circuit, instances, rng) + gen_evm_proof::, VerifierSHPLONK<_>>(params, pk, circuit, instances) } pub fn gen_evm_verifier( diff --git a/snark-verifier-sdk/src/halo2.rs b/snark-verifier-sdk/src/halo2.rs index a4526911..826567f8 100644 --- a/snark-verifier-sdk/src/halo2.rs +++ b/snark-verifier-sdk/src/halo2.rs @@ -1,10 +1,9 @@ -use super::{read_instances, write_instances, CircuitExt, Snark, SnarkWitness}; +use super::{read_instances, write_instances, CircuitExt, Plonk, Snark}; #[cfg(feature = "display")] use ark_std::{end_timer, start_timer}; use halo2_base::halo2_proofs; use halo2_proofs::{ circuit::Layouter, - dev::MockProver, halo2curves::{ bn256::{Bn256, Fr, G1Affine}, group::ff::Field, @@ -14,7 +13,7 @@ use halo2_proofs::{ VerifyingKey, }, poly::{ - commitment::{Params, ParamsProver, Prover, Verifier}, + commitment::{ParamsProver, Prover, Verifier}, kzg::{ commitment::{KZGCommitmentScheme, ParamsKZG}, msm::DualMSM, @@ -26,7 +25,7 @@ use halo2_proofs::{ }; use itertools::Itertools; use lazy_static::lazy_static; -use rand::Rng; +use rand::{rngs::StdRng, SeedableRng}; use snark_verifier::{ cost::CostEstimation, loader::native::NativeLoader, @@ -74,7 +73,6 @@ pub fn gen_proof<'params, C, P, V>( pk: &ProvingKey, circuit: C, instances: Vec>, - rng: &mut (impl Rng + Send), path: Option<(&Path, &Path)>, ) -> Vec where @@ -87,11 +85,6 @@ where MSMAccumulator = DualMSM<'params, Bn256>, >, { - #[cfg(debug_assertions)] - { - MockProver::run(params.k(), &circuit, instances.clone()).unwrap().assert_satisfied(); - } - if let Some((instance_path, proof_path)) = path { let cached_instances = read_instances(instance_path); if matches!(cached_instances, Ok(tmp) if tmp == instances) && proof_path.exists() { @@ -113,6 +106,7 @@ where let mut transcript = PoseidonTranscript::>::from_spec(vec![], POSEIDON_SPEC.clone()); + let rng = StdRng::from_entropy(); create_proof::<_, P, _, _, _, _>(params, pk, &[circuit], &[&instances], rng, &mut transcript) .unwrap(); let proof = transcript.finalize(); @@ -150,10 +144,9 @@ pub fn gen_proof_gwc>( pk: &ProvingKey, circuit: C, instances: Vec>, - rng: &mut (impl Rng + Send), path: Option<(&Path, &Path)>, ) -> Vec { - gen_proof::, VerifierGWC<_>>(params, pk, circuit, instances, rng, path) + gen_proof::, VerifierGWC<_>>(params, pk, circuit, instances, path) } /// Generates a native proof using SHPLONK multi-open scheme. Uses Poseidon for Fiat-Shamir. @@ -164,10 +157,9 @@ pub fn gen_proof_shplonk>( pk: &ProvingKey, circuit: C, instances: Vec>, - rng: &mut (impl Rng + Send), path: Option<(&Path, &Path)>, ) -> Vec { - gen_proof::, VerifierSHPLONK<_>>(params, pk, circuit, instances, rng, path) + gen_proof::, VerifierSHPLONK<_>>(params, pk, circuit, instances, path) } /// Generates a SNARK using either SHPLONK or GWC multi-open scheme. Uses Poseidon for Fiat-Shamir. @@ -178,7 +170,6 @@ pub fn gen_snark<'params, ConcreteCircuit, P, V>( params: &'params ParamsKZG, pk: &ProvingKey, circuit: ConcreteCircuit, - rng: &mut (impl Rng + Send), path: Option>, ) -> Snark where @@ -192,9 +183,12 @@ where >, { if let Some(path) = &path { + #[cfg(feature = "halo2-axiom")] if let Ok(snark) = read_snark(path) { return snark; } + #[cfg(not(feature = "halo2-axiom"))] + unimplemented!("Reading SNARKs is not supported in halo2-pse because we cannot derive Serialize/Deserialize for halo2curves field elements."); } let protocol = compile( params, @@ -205,10 +199,10 @@ where ); let instances = circuit.instances(); - let proof = - gen_proof::(params, pk, circuit, instances.clone(), rng, None); + let proof = gen_proof::(params, pk, circuit, instances.clone(), None); let snark = Snark::new(protocol, instances, proof); + #[cfg(feature = "halo2-axiom")] if let Some(path) = &path { let f = File::create(path).unwrap(); #[cfg(feature = "display")] @@ -228,10 +222,9 @@ pub fn gen_snark_gwc>( params: &ParamsKZG, pk: &ProvingKey, circuit: ConcreteCircuit, - rng: &mut (impl Rng + Send), path: Option>, ) -> Snark { - gen_snark::, VerifierGWC<_>>(params, pk, circuit, rng, path) + gen_snark::, VerifierGWC<_>>(params, pk, circuit, path) } /// Generates a SNARK using SHPLONK multi-open scheme. Uses Poseidon for Fiat-Shamir. @@ -242,17 +235,15 @@ pub fn gen_snark_shplonk>( params: &ParamsKZG, pk: &ProvingKey, circuit: ConcreteCircuit, - rng: &mut (impl Rng + Send), path: Option>, ) -> Snark { - gen_snark::, VerifierSHPLONK<_>>( - params, pk, circuit, rng, path, - ) + gen_snark::, VerifierSHPLONK<_>>(params, pk, circuit, path) } /// Tries to deserialize a SNARK from the specified `path` using `bincode`. /// /// WARNING: The user must keep track of whether the SNARK was generated using the GWC or SHPLONK multi-open scheme. +#[cfg(feature = "halo2-axiom")] pub fn read_snark(path: impl AsRef) -> Result { let f = File::open(path).map_err(Box::::from)?; bincode::deserialize_from(f) diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 4748c930..38abdd74 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -1,70 +1,56 @@ #![allow(clippy::clone_on_copy)] -use crate::{Plonk, BITS, LIMBS}; -#[cfg(feature = "display")] -use ark_std::{end_timer, start_timer}; +use super::Plonk; +use crate::{BITS, LIMBS}; use halo2_base::{ + gates::{ + builder::{ + assign_threads_in, CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, + MultiPhaseThreadBreakPoints, RangeCircuitBuilder, + }, + range::RangeConfig, + RangeChip, + }, halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - halo2curves::bn256::{Bn256, Fq, Fr, G1Affine}, + circuit::{Layouter, SimpleFloorPlanner}, + halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::{self, Circuit, Column, ConstraintSystem, Instance, Selector}, - poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG}, + poly::{ + commitment::{Params, ParamsProver}, + kzg::commitment::ParamsKZG, + }, }, - utils::value_to_option, - AssignedValue, + utils::ScalarField, + AssignedValue, SKIP_FIRST_PASS, }; -use halo2_base::{Context, ContextParams}; use itertools::Itertools; -use rand::Rng; +use rand::{rngs::StdRng, SeedableRng}; +use serde::{Deserialize, Serialize}; use snark_verifier::{ loader::{ self, - halo2::{ - halo2_ecc::{self, ecc::EccChip}, - EccInstructions, - }, + halo2::halo2_ecc::{self, bn254::FpChip}, native::NativeLoader, }, pcs::{ - kzg::{Bdfg21, Kzg, KzgAccumulator, KzgAs, KzgSuccinctVerifyingKey}, + kzg::{KzgAccumulator, KzgAs, KzgSuccinctVerifyingKey}, AccumulationScheme, AccumulationSchemeProver, MultiOpenScheme, PolynomialCommitmentScheme, }, util::arithmetic::fe_to_limbs, verifier::PlonkVerifier, }; -use std::{fs::File, rc::Rc}; +use std::{collections::HashMap, env::set_var, fs::File, path::Path, rc::Rc}; -use super::{CircuitExt, PoseidonTranscript, Snark, SnarkWitness, POSEIDON_SPEC}; +use super::{CircuitExt, PoseidonTranscript, Snark, POSEIDON_SPEC}; pub type Svk = KzgSuccinctVerifyingKey; -pub type BaseFieldEccChip = halo2_ecc::ecc::BaseFieldEccChip; -pub type Halo2Loader<'a> = loader::halo2::Halo2Loader<'a, G1Affine, BaseFieldEccChip>; -pub type Shplonk = Plonk>; - -pub fn load_verify_circuit_degree() -> u32 { - let path = std::env::var("VERIFY_CONFIG") - .unwrap_or_else(|_| "./configs/verify_circuit.config".to_string()); - let params: AggregationConfigParams = serde_json::from_reader( - File::open(path.as_str()).unwrap_or_else(|_| panic!("{path} does not exist")), - ) - .unwrap(); - params.degree -} - -pub fn flatten_accumulator<'b, 'a: 'b>( - accumulator: KzgAccumulator>>, -) -> Vec> { - let KzgAccumulator { lhs, rhs } = accumulator; - let lhs = lhs.into_assigned(); - let rhs = rhs.into_assigned(); - - lhs.x - .truncation - .limbs - .into_iter() - .chain(lhs.y.truncation.limbs.into_iter()) - .chain(rhs.x.truncation.limbs.into_iter()) - .chain(rhs.y.truncation.limbs.into_iter()) - .collect() +pub type BaseFieldEccChip<'chip> = halo2_ecc::ecc::BaseFieldEccChip<'chip, G1Affine>; +pub type Halo2Loader<'chip> = loader::halo2::Halo2Loader>; + +// It is hard to get all the traits to work with Shplonk and PlonkGwc so we'll just use an enum +#[derive(Clone, Copy, Debug, Serialize, Deserialize, Eq, PartialEq)] +pub enum KZGMultiOpenScheme { + SHPLONK, + GWC, } #[allow(clippy::type_complexity)] @@ -73,23 +59,20 @@ pub fn flatten_accumulator<'b, 'a: 'b>( /// Returns the assigned instances of previous snarks and the new final pair that needs to be verified in a pairing check. /// For each previous snark, we concatenate all instances into a single vector. We return a vector of vectors, /// one vector per snark, for convenience. -pub fn aggregate<'a, PCS>( - svk: &PCS::SuccinctVerifyingKey, +pub fn aggregate<'a, MOS>( + svk: &MOS::SuccinctVerifyingKey, loader: &Rc>, - snarks: &[SnarkWitness], - as_proof: Value<&'_ [u8]>, -) -> ( - Vec>::AssignedScalar>>, - KzgAccumulator>>, -) + snarks: &[Snark], + as_proof: &[u8], +) -> (Vec>>, KzgAccumulator>>) where - PCS: PolynomialCommitmentScheme< + MOS: PolynomialCommitmentScheme< G1Affine, Rc>, Accumulator = KzgAccumulator>>, > + MultiOpenScheme>>, { - let assign_instances = |instances: &[Vec>]| { + let assign_instances = |instances: &[Vec]| { instances .iter() .map(|instances| { @@ -98,11 +81,11 @@ where .collect_vec() }; - // TODO pre-allocate capacity better let mut previous_instances = Vec::with_capacity(snarks.len()); - let mut transcript = PoseidonTranscript::>, _>::from_spec( + // to avoid re-loading the spec each time, we create one transcript and clear the stream + let mut transcript = PoseidonTranscript::>, &[u8]>::from_spec( loader, - Value::unknown(), + &[], POSEIDON_SPEC.clone(), ); @@ -110,14 +93,13 @@ where .iter() .flat_map(|snark| { let protocol = snark.protocol.loaded(loader); - // TODO use 1d vector let instances = assign_instances(&snark.instances); // read the transcript and perform Fiat-Shamir // run through verification computation and produce the final pair `succinct` transcript.new_stream(snark.proof()); - let proof = Plonk::::read_proof(svk, &protocol, &instances, &mut transcript); - let accumulator = Plonk::::succinct_verify(svk, &protocol, &instances, &proof); + let proof = Plonk::::read_proof(svk, &protocol, &instances, &mut transcript); + let accumulator = Plonk::::succinct_verify(svk, &protocol, &instances, &proof); previous_instances.push( instances.into_iter().flatten().map(|scalar| scalar.into_assigned()).collect(), @@ -130,8 +112,8 @@ where let accumulator = if accumulators.len() > 1 { transcript.new_stream(as_proof); let proof = - KzgAs::::read_proof(&Default::default(), &accumulators, &mut transcript).unwrap(); - KzgAs::::verify(&Default::default(), &accumulators, &proof).unwrap() + KzgAs::::read_proof(&Default::default(), &accumulators, &mut transcript).unwrap(); + KzgAs::::verify(&Default::default(), &accumulators, &proof).unwrap() } else { accumulators.pop().unwrap() }; @@ -141,107 +123,141 @@ where #[derive(serde::Serialize, serde::Deserialize)] pub struct AggregationConfigParams { - pub strategy: halo2_ecc::fields::fp::FpStrategy, pub degree: u32, - pub num_advice: Vec, - pub num_lookup_advice: Vec, + pub num_advice: usize, + pub num_lookup_advice: usize, pub num_fixed: usize, pub lookup_bits: usize, - pub limb_bits: usize, - pub num_limbs: usize, +} + +impl AggregationConfigParams { + pub fn from_path(path: impl AsRef) -> Self { + serde_json::from_reader(File::open(path).expect("Aggregation config path does not exist")) + .unwrap() + } } #[derive(Clone, Debug)] -pub struct AggregationConfig { - pub base_field_config: halo2_ecc::fields::fp::FpConfig, +pub struct RangeWithInstanceConfig { + pub range: RangeConfig, pub instance: Column, } -impl AggregationConfig { - pub fn configure(meta: &mut ConstraintSystem, params: AggregationConfigParams) -> Self { - assert!( - params.limb_bits == BITS && params.num_limbs == LIMBS, - "For now we fix limb_bits = {}, otherwise change code", - BITS - ); - let base_field_config = halo2_ecc::fields::fp::FpConfig::configure( - meta, - params.strategy, - ¶ms.num_advice, - ¶ms.num_lookup_advice, - params.num_fixed, - params.lookup_bits, - BITS, - LIMBS, - halo2_base::utils::modulus::(), - 0, - params.degree as usize, - ); +/// This is an extension of [`RangeCircuitBuilder`] that adds support for public instances (aka public inputs+outputs) +/// +/// The intended design is that a [`GateThreadBuilder`] is populated and then produces some assigned instances, which are supplied as `assigned_instances` to this struct. +/// The [`Circuit`] implementation for this struct will then expose these instances and constrain them using the Halo2 API. +#[derive(Clone, Debug)] +pub struct RangeWithInstanceCircuitBuilder { + pub circuit: RangeCircuitBuilder, + pub assigned_instances: Vec>, +} - let instance = meta.instance_column(); - meta.enable_equality(instance); +impl RangeWithInstanceCircuitBuilder { + pub fn keygen( + builder: GateThreadBuilder, + assigned_instances: Vec>, + ) -> Self { + Self { circuit: RangeCircuitBuilder::keygen(builder), assigned_instances } + } + + pub fn mock(builder: GateThreadBuilder, assigned_instances: Vec>) -> Self { + Self { circuit: RangeCircuitBuilder::mock(builder), assigned_instances } + } + + pub fn prover( + builder: GateThreadBuilder, + assigned_instances: Vec>, + break_points: MultiPhaseThreadBreakPoints, + ) -> Self { + Self { circuit: RangeCircuitBuilder::prover(builder, break_points), assigned_instances } + } - Self { base_field_config, instance } + pub fn new(circuit: RangeCircuitBuilder, assigned_instances: Vec>) -> Self { + Self { circuit, assigned_instances } } - pub fn range(&self) -> &halo2_base::gates::range::RangeConfig { - &self.base_field_config.range + pub fn config(&self, k: u32, minimum_rows: Option) -> FlexGateConfigParams { + self.circuit.0.builder.borrow().config(k as usize, minimum_rows) } - pub fn gate(&self) -> &halo2_base::gates::flex_gate::FlexGateConfig { - &self.base_field_config.range.gate + pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { + self.circuit.0.break_points.borrow().clone() } - pub fn ecc_chip(&self) -> halo2_ecc::ecc::BaseFieldEccChip { - EccChip::construct(self.base_field_config.clone()) + pub fn instance_count(&self) -> usize { + self.assigned_instances.len() + } + + pub fn instance(&self) -> Vec { + self.assigned_instances.iter().map(|v| *v.value()).collect() } } -/// Aggregation circuit that does not re-expose any public inputs from aggregated snarks -/// -/// This is mostly a reference implementation. In practice one will probably need to re-implement the circuit for one's particular use case with specific instance logic. -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct AggregationCircuit { - svk: Svk, - snarks: Vec, - instances: Vec, - as_proof: Value>, + pub inner: RangeWithInstanceCircuitBuilder, + // the public instances from previous snarks that were aggregated, now collected as PRIVATE assigned values + // the user can optionally append these to `inner.assigned_instances` to expose them + pub previous_instances: Vec>>, + // accumulation scheme proof, private input + pub as_proof: Vec, // not sure this needs to be stored, keeping for now } impl AggregationCircuit { - pub fn new( + /// Given snarks, this creates a circuit and runs the `GateThreadBuilder` to verify all the snarks. + /// By default, the returned circuit has public instances equal to the limbs of the pair of elliptic curve points, referred to as the `accumulator`, that need to be verified in a final pairing check. + /// + /// The user can optionally modify the circuit after calling this function to add more instances to `assigned_instances` to expose. + /// + /// Warning: will fail silently if `snarks` were created using a different multi-open scheme than `MOS` + /// where `MOS` can be either [`crate::SHPLONK`] or [`crate::GWC`] (for original PLONK multi-open scheme) + pub fn new( + stage: CircuitBuilderStage, + break_points: Option, + lookup_bits: usize, params: &ParamsKZG, snarks: impl IntoIterator, - rng: impl Rng + Send, - ) -> Self { - let svk = params.get_g()[0].into(); + ) -> Self + where + for<'a> MOS: PolynomialCommitmentScheme< + G1Affine, + Rc>, + Accumulator = KzgAccumulator>>, + > + MultiOpenScheme>, SuccinctVerifyingKey = Svk> + + PolynomialCommitmentScheme< + G1Affine, + NativeLoader, + Accumulator = KzgAccumulator, + > + MultiOpenScheme, + { + let svk: Svk = params.get_g()[0].into(); let snarks = snarks.into_iter().collect_vec(); - // TODO: this is all redundant calculation to get the public output - // Halo2 should just be able to expose public output to instance column directly let mut transcript_read = PoseidonTranscript::::from_spec(&[], POSEIDON_SPEC.clone()); + // TODO: the snarks can probably store these accumulators let accumulators = snarks .iter() .flat_map(|snark| { - transcript_read.new_stream(snark.proof.as_slice()); - let proof = Shplonk::read_proof( + transcript_read.new_stream(snark.proof()); + let proof = Plonk::::read_proof( &svk, &snark.protocol, &snark.instances, &mut transcript_read, ); - Shplonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof) + Plonk::::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof) }) .collect_vec(); - let (accumulator, as_proof) = { + let (_accumulator, as_proof) = { let mut transcript_write = PoseidonTranscript::>::from_spec( vec![], POSEIDON_SPEC.clone(), ); - // We always use SHPLONK for accumulation scheme when aggregating proofs - let accumulator = KzgAs::>::create_proof( + let rng = StdRng::from_entropy(); + let accumulator = KzgAs::::create_proof( &Default::default(), &accumulators, &mut transcript_write, @@ -251,269 +267,286 @@ impl AggregationCircuit { (accumulator, transcript_write.finalize()) }; - let KzgAccumulator { lhs, rhs } = accumulator; - let instances = [lhs.x, lhs.y, rhs.x, rhs.y].map(fe_to_limbs::<_, _, LIMBS, BITS>).concat(); + // create thread builder and run aggregation witness gen + let builder = match stage { + CircuitBuilderStage::Mock => GateThreadBuilder::mock(), + CircuitBuilderStage::Prover => GateThreadBuilder::prover(), + CircuitBuilderStage::Keygen => GateThreadBuilder::keygen(), + }; + // create halo2loader + let range = RangeChip::::default(lookup_bits); + let fp_chip = FpChip::::new(&range, BITS, LIMBS); + let ecc_chip = BaseFieldEccChip::new(&fp_chip); + let loader = Halo2Loader::new(ecc_chip, builder); + + let (previous_instances, accumulator) = + aggregate::(&svk, &loader, &snarks, as_proof.as_slice()); + let lhs = accumulator.lhs.assigned(); + let rhs = accumulator.rhs.assigned(); + let assigned_instances = lhs + .x + .truncation + .limbs + .iter() + .chain(lhs.y.truncation.limbs.iter()) + .chain(rhs.x.truncation.limbs.iter()) + .chain(rhs.y.truncation.limbs.iter()) + .copied() + .collect_vec(); - Self { - svk, - snarks: snarks.into_iter().map_into().collect(), - instances, - as_proof: Value::known(as_proof), + #[cfg(debug_assertions)] + { + let KzgAccumulator { lhs, rhs } = _accumulator; + let instances = + [lhs.x, lhs.y, rhs.x, rhs.y].map(fe_to_limbs::<_, Fr, LIMBS, BITS>).concat(); + for (lhs, rhs) in instances.iter().zip(assigned_instances.iter()) { + assert_eq!(lhs, rhs.value()); + } } + + let builder = loader.take_ctx(); + let circuit = match stage { + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, break_points.unwrap()) + } + }; + let inner = RangeWithInstanceCircuitBuilder::new(circuit, assigned_instances); + Self { inner, previous_instances, as_proof } } - pub fn instance(&self) -> Vec { - self.instances.clone() + pub fn public( + stage: CircuitBuilderStage, + break_points: Option, + lookup_bits: usize, + params: &ParamsKZG, + snarks: impl IntoIterator, + has_prev_accumulator: bool, + ) -> Self + where + for<'a> MOS: PolynomialCommitmentScheme< + G1Affine, + Rc>, + Accumulator = KzgAccumulator>>, + > + MultiOpenScheme>, SuccinctVerifyingKey = Svk> + + PolynomialCommitmentScheme< + G1Affine, + NativeLoader, + Accumulator = KzgAccumulator, + > + MultiOpenScheme, + { + let mut private = Self::new::(stage, break_points, lookup_bits, params, snarks); + private.expose_previous_instances(has_prev_accumulator); + private } - pub fn succinct_verifying_key(&self) -> &Svk { - &self.svk + // this function is for convenience + pub fn keygen(params: &ParamsKZG, snarks: impl IntoIterator) -> Self + where + for<'a> MOS: PolynomialCommitmentScheme< + G1Affine, + Rc>, + Accumulator = KzgAccumulator>>, + > + MultiOpenScheme>, SuccinctVerifyingKey = Svk> + + PolynomialCommitmentScheme< + G1Affine, + NativeLoader, + Accumulator = KzgAccumulator, + > + MultiOpenScheme, + { + let lookup_bits = params.k() as usize - 1; // almost always we just use the max lookup bits possible, which is k - 1 because of blinding factors + let circuit = + Self::new::(CircuitBuilderStage::Keygen, None, lookup_bits, params, snarks); + circuit.config(params.k(), Some(10)); + set_var("LOOKUP_BITS", lookup_bits.to_string()); + circuit } - pub fn snarks(&self) -> &[SnarkWitness] { - &self.snarks + /// Re-expose the previous public instances of aggregated snarks again. + /// If `hash_prev_accumulator` is true, then we assume all aggregated snarks were themselves + /// aggregation snarks, and we exclude the old accumulators from the public input. + pub fn expose_previous_instances(&mut self, has_prev_accumulator: bool) { + let start = (has_prev_accumulator as usize) * 4 * LIMBS; + for prev in self.previous_instances.iter() { + self.inner.assigned_instances.extend_from_slice(&prev[start..]); + } } - pub fn as_proof(&self) -> Value<&[u8]> { - self.as_proof.as_ref().map(Vec::as_slice) + pub fn as_proof(&self) -> &[u8] { + &self.as_proof[..] } -} -impl CircuitExt for AggregationCircuit { - fn num_instance(&self) -> Vec { - // [..lhs, ..rhs] - vec![4 * LIMBS] + pub fn config(&self, k: u32, minimum_rows: Option) -> FlexGateConfigParams { + self.inner.config(k, minimum_rows) } - fn instances(&self) -> Vec> { - vec![self.instance()] + pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { + self.inner.break_points() } - fn accumulator_indices() -> Option> { - Some((0..4 * LIMBS).map(|idx| (0, idx)).collect()) + pub fn instance_count(&self) -> usize { + self.inner.instance_count() } - fn selectors(config: &Self::Config) -> Vec { - config.gate().basic_gates[0].iter().map(|gate| gate.q_enable).collect() + pub fn instance(&self) -> Vec { + self.inner.instance() } } -impl Circuit for AggregationCircuit { - type Config = AggregationConfig; +impl Circuit for RangeWithInstanceCircuitBuilder { + type Config = RangeWithInstanceConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - Self { - svk: self.svk, - snarks: self.snarks.iter().map(SnarkWitness::without_witnesses).collect(), - instances: Vec::new(), - as_proof: Value::unknown(), - } + unimplemented!() } - fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - let path = std::env::var("VERIFY_CONFIG") - .unwrap_or_else(|_| "configs/verify_circuit.config".to_owned()); - let params: AggregationConfigParams = serde_json::from_reader( - File::open(path.as_str()).unwrap_or_else(|_| panic!("{path:?} does not exist")), - ) - .unwrap(); - - AggregationConfig::configure(meta, params) + fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { + let range = RangeCircuitBuilder::configure(meta); + let instance = meta.instance_column(); + meta.enable_equality(instance); + RangeWithInstanceConfig { range, instance } } fn synthesize( &self, config: Self::Config, - mut layouter: impl Layouter, + mut layouter: impl Layouter, ) -> Result<(), plonk::Error> { - #[cfg(feature = "display")] - let witness_time = start_timer!(|| "synthesize | Aggregation Circuit"); - config.range().load_lookup_table(&mut layouter).expect("load range lookup table"); - let mut first_pass = halo2_base::SKIP_FIRST_PASS; - let mut instances = vec![]; + // copied from RangeCircuitBuilder::synthesize but with extra logic to expose public instances + let range = config.range; + let circuit = &self.circuit.0; + range.load_lookup_table(&mut layouter).expect("load lookup table should not fail"); + + // we later `take` the builder, so we need to save this value + let witness_gen_only = circuit.builder.borrow().witness_gen_only(); + let mut assigned_advices = HashMap::new(); + + let mut first_pass = SKIP_FIRST_PASS; layouter .assign_region( - || "", - |region| { + || "RangeWithInstanceCircuitBuilder", + |mut region| { if first_pass { first_pass = false; return Ok(()); } - let ctx = Context::new( - region, - ContextParams { - max_rows: config.gate().max_rows, - num_context_ids: 1, - fixed_columns: config.gate().constants.clone(), - }, - ); - - let ecc_chip = config.ecc_chip(); - let loader = Halo2Loader::new(ecc_chip, ctx); - let (_, acc) = aggregate::>( - &self.svk, - &loader, - &self.snarks, - self.as_proof(), - ); - - instances.extend( - flatten_accumulator(acc).iter().map(|assigned| assigned.cell().clone()), - ); - - config.range().finalize(&mut loader.ctx_mut()); - #[cfg(feature = "display")] - loader.ctx_mut().print_stats(&["Range"]); + // only support FirstPhase in this Builder because getting challenge value requires more specialized witness generation during synthesize + if !witness_gen_only { + // clone the builder so we can re-use the circuit for both vk and pk gen + let builder = circuit.builder.borrow(); + let assignments = builder.assign_all( + &range.gate, + &range.lookup_advice, + &range.q_lookup, + &mut region, + ); + *circuit.break_points.borrow_mut() = assignments.break_points; + assigned_advices = assignments.assigned_advices; + } else { + #[cfg(feature = "display")] + let start0 = std::time::Instant::now(); + let builder = circuit.builder.take(); + let break_points = circuit.break_points.take(); + for (phase, (threads, break_points)) in builder + .threads + .into_iter() + .zip(break_points.into_iter()) + .enumerate() + .take(1) + { + assign_threads_in( + phase, + threads, + &range.gate, + &range.lookup_advice[phase], + &mut region, + break_points, + ); + } + #[cfg(feature = "display")] + println!("assign threads in {:?}", start0.elapsed()); + } Ok(()) }, ) .unwrap(); - // Expose instances - for (i, cell) in instances.into_iter().enumerate() { - layouter.constrain_instance(cell, config.instance, i); + if !witness_gen_only { + // expose public instances + let mut layouter = layouter.namespace(|| "expose"); + for (i, instance) in self.assigned_instances.iter().enumerate() { + let cell = instance.cell.unwrap(); + let (cell, _) = assigned_advices + .get(&(cell.context_id, cell.offset)) + .expect("instance not assigned"); + layouter.constrain_instance(*cell, config.instance, i); + } } - #[cfg(feature = "display")] - end_timer!(witness_time); Ok(()) } } -/// This circuit takes multiple SNARKs and passes through all of their instances except the old accumulators. -/// -/// * If `has_prev_accumulator = true`, we assume all SNARKs are of aggregation circuits with old accumulators -/// only in the first instance column. -/// * Otherwise if `has_prev_accumulator = false`, then all previous instances are passed through. -#[derive(Clone)] -pub struct PublicAggregationCircuit { - pub aggregation: AggregationCircuit, - pub has_prev_accumulator: bool, -} - -impl PublicAggregationCircuit { - pub fn new( - params: &ParamsKZG, - snarks: Vec, - has_prev_accumulator: bool, - rng: &mut (impl Rng + Send), - ) -> Self { - Self { aggregation: AggregationCircuit::new(params, snarks, rng), has_prev_accumulator } - } -} - -impl CircuitExt for PublicAggregationCircuit { +impl CircuitExt for RangeWithInstanceCircuitBuilder { fn num_instance(&self) -> Vec { - let prev_num = self - .aggregation - .snarks - .iter() - .map(|snark| snark.instances.iter().map(|instance| instance.len()).sum::()) - .sum::() - - self.aggregation.snarks.len() * 4 * LIMBS * usize::from(self.has_prev_accumulator); - vec![4 * LIMBS + prev_num] - } - - fn instances(&self) -> Vec> { - let start_idx = 4 * LIMBS * usize::from(self.has_prev_accumulator); - let instance = self - .aggregation - .instances - .iter() - .cloned() - .chain(self.aggregation.snarks.iter().flat_map(|snark| { - snark.instances.iter().enumerate().flat_map(|(i, instance)| { - instance[usize::from(i == 0) * start_idx..] - .iter() - .map(|v| value_to_option(*v).unwrap()) - }) - })) - .collect_vec(); - vec![instance] + vec![self.instance_count()] } - fn accumulator_indices() -> Option> { - Some((0..4 * LIMBS).map(|idx| (0, idx)).collect()) + fn instances(&self) -> Vec> { + vec![self.instance()] } fn selectors(config: &Self::Config) -> Vec { - AggregationCircuit::selectors(config) + config.range.gate.basic_gates[0].iter().map(|gate| gate.q_enable).collect() } } -impl Circuit for PublicAggregationCircuit { - type Config = AggregationConfig; +impl Circuit for AggregationCircuit { + type Config = RangeWithInstanceConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - Self { - aggregation: self.aggregation.without_witnesses(), - has_prev_accumulator: self.has_prev_accumulator, - } + unimplemented!() } - fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - AggregationCircuit::configure(meta) + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + RangeWithInstanceCircuitBuilder::configure(meta) } fn synthesize( &self, config: Self::Config, - mut layouter: impl Layouter, + layouter: impl Layouter, ) -> Result<(), plonk::Error> { - #[cfg(feature = "display")] - let witness_time = start_timer!(|| { "synthesize | EVM verifier" }); - config.range().load_lookup_table(&mut layouter).expect("load range lookup table"); - let mut first_pass = halo2_base::SKIP_FIRST_PASS; - let mut instances = vec![]; - layouter - .assign_region( - || "", - |region| { - if first_pass { - first_pass = false; - return Ok(()); - } - let ctx = Context::new( - region, - ContextParams { - max_rows: config.gate().max_rows, - num_context_ids: 1, - fixed_columns: config.gate().constants.clone(), - }, - ); - - let ecc_chip = config.ecc_chip(); - let loader = Halo2Loader::new(ecc_chip, ctx); - let (prev_instances, acc) = aggregate::>( - &self.aggregation.svk, - &loader, - &self.aggregation.snarks, - self.aggregation.as_proof(), - ); - - // accumulator - instances.extend(flatten_accumulator(acc).iter().map(|a| a.cell().clone())); - // prev instances except accumulators - let start_idx = 4 * LIMBS * usize::from(self.has_prev_accumulator); - for prev_instance in prev_instances { - instances - .extend(prev_instance[start_idx..].iter().map(|a| a.cell().clone())); - } + self.inner.synthesize(config, layouter) + } +} - config.range().finalize(&mut loader.ctx_mut()); - #[cfg(feature = "display")] - loader.ctx_mut().print_stats(&["Range"]); - Ok(()) - }, - ) - .unwrap(); - // Expose instances - for (i, cell) in instances.into_iter().enumerate() { - layouter.constrain_instance(cell, config.instance, i); - } - #[cfg(feature = "display")] - end_timer!(witness_time); - Ok(()) +impl CircuitExt for AggregationCircuit { + fn num_instance(&self) -> Vec { + self.inner.num_instance() + } + + fn instances(&self) -> Vec> { + self.inner.instances() } + + fn accumulator_indices() -> Option> { + Some((0..4 * LIMBS).map(|idx| (0, idx)).collect()) + } + + fn selectors(config: &Self::Config) -> Vec { + RangeWithInstanceCircuitBuilder::selectors(config) + } +} + +pub fn load_verify_circuit_degree() -> u32 { + let path = std::env::var("VERIFY_CONFIG") + .unwrap_or_else(|_| "./configs/verify_circuit.config".to_string()); + let params: AggregationConfigParams = serde_json::from_reader( + File::open(path.as_str()).unwrap_or_else(|_| panic!("{path} does not exist")), + ) + .unwrap(); + params.degree } diff --git a/snark-verifier-sdk/src/lib.rs b/snark-verifier-sdk/src/lib.rs index c2342866..e53cdcc9 100644 --- a/snark-verifier-sdk/src/lib.rs +++ b/snark-verifier-sdk/src/lib.rs @@ -1,9 +1,8 @@ #![feature(associated_type_defaults)] #[cfg(feature = "display")] use ark_std::{end_timer, start_timer}; -use halo2_base::halo2_proofs; +use halo2_base::halo2_proofs::{self}; use halo2_proofs::{ - circuit::Value, halo2curves::{ bn256::{Bn256, Fr, G1Affine}, group::ff::Field, @@ -15,7 +14,10 @@ use halo2_proofs::{ use itertools::Itertools; use serde::{Deserialize, Serialize}; pub use snark_verifier::loader::native::NativeLoader; -use snark_verifier::{pcs::kzg::LimbsEncoding, verifier, Protocol}; +use snark_verifier::{ + pcs::kzg::{Bdfg21, Gwc19, Kzg, LimbsEncoding}, + verifier, Protocol, +}; use std::{ fs::{self, File}, io::{self, BufReader, BufWriter}, @@ -30,10 +32,14 @@ pub mod halo2; pub const LIMBS: usize = 3; pub const BITS: usize = 88; -/// PCS be either `Kzg` or `Kzg` -pub type Plonk = verifier::Plonk>; +/// MOS stands for multi-open scheme. +/// MOS can be either `Kzg` (the original PLONK KZG multi-open) or `Kzg` (SHPLONK) +pub type Plonk = verifier::Plonk>; +pub type SHPLONK = Kzg; +pub type GWC = Kzg; -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug)] +#[cfg_attr(feature = "halo2-axiom", derive(Serialize, Deserialize))] pub struct Snark { pub protocol: Protocol, pub instances: Vec>, @@ -44,44 +50,9 @@ impl Snark { pub fn new(protocol: Protocol, instances: Vec>, proof: Vec) -> Self { Self { protocol, instances, proof } } -} - -impl From for SnarkWitness { - fn from(snark: Snark) -> Self { - Self { - protocol: snark.protocol, - instances: snark - .instances - .into_iter() - .map(|instances| instances.into_iter().map(Value::known).collect_vec()) - .collect(), - proof: Value::known(snark.proof), - } - } -} - -#[derive(Clone, Debug)] -pub struct SnarkWitness { - pub protocol: Protocol, - pub instances: Vec>>, - pub proof: Value>, -} - -impl SnarkWitness { - pub fn without_witnesses(&self) -> Self { - SnarkWitness { - protocol: self.protocol.clone(), - instances: self - .instances - .iter() - .map(|instances| vec![Value::unknown(); instances.len()]) - .collect(), - proof: Value::unknown(), - } - } - pub fn proof(&self) -> Value<&[u8]> { - self.proof.as_ref().map(Vec::as_slice) + pub fn proof(&self) -> &[u8] { + &self.proof[..] } } diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 97d7c00f..22cd8aa5 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -15,9 +15,9 @@ rustc-hash = "1.1.0" serde = { version = "1.0", features = ["derive"] } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", tag = "v0.2.2", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "upgrade-v0.3.0", default-features = false } # This poseidon is identical to PSE (for now) but uses axiom's halo2curves; otherwise would require patching -poseidon-axiom = { git = "https://github.com/axiom-crypto/halo2.git", branch = "axiom/faster-witness-generation", package = "poseidon", optional = true } +poseidon-axiom = { git = "https://github.com/axiom-crypto/halo2.git", branch = "axiom/dev", package = "poseidon", optional = true } poseidon= { git = "https://github.com/privacy-scaling-explorations/poseidon", optional = true } # parallel @@ -31,7 +31,7 @@ bytes = { version = "1.2", optional = true } rlp = { version = "0.5", default-features = false, features = ["std"], optional = true } # loader_halo2 -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", tag = "v0.2.2", default-features = false, optional = true } +halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "upgrade-v0.3.0", default-features = false, optional = true } [dev-dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } @@ -44,7 +44,7 @@ crossterm = { version = "0.25" } tui = { version = "0.19", default-features = false, features = ["crossterm"] } [features] -default = ["loader_evm", "loader_halo2", "halo2-axiom"] +default = ["loader_evm", "loader_halo2", "halo2-pse", "display"] display = ["halo2-base/display", "halo2-ecc?/display"] loader_evm = ["dep:ethereum-types", "dep:sha3", "dep:revm", "dep:bytes", "dep:rlp"] loader_halo2 = ["halo2-ecc"] diff --git a/snark-verifier/configs/example_evm_accumulator.config b/snark-verifier/configs/example_evm_accumulator.config deleted file mode 100644 index fcda49a0..00000000 --- a/snark-verifier/configs/example_evm_accumulator.config +++ /dev/null @@ -1 +0,0 @@ -{"strategy":"Simple","degree":21,"num_advice":5,"num_lookup_advice":1,"num_fixed":1,"lookup_bits":20,"limb_bits":88,"num_limbs":3} \ No newline at end of file diff --git a/snark-verifier/configs/example_evm_accumulator.json b/snark-verifier/configs/example_evm_accumulator.json new file mode 100644 index 00000000..c7c63783 --- /dev/null +++ b/snark-verifier/configs/example_evm_accumulator.json @@ -0,0 +1,7 @@ +{ + "degree": 21, + "num_advice": 5, + "num_lookup_advice": 1, + "num_fixed": 1, + "lookup_bits": 20 +} diff --git a/snark-verifier/configs/verify_circuit.config b/snark-verifier/configs/verify_circuit.config deleted file mode 100644 index e65b2b52..00000000 --- a/snark-verifier/configs/verify_circuit.config +++ /dev/null @@ -1 +0,0 @@ -{"strategy":"Simple","degree":21,"num_advice":4,"num_lookup_advice":1,"num_fixed":1,"lookup_bits":20,"limb_bits":88,"num_limbs":3} \ No newline at end of file diff --git a/snark-verifier/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs index be936611..bedadf13 100644 --- a/snark-verifier/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -1,11 +1,12 @@ +use aggregation::{AggregationCircuit, AggregationConfigParams}; use ethereum_types::Address; -use halo2_base::halo2_proofs; +use halo2_base::{gates::builder::CircuitBuilderStage, halo2_proofs, utils::fs::gen_srs}; use halo2_proofs::{ dev::MockProver, halo2curves::bn256::{Bn256, Fq, Fr, G1Affine}, plonk::{create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, ProvingKey, VerifyingKey}, poly::{ - commitment::{Params, ParamsProver}, + commitment::ParamsProver, kzg::{ commitment::{KZGCommitmentScheme, ParamsKZG}, multiopen::{ProverGWC, VerifierGWC}, @@ -26,7 +27,7 @@ use snark_verifier::{ system::halo2::{compile, transcript::evm::EvmTranscript, Config}, verifier::{self, PlonkVerifier}, }; -use std::{io::Cursor, rc::Rc}; +use std::{env::set_var, fs::File, io::Cursor, rc::Rc}; const LIMBS: usize = 3; const BITS: usize = 88; @@ -161,18 +162,14 @@ mod application { } #[cfg(feature = "halo2-axiom")] { - region.assign_advice( - config.a, - 0, - Value::known(Assigned::Trivial(self.0)), - )?; + region.assign_advice(config.a, 0, Value::known(Assigned::Trivial(self.0))); region.assign_fixed(config.q_a, 0, Assigned::Trivial(-Fr::one())); region.assign_advice( config.a, 1, Value::known(Assigned::Trivial(-Fr::from(5u64))), - )?; + ); for (idx, column) in (1..).zip([ config.q_a, config.q_b, @@ -187,7 +184,7 @@ mod application { config.a, 2, Value::known(Assigned::Trivial(Fr::one())), - )?; + ); a.copy_advice(&mut region, config.b, 3); a.copy_advice(&mut region, config.c, 4); } @@ -201,15 +198,23 @@ mod application { mod aggregation { use super::halo2_proofs::{ - circuit::{Cell, Layouter, SimpleFloorPlanner, Value}, - plonk::{self, Circuit, Column, ConstraintSystem, Instance}, - poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG}, + circuit::{Layouter, SimpleFloorPlanner}, + plonk::{self, Circuit, Column, Instance}, }; use super::{As, Plonk, BITS, LIMBS}; - use super::{Bn256, Fq, Fr, G1Affine}; - use ark_std::{end_timer, start_timer}; - use halo2_base::{Context, ContextParams}; - use halo2_ecc::ecc::EccChip; + use super::{Fr, G1Affine}; + use halo2_base::{ + gates::{ + builder::{ + assign_threads_in, CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, + MultiPhaseThreadBreakPoints, RangeCircuitBuilder, + }, + range::RangeConfig, + RangeChip, + }, + AssignedValue, SKIP_FIRST_PASS, + }; + use halo2_ecc::bn254::FpChip; use itertools::Itertools; use rand::rngs::OsRng; use snark_verifier::{ @@ -223,7 +228,7 @@ mod aggregation { verifier::PlonkVerifier, Protocol, }; - use std::{fs::File, rc::Rc}; + use std::{collections::HashMap, rc::Rc}; const T: usize = 5; const RATE: usize = 4; @@ -231,11 +236,12 @@ mod aggregation { const R_P: usize = 60; type Svk = KzgSuccinctVerifyingKey; - type BaseFieldEccChip = halo2_ecc::ecc::BaseFieldEccChip; - type Halo2Loader<'a> = loader::halo2::Halo2Loader<'a, G1Affine, BaseFieldEccChip>; + type BaseFieldEccChip<'chip> = halo2_ecc::ecc::BaseFieldEccChip<'chip, G1Affine>; + type Halo2Loader<'chip> = loader::halo2::Halo2Loader>; pub type PoseidonTranscript = system::halo2::transcript::halo2::PoseidonTranscript; + #[derive(Clone)] pub struct Snark { protocol: Protocol, instances: Vec>, @@ -248,52 +254,19 @@ mod aggregation { } } - impl From for SnarkWitness { - fn from(snark: Snark) -> Self { - Self { - protocol: snark.protocol, - instances: snark - .instances - .into_iter() - .map(|instances| instances.into_iter().map(Value::known).collect_vec()) - .collect(), - proof: Value::known(snark.proof), - } - } - } - - #[derive(Clone)] - pub struct SnarkWitness { - protocol: Protocol, - instances: Vec>>, - proof: Value>, - } - - impl SnarkWitness { - fn without_witnesses(&self) -> Self { - SnarkWitness { - protocol: self.protocol.clone(), - instances: self - .instances - .iter() - .map(|instances| vec![Value::unknown(); instances.len()]) - .collect(), - proof: Value::unknown(), - } - } - - fn proof(&self) -> Value<&[u8]> { - self.proof.as_ref().map(Vec::as_slice) + impl Snark { + fn proof(&self) -> &[u8] { + self.proof.as_slice() } } pub fn aggregate<'a>( svk: &Svk, loader: &Rc>, - snarks: &[SnarkWitness], - as_proof: Value<&'_ [u8]>, + snarks: &[Snark], + as_proof: &[u8], ) -> KzgAccumulator>> { - let assign_instances = |instances: &[Vec>]| { + let assign_instances = |instances: &[Vec]| { instances .iter() .map(|instances| { @@ -326,71 +299,38 @@ mod aggregation { #[derive(serde::Serialize, serde::Deserialize)] pub struct AggregationConfigParams { - pub strategy: halo2_ecc::fields::fp::FpStrategy, pub degree: u32, pub num_advice: usize, pub num_lookup_advice: usize, pub num_fixed: usize, pub lookup_bits: usize, - pub limb_bits: usize, - pub num_limbs: usize, } #[derive(Clone)] pub struct AggregationConfig { - pub base_field_config: halo2_ecc::fields::fp::FpConfig, + pub range: RangeConfig, pub instance: Column, } - impl AggregationConfig { - pub fn configure(meta: &mut ConstraintSystem, params: AggregationConfigParams) -> Self { - assert!( - params.limb_bits == BITS && params.num_limbs == LIMBS, - "For now we fix limb_bits = {}, otherwise change code", - BITS - ); - let base_field_config = halo2_ecc::fields::fp::FpConfig::configure( - meta, - params.strategy, - &[params.num_advice], - &[params.num_lookup_advice], - params.num_fixed, - params.lookup_bits, - params.limb_bits, - params.num_limbs, - halo2_base::utils::modulus::(), - 0, - params.degree as usize, - ); - - let instance = meta.instance_column(); - meta.enable_equality(instance); - - Self { base_field_config, instance } - } - - pub fn range(&self) -> &halo2_base::gates::range::RangeConfig { - &self.base_field_config.range - } - - pub fn ecc_chip(&self) -> halo2_ecc::ecc::BaseFieldEccChip { - EccChip::construct(self.base_field_config.clone()) - } - } - - #[derive(Clone)] + #[derive(Clone, Debug)] pub struct AggregationCircuit { - svk: Svk, - snarks: Vec, - instances: Vec, - as_proof: Value>, + pub circuit: RangeCircuitBuilder, + pub as_proof: Vec, + pub assigned_instances: Vec>, } impl AggregationCircuit { - pub fn new(params: &ParamsKZG, snarks: impl IntoIterator) -> Self { - let svk = params.get_g()[0].into(); + pub fn new( + stage: CircuitBuilderStage, + break_points: Option, + lookup_bits: usize, + params_g0: G1Affine, + snarks: impl IntoIterator, + ) -> Self { + let svk: Svk = params_g0.into(); let snarks = snarks.into_iter().collect_vec(); + // verify the snarks natively to get public instances let accumulators = snarks .iter() .flat_map(|snark| { @@ -402,7 +342,7 @@ mod aggregation { }) .collect_vec(); - let (accumulator, as_proof) = { + let (_accumulator, as_proof) = { let mut transcript = PoseidonTranscript::::new(Vec::new()); let accumulator = As::create_proof(&Default::default(), &accumulators, &mut transcript, OsRng) @@ -410,20 +350,64 @@ mod aggregation { (accumulator, transcript.finalize()) }; - let KzgAccumulator { lhs, rhs } = accumulator; - let instances = - [lhs.x, lhs.y, rhs.x, rhs.y].map(fe_to_limbs::<_, _, LIMBS, BITS>).concat(); + // create thread builder and run aggregation witness gen + let builder = match stage { + CircuitBuilderStage::Mock => GateThreadBuilder::mock(), + CircuitBuilderStage::Prover => GateThreadBuilder::prover(), + CircuitBuilderStage::Keygen => GateThreadBuilder::keygen(), + }; + // create halo2loader + let range = RangeChip::::default(lookup_bits); + let fp_chip = FpChip::::new(&range, BITS, LIMBS); + let ecc_chip = BaseFieldEccChip::new(&fp_chip); + let loader = Halo2Loader::new(ecc_chip, builder); + + let KzgAccumulator { lhs, rhs } = + aggregate(&svk, &loader, &snarks, as_proof.as_slice()); + let lhs = lhs.assigned(); + let rhs = rhs.assigned(); + let assigned_instances = lhs + .x + .truncation + .limbs + .iter() + .chain(lhs.y.truncation.limbs.iter()) + .chain(rhs.x.truncation.limbs.iter()) + .chain(rhs.y.truncation.limbs.iter()) + .copied() + .collect_vec(); - Self { - svk, - snarks: snarks.into_iter().map_into().collect(), - instances, - as_proof: Value::known(as_proof), + #[cfg(debug_assertions)] + { + let KzgAccumulator { lhs, rhs } = _accumulator; + let instances = + [lhs.x, lhs.y, rhs.x, rhs.y].map(fe_to_limbs::<_, Fr, LIMBS, BITS>).concat(); + for (lhs, rhs) in instances.iter().zip(assigned_instances.iter()) { + assert_eq!(lhs, rhs.value()); + } } + + let builder = loader.take_ctx(); + let circuit = match stage { + CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder), + CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder), + CircuitBuilderStage::Prover => { + RangeCircuitBuilder::prover(builder, break_points.unwrap()) + } + }; + Self { circuit, as_proof, assigned_instances } + } + + pub fn config(&self, k: u32, minimum_rows: Option) -> FlexGateConfigParams { + self.circuit.0.builder.borrow().config(k as usize, minimum_rows) } - pub fn as_proof(&self) -> Value<&[u8]> { - self.as_proof.as_ref().map(Vec::as_slice) + pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { + self.circuit.0.break_points.borrow().clone() + } + + pub fn as_proof(&self) -> &[u8] { + &self.as_proof[..] } pub fn num_instance() -> Vec { @@ -432,7 +416,7 @@ mod aggregation { } pub fn instances(&self) -> Vec> { - vec![self.instances.clone()] + vec![self.assigned_instances.iter().map(|v| *v.value()).collect_vec()] } pub fn accumulator_indices() -> Vec<(usize, usize)> { @@ -445,23 +429,14 @@ mod aggregation { type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - Self { - svk: self.svk, - snarks: self.snarks.iter().map(SnarkWitness::without_witnesses).collect(), - instances: Vec::new(), - as_proof: Value::unknown(), - } + unimplemented!() } fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - let path = std::env::var("VERIFY_CONFIG").unwrap(); - let params: AggregationConfigParams = serde_json::from_reader( - File::open(path.as_str()) - .unwrap_or_else(|err| panic!("Path {path} does not exist: {err:?}")), - ) - .unwrap(); - - AggregationConfig::configure(meta, params) + let range = RangeCircuitBuilder::configure(meta); + let instance = meta.instance_column(); + meta.enable_equality(instance); + AggregationConfig { range, instance } } fn synthesize( @@ -469,63 +444,75 @@ mod aggregation { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), plonk::Error> { - config.range().load_lookup_table(&mut layouter)?; - let max_rows = config.range().gate.max_rows; - - let mut first_pass = halo2_base::SKIP_FIRST_PASS; // assume using simple floor planner - let mut assigned_instances: Option> = None; - layouter.assign_region( - || "", - |region| { - if first_pass { - first_pass = false; - return Ok(()); - } - let witness_time = start_timer!(|| "Witness Collection"); - let ctx = Context::new( - region, - ContextParams { - max_rows, - num_context_ids: 1, - fixed_columns: config.base_field_config.range.gate.constants.clone(), - }, - ); - - let ecc_chip = config.ecc_chip(); - let loader = Halo2Loader::new(ecc_chip, ctx); - let KzgAccumulator { lhs, rhs } = - aggregate(&self.svk, &loader, &self.snarks, self.as_proof()); - - let lhs = lhs.assigned(); - let rhs = rhs.assigned(); - - config.base_field_config.finalize(&mut loader.ctx_mut()); - #[cfg(feature = "display")] - println!("Total advice cells: {}", loader.ctx().total_advice); - #[cfg(feature = "display")] - println!("Advice columns used: {}", loader.ctx().advice_alloc[0].0 + 1); - - let instances: Vec<_> = lhs - .x - .truncation - .limbs - .iter() - .chain(lhs.y.truncation.limbs.iter()) - .chain(rhs.x.truncation.limbs.iter()) - .chain(rhs.y.truncation.limbs.iter()) - .map(|assigned| assigned.cell().clone()) - .collect(); - assigned_instances = Some(instances); - end_timer!(witness_time); - Ok(()) - }, - )?; - - // Expose instances - // TODO: use less instances by following Scroll's strategy of keeping only last bit of y coordinate - let mut layouter = layouter.namespace(|| "expose"); - for (i, cell) in assigned_instances.unwrap().into_iter().enumerate() { - layouter.constrain_instance(cell, config.instance, i); + // copied from RangeCircuitBuilder::synthesize but with extra logic to expose public instances + let range = config.range; + let circuit = &self.circuit.0; + range.load_lookup_table(&mut layouter).expect("load lookup table should not fail"); + + // we later `take` the builder, so we need to save this value + let witness_gen_only = circuit.builder.borrow().witness_gen_only(); + let mut assigned_advices = HashMap::new(); + + let mut first_pass = SKIP_FIRST_PASS; + layouter + .assign_region( + || "AggregationCircuit", + |mut region| { + if first_pass { + first_pass = false; + return Ok(()); + } + // only support FirstPhase in this Builder because getting challenge value requires more specialized witness generation during synthesize + if !witness_gen_only { + // clone the builder so we can re-use the circuit for both vk and pk gen + let builder = circuit.builder.borrow(); + let assignments = builder.assign_all( + &range.gate, + &range.lookup_advice, + &range.q_lookup, + &mut region, + ); + *circuit.break_points.borrow_mut() = assignments.break_points; + assigned_advices = assignments.assigned_advices; + } else { + #[cfg(feature = "display")] + let start0 = std::time::Instant::now(); + let builder = circuit.builder.take(); + let break_points = circuit.break_points.take(); + for (phase, (threads, break_points)) in builder + .threads + .into_iter() + .zip(break_points.into_iter()) + .enumerate() + .take(1) + { + assign_threads_in( + phase, + threads, + &range.gate, + &range.lookup_advice[phase], + &mut region, + break_points, + ); + } + #[cfg(feature = "display")] + println!("assign threads in {:?}", start0.elapsed()); + } + Ok(()) + }, + ) + .unwrap(); + + if !witness_gen_only { + // expose public instances + let mut layouter = layouter.namespace(|| "expose"); + for (i, instance) in self.assigned_instances.iter().enumerate() { + let cell = instance.cell.unwrap(); + let (cell, _) = assigned_advices + .get(&(cell.context_id, cell.offset)) + .expect("instance not assigned"); + layouter.constrain_instance(*cell, config.instance, i); + } } Ok(()) } @@ -534,7 +521,10 @@ mod aggregation { fn gen_pk>(params: &ParamsKZG, circuit: &C) -> ProvingKey { let vk = keygen_vk(params, circuit).unwrap(); - keygen_pk(params, vk, circuit).unwrap() + println!("finished vk"); + let pk = keygen_pk(params, vk, circuit).unwrap(); + println!("finished pk"); + pk } fn gen_proof< @@ -548,8 +538,6 @@ fn gen_proof< circuit: C, instances: Vec>, ) -> Vec { - MockProver::run(params.k(), &circuit, instances.clone()).unwrap().assert_satisfied(); - let instances = instances.iter().map(|instances| instances.as_slice()).collect_vec(); let proof = { let mut transcript = TW::init(Vec::new()); @@ -646,16 +634,33 @@ fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) } fn main() { - std::env::set_var("VERIFY_CONFIG", "./configs/example_evm_accumulator.config"); - let params = halo2_base::utils::fs::gen_srs(21); - let params_app = { - let mut params = params.clone(); - params.downsize(8); - params - }; + let params_app = gen_srs(8); let snarks = [(); 3].map(|_| gen_application_snark(¶ms_app)); - let agg_circuit = aggregation::AggregationCircuit::new(¶ms, snarks); + + let path = "./configs/example_evm_accumulator.json"; + let agg_config: AggregationConfigParams = serde_json::from_reader( + File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")), + ) + .unwrap(); + let agg_circuit = AggregationCircuit::new( + CircuitBuilderStage::Mock, + None, + agg_config.lookup_bits, + params_app.get_g()[0], + snarks.clone(), + ); + agg_circuit.config(agg_config.degree, Some(6)); + set_var("LOOKUP_BITS", agg_config.lookup_bits.to_string()); + #[cfg(debug_assertions)] + { + MockProver::run(agg_config.degree, &agg_circuit, agg_circuit.instances()) + .unwrap() + .assert_satisfied(); + println!("mock prover passed"); + } + + let params = gen_srs(agg_config.degree); let pk = gen_pk(¶ms, &agg_circuit); let deployment_code = gen_aggregation_evm_verifier( ¶ms, @@ -664,11 +669,22 @@ fn main() { aggregation::AggregationCircuit::accumulator_indices(), ); + let break_points = agg_circuit.break_points(); + drop(agg_circuit); + + let agg_circuit = AggregationCircuit::new( + CircuitBuilderStage::Prover, + Some(break_points), + agg_config.lookup_bits, + params_app.get_g()[0], + snarks, + ); + let instances = agg_circuit.instances(); let proof = gen_proof::<_, _, EvmTranscript, EvmTranscript>( ¶ms, &pk, - agg_circuit.clone(), - agg_circuit.instances(), + agg_circuit, + instances.clone(), ); - evm_verify(deployment_code, agg_circuit.instances(), proof); + evm_verify(deployment_code, instances, proof); } diff --git a/snark-verifier/examples/evm-verifier.rs b/snark-verifier/examples/evm-verifier.rs index e206b5e0..a2bfe4db 100644 --- a/snark-verifier/examples/evm-verifier.rs +++ b/snark-verifier/examples/evm-verifier.rs @@ -140,14 +140,14 @@ impl Circuit for StandardPlonk { } #[cfg(feature = "halo2-axiom")] { - region.assign_advice(config.a, 0, Value::known(Assigned::Trivial(self.0)))?; + region.assign_advice(config.a, 0, Value::known(Assigned::Trivial(self.0))); region.assign_fixed(config.q_a, 0, Assigned::Trivial(-Fr::one())); region.assign_advice( config.a, 1, Value::known(Assigned::Trivial(-Fr::from(5u64))), - )?; + ); for (idx, column) in (1..).zip([ config.q_a, config.q_b, @@ -162,7 +162,7 @@ impl Circuit for StandardPlonk { config.a, 2, Value::known(Assigned::Trivial(Fr::one())), - )?; + ); a.copy_advice(&mut region, config.b, 3); a.copy_advice(&mut region, config.c, 4); } diff --git a/snark-verifier/src/loader.rs b/snark-verifier/src/loader.rs index 297390d0..67a634cf 100644 --- a/snark-verifier/src/loader.rs +++ b/snark-verifier/src/loader.rs @@ -1,9 +1,6 @@ -use crate::{ - util::{ - arithmetic::{CurveAffine, FieldOps, PrimeField}, - Itertools, - }, - Error, +use crate::util::{ + arithmetic::{CurveAffine, FieldOps, PrimeField}, + Itertools, }; use std::{borrow::Cow, fmt::Debug, iter, ops::Deref}; @@ -83,7 +80,7 @@ pub trait EcPointLoader { annotation: &str, lhs: &Self::LoadedEcPoint, rhs: &Self::LoadedEcPoint, - ) -> Result<(), Error>; + ); fn multi_scalar_multiplication( pairs: &[(&Self::LoadedScalar, &Self::LoadedEcPoint)], @@ -105,12 +102,7 @@ pub trait ScalarLoader { self.load_const(&F::one()) } - fn assert_eq( - &self, - annotation: &str, - lhs: &Self::LoadedScalar, - rhs: &Self::LoadedScalar, - ) -> Result<(), Error>; + fn assert_eq(&self, annotation: &str, lhs: &Self::LoadedScalar, rhs: &Self::LoadedScalar); fn sum_with_coeff_and_const( &self, @@ -151,11 +143,7 @@ pub trait ScalarLoader { let loader = values.first().unwrap().1.loader(); iter::empty() - .chain(if constant == F::zero() { - None - } else { - Some(loader.load_const(&constant)) - }) + .chain(if constant == F::zero() { None } else { Some(loader.load_const(&constant)) }) .chain(values.iter().map(|&(coeff, lhs, rhs)| { if coeff == F::one() { lhs.clone() * rhs @@ -195,10 +183,7 @@ pub trait ScalarLoader { constant: F, ) -> Self::LoadedScalar { self.sum_products_with_coeff_and_const( - &values - .iter() - .map(|&(lhs, rhs)| (F::one(), lhs, rhs)) - .collect_vec(), + &values.iter().map(|&(lhs, rhs)| (F::one(), lhs, rhs)).collect_vec(), constant, ) } @@ -211,9 +196,7 @@ pub trait ScalarLoader { } fn product(&self, values: &[&Self::LoadedScalar]) -> Self::LoadedScalar { - values - .iter() - .fold(self.load_one(), |acc, value| acc * *value) + values.iter().fold(self.load_one(), |acc, value| acc * *value) } fn batch_invert<'a>(values: impl IntoIterator) diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index db15c8d7..1680eba0 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -10,7 +10,6 @@ use crate::{ arithmetic::{CurveAffine, FieldOps, PrimeField}, Itertools, }, - Error, }; use ethereum_types::{U256, U512}; use hex; @@ -93,10 +92,9 @@ impl EvmLoader { return(0, 0)" .to_string(); self.code.borrow_mut().runtime_append(code); - self.code.borrow().code( - hex_encode_u256(&self.base_modulus), - hex_encode_u256(&self.scalar_modulus), - ) + self.code + .borrow() + .code(hex_encode_u256(&self.base_modulus), hex_encode_u256(&self.scalar_modulus)) } pub fn allocate(self: &Rc, size: usize) -> usize { @@ -210,10 +208,7 @@ impl EvmLoader { } pub(crate) fn scalar(self: &Rc, value: Value) -> Scalar { - let value = if matches!( - value, - Value::Constant(_) | Value::Memory(_) | Value::Negated(_) - ) { + let value = if matches!(value, Value::Constant(_) | Value::Memory(_) | Value::Negated(_)) { value } else { let identifier = value.identifier(); @@ -221,30 +216,19 @@ impl EvmLoader { let ptr = if let Some(ptr) = some_ptr { ptr } else { - let v = self.push(&Scalar { - loader: self.clone(), - value, - }); + let v = self.push(&Scalar { loader: self.clone(), value }); let ptr = self.allocate(0x20); - self.code - .borrow_mut() - .runtime_append(format!("mstore({ptr:#x}, {v})")); + self.code.borrow_mut().runtime_append(format!("mstore({ptr:#x}, {v})")); self.cache.borrow_mut().insert(identifier, ptr); ptr }; Value::Memory(ptr) }; - Scalar { - loader: self.clone(), - value, - } + Scalar { loader: self.clone(), value } } fn ec_point(self: &Rc, value: Value<(U256, U256)>) -> EcPoint { - EcPoint { - loader: self.clone(), - value, - } + EcPoint { loader: self.clone(), value } } pub fn keccak256(self: &Rc, ptr: usize, len: usize) -> usize { @@ -256,9 +240,7 @@ impl EvmLoader { pub fn copy_scalar(self: &Rc, scalar: &Scalar, ptr: usize) { let scalar = self.push(scalar); - self.code - .borrow_mut() - .runtime_append(format!("mstore({ptr:#x}, {scalar})")); + self.code.borrow_mut().runtime_append(format!("mstore({ptr:#x}, {scalar})")); } pub fn dup_scalar(self: &Rc, scalar: &Scalar) -> Scalar { @@ -392,10 +374,7 @@ impl EvmLoader { return self.scalar(Value::Constant(out.try_into().unwrap())); } - self.scalar(Value::Sum( - Box::new(lhs.value.clone()), - Box::new(rhs.value.clone()), - )) + self.scalar(Value::Sum(Box::new(lhs.value.clone()), Box::new(rhs.value.clone()))) } fn sub(self: &Rc, lhs: &Scalar, rhs: &Scalar) -> Scalar { @@ -415,10 +394,7 @@ impl EvmLoader { return self.scalar(Value::Constant(out.try_into().unwrap())); } - self.scalar(Value::Product( - Box::new(lhs.value.clone()), - Box::new(rhs.value.clone()), - )) + self.scalar(Value::Product(Box::new(lhs.value.clone()), Box::new(rhs.value.clone()))) } fn neg(self: &Rc, scalar: &Scalar) -> Scalar { @@ -433,18 +409,14 @@ impl EvmLoader { #[cfg(test)] impl EvmLoader { fn start_gas_metering(self: &Rc, identifier: &str) { - self.gas_metering_ids - .borrow_mut() - .push(identifier.to_string()); + self.gas_metering_ids.borrow_mut().push(identifier.to_string()); let code = format!("let {identifier} := gas()"); self.code.borrow_mut().runtime_append(code); } fn end_gas_metering(self: &Rc) { - let code = format!( - "log1(0, 0, sub({}, gas()))", - self.gas_metering_ids.borrow().last().unwrap() - ); + let code = + format!("log1(0, 0, sub({}, gas()))", self.gas_metering_ids.borrow().last().unwrap()); self.code.borrow_mut().runtime_append(code); } @@ -480,9 +452,7 @@ impl EcPoint { impl Debug for EcPoint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("EcPoint") - .field("value", &self.value) - .finish() + f.debug_struct("EcPoint").field("value", &self.value).finish() } } @@ -526,21 +496,14 @@ impl Scalar { pub(crate) fn ptr(&self) -> usize { match self.value { Value::Memory(ptr) => ptr, - _ => *self - .loader - .cache - .borrow() - .get(&self.value.identifier()) - .unwrap(), + _ => *self.loader.cache.borrow().get(&self.value.identifier()).unwrap(), } } } impl Debug for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Scalar") - .field("value", &self.value) - .finish() + f.debug_struct("Scalar").field("value", &self.value).finish() } } @@ -670,9 +633,7 @@ where self.ec_point(Value::Constant((x, y))) } - fn ec_point_assert_eq(&self, _: &str, _: &EcPoint, _: &EcPoint) -> Result<(), Error> { - unimplemented!() - } + fn ec_point_assert_eq(&self, _: &str, _: &EcPoint, _: &EcPoint) {} fn multi_scalar_multiplication( pairs: &[(&>::LoadedScalar, &EcPoint)], @@ -696,9 +657,7 @@ impl> ScalarLoader for Rc { self.scalar(Value::Constant(fe_to_u256(*value))) } - fn assert_eq(&self, _: &str, _: &Scalar, _: &Scalar) -> Result<(), Error> { - unimplemented!() - } + fn assert_eq(&self, _: &str, _: &Scalar, _: &Scalar) {} fn sum_with_coeff_and_const(&self, values: &[(F, &Scalar)], constant: F) -> Scalar { if values.is_empty() { @@ -709,9 +668,9 @@ impl> ScalarLoader for Rc { assert_ne!(*coeff, F::zero()); match (*coeff == F::one(), &value.value) { (true, _) => self.push(value), - (false, Value::Constant(value)) => self.push(&self.scalar(Value::Constant( - fe_to_u256(*coeff * u256_to_fe::(*value)), - ))), + (false, Value::Constant(value)) => self.push( + &self.scalar(Value::Constant(fe_to_u256(*coeff * u256_to_fe::(*value)))), + ), (false, _) => { let value = self.push(value); let coeff = self.push(&self.scalar(Value::Constant(fe_to_u256(*coeff)))); @@ -765,9 +724,10 @@ impl> ScalarLoader for Rc { (_, value @ Value::Memory(_), Value::Constant(constant)) | (_, Value::Constant(constant), value @ Value::Memory(_)) => { let v1 = self.push(&self.scalar(value.clone())); - let v2 = self.push(&self.scalar(Value::Constant(fe_to_u256( - *coeff * u256_to_fe::(*constant), - )))); + let v2 = + self.push(&self.scalar(Value::Constant(fe_to_u256( + *coeff * u256_to_fe::(*constant), + )))); format!("mulmod({v1}, {v2}, f_q)") } (true, _, _) => { @@ -858,14 +818,9 @@ impl> ScalarLoader for Rc { let v " ); - for (value, product) in values.iter().rev().zip( - products - .iter() - .rev() - .skip(1) - .map(Some) - .chain(iter::once(None)), - ) { + for (value, product) in + values.iter().rev().zip(products.iter().rev().skip(1).map(Some).chain(iter::once(None))) + { if let Some(product) = product { let val_ptr = value.ptr(); let prod_ptr = product.ptr(); diff --git a/snark-verifier/src/loader/halo2.rs b/snark-verifier/src/loader/halo2.rs index 0e84d506..9989462b 100644 --- a/snark-verifier/src/loader/halo2.rs +++ b/snark-verifier/src/loader/halo2.rs @@ -1,4 +1,3 @@ -use crate::halo2_proofs::circuit; use crate::{util::arithmetic::CurveAffine, Protocol}; use std::rc::Rc; @@ -9,7 +8,7 @@ mod shim; pub(crate) mod test; pub use loader::{EcPoint, Halo2Loader, Scalar}; -pub use shim::{Context, EccInstructions, IntegerInstructions}; +pub use shim::{EccInstructions, IntegerInstructions}; pub use util::Valuetools; pub use halo2_ecc; @@ -36,19 +35,19 @@ impl Protocol where C: CurveAffine, { - pub fn loaded_preprocessed_as_witness<'a, EccChip: EccInstructions<'a, C>>( + pub fn loaded_preprocessed_as_witness>( &self, - loader: &Rc>, - ) -> Protocol>> { + loader: &Rc>, + ) -> Protocol>> { let preprocessed = self .preprocessed .iter() - .map(|preprocessed| loader.assign_ec_point(circuit::Value::known(*preprocessed))) + .map(|preprocessed| loader.assign_ec_point(*preprocessed)) .collect(); - let transcript_initial_state = - self.transcript_initial_state.as_ref().map(|transcript_initial_state| { - loader.assign_scalar(circuit::Value::known(*transcript_initial_state)) - }); + let transcript_initial_state = self + .transcript_initial_state + .as_ref() + .map(|transcript_initial_state| loader.assign_scalar(*transcript_initial_state)); Protocol { domain: self.domain.clone(), preprocessed, diff --git a/snark-verifier/src/loader/halo2/loader.rs b/snark-verifier/src/loader/halo2/loader.rs index 24b9df6e..7af3e1d2 100644 --- a/snark-verifier/src/loader/halo2/loader.rs +++ b/snark-verifier/src/loader/halo2/loader.rs @@ -1,4 +1,3 @@ -use crate::halo2_proofs::circuit; use crate::{ loader::{ halo2::shim::{EccInstructions, IntegerInstructions}, @@ -18,7 +17,7 @@ use std::{ }; #[derive(Debug)] -pub struct Halo2Loader<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { +pub struct Halo2Loader> { ecc_chip: RefCell, ctx: RefCell, num_scalar: RefCell, @@ -28,7 +27,7 @@ pub struct Halo2Loader<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { row_meterings: RefCell>, } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, EccChip> { +impl> Halo2Loader { pub fn new(ecc_chip: EccChip, ctx: EccChip::Context) -> Rc { Rc::new(Self { ecc_chip: RefCell::new(ecc_chip), @@ -45,6 +44,10 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc self.ctx.into_inner() } + pub fn take_ctx(&self) -> EccChip::Context { + self.ctx.take() + } + pub fn ecc_chip(&self) -> Ref { self.ecc_chip.borrow() } @@ -62,56 +65,47 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc } fn assign_const_scalar(self: &Rc, constant: C::Scalar) -> EccChip::AssignedScalar { - self.scalar_chip().assign_constant(&mut self.ctx_mut(), constant).unwrap() + self.scalar_chip().assign_constant(&mut self.ctx_mut(), constant) } - pub fn assign_scalar( - self: &Rc, - scalar: circuit::Value, - ) -> Scalar<'a, C, EccChip> { - let assigned = self.scalar_chip().assign_integer(&mut self.ctx_mut(), scalar).unwrap(); + pub fn assign_scalar(self: &Rc, scalar: C::Scalar) -> Scalar { + let assigned = self.scalar_chip().assign_integer(&mut self.ctx_mut(), scalar); self.scalar_from_assigned(assigned) } pub fn scalar_from_assigned( self: &Rc, assigned: EccChip::AssignedScalar, - ) -> Scalar<'a, C, EccChip> { + ) -> Scalar { self.scalar(Value::Assigned(assigned)) } fn scalar( self: &Rc, value: Value, - ) -> Scalar<'a, C, EccChip> { + ) -> Scalar { let index = *self.num_scalar.borrow(); *self.num_scalar.borrow_mut() += 1; Scalar { loader: self.clone(), index, value: value.into() } } fn assign_const_ec_point(self: &Rc, constant: C) -> EccChip::AssignedEcPoint { - self.ecc_chip().assign_constant(&mut self.ctx_mut(), constant).unwrap() + self.ecc_chip().assign_constant(&mut self.ctx_mut(), constant) } - pub fn assign_ec_point( - self: &Rc, - ec_point: circuit::Value, - ) -> EcPoint<'a, C, EccChip> { - let assigned = self.ecc_chip().assign_point(&mut self.ctx_mut(), ec_point).unwrap(); + pub fn assign_ec_point(self: &Rc, ec_point: C) -> EcPoint { + let assigned = self.ecc_chip().assign_point(&mut self.ctx_mut(), ec_point); self.ec_point_from_assigned(assigned) } pub fn ec_point_from_assigned( self: &Rc, assigned: EccChip::AssignedEcPoint, - ) -> EcPoint<'a, C, EccChip> { + ) -> EcPoint { self.ec_point(Value::Assigned(assigned)) } - fn ec_point( - self: &Rc, - value: Value, - ) -> EcPoint<'a, C, EccChip> { + fn ec_point(self: &Rc, value: Value) -> EcPoint { let index = *self.num_ec_point.borrow(); *self.num_ec_point.borrow_mut() += 1; EcPoint { loader: self.clone(), index, value: value.into() } @@ -119,149 +113,109 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, Ecc fn add( self: &Rc, - lhs: &Scalar<'a, C, EccChip>, - rhs: &Scalar<'a, C, EccChip>, - ) -> Scalar<'a, C, EccChip> { + lhs: &Scalar, + rhs: &Scalar, + ) -> Scalar { let output = match (lhs.value().deref(), rhs.value().deref()) { (Value::Constant(lhs), Value::Constant(rhs)) => Value::Constant(*lhs + rhs), (Value::Assigned(assigned), Value::Constant(constant)) - | (Value::Constant(constant), Value::Assigned(assigned)) => self - .scalar_chip() - .sum_with_coeff_and_const( + | (Value::Constant(constant), Value::Assigned(assigned)) => { + Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( &mut self.ctx_mut(), &[(C::Scalar::one(), assigned)], *constant, - ) - .map(Value::Assigned) - .unwrap(), - (Value::Assigned(lhs), Value::Assigned(rhs)) => self - .scalar_chip() - .sum_with_coeff_and_const( + )) + } + (Value::Assigned(lhs), Value::Assigned(rhs)) => { + Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( &mut self.ctx_mut(), &[(C::Scalar::one(), lhs), (C::Scalar::one(), rhs)], C::Scalar::zero(), - ) - .map(Value::Assigned) - .unwrap(), + )) + } }; self.scalar(output) } fn sub( self: &Rc, - lhs: &Scalar<'a, C, EccChip>, - rhs: &Scalar<'a, C, EccChip>, - ) -> Scalar<'a, C, EccChip> { + lhs: &Scalar, + rhs: &Scalar, + ) -> Scalar { let output = match (lhs.value().deref(), rhs.value().deref()) { (Value::Constant(lhs), Value::Constant(rhs)) => Value::Constant(*lhs - rhs), - (Value::Constant(constant), Value::Assigned(assigned)) => self - .scalar_chip() - .sum_with_coeff_and_const( + (Value::Constant(constant), Value::Assigned(assigned)) => { + Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( &mut self.ctx_mut(), &[(-C::Scalar::one(), assigned)], *constant, - ) - .map(Value::Assigned) - .unwrap(), - (Value::Assigned(assigned), Value::Constant(constant)) => self - .scalar_chip() - .sum_with_coeff_and_const( + )) + } + (Value::Assigned(assigned), Value::Constant(constant)) => { + Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( &mut self.ctx_mut(), &[(C::Scalar::one(), assigned)], -*constant, - ) - .map(Value::Assigned) - .unwrap(), - (Value::Assigned(lhs), Value::Assigned(rhs)) => { - IntegerInstructions::sub(self.scalar_chip().deref(), &mut self.ctx_mut(), lhs, rhs) - .map(Value::Assigned) - .unwrap() + )) } + (Value::Assigned(lhs), Value::Assigned(rhs)) => Value::Assigned( + IntegerInstructions::sub(self.scalar_chip().deref(), &mut self.ctx_mut(), lhs, rhs), + ), }; self.scalar(output) } fn mul( self: &Rc, - lhs: &Scalar<'a, C, EccChip>, - rhs: &Scalar<'a, C, EccChip>, - ) -> Scalar<'a, C, EccChip> { + lhs: &Scalar, + rhs: &Scalar, + ) -> Scalar { let output = match (lhs.value().deref(), rhs.value().deref()) { (Value::Constant(lhs), Value::Constant(rhs)) => Value::Constant(*lhs * rhs), (Value::Assigned(assigned), Value::Constant(constant)) - | (Value::Constant(constant), Value::Assigned(assigned)) => self - .scalar_chip() - .sum_with_coeff_and_const( + | (Value::Constant(constant), Value::Assigned(assigned)) => { + Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( &mut self.ctx_mut(), &[(*constant, assigned)], C::Scalar::zero(), - ) - .map(Value::Assigned) - .unwrap(), - (Value::Assigned(lhs), Value::Assigned(rhs)) => self - .scalar_chip() - .sum_products_with_coeff_and_const( + )) + } + (Value::Assigned(lhs), Value::Assigned(rhs)) => { + Value::Assigned(self.scalar_chip().sum_products_with_coeff_and_const( &mut self.ctx_mut(), &[(C::Scalar::one(), lhs, rhs)], C::Scalar::zero(), - ) - .map(Value::Assigned) - .unwrap(), + )) + } }; self.scalar(output) } - fn neg(self: &Rc, scalar: &Scalar<'a, C, EccChip>) -> Scalar<'a, C, EccChip> { + fn neg(self: &Rc, scalar: &Scalar) -> Scalar { let output = match scalar.value().deref() { Value::Constant(constant) => Value::Constant(constant.neg()), - Value::Assigned(assigned) => { - IntegerInstructions::neg(self.scalar_chip().deref(), &mut self.ctx_mut(), assigned) - .map(Value::Assigned) - .unwrap() - } + Value::Assigned(assigned) => Value::Assigned(IntegerInstructions::neg( + self.scalar_chip().deref(), + &mut self.ctx_mut(), + assigned, + )), }; self.scalar(output) } - fn invert(self: &Rc, scalar: &Scalar<'a, C, EccChip>) -> Scalar<'a, C, EccChip> { + fn invert(self: &Rc, scalar: &Scalar) -> Scalar { let output = match scalar.value().deref() { Value::Constant(constant) => Value::Constant(Field::invert(constant).unwrap()), - Value::Assigned(assigned) => Value::Assigned( - IntegerInstructions::invert( - self.scalar_chip().deref(), - &mut self.ctx_mut(), - assigned, - ) - .unwrap(), - ), + Value::Assigned(assigned) => Value::Assigned(IntegerInstructions::invert( + self.scalar_chip().deref(), + &mut self.ctx_mut(), + assigned, + )), }; self.scalar(output) } } -#[cfg(test)] -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Halo2Loader<'a, C, EccChip> { - fn start_row_metering(self: &Rc, identifier: &str) { - use crate::loader::halo2::shim::Context; - - self.row_meterings.borrow_mut().push((identifier.to_string(), self.ctx().offset())) - } - - fn end_row_metering(self: &Rc) { - use crate::loader::halo2::shim::Context; - - let mut row_meterings = self.row_meterings.borrow_mut(); - let (_, row) = row_meterings.last_mut().unwrap(); - *row = self.ctx().offset() - *row; - } - - pub fn print_row_metering(self: &Rc) { - for (identifier, cost) in self.row_meterings.borrow().iter() { - println!("{identifier}: {cost}"); - } - } -} - #[derive(Clone, Debug)] pub enum Value { Constant(T), @@ -288,14 +242,14 @@ impl Value { } #[derive(Clone)] -pub struct Scalar<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { - loader: Rc>, +pub struct Scalar> { + loader: Rc>, index: usize, value: RefCell>, } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Scalar<'a, C, EccChip> { - pub fn loader(&self) -> &Rc> { +impl> Scalar { + pub fn loader(&self) -> &Rc> { &self.loader } @@ -322,35 +276,33 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Scalar<'a, C, EccChip> } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> PartialEq for Scalar<'a, C, EccChip> { +impl> PartialEq for Scalar { fn eq(&self, other: &Self) -> bool { self.index == other.index } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> LoadedScalar - for Scalar<'a, C, EccChip> -{ - type Loader = Rc>; +impl> LoadedScalar for Scalar { + type Loader = Rc>; fn loader(&self) -> &Self::Loader { &self.loader } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Debug for Scalar<'a, C, EccChip> { +impl> Debug for Scalar { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Scalar").field("value", &self.value).finish() } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> FieldOps for Scalar<'a, C, EccChip> { +impl> FieldOps for Scalar { fn invert(&self) -> Option { Some(self.loader.invert(self)) } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Add for Scalar<'a, C, EccChip> { +impl> Add for Scalar { type Output = Self; fn add(self, rhs: Self) -> Self::Output { @@ -358,7 +310,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Add for Scalar<'a, C, } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Sub for Scalar<'a, C, EccChip> { +impl> Sub for Scalar { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { @@ -366,7 +318,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Sub for Scalar<'a, C, } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Mul for Scalar<'a, C, EccChip> { +impl> Mul for Scalar { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { @@ -374,7 +326,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Mul for Scalar<'a, C, } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Neg for Scalar<'a, C, EccChip> { +impl> Neg for Scalar { type Output = Self; fn neg(self) -> Self::Output { @@ -382,9 +334,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Neg for Scalar<'a, C, } } -impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> Add<&'b Self> - for Scalar<'a, C, EccChip> -{ +impl<'b, C: CurveAffine, EccChip: EccInstructions> Add<&'b Self> for Scalar { type Output = Self; fn add(self, rhs: &'b Self) -> Self::Output { @@ -392,9 +342,7 @@ impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> Add<&'b Self> } } -impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> Sub<&'b Self> - for Scalar<'a, C, EccChip> -{ +impl<'b, C: CurveAffine, EccChip: EccInstructions> Sub<&'b Self> for Scalar { type Output = Self; fn sub(self, rhs: &'b Self) -> Self::Output { @@ -402,9 +350,7 @@ impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> Sub<&'b Self> } } -impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> Mul<&'b Self> - for Scalar<'a, C, EccChip> -{ +impl<'b, C: CurveAffine, EccChip: EccInstructions> Mul<&'b Self> for Scalar { type Output = Self; fn mul(self, rhs: &'b Self) -> Self::Output { @@ -412,56 +358,50 @@ impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> Mul<&'b Self> } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> AddAssign for Scalar<'a, C, EccChip> { +impl> AddAssign for Scalar { fn add_assign(&mut self, rhs: Self) { *self = Halo2Loader::add(&self.loader, self, &rhs) } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> SubAssign for Scalar<'a, C, EccChip> { +impl> SubAssign for Scalar { fn sub_assign(&mut self, rhs: Self) { *self = Halo2Loader::sub(&self.loader, self, &rhs) } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> MulAssign for Scalar<'a, C, EccChip> { +impl> MulAssign for Scalar { fn mul_assign(&mut self, rhs: Self) { *self = Halo2Loader::mul(&self.loader, self, &rhs) } } -impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> AddAssign<&'b Self> - for Scalar<'a, C, EccChip> -{ +impl<'b, C: CurveAffine, EccChip: EccInstructions> AddAssign<&'b Self> for Scalar { fn add_assign(&mut self, rhs: &'b Self) { *self = Halo2Loader::add(&self.loader, self, rhs) } } -impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> SubAssign<&'b Self> - for Scalar<'a, C, EccChip> -{ +impl<'b, C: CurveAffine, EccChip: EccInstructions> SubAssign<&'b Self> for Scalar { fn sub_assign(&mut self, rhs: &'b Self) { *self = Halo2Loader::sub(&self.loader, self, rhs) } } -impl<'a, 'b, C: CurveAffine, EccChip: EccInstructions<'a, C>> MulAssign<&'b Self> - for Scalar<'a, C, EccChip> -{ +impl<'b, C: CurveAffine, EccChip: EccInstructions> MulAssign<&'b Self> for Scalar { fn mul_assign(&mut self, rhs: &'b Self) { *self = Halo2Loader::mul(&self.loader, self, rhs) } } #[derive(Clone)] -pub struct EcPoint<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> { - loader: Rc>, +pub struct EcPoint> { + loader: Rc>, index: usize, value: RefCell>, } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPoint<'a, C, EccChip> { +impl> EcPoint { pub fn into_assigned(self) -> EccChip::AssignedEcPoint { match self.value.into_inner() { Value::Constant(constant) => self.loader.assign_const_ec_point(constant), @@ -485,110 +425,96 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPoint<'a, C, EccChip } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> PartialEq for EcPoint<'a, C, EccChip> { +impl> PartialEq for EcPoint { fn eq(&self, other: &Self) -> bool { self.index == other.index } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> LoadedEcPoint - for EcPoint<'a, C, EccChip> -{ - type Loader = Rc>; +impl> LoadedEcPoint for EcPoint { + type Loader = Rc>; fn loader(&self) -> &Self::Loader { &self.loader } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Debug for EcPoint<'a, C, EccChip> { +impl> Debug for EcPoint { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("EcPoint").field("index", &self.index).field("value", &self.value).finish() } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> ScalarLoader - for Rc> +impl> ScalarLoader + for Rc> { - type LoadedScalar = Scalar<'a, C, EccChip>; + type LoadedScalar = Scalar; - fn load_const(&self, value: &C::Scalar) -> Scalar<'a, C, EccChip> { + fn load_const(&self, value: &C::Scalar) -> Scalar { self.scalar(Value::Constant(*value)) } - fn assert_eq( - &self, - annotation: &str, - lhs: &Scalar<'a, C, EccChip>, - rhs: &Scalar<'a, C, EccChip>, - ) -> Result<(), crate::Error> { - self.scalar_chip() - .assert_equal(&mut self.ctx_mut(), &lhs.assigned(), &rhs.assigned()) - .map_err(|_| crate::Error::AssertionFailure(annotation.to_string())) + fn assert_eq(&self, _annotation: &str, lhs: &Scalar, rhs: &Scalar) { + self.scalar_chip().assert_equal(&mut self.ctx_mut(), &lhs.assigned(), &rhs.assigned()); } fn sum_with_coeff_and_const( &self, - values: &[(C::Scalar, &Scalar<'a, C, EccChip>)], + values: &[(C::Scalar, &Scalar)], constant: C::Scalar, - ) -> Scalar<'a, C, EccChip> { + ) -> Scalar { let values = values.iter().map(|(coeff, value)| (*coeff, value.assigned())).collect_vec(); - self.scalar(Value::Assigned( - self.scalar_chip() - .sum_with_coeff_and_const(&mut self.ctx_mut(), &values, constant) - .unwrap(), - )) + self.scalar(Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( + &mut self.ctx_mut(), + &values, + constant, + ))) } fn sum_products_with_coeff_and_const( &self, - values: &[(C::Scalar, &Scalar<'a, C, EccChip>, &Scalar<'a, C, EccChip>)], + values: &[(C::Scalar, &Scalar, &Scalar)], constant: C::Scalar, - ) -> Scalar<'a, C, EccChip> { + ) -> Scalar { let values = values .iter() .map(|(coeff, lhs, rhs)| (*coeff, lhs.assigned(), rhs.assigned())) .collect_vec(); - self.scalar(Value::Assigned( - self.scalar_chip() - .sum_products_with_coeff_and_const(&mut self.ctx_mut(), &values, constant) - .unwrap(), - )) + self.scalar(Value::Assigned(self.scalar_chip().sum_products_with_coeff_and_const( + &mut self.ctx_mut(), + &values, + constant, + ))) } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPointLoader - for Rc> -{ - type LoadedEcPoint = EcPoint<'a, C, EccChip>; +impl> EcPointLoader for Rc> { + type LoadedEcPoint = EcPoint; - fn ec_point_load_const(&self, ec_point: &C) -> EcPoint<'a, C, EccChip> { + fn ec_point_load_const(&self, ec_point: &C) -> EcPoint { self.ec_point(Value::Constant(*ec_point)) } fn ec_point_assert_eq( &self, - annotation: &str, - lhs: &EcPoint<'a, C, EccChip>, - rhs: &EcPoint<'a, C, EccChip>, - ) -> Result<(), crate::Error> { + _annotation: &str, + lhs: &EcPoint, + rhs: &EcPoint, + ) { if let (Value::Constant(lhs), Value::Constant(rhs)) = (lhs.value().deref(), rhs.value().deref()) { assert_eq!(lhs, rhs); - Ok(()) } else { let lhs = lhs.assigned(); let rhs = rhs.assigned(); - self.ecc_chip() - .assert_equal(&mut self.ctx_mut(), lhs.deref(), rhs.deref()) - .map_err(|_| crate::Error::AssertionFailure(annotation.to_string())) + self.ecc_chip().assert_equal(&mut self.ctx_mut(), lhs.deref(), rhs.deref()); } } fn multi_scalar_multiplication( - pairs: &[(&>::LoadedScalar, &EcPoint<'a, C, EccChip>)], - ) -> EcPoint<'a, C, EccChip> { + pairs: &[(&>::LoadedScalar, &EcPoint)], + ) -> EcPoint { let loader = &pairs[0].0.loader; let (constant, fixed_base, variable_base_non_scaled, variable_base_scaled) = @@ -625,11 +551,7 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPointLoader .into_iter() .map(|(scalar, base)| (scalar.assigned(), base)) .collect_vec(); - loader - .ecc_chip - .borrow_mut() - .fixed_base_msm(&mut loader.ctx_mut(), &fixed_base) - .unwrap() + loader.ecc_chip.borrow_mut().fixed_base_msm(&mut loader.ctx_mut(), &fixed_base) }) .map(RefCell::new); let variable_base_msm = (!variable_base_scaled.is_empty()) @@ -642,37 +564,21 @@ impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> EcPointLoader .ecc_chip .borrow_mut() .variable_base_msm(&mut loader.ctx_mut(), &variable_base_scaled) - .unwrap() }) .map(RefCell::new); - let output = loader - .ecc_chip() - .sum_with_const( - &mut loader.ctx_mut(), - &variable_base_non_scaled - .into_iter() - .map(EcPoint::assigned) - .chain(fixed_base_msm.as_ref().map(RefCell::borrow)) - .chain(variable_base_msm.as_ref().map(RefCell::borrow)) - .collect_vec(), - constant, - ) - .unwrap(); + let output = loader.ecc_chip().sum_with_const( + &mut loader.ctx_mut(), + &variable_base_non_scaled + .into_iter() + .map(EcPoint::assigned) + .chain(fixed_base_msm.as_ref().map(RefCell::borrow)) + .chain(variable_base_msm.as_ref().map(RefCell::borrow)) + .collect_vec(), + constant, + ); loader.ec_point_from_assigned(output) } } -impl<'a, C: CurveAffine, EccChip: EccInstructions<'a, C>> Loader - for Rc> -{ - #[cfg(test)] - fn start_cost_metering(&self, identifier: &str) { - self.start_row_metering(identifier) - } - - #[cfg(test)] - fn end_cost_metering(&self) { - self.end_row_metering() - } -} +impl> Loader for Rc> {} diff --git a/snark-verifier/src/loader/halo2/shim.rs b/snark-verifier/src/loader/halo2/shim.rs index 588e9482..6192bfe6 100644 --- a/snark-verifier/src/loader/halo2/shim.rs +++ b/snark-verifier/src/loader/halo2/shim.rs @@ -1,39 +1,25 @@ -use crate::halo2_proofs::{ - circuit::{Cell, Value}, - plonk::Error, -}; use crate::util::arithmetic::{CurveAffine, FieldExt}; use std::{fmt::Debug, ops::Deref}; -pub trait Context: Debug { - fn constrain_equal(&mut self, lhs: Cell, rhs: Cell) -> Result<(), Error>; - - fn offset(&self) -> usize; -} - -pub trait IntegerInstructions<'a, F: FieldExt>: Clone + Debug { - type Context: Context; +pub trait IntegerInstructions: Clone + Debug { + type Context: Debug; type AssignedCell: Clone + Debug; type AssignedInteger: Clone + Debug; fn assign_integer( &self, ctx: &mut Self::Context, - integer: Value, - ) -> Result; + integer: F, // witness + ) -> Self::AssignedInteger; - fn assign_constant( - &self, - ctx: &mut Self::Context, - integer: F, - ) -> Result; + fn assign_constant(&self, ctx: &mut Self::Context, integer: F) -> Self::AssignedInteger; fn sum_with_coeff_and_const( &self, ctx: &mut Self::Context, values: &[(F::Scalar, impl Deref)], constant: F::Scalar, - ) -> Result; + ) -> Self::AssignedInteger; fn sum_products_with_coeff_and_const( &self, @@ -44,39 +30,34 @@ pub trait IntegerInstructions<'a, F: FieldExt>: Clone + Debug { impl Deref, )], constant: F::Scalar, - ) -> Result; + ) -> Self::AssignedInteger; fn sub( &self, ctx: &mut Self::Context, lhs: &Self::AssignedInteger, rhs: &Self::AssignedInteger, - ) -> Result; + ) -> Self::AssignedInteger; - fn neg( - &self, - ctx: &mut Self::Context, - value: &Self::AssignedInteger, - ) -> Result; + fn neg(&self, ctx: &mut Self::Context, value: &Self::AssignedInteger) -> Self::AssignedInteger; fn invert( &self, ctx: &mut Self::Context, value: &Self::AssignedInteger, - ) -> Result; + ) -> Self::AssignedInteger; fn assert_equal( &self, ctx: &mut Self::Context, lhs: &Self::AssignedInteger, rhs: &Self::AssignedInteger, - ) -> Result<(), Error>; + ); } -pub trait EccInstructions<'a, C: CurveAffine>: Clone + Debug { - type Context: Context; +pub trait EccInstructions: Clone + Debug { + type Context: Debug + Default; type ScalarChip: IntegerInstructions< - 'a, C::Scalar, Context = Self::Context, AssignedCell = Self::AssignedCell, @@ -88,30 +69,22 @@ pub trait EccInstructions<'a, C: CurveAffine>: Clone + Debug { fn scalar_chip(&self) -> &Self::ScalarChip; - fn assign_constant( - &self, - ctx: &mut Self::Context, - ec_point: C, - ) -> Result; + fn assign_constant(&self, ctx: &mut Self::Context, ec_point: C) -> Self::AssignedEcPoint; - fn assign_point( - &self, - ctx: &mut Self::Context, - ec_point: Value, - ) -> Result; + fn assign_point(&self, ctx: &mut Self::Context, ec_point: C) -> Self::AssignedEcPoint; fn sum_with_const( &self, ctx: &mut Self::Context, values: &[impl Deref], constant: C, - ) -> Result; + ) -> Self::AssignedEcPoint; fn fixed_base_msm( &mut self, ctx: &mut Self::Context, pairs: &[(impl Deref, C)], - ) -> Result; + ) -> Self::AssignedEcPoint; fn variable_base_msm( &mut self, @@ -120,76 +93,49 @@ pub trait EccInstructions<'a, C: CurveAffine>: Clone + Debug { impl Deref, impl Deref, )], - ) -> Result; + ) -> Self::AssignedEcPoint; fn assert_equal( &self, ctx: &mut Self::Context, lhs: &Self::AssignedEcPoint, rhs: &Self::AssignedEcPoint, - ) -> Result<(), Error>; + ); } mod halo2_lib { - use crate::halo2_proofs::{ - circuit::{Cell, Value}, - halo2curves::CurveAffineExt, - plonk::Error, - }; + use crate::halo2_proofs::halo2curves::CurveAffineExt; use crate::{ - loader::halo2::{Context, EccInstructions, IntegerInstructions}, + loader::halo2::{EccInstructions, IntegerInstructions}, util::arithmetic::{CurveAffine, Field}, }; use halo2_base::{ self, - gates::{flex_gate::FlexGateConfig, GateInstructions, RangeInstructions}, - utils::PrimeField, + gates::{builder::GateThreadBuilder, GateChip, GateInstructions, RangeInstructions}, AssignedValue, - QuantumCell::{Constant, Existing, Witness}, + QuantumCell::{Constant, Existing}, }; use halo2_ecc::{ bigint::CRTInteger, ecc::{fixed_base::FixedEcPoint, BaseFieldEccChip, EcPoint}, - fields::FieldChip, + fields::{FieldChip, PrimeField}, }; - use std::ops::Deref; - - type AssignedInteger<'v, C> = CRTInteger<'v, ::ScalarExt>; - type AssignedEcPoint<'v, C> = EcPoint<::ScalarExt, AssignedInteger<'v, C>>; - - impl<'a, F: PrimeField> Context for halo2_base::Context<'a, F> { - fn constrain_equal(&mut self, lhs: Cell, rhs: Cell) -> Result<(), Error> { - #[cfg(feature = "halo2-axiom")] - self.region.constrain_equal(&lhs, &rhs); - #[cfg(feature = "halo2-pse")] - self.region.constrain_equal(lhs, rhs); - Ok(()) - } + use std::{ops::Deref, sync::Mutex}; - fn offset(&self) -> usize { - unreachable!() - } - } + type AssignedInteger = CRTInteger<::ScalarExt>; + type AssignedEcPoint = EcPoint<::ScalarExt, AssignedInteger>; - impl<'a, F: PrimeField> IntegerInstructions<'a, F> for FlexGateConfig { - type Context = halo2_base::Context<'a, F>; - type AssignedCell = AssignedValue<'a, F>; - type AssignedInteger = AssignedValue<'a, F>; + impl IntegerInstructions for GateChip { + type Context = GateThreadBuilder; + type AssignedCell = AssignedValue; + type AssignedInteger = AssignedValue; - fn assign_integer( - &self, - ctx: &mut Self::Context, - integer: Value, - ) -> Result { - Ok(self.assign_region_last(ctx, vec![Witness(integer)], vec![])) + fn assign_integer(&self, ctx: &mut Self::Context, integer: F) -> Self::AssignedInteger { + ctx.main(0).load_witness(integer) } - fn assign_constant( - &self, - ctx: &mut Self::Context, - integer: F, - ) -> Result { - Ok(self.assign_region_last(ctx, vec![Constant(integer)], vec![])) + fn assign_constant(&self, ctx: &mut Self::Context, integer: F) -> Self::AssignedInteger { + ctx.main(0).load_constant(integer) } fn sum_with_coeff_and_const( @@ -197,16 +143,16 @@ mod halo2_lib { ctx: &mut Self::Context, values: &[(F::Scalar, impl Deref)], constant: F, - ) -> Result { + ) -> Self::AssignedInteger { let mut a = Vec::with_capacity(values.len() + 1); let mut b = Vec::with_capacity(values.len() + 1); if constant != F::zero() { a.push(Constant(constant)); b.push(Constant(F::one())); } - a.extend(values.iter().map(|(_, a)| Existing(a))); + a.extend(values.iter().map(|(_, a)| Existing(*a.deref()))); b.extend(values.iter().map(|(c, _)| Constant(*c))); - Ok(self.inner_product(ctx, a, b)) + self.inner_product(ctx.main(0), a, b) } fn sum_products_with_coeff_and_const( @@ -218,14 +164,14 @@ mod halo2_lib { impl Deref, )], constant: F, - ) -> Result { + ) -> Self::AssignedInteger { match values.len() { - 0 => self.assign_constant(ctx, constant), - _ => Ok(self.sum_products_with_coeff_and_var( - ctx, - values.iter().map(|(c, a, b)| (*c, Existing(a), Existing(b))), + 0 => ctx.main(0).load_constant(constant), + _ => self.sum_products_with_coeff_and_var( + ctx.main(0), + values.iter().map(|(c, a, b)| (*c, Existing(*a.deref()), Existing(*b.deref()))), Constant(constant), - )), + ), } } @@ -234,27 +180,23 @@ mod halo2_lib { ctx: &mut Self::Context, a: &Self::AssignedInteger, b: &Self::AssignedInteger, - ) -> Result { - Ok(GateInstructions::sub(self, ctx, Existing(a), Existing(b))) + ) -> Self::AssignedInteger { + GateInstructions::sub(self, ctx.main(0), Existing(*a), Existing(*b)) } - fn neg( - &self, - ctx: &mut Self::Context, - a: &Self::AssignedInteger, - ) -> Result { - Ok(GateInstructions::neg(self, ctx, Existing(a))) + fn neg(&self, ctx: &mut Self::Context, a: &Self::AssignedInteger) -> Self::AssignedInteger { + GateInstructions::neg(self, ctx.main(0), Existing(*a)) } fn invert( &self, ctx: &mut Self::Context, a: &Self::AssignedInteger, - ) -> Result { + ) -> Self::AssignedInteger { // make sure scalar != 0 - let is_zero = self.is_zero(ctx, a); - self.assert_is_const(ctx, &is_zero, F::zero()); - Ok(GateInstructions::div_unsafe(self, ctx, Constant(F::one()), Existing(a))) + let is_zero = self.is_zero(ctx.main(0), *a); + self.assert_is_const(ctx.main(0), &is_zero, &F::zero()); + GateInstructions::div_unsafe(self, ctx.main(0), Constant(F::one()), Existing(*a)) } fn assert_equal( @@ -262,54 +204,40 @@ mod halo2_lib { ctx: &mut Self::Context, a: &Self::AssignedInteger, b: &Self::AssignedInteger, - ) -> Result<(), Error> { - ctx.region.constrain_equal(a.cell(), b.cell()); - Ok(()) + ) { + ctx.main(0).constrain_equal(a, b); } } - impl<'a, C: CurveAffineExt> EccInstructions<'a, C> for BaseFieldEccChip + impl<'chip, C: CurveAffineExt> EccInstructions for BaseFieldEccChip<'chip, C> where C::ScalarExt: PrimeField, C::Base: PrimeField, { - type Context = halo2_base::Context<'a, C::Scalar>; - type ScalarChip = FlexGateConfig; - type AssignedCell = AssignedValue<'a, C::Scalar>; - type AssignedScalar = AssignedValue<'a, C::Scalar>; - type AssignedEcPoint = AssignedEcPoint<'a, C>; + type Context = GateThreadBuilder; + type ScalarChip = GateChip; + type AssignedCell = AssignedValue; + type AssignedScalar = AssignedValue; + type AssignedEcPoint = AssignedEcPoint; fn scalar_chip(&self) -> &Self::ScalarChip { self.field_chip.range().gate() } - fn assign_constant( - &self, - ctx: &mut Self::Context, - point: C, - ) -> Result { + fn assign_constant(&self, ctx: &mut Self::Context, point: C) -> Self::AssignedEcPoint { let fixed = FixedEcPoint::::from_curve( point, self.field_chip.num_limbs, self.field_chip.limb_bits, ); - Ok(FixedEcPoint::assign( - fixed, - self.field_chip(), - ctx, - self.field_chip().native_modulus(), - )) + FixedEcPoint::assign(fixed, self.field_chip(), ctx.main(0)) } - fn assign_point( - &self, - ctx: &mut Self::Context, - point: Value, - ) -> Result { - let assigned = self.assign_point(ctx, point); - let is_valid = self.is_on_curve_or_infinity::(ctx, &assigned); - self.field_chip.range.gate.assert_is_const(ctx, &is_valid, C::Scalar::one()); - Ok(assigned) + fn assign_point(&self, ctx: &mut Self::Context, point: C) -> Self::AssignedEcPoint { + let assigned = self.assign_point(ctx.main(0), point); + let is_valid = self.is_on_curve_or_infinity::(ctx.main(0), &assigned); + self.field_chip().gate().assert_is_const(ctx.main(0), &is_valid, &C::Scalar::one()); + assigned } fn sum_with_const( @@ -317,14 +245,14 @@ mod halo2_lib { ctx: &mut Self::Context, values: &[impl Deref], constant: C, - ) -> Result { + ) -> Self::AssignedEcPoint { let constant = if bool::from(constant.is_identity()) { None } else { - let constant = EccInstructions::::assign_constant(self, ctx, constant).unwrap(); + let constant = EccInstructions::::assign_constant(self, ctx, constant); Some(constant) }; - Ok(self.sum::(ctx, constant.iter().chain(values.iter().map(Deref::deref)))) + self.sum::(ctx.main(0), constant.iter().chain(values.iter().map(Deref::deref))) } fn variable_base_msm( @@ -334,47 +262,48 @@ mod halo2_lib { impl Deref, impl Deref, )], - ) -> Result { + ) -> Self::AssignedEcPoint { let (scalars, points): (Vec<_>, Vec<_>) = pairs .iter() - .map(|(scalar, point)| (vec![scalar.deref().clone()], point.deref().clone())) + .map(|(scalar, point)| (vec![*scalar.deref()], point.deref().clone())) .unzip(); - - Ok(BaseFieldEccChip::::variable_base_msm::( + let thread_pool = Mutex::new(std::mem::take(ctx)); + let res = BaseFieldEccChip::::variable_base_msm::( self, - ctx, + &thread_pool, &points, - &scalars, + scalars, C::Scalar::NUM_BITS as usize, - 4, // empirically clump factor of 4 seems to be best - )) + ); + *ctx = thread_pool.into_inner().unwrap(); + res } fn fixed_base_msm( &mut self, ctx: &mut Self::Context, pairs: &[(impl Deref, C)], - ) -> Result { + ) -> Self::AssignedEcPoint { let (scalars, points): (Vec<_>, Vec<_>) = pairs .iter() .filter_map(|(scalar, point)| { if point.is_identity().into() { None } else { - Some((vec![scalar.deref().clone()], *point)) + Some((vec![*scalar.deref()], *point)) } }) .unzip(); - - Ok(BaseFieldEccChip::::fixed_base_msm::( + let thread_pool = Mutex::new(std::mem::take(ctx)); + let res = BaseFieldEccChip::::fixed_base_msm::( self, - ctx, + &thread_pool, &points, - &scalars, + scalars, C::Scalar::NUM_BITS as usize, - 0, - 4, - )) + ); + *ctx = thread_pool.into_inner().unwrap(); + res } fn assert_equal( @@ -382,322 +311,8 @@ mod halo2_lib { ctx: &mut Self::Context, a: &Self::AssignedEcPoint, b: &Self::AssignedEcPoint, - ) -> Result<(), Error> { - self.assert_equal(ctx, a, b); - Ok(()) - } - } -} - -/* -mod halo2_wrong { - use crate::{ - loader::halo2::{Context, EccInstructions, IntegerInstructions}, - util::{ - arithmetic::{CurveAffine, FieldExt, Group}, - Itertools, - }, - }; - use halo2_proofs::{ - circuit::{AssignedCell, Cell, Value}, - plonk::Error, - }; - use halo2_wrong_ecc::{ - integer::rns::Common, - maingate::{ - CombinationOption, CombinationOptionCommon, MainGate, MainGateInstructions, RegionCtx, - Term, - }, - AssignedPoint, BaseFieldEccChip, - }; - use rand::rngs::OsRng; - use std::{iter, ops::Deref}; - - impl<'a, F: FieldExt> Context for RegionCtx<'a, F> { - fn constrain_equal(&mut self, lhs: Cell, rhs: Cell) -> Result<(), Error> { - self.constrain_equal(lhs, rhs) - } - - fn offset(&self) -> usize { - self.offset() - } - } - - impl<'a, F: FieldExt> IntegerInstructions<'a, F> for MainGate { - type Context = RegionCtx<'a, F>; - type AssignedCell = AssignedCell; - type AssignedInteger = AssignedCell; - - fn assign_integer( - &self, - ctx: &mut Self::Context, - integer: Value, - ) -> Result { - self.assign_value(ctx, integer) - } - - fn assign_constant( - &self, - ctx: &mut Self::Context, - integer: F, - ) -> Result { - MainGateInstructions::assign_constant(self, ctx, integer) - } - - fn sum_with_coeff_and_const( - &self, - ctx: &mut Self::Context, - values: &[(F, impl Deref)], - constant: F, - ) -> Result { - self.compose( - ctx, - &values - .iter() - .map(|(coeff, assigned)| Term::Assigned(assigned, *coeff)) - .collect_vec(), - constant, - ) - } - - fn sum_products_with_coeff_and_const( - &self, - ctx: &mut Self::Context, - values: &[( - F, - impl Deref, - impl Deref, - )], - constant: F, - ) -> Result { - match values.len() { - 0 => MainGateInstructions::assign_constant(self, ctx, constant), - 1 => { - let (scalar, lhs, rhs) = &values[0]; - let output = lhs - .value() - .zip(rhs.value()) - .map(|(lhs, rhs)| *scalar * lhs * rhs + constant); - - Ok(self - .apply( - ctx, - [ - Term::Zero, - Term::Zero, - Term::assigned_to_mul(lhs), - Term::assigned_to_mul(rhs), - Term::unassigned_to_sub(output), - ], - constant, - CombinationOption::OneLinerDoubleMul(*scalar), - )? - .swap_remove(4)) - } - _ => { - let (scalar, lhs, rhs) = &values[0]; - self.apply( - ctx, - [Term::assigned_to_mul(lhs), Term::assigned_to_mul(rhs)], - constant, - CombinationOptionCommon::CombineToNextScaleMul(-F::one(), *scalar).into(), - )?; - let acc = - Value::known(*scalar) * lhs.value() * rhs.value() + Value::known(constant); - let output = values.iter().skip(1).fold( - Ok::<_, Error>(acc), - |acc, (scalar, lhs, rhs)| { - acc.and_then(|acc| { - self.apply( - ctx, - [ - Term::assigned_to_mul(lhs), - Term::assigned_to_mul(rhs), - Term::Zero, - Term::Zero, - Term::Unassigned(acc, F::one()), - ], - F::zero(), - CombinationOptionCommon::CombineToNextScaleMul( - -F::one(), - *scalar, - ) - .into(), - )?; - Ok(acc + Value::known(*scalar) * lhs.value() * rhs.value()) - }) - }, - )?; - self.apply( - ctx, - [ - Term::Zero, - Term::Zero, - Term::Zero, - Term::Zero, - Term::Unassigned(output, F::zero()), - ], - F::zero(), - CombinationOptionCommon::OneLinerAdd.into(), - ) - .map(|mut outputs| outputs.swap_remove(4)) - } - } - } - - fn sub( - &self, - ctx: &mut Self::Context, - lhs: &Self::AssignedInteger, - rhs: &Self::AssignedInteger, - ) -> Result { - MainGateInstructions::sub(self, ctx, lhs, rhs) - } - - fn neg( - &self, - ctx: &mut Self::Context, - value: &Self::AssignedInteger, - ) -> Result { - MainGateInstructions::neg_with_constant(self, ctx, value, F::zero()) - } - - fn invert( - &self, - ctx: &mut Self::Context, - value: &Self::AssignedInteger, - ) -> Result { - MainGateInstructions::invert_unsafe(self, ctx, value) - } - - fn assert_equal( - &self, - ctx: &mut Self::Context, - lhs: &Self::AssignedInteger, - rhs: &Self::AssignedInteger, - ) -> Result<(), Error> { - let mut eq = true; - lhs.value().zip(rhs.value()).map(|(lhs, rhs)| { - eq &= lhs == rhs; - }); - MainGateInstructions::assert_equal(self, ctx, lhs, rhs) - .and(eq.then_some(()).ok_or(Error::Synthesis)) - } - } - - impl<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize> EccInstructions<'a, C> - for BaseFieldEccChip - { - type Context = RegionCtx<'a, C::Scalar>; - type ScalarChip = MainGate; - type AssignedCell = AssignedCell; - type AssignedScalar = AssignedCell; - type AssignedEcPoint = AssignedPoint; - - fn scalar_chip(&self) -> &Self::ScalarChip { - self.main_gate() - } - - fn assign_constant( - &self, - ctx: &mut Self::Context, - ec_point: C, - ) -> Result { - self.assign_constant(ctx, ec_point) - } - - fn assign_point( - &self, - ctx: &mut Self::Context, - ec_point: Value, - ) -> Result { - self.assign_point(ctx, ec_point) - } - - fn sum_with_const( - &self, - ctx: &mut Self::Context, - values: &[impl Deref], - constant: C, - ) -> Result { - if values.is_empty() { - return self.assign_constant(ctx, constant); - } - - let constant = (!bool::from(constant.is_identity())) - .then(|| self.assign_constant(ctx, constant)) - .transpose()?; - let output = iter::empty() - .chain(constant) - .chain(values.iter().map(|value| value.deref().clone())) - .map(Ok) - .reduce(|acc, ec_point| self.add(ctx, &acc?, &ec_point?)) - .unwrap()?; - self.normalize(ctx, &output) - } - - fn fixed_base_msm( - &mut self, - ctx: &mut Self::Context, - pairs: &[(impl Deref, C)], - ) -> Result { - assert!(!pairs.is_empty()); - - // FIXME: Implement fixed base MSM in halo2_wrong - let pairs = pairs - .iter() - .filter(|(_, base)| !bool::from(base.is_identity())) - .map(|(scalar, base)| { - Ok::<_, Error>((scalar.deref().clone(), self.assign_constant(ctx, *base)?)) - }) - .collect::, _>>()?; - let pairs = pairs.iter().map(|(scalar, base)| (scalar, base)).collect_vec(); - self.variable_base_msm(ctx, &pairs) - } - - fn variable_base_msm( - &mut self, - ctx: &mut Self::Context, - pairs: &[( - impl Deref, - impl Deref, - )], - ) -> Result { - assert!(!pairs.is_empty()); - - const WINDOW_SIZE: usize = 3; - let pairs = pairs - .iter() - .map(|(scalar, base)| (base.deref().clone(), scalar.deref().clone())) - .collect_vec(); - let output = match self.mul_batch_1d_horizontal(ctx, pairs.clone(), WINDOW_SIZE) { - Err(_) => { - if self.assign_aux(ctx, WINDOW_SIZE, pairs.len()).is_err() { - let aux_generator = Value::known(C::Curve::random(OsRng).into()); - self.assign_aux_generator(ctx, aux_generator)?; - self.assign_aux(ctx, WINDOW_SIZE, pairs.len())?; - } - self.mul_batch_1d_horizontal(ctx, pairs, WINDOW_SIZE) - } - result => result, - }?; - self.normalize(ctx, &output) - } - - fn assert_equal( - &self, - ctx: &mut Self::Context, - lhs: &Self::AssignedEcPoint, - rhs: &Self::AssignedEcPoint, - ) -> Result<(), Error> { - let mut eq = true; - [(lhs.x(), rhs.x()), (lhs.y(), rhs.y())].map(|(lhs, rhs)| { - lhs.integer().zip(rhs.integer()).map(|(lhs, rhs)| { - eq &= lhs.value() == rhs.value(); - }); - }); - self.assert_equal(ctx, lhs, rhs).and(eq.then_some(()).ok_or(Error::Synthesis)) + ) { + self.assert_equal(ctx.main(0), a, b); } } } -*/ diff --git a/snark-verifier/src/loader/native.rs b/snark-verifier/src/loader/native.rs index 6fce383a..f76ca5ef 100644 --- a/snark-verifier/src/loader/native.rs +++ b/snark-verifier/src/loader/native.rs @@ -47,10 +47,10 @@ impl EcPointLoader for NativeLoader { annotation: &str, lhs: &Self::LoadedEcPoint, rhs: &Self::LoadedEcPoint, - ) -> Result<(), Error> { + ) { lhs.eq(rhs) .then_some(()) - .ok_or_else(|| Error::AssertionFailure(annotation.to_string())) + .unwrap_or_else(|| panic!("{:?}", Error::AssertionFailure(annotation.to_string()))); } fn multi_scalar_multiplication( @@ -73,15 +73,10 @@ impl ScalarLoader for NativeLoader { *value } - fn assert_eq( - &self, - annotation: &str, - lhs: &Self::LoadedScalar, - rhs: &Self::LoadedScalar, - ) -> Result<(), Error> { + fn assert_eq(&self, annotation: &str, lhs: &Self::LoadedScalar, rhs: &Self::LoadedScalar) { lhs.eq(rhs) .then_some(()) - .ok_or_else(|| Error::AssertionFailure(annotation.to_string())) + .unwrap_or_else(|| panic!("{:?}", Error::AssertionFailure(annotation.to_string()))); } } diff --git a/snark-verifier/src/pcs/ipa.rs b/snark-verifier/src/pcs/ipa.rs index a2b34824..a29515f0 100644 --- a/snark-verifier/src/pcs/ipa.rs +++ b/snark-verifier/src/pcs/ipa.rs @@ -1,3 +1,4 @@ +// IPA is turned off in this repo for now! use crate::{ loader::{native::NativeLoader, LoadedScalar, Loader, ScalarLoader}, pcs::PolynomialCommitmentScheme, @@ -151,11 +152,8 @@ where let h_prime = h * &proof.xi_0; let lhs = { - let c_prime = match ( - s.as_ref(), - proof.c_bar_alpha.as_ref(), - proof.omega_prime.as_ref(), - ) { + let c_prime = match (s.as_ref(), proof.c_bar_alpha.as_ref(), proof.omega_prime.as_ref()) + { (Some(s), Some((c_bar, alpha)), Some(omega_prime)) => { let s = Msm::::base(s); commitment.clone() + Msm::base(c_bar) * alpha - s * omega_prime @@ -230,9 +228,7 @@ impl IpaProvingKey { let domain = Domain::new(k, root_of_unity(k)); let mut g = vec![C::default(); 1 << k]; C::Curve::batch_normalize( - &iter::repeat_with(|| C::Curve::random(&mut rng)) - .take(1 << k) - .collect_vec(), + &iter::repeat_with(|| C::Curve::random(&mut rng)).take(1 << k).collect_vec(), &mut g, ); let h = C::Curve::random(&mut rng).to_affine(); @@ -285,14 +281,7 @@ where u: L::LoadedEcPoint, c: L::LoadedScalar, ) -> Self { - Self { - c_bar_alpha, - omega_prime, - xi_0, - rounds, - u, - c, - } + Self { c_bar_alpha, omega_prime, xi_0, rounds, u, c } } pub fn read(svk: &IpaSuccinctVerifyingKey, transcript: &mut T) -> Result @@ -320,14 +309,7 @@ where .collect::, _>>()?; let u = transcript.read_ec_point()?; let c = transcript.read_scalar()?; - Ok(Self { - c_bar_alpha, - omega_prime, - xi_0, - rounds, - u, - c, - }) + Ok(Self { c_bar_alpha, omega_prime, xi_0, rounds, u, c }) } pub fn xi(&self) -> Vec { @@ -338,10 +320,7 @@ where let mut xi_inv = self.xi().into_iter().map(Fraction::one_over).collect_vec(); L::batch_invert(xi_inv.iter_mut().filter_map(Fraction::denom_mut)); xi_inv.iter_mut().for_each(Fraction::evaluate); - xi_inv - .into_iter() - .map(|xi_inv| xi_inv.evaluated().clone()) - .collect() + xi_inv.into_iter().map(|xi_inv| xi_inv.evaluated().clone()).collect() } } diff --git a/snark-verifier/src/pcs/kzg/accumulator.rs b/snark-verifier/src/pcs/kzg/accumulator.rs index efc28cd8..7ef593d0 100644 --- a/snark-verifier/src/pcs/kzg/accumulator.rs +++ b/snark-verifier/src/pcs/kzg/accumulator.rs @@ -61,7 +61,7 @@ mod native { .into_iter() .map(|limbs| { fe_from_limbs::<_, _, LIMBS, BITS>( - limbs.iter().map(|limb| **limb).collect_vec().try_into().unwrap(), + &limbs.iter().map(|limb| **limb).collect_vec(), ) }) .collect_vec() @@ -131,9 +131,8 @@ pub use halo2::LimbsEncodingInstructions; #[cfg(feature = "loader_halo2")] mod halo2 { - use crate::halo2_proofs::{circuit::Value, plonk}; use crate::{ - loader::halo2::{EccInstructions, Halo2Loader, Scalar, Valuetools}, + loader::halo2::{EccInstructions, Halo2Loader, Scalar}, pcs::{ kzg::{KzgAccumulator, LimbsEncoding}, AccumulatorEncoding, PolynomialCommitmentScheme, @@ -147,64 +146,52 @@ mod halo2 { use std::{iter, ops::Deref, rc::Rc}; fn ec_point_from_limbs( - limbs: &[Value<&C::Scalar>], - ) -> Value { + limbs: &[C::Scalar], + ) -> C { assert_eq!(limbs.len(), 2 * LIMBS); - let [x, y] = [&limbs[..LIMBS], &limbs[LIMBS..]].map(|limbs| { - limbs - .iter() - .cloned() - .fold_zipped(Vec::new(), |mut acc, limb| { - acc.push(*limb); - acc - }) - .map(|limbs| fe_from_limbs::<_, _, LIMBS, BITS>(limbs.try_into().unwrap())) - }); + let [x, y] = [&limbs[..LIMBS], &limbs[LIMBS..]].map(fe_from_limbs::<_, _, LIMBS, BITS>); - x.zip(y).map(|(x, y)| C::from_xy(x, y).unwrap()) + C::from_xy(x, y).unwrap() } - pub trait LimbsEncodingInstructions<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize>: - EccInstructions<'a, C> + pub trait LimbsEncodingInstructions: + EccInstructions { fn assign_ec_point_from_limbs( &self, ctx: &mut Self::Context, limbs: &[impl Deref], - ) -> Result; + ) -> Self::AssignedEcPoint; fn assign_ec_point_to_limbs( &self, ctx: &mut Self::Context, ec_point: impl Deref, - ) -> Result, plonk::Error>; + ) -> Vec; } - impl<'a, C, PCS, EccChip, const LIMBS: usize, const BITS: usize> - AccumulatorEncoding>, PCS> for LimbsEncoding + impl + AccumulatorEncoding>, PCS> for LimbsEncoding where C: CurveAffine, PCS: PolynomialCommitmentScheme< C, - Rc>, - Accumulator = KzgAccumulator>>, + Rc>, + Accumulator = KzgAccumulator>>, >, - EccChip: LimbsEncodingInstructions<'a, C, LIMBS, BITS>, + EccChip: LimbsEncodingInstructions, { - fn from_repr(limbs: &[&Scalar<'a, C, EccChip>]) -> Result { + fn from_repr(limbs: &[&Scalar]) -> Result { assert_eq!(limbs.len(), 4 * LIMBS); let loader = limbs[0].loader(); let [lhs, rhs] = [&limbs[..2 * LIMBS], &limbs[2 * LIMBS..]].map(|limbs| { - let assigned = loader - .ecc_chip() - .assign_ec_point_from_limbs( - &mut loader.ctx_mut(), - &limbs.iter().map(|limb| limb.assigned()).collect_vec(), - ) - .unwrap(); + let assigned = loader.ecc_chip().assign_ec_point_from_limbs( + &mut loader.ctx_mut(), + &limbs.iter().map(|limb| limb.assigned()).collect_vec(), + ); loader.ec_point_from_assigned(assigned) }); @@ -214,11 +201,11 @@ mod halo2 { mod halo2_lib { use super::*; - use halo2_base::{halo2_proofs::halo2curves::CurveAffineExt, utils::PrimeField}; - use halo2_ecc::ecc::BaseFieldEccChip; + use halo2_base::halo2_proofs::halo2curves::CurveAffineExt; + use halo2_ecc::{ecc::BaseFieldEccChip, fields::PrimeField}; - impl<'a, C, const LIMBS: usize, const BITS: usize> - LimbsEncodingInstructions<'a, C, LIMBS, BITS> for BaseFieldEccChip + impl<'chip, C, const LIMBS: usize, const BITS: usize> + LimbsEncodingInstructions for BaseFieldEccChip<'chip, C> where C: CurveAffineExt, C::ScalarExt: PrimeField, @@ -228,13 +215,13 @@ mod halo2 { &self, ctx: &mut Self::Context, limbs: &[impl Deref], - ) -> Result { + ) -> Self::AssignedEcPoint { assert_eq!(limbs.len(), 2 * LIMBS); let ec_point = self.assign_point::( - ctx, + ctx.main(0), ec_point_from_limbs::<_, LIMBS, BITS>( - &limbs.iter().map(|limb| limb.value()).collect_vec(), + &limbs.iter().map(|limb| *limb.value()).collect_vec(), ), ); @@ -242,71 +229,23 @@ mod halo2 { .iter() .zip_eq(iter::empty().chain(ec_point.x().limbs()).chain(ec_point.y().limbs())) { - ctx.region.constrain_equal(src.cell(), dst.cell()); - } - - Ok(ec_point) - } - - fn assign_ec_point_to_limbs( - &self, - _: &mut Self::Context, - ec_point: impl Deref, - ) -> Result, plonk::Error> { - Ok(iter::empty() - .chain(ec_point.x().limbs()) - .chain(ec_point.y().limbs()) - .cloned() - .collect()) - } - } - } - - /* - mod halo2_wrong { - use super::*; - use halo2_wrong_ecc::BaseFieldEccChip; - - impl<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize> - LimbsEncodingInstructions<'a, C, LIMBS, BITS> for BaseFieldEccChip - { - fn assign_ec_point_from_limbs( - &self, - ctx: &mut Self::Context, - limbs: &[impl Deref], - ) -> Result { - assert_eq!(limbs.len(), 2 * LIMBS); - - let ec_point = self.assign_point( - ctx, - ec_point_from_limbs::<_, LIMBS, BITS>( - &limbs.iter().map(|limb| limb.value()).collect_vec(), - ), - )?; - - for (src, dst) in limbs - .iter() - .zip_eq(iter::empty().chain(ec_point.x().limbs()).chain(ec_point.y().limbs())) - { - ctx.constrain_equal(src.cell(), dst.as_ref().cell())?; + ctx.main(0).constrain_equal(src, dst); } - Ok(ec_point) + ec_point } fn assign_ec_point_to_limbs( &self, _: &mut Self::Context, ec_point: impl Deref, - ) -> Result, plonk::Error> { - Ok(iter::empty() + ) -> Vec { + iter::empty() .chain(ec_point.x().limbs()) .chain(ec_point.y().limbs()) - .map(|limb| limb.as_ref()) - .cloned() - .collect()) + .copied() + .collect() } } } - */ } diff --git a/snark-verifier/src/system/halo2.rs b/snark-verifier/src/system/halo2.rs index 1ba7c1cc..37f6e151 100644 --- a/snark-verifier/src/system/halo2.rs +++ b/snark-verifier/src/system/halo2.rs @@ -19,9 +19,9 @@ use std::{io, iter, mem::size_of}; // pub mod strategy; pub mod transcript; -#[cfg(test)] -#[cfg(feature = "loader_halo2")] -pub(crate) mod test; +// #[cfg(test)] +// #[cfg(feature = "loader_halo2")] +// pub(crate) mod test; #[derive(Clone, Debug, Default)] pub struct Config { diff --git a/snark-verifier/src/system/halo2/test.rs b/snark-verifier/src/system/halo2/test.rs index 88a2ff26..e492cac2 100644 --- a/snark-verifier/src/system/halo2/test.rs +++ b/snark-verifier/src/system/halo2/test.rs @@ -1,3 +1,4 @@ +// this module is outdated and turned off! see examples instead #![allow(dead_code)] #![allow(clippy::all)] use crate::halo2_proofs::{ diff --git a/snark-verifier/src/system/halo2/test/kzg/halo2.rs b/snark-verifier/src/system/halo2/test/kzg/halo2.rs index 9090a0a1..b962e779 100644 --- a/snark-verifier/src/system/halo2/test/kzg/halo2.rs +++ b/snark-verifier/src/system/halo2/test/kzg/halo2.rs @@ -41,7 +41,7 @@ use crate::{ verifier::{self, PlonkVerifier}, }; use ark_std::{end_timer, start_timer}; -use halo2_base::{Context, ContextParams}; +use halo2_base::Context; use halo2_ecc::ecc::EccChip; use halo2_ecc::fields::fp::FpConfig; use paste::paste; @@ -58,8 +58,8 @@ const RATE: usize = 4; const R_F: usize = 8; const R_P: usize = 60; -type BaseFieldEccChip = halo2_ecc::ecc::BaseFieldEccChip; -type Halo2Loader<'a> = loader::halo2::Halo2Loader<'a, G1Affine, BaseFieldEccChip>; +type BaseFieldEccChip<'chip> = halo2_ecc::ecc::BaseFieldEccChip<'chip, G1Affine>; +type Halo2Loader<'chip> = loader::halo2::Halo2Loader>; type PoseidonTranscript = GenericPoseidonTranscript; type Pcs = Kzg; @@ -69,26 +69,6 @@ type AsPk = KzgAsProvingKey; type AsVk = KzgAsVerifyingKey; type Plonk = verifier::Plonk>; -// for tuning the circuit -#[derive(Serialize, Deserialize)] -pub struct Halo2VerifierCircuitConfigParams { - pub strategy: halo2_ecc::fields::fp::FpStrategy, - pub degree: u32, - pub num_advice: usize, - pub num_lookup_advice: usize, - pub num_fixed: usize, - pub lookup_bits: usize, - pub limb_bits: usize, - pub num_limbs: usize, -} - -pub fn load_verify_circuit_degree() -> u32 { - let path = "./configs/verify_circuit.config"; - let params: Halo2VerifierCircuitConfigParams = - serde_json::from_reader(File::open(path).unwrap_or_else(|err| panic!("{err:?}"))).unwrap(); - params.degree -} - #[derive(Clone)] pub struct Halo2VerifierCircuitConfig { pub base_field_config: halo2_ecc::fields::fp::FpConfig, diff --git a/snark-verifier/src/system/halo2/transcript/halo2.rs b/snark-verifier/src/system/halo2/transcript/halo2.rs index 3c82d83b..73934b01 100644 --- a/snark-verifier/src/system/halo2/transcript/halo2.rs +++ b/snark-verifier/src/system/halo2/transcript/halo2.rs @@ -13,14 +13,14 @@ use crate::{ }, Error, }; -use halo2_proofs::{circuit::Value, transcript::EncodedChallenge}; +use halo2_proofs::transcript::EncodedChallenge; use std::{ io::{self, Read, Write}, rc::Rc, }; /// Encoding that encodes elliptic curve point into native field elements. -pub trait NativeEncoding<'a, C>: EccInstructions<'a, C> +pub trait NativeEncoding: EccInstructions where C: CurveAffine, { @@ -48,55 +48,55 @@ pub struct PoseidonTranscript< buf: Poseidon>::LoadedScalar, T, RATE>, } -impl<'a, C, R, EccChip, const T: usize, const RATE: usize, const R_F: usize, const R_P: usize> - PoseidonTranscript>, Value, T, RATE, R_F, R_P> +impl + PoseidonTranscript>, R, T, RATE, R_F, R_P> where C: CurveAffine, R: Read, - EccChip: NativeEncoding<'a, C>, + EccChip: NativeEncoding, { - pub fn new(loader: &Rc>, stream: Value) -> Self { + pub fn new(loader: &Rc>, stream: R) -> Self { let buf = Poseidon::new(loader, R_F, R_P); Self { loader: loader.clone(), stream, buf } } pub fn from_spec( - loader: &Rc>, - stream: Value, + loader: &Rc>, + stream: R, spec: crate::poseidon::Spec, ) -> Self { let buf = Poseidon::from_spec(loader, spec); Self { loader: loader.clone(), stream, buf } } - pub fn new_stream(&mut self, stream: Value) { + pub fn new_stream(&mut self, stream: R) { self.buf.clear(); self.stream = stream; } } -impl<'a, C, R, EccChip, const T: usize, const RATE: usize, const R_F: usize, const R_P: usize> - Transcript>> - for PoseidonTranscript>, Value, T, RATE, R_F, R_P> +impl + Transcript>> + for PoseidonTranscript>, R, T, RATE, R_F, R_P> where C: CurveAffine, R: Read, - EccChip: NativeEncoding<'a, C>, + EccChip: NativeEncoding, { - fn loader(&self) -> &Rc> { + fn loader(&self) -> &Rc> { &self.loader } - fn squeeze_challenge(&mut self) -> Scalar<'a, C, EccChip> { + fn squeeze_challenge(&mut self) -> Scalar { self.buf.squeeze() } - fn common_scalar(&mut self, scalar: &Scalar<'a, C, EccChip>) -> Result<(), Error> { + fn common_scalar(&mut self, scalar: &Scalar) -> Result<(), Error> { self.buf.update(&[scalar.clone()]); Ok(()) } - fn common_ec_point(&mut self, ec_point: &EcPoint<'a, C, EccChip>) -> Result<(), Error> { + fn common_ec_point(&mut self, ec_point: &EcPoint) -> Result<(), Error> { let encoded = self .loader .ecc_chip() @@ -118,39 +118,31 @@ where } } -impl<'a, C, R, EccChip, const T: usize, const RATE: usize, const R_F: usize, const R_P: usize> - TranscriptRead>> - for PoseidonTranscript>, Value, T, RATE, R_F, R_P> +impl + TranscriptRead>> + for PoseidonTranscript>, R, T, RATE, R_F, R_P> where C: CurveAffine, R: Read, - EccChip: NativeEncoding<'a, C>, + EccChip: NativeEncoding, { - fn read_scalar(&mut self) -> Result, Error> { - let scalar = self.stream.as_mut().and_then(|stream| { + fn read_scalar(&mut self) -> Result, Error> { + let scalar = { let mut data = ::Repr::default(); - if stream.read_exact(data.as_mut()).is_err() { - return Value::unknown(); - } - Option::::from(C::Scalar::from_repr(data)) - .map(Value::known) - .unwrap_or_else(Value::unknown) - }); + self.stream.read_exact(data.as_mut()).unwrap(); + C::Scalar::from_repr(data).unwrap() + }; let scalar = self.loader.assign_scalar(scalar); self.common_scalar(&scalar)?; Ok(scalar) } - fn read_ec_point(&mut self) -> Result, Error> { - let ec_point = self.stream.as_mut().and_then(|stream| { + fn read_ec_point(&mut self) -> Result, Error> { + let ec_point = { let mut compressed = C::Repr::default(); - if stream.read_exact(compressed.as_mut()).is_err() { - return Value::unknown(); - } - Option::::from(C::from_bytes(&compressed)) - .map(Value::known) - .unwrap_or_else(Value::unknown) - }); + self.stream.read_exact(compressed.as_mut()).unwrap(); + C::from_bytes(&compressed).unwrap() + }; let ec_point = self.loader.assign_ec_point(ec_point); self.common_ec_point(&ec_point)?; Ok(ec_point) @@ -405,10 +397,9 @@ where mod halo2_lib { use crate::halo2_curves::CurveAffineExt; use crate::system::halo2::transcript::halo2::NativeEncoding; - use halo2_base::utils::PrimeField; - use halo2_ecc::ecc::BaseFieldEccChip; + use halo2_ecc::{ecc::BaseFieldEccChip, fields::PrimeField}; - impl<'a, C: CurveAffineExt> NativeEncoding<'a, C> for BaseFieldEccChip + impl<'chip, C: CurveAffineExt> NativeEncoding for BaseFieldEccChip<'chip, C> where C::Scalar: PrimeField, C::Base: PrimeField, @@ -418,31 +409,7 @@ mod halo2_lib { _: &mut Self::Context, ec_point: &Self::AssignedEcPoint, ) -> Result, crate::Error> { - Ok(vec![ec_point.x().native().clone(), ec_point.y().native().clone()]) + Ok(vec![*ec_point.x().native(), *ec_point.y().native()]) } } } - -/* -mod halo2_wrong { - use crate::system::halo2::transcript::halo2::NativeEncoding; - use halo2_curves::CurveAffine; - use halo2_proofs::circuit::AssignedCell; - use halo2_wrong_ecc::BaseFieldEccChip; - - impl<'a, C: CurveAffine, const LIMBS: usize, const BITS: usize> NativeEncoding<'a, C> - for BaseFieldEccChip - { - fn encode( - &self, - _: &mut Self::Context, - ec_point: &Self::AssignedEcPoint, - ) -> Result>, crate::Error> { - Ok(vec![ - ec_point.x().native().clone(), - ec_point.y().native().clone(), - ]) - } - } -} -*/ diff --git a/snark-verifier/src/util/arithmetic.rs b/snark-verifier/src/util/arithmetic.rs index 2d24961e..6422a968 100644 --- a/snark-verifier/src/util/arithmetic.rs +++ b/snark-verifier/src/util/arithmetic.rs @@ -210,8 +210,9 @@ pub fn fe_to_fe(fe: F1) -> F2 { } pub fn fe_from_limbs( - limbs: [F1; LIMBS], + limbs: &[F1], ) -> F2 { + assert_eq!(limbs.len(), LIMBS); fe_from_big( limbs .iter() From c9e2d2cfb539c854e113efc464e6a5b1fe803715 Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Sun, 19 Feb 2023 13:35:24 -0800 Subject: [PATCH 18/73] feat: update zkevm bench --- snark-verifier-sdk/Cargo.toml | 8 +- snark-verifier-sdk/benches/zkevm.rs | 24 +- .../benches/zkevm_plus_state.rs | 137 +++--- snark-verifier-sdk/configs/bench_zkevm.json | 7 + .../configs/bench_zkevm_plus_state.json | 7 + .../configs/example_evm_accumulator.json | 10 + .../configs/verify_circuit.config | 1 - snark-verifier-sdk/src/halo2/aggregation.rs | 41 +- snark-verifier-sdk/src/lib.rs | 4 +- snark-verifier/examples/recursion.rs | 449 +++++++----------- 10 files changed, 343 insertions(+), 345 deletions(-) create mode 100644 snark-verifier-sdk/configs/bench_zkevm.json create mode 100644 snark-verifier-sdk/configs/bench_zkevm_plus_state.json create mode 100644 snark-verifier-sdk/configs/example_evm_accumulator.json delete mode 100644 snark-verifier-sdk/configs/verify_circuit.config diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 515c4546..f7339196 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -28,10 +28,10 @@ ethereum-types = { version = "0.14", default-features = false, features = ["std" # rlp = { version = "0.5", default-features = false, features = ["std"], optional = true } # zkevm benchmarks -zkevm-circuits = { git = "https://github.com/jonathanpwang/zkevm-circuits.git", branch = "bench-12-04", features = ["test"], optional = true } -bus-mapping = { git = "https://github.com/jonathanpwang/zkevm-circuits.git", branch = "bench-12-04", optional = true } -eth-types = { git = "https://github.com/jonathanpwang/zkevm-circuits.git", branch = "bench-12-04", optional = true } -mock = { git = "https://github.com/jonathanpwang/zkevm-circuits.git", branch = "bench-12-04", optional = true } +zkevm-circuits = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", features = ["test"], optional = true } +bus-mapping = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } +eth-types = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } +mock = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } [dev-dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } diff --git a/snark-verifier-sdk/benches/zkevm.rs b/snark-verifier-sdk/benches/zkevm.rs index e6b4c4e7..e4ab7e16 100644 --- a/snark-verifier-sdk/benches/zkevm.rs +++ b/snark-verifier-sdk/benches/zkevm.rs @@ -1,6 +1,6 @@ use ark_std::{end_timer, start_timer}; -use halo2_base::halo2_proofs; use halo2_base::utils::fs::gen_srs; +use halo2_base::{gates::builder::CircuitBuilderStage, halo2_proofs}; use halo2_proofs::halo2curves::bn256::Fr; use rand::SeedableRng; use rand_chacha::ChaCha20Rng; @@ -53,10 +53,6 @@ pub mod zkevm { } fn bench(c: &mut Criterion) { - let mut rng = ChaCha20Rng::from_entropy(); - let mut transcript = - PoseidonTranscript::::from_spec(vec![], POSEIDON_SPEC.clone()); - // === create zkevm evm circuit snark === let k: u32 = var("DEGREE") .unwrap_or_else(|_| { @@ -68,13 +64,12 @@ fn bench(c: &mut Criterion) { let circuit = zkevm::test_circuit(); let params_app = gen_srs(k); let pk = gen_pk(¶ms_app, &circuit, Some(Path::new("data/zkevm_evm.pkey"))); - let snark = - gen_snark_shplonk(¶ms_app, &pk, circuit, Some(Path::new("data/zkevm_evm.snark"))); + let snark = gen_snark_shplonk(¶ms_app, &pk, circuit, None::<&str>); let snarks = [snark]; // === finished zkevm evm circuit === // === now to do aggregation === - let path = "./configs/bench_zkevm.config"; + let path = "./configs/bench_zkevm.json"; let agg_config = AggregationConfigParams::from_path(path); let k = agg_config.degree; let lookup_bits = k as usize - 1; @@ -106,14 +101,15 @@ fn bench(c: &mut Criterion) { let deployment_code = gen_evm_verifier_shplonk::( ¶ms, pk.get_vk(), - num_instances, - None::<&str>, + num_instances.clone(), + None, ); evm_verify(deployment_code, instances.clone(), proof); let start2 = start_timer!(|| "Create EVM GWC proof"); - let agg_circuit = AggregationCircuit::new::( + let agg_circuit = AggregationCircuit::new::( + // note this is still SHPLONK because it refers to how the evm circuit's snark was generated, NOT how the aggregation proof is going to be generated CircuitBuilderStage::Prover, Some(break_points.clone()), lookup_bits, @@ -123,11 +119,11 @@ fn bench(c: &mut Criterion) { let proof = gen_evm_proof_gwc(¶ms, &pk, agg_circuit, instances.clone()); end_timer!(start2); - let deployment_code = gen_evm_verifier_shplonk::( + let deployment_code = gen_evm_verifier_gwc::( ¶ms, pk.get_vk(), - num_instances, - None::<&str>, + num_instances.clone(), + None, ); evm_verify(deployment_code, instances, proof); diff --git a/snark-verifier-sdk/benches/zkevm_plus_state.rs b/snark-verifier-sdk/benches/zkevm_plus_state.rs index 8ab021f2..a0aabf02 100644 --- a/snark-verifier-sdk/benches/zkevm_plus_state.rs +++ b/snark-verifier-sdk/benches/zkevm_plus_state.rs @@ -16,7 +16,7 @@ use snark_verifier_sdk::{ aggregation::load_verify_circuit_degree, aggregation::AggregationCircuit, gen_proof_gwc, gen_proof_shplonk, gen_snark_gwc, gen_snark_shplonk, PoseidonTranscript, POSEIDON_SPEC, }, - CircuitExt, + CircuitExt, SHPLONK, }; use std::env::{set_var, var}; use std::path::Path; @@ -76,40 +76,93 @@ fn bench(c: &mut Criterion) { let params_app = gen_srs(k); let evm_snark = { let pk = gen_pk(¶ms_app, &evm_circuit, Some(Path::new("data/zkevm_evm.pkey"))); - gen_snark_shplonk(¶ms_app, &pk, evm_circuit, Some(Path::new("data/zkevm_evm.snark"))) + gen_snark_shplonk(¶ms_app, &pk, evm_circuit, None::<&str>) }; let state_snark = { let pk = gen_pk(¶ms_app, &state_circuit, Some(Path::new("data/zkevm_state.pkey"))); - gen_snark_shplonk( - ¶ms_app, - &pk, - state_circuit, - Some(Path::new("data/zkevm_state.snark")), - ) + gen_snark_shplonk(¶ms_app, &pk, state_circuit, None::<&str>) }; let snarks = [evm_snark, state_snark]; // === finished zkevm evm circuit === // === now to do aggregation === - set_var("VERIFY_CONFIG", "./configs/bench_zkevm_plus_state.config"); - let k = load_verify_circuit_degree(); + let path = "./configs/bench_zkevm_plus_state.json"; + // everything below exact same as in zkevm bench + let agg_config = AggregationConfigParams::from_path(path); + let k = agg_config.degree; + let lookup_bits = k as usize - 1; let params = gen_srs(k); - let start1 = start_timer!(|| "Create aggregation circuit"); - let agg_circuit = AggregationCircuit::new(¶ms, snarks, &mut transcript, &mut rng); - end_timer!(start1); + let agg_circuit = AggregationCircuit::keygen::(¶ms, snarks.clone()); + let start1 = start_timer!(|| "gen vk & pk"); let pk = gen_pk(¶ms, &agg_circuit, None); + end_timer!(start1); + let break_points = agg_circuit.break_points(); + + #[cfg(feature = "loader_evm")] + { + let start2 = start_timer!(|| "Create EVM SHPLONK proof"); + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + Some(break_points.clone()), + lookup_bits, + ¶ms, + snarks.clone(), + ); + let instances = agg_circuit.instances(); + let num_instances = agg_circuit.num_instance(); + + let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); + end_timer!(start2); + + let deployment_code = gen_evm_verifier_shplonk::( + ¶ms, + pk.get_vk(), + num_instances.clone(), + None, + ); + + evm_verify(deployment_code, instances.clone(), proof); + + let start2 = start_timer!(|| "Create EVM GWC proof"); + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + Some(break_points.clone()), + lookup_bits, + ¶ms, + snarks.clone(), + ); + let proof = gen_evm_proof_gwc(¶ms, &pk, agg_circuit, instances.clone()); + end_timer!(start2); + + let deployment_code = gen_evm_verifier_gwc::( + ¶ms, + pk.get_vk(), + num_instances.clone(), + None, + ); + + evm_verify(deployment_code, instances, proof); + } + // run benches let mut group = c.benchmark_group("shplonk-proof"); group.sample_size(10); group.bench_with_input( - BenchmarkId::new("zkevm-evm-state-agg", k), - &(¶ms, &pk, &agg_circuit), - |b, &(params, pk, agg_circuit)| { + BenchmarkId::new("zkevm-evm-agg", k), + &(¶ms, &pk, &break_points, &snarks), + |b, &(params, pk, break_points, snarks)| { b.iter(|| { + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + Some(break_points.clone()), + lookup_bits, + params, + snarks.clone(), + ); let instances = agg_circuit.instances(); - gen_proof_shplonk(params, pk, agg_circuit.clone(), instances, None); + gen_proof_shplonk(params, pk, agg_circuit, instances, None) }) }, ); @@ -118,52 +171,24 @@ fn bench(c: &mut Criterion) { let mut group = c.benchmark_group("gwc-proof"); group.sample_size(10); group.bench_with_input( - BenchmarkId::new("zkevm-evm-state-agg", k), - &(¶ms, &pk, &agg_circuit), - |b, &(params, pk, agg_circuit)| { + BenchmarkId::new("zkevm-evm-agg", k), + &(¶ms, &pk, &break_points, &snarks), + |b, &(params, pk, break_points, snarks)| { b.iter(|| { - let instances = agg_circuit.instances(); - gen_proof_gwc( + // note that the generic here remains SHPLONK because it reflects the multi-open scheme for the previous snark (= the zkevm snark) + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + Some(break_points.clone()), + lookup_bits, params, - pk, - agg_circuit.clone(), - instances, - &mut transcript, - &mut rng, - None, + snarks.clone(), ); + let instances = agg_circuit.instances(); + gen_proof_gwc(params, pk, agg_circuit, instances, None) }) }, ); group.finish(); - - #[cfg(feature = "loader_evm")] - { - let deployment_code = - gen_evm_verifier_shplonk::(¶ms, pk.get_vk(), &(), None::<&str>); - - let start2 = start_timer!(|| "Create EVM SHPLONK proof"); - let proof = gen_evm_proof_shplonk( - ¶ms, - &pk, - agg_circuit.clone(), - agg_circuit.instances(), - &mut rng, - ); - end_timer!(start2); - - evm_verify(deployment_code, agg_circuit.instances(), proof); - - let deployment_code = - gen_evm_verifier_shplonk::(¶ms, pk.get_vk(), &(), None::<&str>); - - let start2 = start_timer!(|| "Create EVM GWC proof"); - let proof = - gen_evm_proof_gwc(¶ms, &pk, agg_circuit.clone(), agg_circuit.instances(), &mut rng); - end_timer!(start2); - - evm_verify(deployment_code, agg_circuit.instances(), proof); - } } criterion_group!(benches, bench); diff --git a/snark-verifier-sdk/configs/bench_zkevm.json b/snark-verifier-sdk/configs/bench_zkevm.json new file mode 100644 index 00000000..0d2a05c4 --- /dev/null +++ b/snark-verifier-sdk/configs/bench_zkevm.json @@ -0,0 +1,7 @@ +{ + "degree": 23, + "num_advice": 5, + "num_lookup_advice": 1, + "num_fixed": 1, + "lookup_bits": 22 +} diff --git a/snark-verifier-sdk/configs/bench_zkevm_plus_state.json b/snark-verifier-sdk/configs/bench_zkevm_plus_state.json new file mode 100644 index 00000000..03412bff --- /dev/null +++ b/snark-verifier-sdk/configs/bench_zkevm_plus_state.json @@ -0,0 +1,7 @@ +{ + "degree": 24, + "num_advice": 5, + "num_lookup_advice": 1, + "num_fixed": 1, + "lookup_bits": 22 +} diff --git a/snark-verifier-sdk/configs/example_evm_accumulator.json b/snark-verifier-sdk/configs/example_evm_accumulator.json new file mode 100644 index 00000000..38282d4b --- /dev/null +++ b/snark-verifier-sdk/configs/example_evm_accumulator.json @@ -0,0 +1,10 @@ +{ + "strategy": "Simple", + "degree": 21, + "num_advice": 5, + "num_lookup_advice": 1, + "num_fixed": 1, + "lookup_bits": 20, + "limb_bits": 88, + "num_limbs": 3 +} diff --git a/snark-verifier-sdk/configs/verify_circuit.config b/snark-verifier-sdk/configs/verify_circuit.config deleted file mode 100644 index 90aff847..00000000 --- a/snark-verifier-sdk/configs/verify_circuit.config +++ /dev/null @@ -1 +0,0 @@ -{"strategy":"Simple","degree":21,"num_advice":[4],"num_lookup_advice":[1],"num_fixed":1,"lookup_bits":20,"limb_bits":88,"num_limbs":3} diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 38abdd74..c3e2ceda 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -38,7 +38,13 @@ use snark_verifier::{ util::arithmetic::fe_to_limbs, verifier::PlonkVerifier, }; -use std::{collections::HashMap, env::set_var, fs::File, path::Path, rc::Rc}; +use std::{ + collections::HashMap, + env::{set_var, var}, + fs::File, + path::Path, + rc::Rc, +}; use super::{CircuitExt, PoseidonTranscript, Snark, POSEIDON_SPEC}; @@ -342,6 +348,7 @@ impl AggregationCircuit { } // this function is for convenience + /// `params` should be the universal trusted setup to be used for the aggregation circuit, not the one used to generate the previous snarks, although we assume both use the same generator g[0] pub fn keygen(params: &ParamsKZG, snarks: impl IntoIterator) -> Self where for<'a> MOS: PolynomialCommitmentScheme< @@ -363,6 +370,38 @@ impl AggregationCircuit { circuit } + // this function is for convenience + pub fn prover( + params: &ParamsKZG, + snarks: impl IntoIterator, + break_points: MultiPhaseThreadBreakPoints, + ) -> Self + where + for<'a> MOS: PolynomialCommitmentScheme< + G1Affine, + Rc>, + Accumulator = KzgAccumulator>>, + > + MultiOpenScheme>, SuccinctVerifyingKey = Svk> + + PolynomialCommitmentScheme< + G1Affine, + NativeLoader, + Accumulator = KzgAccumulator, + > + MultiOpenScheme, + { + let lookup_bits: usize = var("LOOKUP_BITS").expect("LOOKUP_BITS not set").parse().unwrap(); + let circuit = Self::new::( + CircuitBuilderStage::Prover, + Some(break_points), + lookup_bits, + params, + snarks, + ); + let minimum_rows = var("MINIMUM_ROWS").map(|s| s.parse().unwrap_or(10)).unwrap_or(10); + circuit.config(params.k(), Some(minimum_rows)); + set_var("LOOKUP_BITS", lookup_bits.to_string()); + circuit + } + /// Re-expose the previous public instances of aggregated snarks again. /// If `hash_prev_accumulator` is true, then we assume all aggregated snarks were themselves /// aggregation snarks, and we exclude the old accumulators from the public input. diff --git a/snark-verifier-sdk/src/lib.rs b/snark-verifier-sdk/src/lib.rs index e53cdcc9..f5294fb2 100644 --- a/snark-verifier-sdk/src/lib.rs +++ b/snark-verifier-sdk/src/lib.rs @@ -165,7 +165,7 @@ mod zkevm { fn instances(&self) -> Vec> { vec![] } - fn num_instance() -> Vec { + fn num_instance(&self) -> Vec { vec![] } } @@ -174,7 +174,7 @@ mod zkevm { fn instances(&self) -> Vec> { vec![] } - fn num_instance() -> Vec { + fn num_instance(&self) -> Vec { vec![] } } diff --git a/snark-verifier/examples/recursion.rs b/snark-verifier/examples/recursion.rs index abc0c808..c126a693 100644 --- a/snark-verifier/examples/recursion.rs +++ b/snark-verifier/examples/recursion.rs @@ -75,6 +75,7 @@ mod common { hasher.squeeze() } + #[derive(Clone)] pub struct Snark { pub protocol: Protocol, pub instances: Vec>, @@ -85,44 +86,9 @@ mod common { pub fn new(protocol: Protocol, instances: Vec>, proof: Vec) -> Self { Self { protocol, instances, proof } } - } - - impl From for SnarkWitness { - fn from(snark: Snark) -> Self { - Self { - protocol: snark.protocol, - instances: snark - .instances - .into_iter() - .map(|instances| instances.into_iter().map(Value::known).collect_vec()) - .collect(), - proof: Value::known(snark.proof), - } - } - } - - #[derive(Clone)] - pub struct SnarkWitness { - pub protocol: Protocol, - pub instances: Vec>>, - pub proof: Value>, - } - - impl SnarkWitness { - pub fn without_witnesses(&self) -> Self { - SnarkWitness { - protocol: self.protocol.clone(), - instances: self - .instances - .iter() - .map(|instances| vec![Value::unknown(); instances.len()]) - .collect(), - proof: Value::unknown(), - } - } - pub fn proof(&self) -> Value<&[u8]> { - self.proof.as_ref().map(Vec::as_slice) + pub fn proof(&self) -> &[u8] { + &self.proof[..] } } @@ -344,19 +310,25 @@ mod application { } mod recursion { - use std::fs::File; + use std::{collections::HashMap, env::var, fs::File}; use halo2_base::{ - gates::GateInstructions, AssignedValue, Context, ContextParams, QuantumCell::Existing, + gates::{ + builder::{GateThreadBuilder, RangeCircuitBuilder}, + range::RangeConfig, + GateInstructions, RangeChip, RangeInstructions, + }, + AssignedValue, Context, + QuantumCell::Existing, }; - use halo2_ecc::ecc::EccChip; + use halo2_ecc::{bn254::FpChip, ecc::EccChip, fields::fp::FpConfig}; use halo2_proofs::plonk::{Column, Instance}; use snark_verifier::loader::halo2::{EccInstructions, IntegerInstructions}; use super::*; - type BaseFieldEccChip = halo2_ecc::ecc::BaseFieldEccChip; - type Halo2Loader<'a> = loader::halo2::Halo2Loader<'a, G1Affine, BaseFieldEccChip>; + type BaseFieldEccChip<'chip> = halo2_ecc::ecc::BaseFieldEccChip<'chip, G1Affine>; + type Halo2Loader<'chip> = loader::halo2::Halo2Loader>; pub trait StateTransition { type Input; @@ -369,9 +341,9 @@ mod recursion { fn succinct_verify<'a>( svk: &Svk, loader: &Rc>, - snark: &SnarkWitness, - preprocessed_digest: Option>, - ) -> (Vec>>, Vec>>>) { + snark: &Snark, + preprocessed_digest: Option>, + ) -> (Vec>>, Vec>>>) { let protocol = if let Some(preprocessed_digest) = preprocessed_digest { let preprocessed_digest = loader.scalar_from_assigned(preprocessed_digest); let protocol = snark.protocol.loaded_preprocessed_as_witness(loader); @@ -385,7 +357,7 @@ mod recursion { }) .chain(protocol.transcript_initial_state.clone()) .collect_vec(); - loader.assert_eq("", &poseidon(loader, &inputs), &preprocessed_digest).unwrap(); + loader.assert_eq("", &poseidon(loader, &inputs), &preprocessed_digest); protocol } else { snark.protocol.loaded(loader) @@ -415,14 +387,16 @@ mod recursion { fn select_accumulator<'a>( loader: &Rc>, - condition: &AssignedValue<'a, Fr>, + condition: &AssignedValue, lhs: &KzgAccumulator>>, rhs: &KzgAccumulator>>, ) -> Result>>, Error> { let [lhs, rhs]: [_; 2] = [lhs.lhs.assigned(), lhs.rhs.assigned()] .iter() .zip([rhs.lhs.assigned(), rhs.rhs.assigned()].iter()) - .map(|(lhs, rhs)| loader.ecc_chip().select(&mut loader.ctx_mut(), lhs, rhs, condition)) + .map(|(lhs, rhs)| { + loader.ecc_chip().select(&mut loader.ctx_mut().main(0), lhs, rhs, *condition) + }) .collect::>() .try_into() .unwrap(); @@ -435,7 +409,7 @@ mod recursion { fn accumulate<'a>( loader: &Rc>, accumulators: Vec>>>, - as_proof: Value<&'_ [u8]>, + as_proof: &[u8], ) -> KzgAccumulator>> { let mut transcript = PoseidonTranscript::, _>::new(loader, as_proof); let proof = As::read_proof(&Default::default(), &accumulators, &mut transcript).unwrap(); @@ -444,71 +418,31 @@ mod recursion { #[derive(serde::Serialize, serde::Deserialize)] pub struct AggregationConfigParams { - pub strategy: halo2_ecc::fields::fp::FpStrategy, pub degree: u32, pub num_advice: usize, pub num_lookup_advice: usize, pub num_fixed: usize, pub lookup_bits: usize, - pub limb_bits: usize, - pub num_limbs: usize, } #[derive(Clone)] pub struct RecursionConfig { - pub base_field_config: halo2_ecc::fields::fp::FpConfig, + pub range: RangeConfig, pub instance: Column, } - impl RecursionConfig { - pub fn configure(meta: &mut ConstraintSystem, params: AggregationConfigParams) -> Self { - assert!( - params.limb_bits == BITS && params.num_limbs == LIMBS, - "For now we fix limb_bits = {}, otherwise change code", - BITS - ); - let base_field_config = halo2_ecc::fields::fp::FpConfig::configure( - meta, - params.strategy, - &[params.num_advice], - &[params.num_lookup_advice], - params.num_fixed, - params.lookup_bits, - params.limb_bits, - params.num_limbs, - halo2_base::utils::modulus::(), - 0, - params.degree as usize, - ); - - let instance = meta.instance_column(); - meta.enable_equality(instance); - - Self { base_field_config, instance } - } - - pub fn gate(&self) -> &halo2_base::gates::flex_gate::FlexGateConfig { - &self.base_field_config.range.gate - } - - pub fn range(&self) -> &halo2_base::gates::range::RangeConfig { - &self.base_field_config.range - } - - pub fn ecc_chip(&self) -> halo2_ecc::ecc::BaseFieldEccChip { - EccChip::construct(self.base_field_config.clone()) - } - } - #[derive(Clone)] pub struct RecursionCircuit { svk: Svk, default_accumulator: KzgAccumulator, - app: SnarkWitness, - previous: SnarkWitness, + app: Snark, + previous: Snark, round: usize, instances: Vec, - as_proof: Value>, + as_proof: Vec, + + inner: RangeCircuitBuilder, + assigned_instances: Vec>, } impl RecursionCircuit { @@ -570,15 +504,119 @@ mod recursion { .chain([preprocessed_digest, initial_state, state, Fr::from(round as u64)]) .collect(); - Self { + let builder = GateThreadBuilder::mock(); + let inner = RangeCircuitBuilder::mock(builder); + let circuit = Self { svk, default_accumulator, app: app.into(), previous: previous.into(), round, instances, - as_proof: Value::known(as_proof), + as_proof, + inner, + assigned_instances: vec![], + }; + circuit.build(); + circuit + } + + fn build(&mut self) { + let lookup_bits = var("LOOKUP_BITS").unwrap().parse().unwrap(); + let range = RangeChip::::default(lookup_bits); + let main_gate = range.gate(); + let mut builder = GateThreadBuilder::mock(); + let ctx = &mut builder; + let [preprocessed_digest, initial_state, state, round] = [ + self.instances[Self::PREPROCESSED_DIGEST_ROW], + self.instances[Self::INITIAL_STATE_ROW], + self.instances[Self::STATE_ROW], + self.instances[Self::ROUND_ROW], + ] + .map(|instance| main_gate.assign_integer(ctx, instance)); + let first_round = main_gate.is_zero(ctx.main(0), round); + let not_first_round = main_gate.not(ctx.main(0), first_round); + drop(ctx); + + let fp_chip = FpChip::::new(&range, BITS, LIMBS); + let ecc_chip = BaseFieldEccChip::new(&fp_chip); + let loader = Halo2Loader::new(ecc_chip, builder); + let (mut app_instances, app_accumulators) = + succinct_verify(&self.svk, &loader, &self.app, None); + let (mut previous_instances, previous_accumulators) = succinct_verify( + &self.svk, + &loader, + &self.previous, + Some(preprocessed_digest.clone()), + ); + + let default_accmulator = self.load_default_accumulator(&loader).unwrap(); + let previous_accumulators = previous_accumulators + .iter() + .map(|previous_accumulator| { + select_accumulator( + &loader, + &first_round, + &default_accmulator, + previous_accumulator, + ) + .unwrap() + }) + .collect::>(); + + let KzgAccumulator { lhs, rhs } = accumulate( + &loader, + [app_accumulators, previous_accumulators].concat(), + self.as_proof(), + ); + + let lhs = lhs.into_assigned(); + let rhs = rhs.into_assigned(); + let app_instances = app_instances.pop().unwrap(); + let previous_instances = previous_instances.pop().unwrap(); + + let mut builder = loader.take_ctx(); + let ctx = builder.main(0); + for (lhs, rhs) in [ + // Propagate preprocessed_digest + ( + &main_gate.mul(ctx, preprocessed_digest, not_first_round), + &previous_instances[Self::PREPROCESSED_DIGEST_ROW], + ), + // Propagate initial_state + ( + &main_gate.mul(ctx, initial_state, not_first_round), + &previous_instances[Self::INITIAL_STATE_ROW], + ), + // Verify initial_state is same as the first application snark + ( + &main_gate.mul(ctx, initial_state, first_round), + &main_gate.mul(ctx, app_instances[0], first_round), + ), + // Verify current state is same as the current application snark + (&state, &app_instances[1]), + // Verify previous state is same as the current application snark + ( + &main_gate.mul(ctx, app_instances[0], not_first_round), + &previous_instances[Self::STATE_ROW], + ), + // Verify round is increased by 1 when not at first round + ( + &round, + &main_gate.add(&mut ctx, not_first_round, previous_instances[Self::ROUND_ROW]), + ), + ] { + ctx.constrain_equal(lhs, rhs); } + *self.inner.0.builder.borrow_mut() = builder; + + self.assigned_instances.extend( + [lhs.x(), lhs.y(), rhs.x(), rhs.y()] + .into_iter() + .flat_map(|coordinate| coordinate.limbs()) + .chain([preprocessed_digest, initial_state, state, round].iter()) + .copied(), + ); } fn initial_snark(params: &ParamsKZG, vk: Option<&VerifyingKey>) -> Snark { @@ -592,8 +630,8 @@ mod recursion { snark } - fn as_proof(&self) -> Value<&[u8]> { - self.as_proof.as_ref().map(Vec::as_slice) + fn as_proof(&self) -> &[u8] { + &self.as_proof[..] } fn load_default_accumulator<'a>( @@ -603,7 +641,7 @@ mod recursion { let [lhs, rhs] = [self.default_accumulator.lhs, self.default_accumulator.rhs].map(|default| { let assigned = - loader.ecc_chip().assign_constant(&mut loader.ctx_mut(), default).unwrap(); + loader.ecc_chip().assign_constant(&mut loader.ctx_mut(), default); loader.ec_point_from_assigned(assigned) }); Ok(KzgAccumulator::new(lhs, rhs)) @@ -615,26 +653,14 @@ mod recursion { type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { - Self { - svk: self.svk, - default_accumulator: self.default_accumulator.clone(), - app: self.app.without_witnesses(), - previous: self.previous.without_witnesses(), - round: self.round, - instances: self.instances.clone(), - as_proof: Value::unknown(), - } + unimplemented!() } fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - let path = std::env::var("VERIFY_CONFIG") - .unwrap_or_else(|_| "configs/verify_circuit.config".to_owned()); - let params: AggregationConfigParams = serde_json::from_reader( - File::open(path.as_str()).unwrap_or_else(|err| panic!("{err:?}")), - ) - .unwrap(); - - RecursionConfig::configure(meta, params) + let range = RangeCircuitBuilder::configure(meta); + let instance = meta.instance_column(); + meta.enable_equality(instance); + RecursionConfig { range, instance } } fn synthesize( @@ -642,152 +668,44 @@ mod recursion { config: Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - config.range().load_lookup_table(&mut layouter)?; - let max_rows = config.range().gate.max_rows; - let main_gate = config.gate(); + let range = config.range; + range.load_lookup_table(&mut layouter).expect("load lookup table should not fail"); + let circuit = &self.inner.0; + let mut assigned_advices = HashMap::new(); + // POC so will only do mock prover and not real prover let mut first_pass = halo2_base::SKIP_FIRST_PASS; // assume using simple floor planner - let mut assigned_instances = Vec::new(); - layouter.assign_region( - || "", - |region| { - if first_pass { - first_pass = false; - return Ok(()); - } - let mut ctx = Context::new( - region, - ContextParams { - max_rows, - num_context_ids: 1, - fixed_columns: config.base_field_config.range.gate.constants.clone(), - }, - ); - - let [preprocessed_digest, initial_state, state, round] = [ - self.instances[Self::PREPROCESSED_DIGEST_ROW], - self.instances[Self::INITIAL_STATE_ROW], - self.instances[Self::STATE_ROW], - self.instances[Self::ROUND_ROW], - ] - .map(|instance| { - main_gate.assign_integer(&mut ctx, Value::known(instance)).unwrap() - }); - let first_round = main_gate.is_zero(&mut ctx, &round); - let not_first_round = main_gate.not(&mut ctx, Existing(&first_round)); - - let loader = Halo2Loader::new(config.ecc_chip(), ctx); - let (mut app_instances, app_accumulators) = - succinct_verify(&self.svk, &loader, &self.app, None); - let (mut previous_instances, previous_accumulators) = succinct_verify( - &self.svk, - &loader, - &self.previous, - Some(preprocessed_digest.clone()), - ); - - let default_accmulator = self.load_default_accumulator(&loader)?; - let previous_accumulators = previous_accumulators - .iter() - .map(|previous_accumulator| { - select_accumulator( - &loader, - &first_round, - &default_accmulator, - previous_accumulator, - ) - }) - .collect::, Error>>()?; - - let KzgAccumulator { lhs, rhs } = accumulate( - &loader, - [app_accumulators, previous_accumulators].concat(), - self.as_proof(), - ); - - let lhs = lhs.into_assigned(); - let rhs = rhs.into_assigned(); - let app_instances = app_instances.pop().unwrap(); - let previous_instances = previous_instances.pop().unwrap(); - - let mut ctx = loader.ctx_mut(); - for (lhs, rhs) in [ - // Propagate preprocessed_digest - ( - &main_gate.mul( - &mut ctx, - Existing(&preprocessed_digest), - Existing(¬_first_round), - ), - &previous_instances[Self::PREPROCESSED_DIGEST_ROW], - ), - // Propagate initial_state - ( - &main_gate.mul( - &mut ctx, - Existing(&initial_state), - Existing(¬_first_round), - ), - &previous_instances[Self::INITIAL_STATE_ROW], - ), - // Verify initial_state is same as the first application snark - ( - &main_gate.mul( - &mut ctx, - Existing(&initial_state), - Existing(&first_round), - ), - &main_gate.mul( - &mut ctx, - Existing(&app_instances[0]), - Existing(&first_round), - ), - ), - // Verify current state is same as the current application snark - (&state, &app_instances[1]), - // Verify previous state is same as the current application snark - ( - &main_gate.mul( - &mut ctx, - Existing(&app_instances[0]), - Existing(¬_first_round), - ), - &previous_instances[Self::STATE_ROW], - ), - // Verify round is increased by 1 when not at first round - ( - &round, - &main_gate.add( - &mut ctx, - Existing(¬_first_round), - Existing(&previous_instances[Self::ROUND_ROW]), - ), - ), - ] { - ctx.region.constrain_equal(lhs.cell(), rhs.cell()); - } - - // IMPORTANT: - config.base_field_config.finalize(&mut ctx); - #[cfg(feature = "display")] - dbg!(ctx.total_advice); - #[cfg(feature = "display")] - println!("Advice columns used: {}", ctx.advice_alloc[0][0].0 + 1); - - assigned_instances.extend( - [lhs.x(), lhs.y(), rhs.x(), rhs.y()] - .into_iter() - .flat_map(|coordinate| coordinate.limbs()) - .chain([preprocessed_digest, initial_state, state, round].iter()) - .map(|assigned| assigned.cell()), - ); - Ok(()) - }, - )?; - - assert_eq!(assigned_instances.len(), 4 * LIMBS + 4); - for (row, limb) in assigned_instances.into_iter().enumerate() { - layouter.constrain_instance(limb, config.instance, row); + layouter + .assign_region( + || "", + |region| { + if first_pass { + first_pass = false; + return Ok(()); + } + // clone the builder so we can re-use the circuit for both vk and pk gen + let builder = circuit.builder.borrow(); + let assignments = builder.assign_all( + &range.gate, + &range.lookup_advice, + &range.q_lookup, + &mut region, + ); + *circuit.break_points.borrow_mut() = assignments.break_points; + assigned_advices = assignments.assigned_advices; + Ok(()) + }, + ) + .unwrap(); + + // expose public instances + let mut layouter = layouter.namespace(|| "expose"); + for (i, instance) in self.assigned_instances.iter().enumerate() { + let cell = instance.cell.unwrap(); + let (cell, _) = assigned_advices + .get(&(cell.context_id, cell.offset)) + .expect("instance not assigned"); + layouter.constrain_instance(*cell, config.instance, i); } Ok(()) @@ -809,10 +727,7 @@ mod recursion { } fn selectors(config: &Self::Config) -> Vec { - config.base_field_config.range.gate.basic_gates[0] - .iter() - .map(|gate| gate.q_enable) - .collect() + config.range.gate.basic_gates[0].iter().map(|gate| gate.q_enable).collect() } } @@ -867,7 +782,7 @@ mod recursion { fn main() { let app_params = gen_srs(3); let recursion_config: AggregationConfigParams = - serde_json::from_reader(fs::File::open("configs/verify_circuit.config").unwrap()).unwrap(); + serde_json::from_reader(fs::File::open("configs/verify_circuit.json").unwrap()).unwrap(); let k = recursion_config.degree; let recursion_params = gen_srs(k); From 2db9f42df5238f494ec4a9d10f704616a6811d67 Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Sun, 19 Feb 2023 13:57:26 -0800 Subject: [PATCH 19/73] feat: update recursion example --- snark-verifier/configs/example_recursion.json | 7 ++++ snark-verifier/examples/recursion.rs | 32 ++++++++++++------- 2 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 snark-verifier/configs/example_recursion.json diff --git a/snark-verifier/configs/example_recursion.json b/snark-verifier/configs/example_recursion.json new file mode 100644 index 00000000..986e925e --- /dev/null +++ b/snark-verifier/configs/example_recursion.json @@ -0,0 +1,7 @@ +{ + "degree": 21, + "num_advice": 4, + "num_lookup_advice": 1, + "num_fixed": 1, + "lookup_bits": 20 +} diff --git a/snark-verifier/examples/recursion.rs b/snark-verifier/examples/recursion.rs index c126a693..edf2614f 100644 --- a/snark-verifier/examples/recursion.rs +++ b/snark-verifier/examples/recursion.rs @@ -2,8 +2,9 @@ use ark_std::{end_timer, start_timer}; use common::*; -use halo2_base::halo2_proofs; +use halo2_base::gates::flex_gate::GateStrategy; use halo2_base::utils::fs::gen_srs; +use halo2_base::{gates::builder::FlexGateConfigParams, halo2_proofs}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner, Value}, dev::MockProver, @@ -42,7 +43,7 @@ use snark_verifier::{ verifier::{self, PlonkProof, PlonkVerifier}, Protocol, }; -use std::{fs, iter, marker::PhantomData, rc::Rc}; +use std::{env::set_var, fs, iter, marker::PhantomData, rc::Rc}; use crate::recursion::AggregationConfigParams; @@ -318,6 +319,7 @@ mod recursion { range::RangeConfig, GateInstructions, RangeChip, RangeInstructions, }, + halo2_proofs::poly::commitment::Params, AssignedValue, Context, QuantumCell::Existing, }; @@ -506,7 +508,7 @@ mod recursion { let builder = GateThreadBuilder::mock(); let inner = RangeCircuitBuilder::mock(builder); - let circuit = Self { + let mut circuit = Self { svk, default_accumulator, app: app.into(), @@ -536,7 +538,6 @@ mod recursion { .map(|instance| main_gate.assign_integer(ctx, instance)); let first_round = main_gate.is_zero(ctx.main(0), round); let not_first_round = main_gate.not(ctx.main(0), first_round); - drop(ctx); let fp_chip = FpChip::::new(&range, BITS, LIMBS); let ecc_chip = BaseFieldEccChip::new(&fp_chip); @@ -601,10 +602,7 @@ mod recursion { &previous_instances[Self::STATE_ROW], ), // Verify round is increased by 1 when not at first round - ( - &round, - &main_gate.add(&mut ctx, not_first_round, previous_instances[Self::ROUND_ROW]), - ), + (&round, &main_gate.add(ctx, not_first_round, previous_instances[Self::ROUND_ROW])), ] { ctx.constrain_equal(lhs, rhs); } @@ -677,8 +675,8 @@ mod recursion { let mut first_pass = halo2_base::SKIP_FIRST_PASS; // assume using simple floor planner layouter .assign_region( - || "", - |region| { + || "Recursion Circuit", + |mut region| { if first_pass { first_pass = false; return Ok(()); @@ -744,6 +742,9 @@ mod recursion { Fr::zero(), 0, ); + // we cannot auto-configure the circuit because dummy_snark must know the configuration beforehand + // uncomment the following line only in development to test and print out the optimal configuration ahead of time + // recursion.inner.0.builder.borrow().config(recursion_params.k() as usize, Some(10)); gen_pk(recursion_params, &recursion) } @@ -782,9 +783,18 @@ mod recursion { fn main() { let app_params = gen_srs(3); let recursion_config: AggregationConfigParams = - serde_json::from_reader(fs::File::open("configs/verify_circuit.json").unwrap()).unwrap(); + serde_json::from_reader(fs::File::open("configs/example_recursion.json").unwrap()).unwrap(); let k = recursion_config.degree; let recursion_params = gen_srs(k); + let flex_gate_config = FlexGateConfigParams { + strategy: GateStrategy::Vertical, + k: k as usize, + num_advice_per_phase: vec![recursion_config.num_advice], + num_lookup_advice_per_phase: vec![recursion_config.num_lookup_advice], + num_fixed: recursion_config.num_fixed, + }; + set_var("FLEX_GATE_CONFIG_PARAMS", serde_json::to_string(&flex_gate_config).unwrap()); + set_var("LOOKUP_BITS", recursion_config.lookup_bits.to_string()); let app_pk = gen_pk(&app_params, &application::Square::default()); From 396aea6d8ca7dcae115db68e8bd5ed2309daf174 Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Sun, 19 Feb 2023 23:27:15 -0800 Subject: [PATCH 20/73] feat: switch poseidon native implementation to Scroll's audited version --- snark-verifier-sdk/Cargo.toml | 4 +- snark-verifier-sdk/src/halo2.rs | 22 +- snark-verifier/Cargo.toml | 13 +- .../examples/evm-verifier-with-accumulator.rs | 33 +- snark-verifier/examples/recursion.rs | 48 ++- snark-verifier/src/lib.rs | 5 - .../src/system/halo2/transcript/halo2.rs | 22 +- snark-verifier/src/util/hash.rs | 2 +- snark-verifier/src/util/hash/poseidon.rs | 362 +++++++++++++++++- .../src/util/hash/poseidon/tests.rs | 85 ++++ 10 files changed, 507 insertions(+), 89 deletions(-) create mode 100644 snark-verifier/src/util/hash/poseidon/tests.rs diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index f7339196..6e845397 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier-sdk" -version = "0.0.1" +version = "0.1.1" edition = "2021" [dependencies] @@ -44,7 +44,7 @@ crossterm = { version = "0.25" } tui = { version = "0.19", default-features = false, features = ["crossterm"] } [features] -default = ["loader_halo2", "loader_evm", "halo2-pse", "halo2-base/jemallocator", "display"] +default = ["loader_halo2", "loader_evm", "halo2-axiom", "halo2-base/jemallocator", "display"] display = ["snark-verifier/display", "dep:ark-std"] loader_evm = ["snark-verifier/loader_evm", "dep:ethereum-types"] loader_halo2 = ["snark-verifier/loader_halo2"] diff --git a/snark-verifier-sdk/src/halo2.rs b/snark-verifier-sdk/src/halo2.rs index 826567f8..3db16529 100644 --- a/snark-verifier-sdk/src/halo2.rs +++ b/snark-verifier-sdk/src/halo2.rs @@ -26,6 +26,7 @@ use halo2_proofs::{ use itertools::Itertools; use lazy_static::lazy_static; use rand::{rngs::StdRng, SeedableRng}; +pub use snark_verifier::util::hash::OptimizedPoseidonSpec; use snark_verifier::{ cost::CostEstimation, loader::native::NativeLoader, @@ -33,7 +34,6 @@ use snark_verifier::{ system::halo2::{compile, Config}, util::transcript::TranscriptWrite, verifier::PlonkProof, - PoseidonSpec, }; use std::{ fs::{self, File}, @@ -44,10 +44,13 @@ use std::{ pub mod aggregation; // Poseidon parameters -const T: usize = 5; -const RATE: usize = 4; -const R_F: usize = 8; -const R_P: usize = 60; +// We use the same ones Scroll uses for security: https://github.com/scroll-tech/poseidon-circuit/blob/714f50c7572a4ff6f2b1fa51a9604a99cd7b6c71/src/poseidon/primitives/bn256/fp.rs +// Verify generated constants: https://github.com/scroll-tech/poseidon-circuit/blob/714f50c7572a4ff6f2b1fa51a9604a99cd7b6c71/src/poseidon/primitives/bn256/mod.rs#L65 +const T: usize = 3; +const RATE: usize = 2; +const R_F: usize = 8; // https://github.com/scroll-tech/poseidon-circuit/blob/714f50c7572a4ff6f2b1fa51a9604a99cd7b6c71/src/poseidon/primitives/p128pow5t3.rs#L26 +const R_P: usize = 57; // https://github.com/scroll-tech/poseidon-circuit/blob/714f50c7572a4ff6f2b1fa51a9604a99cd7b6c71/src/poseidon/primitives/bn256/mod.rs#L8 +const SECURE_MDS: usize = 0; pub type PoseidonTranscript = snark_verifier::system::halo2::transcript::halo2::PoseidonTranscript< @@ -61,7 +64,8 @@ pub type PoseidonTranscript = >; lazy_static! { - pub static ref POSEIDON_SPEC: PoseidonSpec = PoseidonSpec::new(R_F, R_P); + pub static ref POSEIDON_SPEC: OptimizedPoseidonSpec = + OptimizedPoseidonSpec::new::(); } /// Generates a native proof using either SHPLONK or GWC proving method. Uses Poseidon for Fiat-Shamir. @@ -120,7 +124,8 @@ where } debug_assert!({ - let mut transcript_read = PoseidonTranscript::::new(proof.as_slice()); + let mut transcript_read = + PoseidonTranscript::::new::(proof.as_slice()); VerificationStrategy::<_, V>::finalize( verify_proof::<_, V, _, _, _>( params.verifier_params(), @@ -249,6 +254,7 @@ pub fn read_snark(path: impl AsRef) -> Result { bincode::deserialize_from(f) } +// copied from snark_verifier --example recursion pub fn gen_dummy_snark( params: &ParamsKZG, vk: Option<&VerifyingKey>, @@ -305,7 +311,7 @@ where ); let instances = num_instance.into_iter().map(|n| vec![Fr::default(); n]).collect(); let proof = { - let mut transcript = PoseidonTranscript::::new(Vec::new()); + let mut transcript = PoseidonTranscript::::new::(Vec::new()); for _ in 0..protocol .num_witness .iter() diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 22cd8aa5..6e797e15 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier" -version = "0.1.0" +version = "0.1.1" edition = "2021" [dependencies] @@ -16,9 +16,8 @@ serde = { version = "1.0", features = ["derive"] } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "upgrade-v0.3.0", default-features = false } -# This poseidon is identical to PSE (for now) but uses axiom's halo2curves; otherwise would require patching -poseidon-axiom = { git = "https://github.com/axiom-crypto/halo2.git", branch = "axiom/dev", package = "poseidon", optional = true } -poseidon= { git = "https://github.com/privacy-scaling-explorations/poseidon", optional = true } +# This is Scroll's audited poseidon circuit. We only use it for the Native Poseidon spec. We do not use the halo2 circuit at all (and it wouldn't even work because the halo2_proofs tag is not compatbile). +poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git" } # parallel rayon = { version = "1.5.3", optional = true } @@ -44,14 +43,14 @@ crossterm = { version = "0.25" } tui = { version = "0.19", default-features = false, features = ["crossterm"] } [features] -default = ["loader_evm", "loader_halo2", "halo2-pse", "display"] +default = ["loader_evm", "loader_halo2", "halo2-axiom", "display"] display = ["halo2-base/display", "halo2-ecc?/display"] loader_evm = ["dep:ethereum-types", "dep:sha3", "dep:revm", "dep:bytes", "dep:rlp"] loader_halo2 = ["halo2-ecc"] parallel = ["dep:rayon"] # EXACTLY one of halo2-pse / halo2-axiom should always be turned on; not sure how to enforce this with Cargo -halo2-pse = ["halo2-base/halo2-pse", "halo2-ecc?/halo2-pse", "poseidon"] -halo2-axiom = ["halo2-base/halo2-axiom", "halo2-ecc?/halo2-axiom", "poseidon-axiom"] +halo2-pse = ["halo2-base/halo2-pse", "halo2-ecc?/halo2-pse"] +halo2-axiom = ["halo2-base/halo2-axiom", "halo2-ecc?/halo2-axiom"] [[example]] name = "evm-verifier" diff --git a/snark-verifier/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs index bedadf13..b9584b9d 100644 --- a/snark-verifier/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -230,10 +230,11 @@ mod aggregation { }; use std::{collections::HashMap, rc::Rc}; - const T: usize = 5; - const RATE: usize = 4; + const T: usize = 3; + const RATE: usize = 2; const R_F: usize = 8; - const R_P: usize = 60; + const R_P: usize = 57; + const SECURE_MDS: usize = 0; type Svk = KzgSuccinctVerifyingKey; type BaseFieldEccChip<'chip> = halo2_ecc::ecc::BaseFieldEccChip<'chip, G1Affine>; @@ -281,20 +282,16 @@ mod aggregation { let protocol = snark.protocol.loaded(loader); let instances = assign_instances(&snark.instances); let mut transcript = - PoseidonTranscript::, _>::new(loader, snark.proof()); + PoseidonTranscript::, _>::new::<0>(loader, snark.proof()); let proof = Plonk::read_proof(svk, &protocol, &instances, &mut transcript); Plonk::succinct_verify(svk, &protocol, &instances, &proof) }) .collect_vec(); - let acccumulator = { - let mut transcript = PoseidonTranscript::, _>::new(loader, as_proof); - let proof = - As::read_proof(&Default::default(), &accumulators, &mut transcript).unwrap(); - As::verify(&Default::default(), &accumulators, &proof).unwrap() - }; - - acccumulator + let mut transcript = + PoseidonTranscript::, _>::new::(loader, as_proof); + let proof = As::read_proof(&Default::default(), &accumulators, &mut transcript).unwrap(); + As::verify(&Default::default(), &accumulators, &proof).unwrap() } #[derive(serde::Serialize, serde::Deserialize)] @@ -334,8 +331,9 @@ mod aggregation { let accumulators = snarks .iter() .flat_map(|snark| { - let mut transcript = - PoseidonTranscript::::new(snark.proof.as_slice()); + let mut transcript = PoseidonTranscript::::new::( + snark.proof.as_slice(), + ); let proof = Plonk::read_proof(&svk, &snark.protocol, &snark.instances, &mut transcript); Plonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof) @@ -343,7 +341,8 @@ mod aggregation { .collect_vec(); let (_accumulator, as_proof) = { - let mut transcript = PoseidonTranscript::::new(Vec::new()); + let mut transcript = + PoseidonTranscript::::new::(Vec::new()); let accumulator = As::create_proof(&Default::default(), &accumulators, &mut transcript, OsRng) .unwrap(); @@ -406,10 +405,6 @@ mod aggregation { self.circuit.0.break_points.borrow().clone() } - pub fn as_proof(&self) -> &[u8] { - &self.as_proof[..] - } - pub fn num_instance() -> Vec { // [..lhs, ..rhs] vec![4 * LIMBS] diff --git a/snark-verifier/examples/recursion.rs b/snark-verifier/examples/recursion.rs index edf2614f..41f5553e 100644 --- a/snark-verifier/examples/recursion.rs +++ b/snark-verifier/examples/recursion.rs @@ -6,10 +6,10 @@ use halo2_base::gates::flex_gate::GateStrategy; use halo2_base::utils::fs::gen_srs; use halo2_base::{gates::builder::FlexGateConfigParams, halo2_proofs}; use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, + circuit::{Layouter, SimpleFloorPlanner}, dev::MockProver, halo2curves::{ - bn256::{Bn256, Fq, Fr, G1Affine}, + bn256::{Bn256, Fr, G1Affine}, group::ff::Field, FieldExt, }, @@ -49,10 +49,11 @@ use crate::recursion::AggregationConfigParams; const LIMBS: usize = 3; const BITS: usize = 88; -const T: usize = 5; -const RATE: usize = 4; +const T: usize = 3; +const RATE: usize = 2; const R_F: usize = 8; -const R_P: usize = 60; +const R_P: usize = 57; +const SECURE_MDS: usize = 0; type Pcs = Kzg; type Svk = KzgSuccinctVerifyingKey; @@ -71,7 +72,8 @@ mod common { loader: &L, inputs: &[L::LoadedScalar], ) -> L::LoadedScalar { - let mut hasher = Poseidon::new(loader, R_F, R_P); + // warning: generating a new spec is time intensive, use lazy_static in production + let mut hasher = Poseidon::new::(loader); hasher.update(inputs); hasher.squeeze() } @@ -127,7 +129,8 @@ mod common { let instances = instances.iter().map(Vec::as_slice).collect_vec(); let proof = { - let mut transcript = PoseidonTranscript::::new(Vec::new()); + let mut transcript = + PoseidonTranscript::::new::(Vec::new()); create_proof::<_, ProverGWC<_>, _, _, _, _>( params, pk, @@ -141,7 +144,8 @@ mod common { }; let accept = { - let mut transcript = PoseidonTranscript::::new(proof.as_slice()); + let mut transcript = + PoseidonTranscript::::new::(proof.as_slice()); VerificationStrategy::<_, VerifierGWC<_>>::finalize( verify_proof::<_, VerifierGWC<_>, _, _, _>( params.verifier_params(), @@ -230,7 +234,8 @@ mod common { .map(|n| iter::repeat_with(|| Fr::random(OsRng)).take(n).collect()) .collect(); let proof = { - let mut transcript = PoseidonTranscript::::new(Vec::new()); + let mut transcript = + PoseidonTranscript::::new::(Vec::new()); for _ in 0..protocol .num_witness .iter() @@ -311,7 +316,7 @@ mod application { } mod recursion { - use std::{collections::HashMap, env::var, fs::File}; + use std::{collections::HashMap, env::var}; use halo2_base::{ gates::{ @@ -319,11 +324,9 @@ mod recursion { range::RangeConfig, GateInstructions, RangeChip, RangeInstructions, }, - halo2_proofs::poly::commitment::Params, - AssignedValue, Context, - QuantumCell::Existing, + AssignedValue, }; - use halo2_ecc::{bn254::FpChip, ecc::EccChip, fields::fp::FpConfig}; + use halo2_ecc::bn254::FpChip; use halo2_proofs::plonk::{Column, Instance}; use snark_verifier::loader::halo2::{EccInstructions, IntegerInstructions}; @@ -372,7 +375,8 @@ mod recursion { instances.iter().map(|instance| loader.assign_scalar(*instance)).collect_vec() }) .collect_vec(); - let mut transcript = PoseidonTranscript::, _>::new(loader, snark.proof()); + let mut transcript = + PoseidonTranscript::, _>::new::(loader, snark.proof()); let proof = Plonk::read_proof(svk, &protocol, &instances, &mut transcript); let accumulators = Plonk::succinct_verify(svk, &protocol, &instances, &proof); @@ -413,7 +417,8 @@ mod recursion { accumulators: Vec>>>, as_proof: &[u8], ) -> KzgAccumulator>> { - let mut transcript = PoseidonTranscript::, _>::new(loader, as_proof); + let mut transcript = + PoseidonTranscript::, _>::new::(loader, as_proof); let proof = As::read_proof(&Default::default(), &accumulators, &mut transcript).unwrap(); As::verify(&Default::default(), &accumulators, &proof).unwrap() } @@ -465,8 +470,9 @@ mod recursion { let default_accumulator = KzgAccumulator::new(params.get_g()[1], params.get_g()[0]); let succinct_verify = |snark: &Snark| { - let mut transcript = - PoseidonTranscript::::new(snark.proof.as_slice()); + let mut transcript = PoseidonTranscript::::new::( + snark.proof.as_slice(), + ); let proof = Plonk::read_proof(&svk, &snark.protocol, &snark.instances, &mut transcript); Plonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof) @@ -481,7 +487,8 @@ mod recursion { .collect_vec(); let (accumulator, as_proof) = { - let mut transcript = PoseidonTranscript::::new(Vec::new()); + let mut transcript = + PoseidonTranscript::::new::(Vec::new()); let accumulator = As::create_proof(&Default::default(), &accumulators, &mut transcript, OsRng) .unwrap(); @@ -822,7 +829,8 @@ fn main() { let accept = { let svk = recursion_params.get_g()[0].into(); let dk = (recursion_params.g2(), recursion_params.s_g2()).into(); - let mut transcript = PoseidonTranscript::::new(snark.proof.as_slice()); + let mut transcript = + PoseidonTranscript::::new::(snark.proof.as_slice()); let proof = Plonk::read_proof(&svk, &snark.protocol, &snark.instances, &mut transcript); Plonk::verify(&svk, &dk, &snark.protocol, &snark.instances, &proof) }; diff --git a/snark-verifier/src/lib.rs b/snark-verifier/src/lib.rs index 1976def7..4e1d36ec 100644 --- a/snark-verifier/src/lib.rs +++ b/snark-verifier/src/lib.rs @@ -11,12 +11,7 @@ pub mod verifier; pub(crate) use halo2_base::halo2_proofs; pub(crate) use halo2_proofs::halo2curves as halo2_curves; -#[cfg(feature = "halo2-pse")] -pub(crate) use poseidon; -#[cfg(feature = "halo2-axiom")] -pub(crate) use poseidon_axiom as poseidon; -pub use poseidon::Spec as PoseidonSpec; use serde::{Deserialize, Serialize}; #[derive(Clone, Debug)] diff --git a/snark-verifier/src/system/halo2/transcript/halo2.rs b/snark-verifier/src/system/halo2/transcript/halo2.rs index 73934b01..23753676 100644 --- a/snark-verifier/src/system/halo2/transcript/halo2.rs +++ b/snark-verifier/src/system/halo2/transcript/halo2.rs @@ -7,7 +7,7 @@ use crate::{ }, util::{ arithmetic::{fe_to_fe, CurveAffine, PrimeField}, - hash::Poseidon, + hash::{OptimizedPoseidonSpec, Poseidon}, transcript::{Transcript, TranscriptRead, TranscriptWrite}, Itertools, }, @@ -55,15 +55,15 @@ where R: Read, EccChip: NativeEncoding, { - pub fn new(loader: &Rc>, stream: R) -> Self { - let buf = Poseidon::new(loader, R_F, R_P); + pub fn new(loader: &Rc>, stream: R) -> Self { + let buf = Poseidon::new::(loader); Self { loader: loader.clone(), stream, buf } } pub fn from_spec( loader: &Rc>, stream: R, - spec: crate::poseidon::Spec, + spec: OptimizedPoseidonSpec, ) -> Self { let buf = Poseidon::from_spec(loader, spec); Self { loader: loader.clone(), stream, buf } @@ -152,11 +152,15 @@ where impl PoseidonTranscript { - pub fn new(stream: S) -> Self { - Self { loader: NativeLoader, stream, buf: Poseidon::new(&NativeLoader, R_F, R_P) } + pub fn new(stream: S) -> Self { + Self { + loader: NativeLoader, + stream, + buf: Poseidon::new::(&NativeLoader), + } } - pub fn from_spec(stream: S, spec: crate::poseidon::Spec) -> Self { + pub fn from_spec(stream: S, spec: OptimizedPoseidonSpec) -> Self { Self { loader: NativeLoader, stream, buf: Poseidon::from_spec(&NativeLoader, spec) } } @@ -352,7 +356,7 @@ where R: Read, { fn init(reader: R) -> Self { - Self::new(reader) + Self::new::<0>(reader) } } @@ -386,7 +390,7 @@ where W: Write, { fn init(writer: W) -> Self { - Self::new(writer) + Self::new::<0>(writer) } fn finalize(self) -> W { diff --git a/snark-verifier/src/util/hash.rs b/snark-verifier/src/util/hash.rs index 17ede0b3..d9faf98e 100644 --- a/snark-verifier/src/util/hash.rs +++ b/snark-verifier/src/util/hash.rs @@ -1,6 +1,6 @@ mod poseidon; -pub use crate::util::hash::poseidon::Poseidon; +pub use crate::util::hash::poseidon::{OptimizedPoseidonSpec, Poseidon}; #[cfg(feature = "loader_evm")] pub use sha3::{Digest, Keccak256}; diff --git a/snark-verifier/src/util/hash/poseidon.rs b/snark-verifier/src/util/hash/poseidon.rs index fa7442f4..df167081 100644 --- a/snark-verifier/src/util/hash/poseidon.rs +++ b/snark-verifier/src/util/hash/poseidon.rs @@ -1,21 +1,345 @@ -use crate::poseidon::{self, SparseMDSMatrix, Spec}; +#![allow(clippy::needless_range_loop)] // for clarity of matrix operations use crate::{ loader::{LoadedScalar, ScalarLoader}, util::{arithmetic::FieldExt, Itertools}, }; +use poseidon_circuit::poseidon::primitives::Spec as PoseidonSpec; // trait use std::{iter, marker::PhantomData, mem}; +#[cfg(test)] +mod tests; + +// struct so we can use PoseidonSpec trait to generate round constants and MDS matrix +#[derive(Debug)] +pub struct Poseidon128Pow5Gen< + F: FieldExt, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + const SECURE_MDS: usize, +> { + _marker: PhantomData, +} + +impl< + F: FieldExt, + const T: usize, + const RATE: usize, + const R_F: usize, + const R_P: usize, + const SECURE_MDS: usize, + > PoseidonSpec for Poseidon128Pow5Gen +{ + fn full_rounds() -> usize { + R_F + } + + fn partial_rounds() -> usize { + R_P + } + + fn sbox(val: F) -> F { + val.pow_vartime([5]) + } + + // see "Avoiding insecure matrices" in Section 2.3 of https://eprint.iacr.org/2019/458.pdf + // most Specs used in practice have SECURE_MDS = 0 + fn secure_mds() -> usize { + SECURE_MDS + } +} + +// We use the optimized Poseidon implementation described in Supplementary Material Section B of https://eprint.iacr.org/2019/458.pdf +// This involves some further computation of optimized constants and sparse MDS matrices beyond what the Scroll PoseidonSpec generates +// The implementation below is adapted from https://github.com/privacy-scaling-explorations/poseidon + +/// `OptimizedPoseidonSpec` holds construction parameters as well as constants that are used in +/// permutation step. +#[derive(Debug, Clone)] +pub struct OptimizedPoseidonSpec { + pub(crate) r_f: usize, + pub(crate) mds_matrices: MDSMatrices, + pub(crate) constants: OptimizedConstants, +} + +/// `OptimizedConstants` has round constants that are added each round. While +/// full rounds has T sized constants there is a single constant for each +/// partial round +#[derive(Debug, Clone)] +pub struct OptimizedConstants { + pub(crate) start: Vec<[F; T]>, + pub(crate) partial: Vec, + pub(crate) end: Vec<[F; T]>, +} + +/// The type used to hold the MDS matrix +pub(crate) type Mds = [[F; T]; T]; + +/// `MDSMatrices` holds the MDS matrix as well as transition matrix which is +/// also called `pre_sparse_mds` and sparse matrices that enables us to reduce +/// number of multiplications in apply MDS step +#[derive(Debug, Clone)] +pub struct MDSMatrices { + pub(crate) mds: MDSMatrix, + pub(crate) pre_sparse_mds: MDSMatrix, + pub(crate) sparse_matrices: Vec>, +} + +/// `SparseMDSMatrix` are in `[row], [hat | identity]` form and used in linear +/// layer of partial rounds instead of the original MDS +#[derive(Debug, Clone)] +pub struct SparseMDSMatrix { + pub(crate) row: [F; T], + pub(crate) col_hat: [F; RATE], +} + +/// `MDSMatrix` is applied to `State` to achive linear layer of Poseidon +#[derive(Clone, Debug)] +pub struct MDSMatrix(pub(crate) Mds); + +impl MDSMatrix { + pub(crate) fn mul_vector(&self, v: &[F; T]) -> [F; T] { + let mut res = [F::zero(); T]; + for i in 0..T { + for j in 0..T { + res[i] += self.0[i][j] * v[j]; + } + } + res + } + + fn identity() -> Mds { + let mut mds = [[F::zero(); T]; T]; + for i in 0..T { + mds[i][i] = F::one(); + } + mds + } + + /// Multiplies two MDS matrices. Used in sparse matrix calculations + fn mul(&self, other: &Self) -> Self { + let mut res = [[F::zero(); T]; T]; + for i in 0..T { + for j in 0..T { + for k in 0..T { + res[i][j] += self.0[i][k] * other.0[k][j]; + } + } + } + Self(res) + } + + fn transpose(&self) -> Self { + let mut res = [[F::zero(); T]; T]; + for i in 0..T { + for j in 0..T { + res[i][j] = self.0[j][i]; + } + } + Self(res) + } + + fn determinant(m: [[F; N]; N]) -> F { + let mut res = F::one(); + let mut m = m; + for i in 0..N { + let mut pivot = i; + while m[pivot][i] == F::zero() { + pivot += 1; + assert!(pivot < N, "matrix is not invertible"); + } + if pivot != i { + res = -res; + m.swap(pivot, i); + } + res *= m[i][i]; + let inv = m[i][i].invert().unwrap(); + for j in i + 1..N { + let factor = m[j][i] * inv; + for k in i + 1..N { + m[j][k] -= m[i][k] * factor; + } + } + } + res + } + + /// See Section B in Supplementary Material https://eprint.iacr.org/2019/458.pdf + /// Factorises an MDS matrix `M` into `M'` and `M''` where `M = M' * M''`. + /// Resulted `M''` matrices are the sparse ones while `M'` will contribute + /// to the accumulator of the process + fn factorise(&self) -> (Self, SparseMDSMatrix) { + assert_eq!(RATE + 1, T); + // Given `(t-1 * t-1)` MDS matrix called `hat` constructs the `t * t` matrix in + // form `[[1 | 0], [0 | m]]`, ie `hat` is the right bottom sub-matrix + let prime = |hat: Mds| -> Self { + let mut prime = Self::identity(); + for (prime_row, hat_row) in prime.iter_mut().skip(1).zip(hat.iter()) { + for (el_prime, el_hat) in prime_row.iter_mut().skip(1).zip(hat_row.iter()) { + *el_prime = *el_hat; + } + } + Self(prime) + }; + + // Given `(t-1)` sized `w_hat` vector constructs the matrix in form + // `[[m_0_0 | m_0_i], [w_hat | identity]]` + let prime_prime = |w_hat: [F; RATE]| -> Mds { + let mut prime_prime = Self::identity(); + prime_prime[0] = self.0[0]; + for (row, w) in prime_prime.iter_mut().skip(1).zip(w_hat.iter()) { + row[0] = *w + } + prime_prime + }; + + let w = self.0.iter().skip(1).map(|row| row[0]).collect::>(); + // m_hat is the `(t-1 * t-1)` right bottom sub-matrix of m := self.0 + let mut m_hat = [[F::zero(); RATE]; RATE]; + for i in 0..RATE { + for j in 0..RATE { + m_hat[i][j] = self.0[i + 1][j + 1]; + } + } + // w_hat = m_hat^{-1} * w, where m_hat^{-1} is matrix inverse and * is matrix mult + // we avoid computing m_hat^{-1} explicitly by using Cramer's rule: https://en.wikipedia.org/wiki/Cramer%27s_rule + let mut w_hat = [F::zero(); RATE]; + let det = Self::determinant(m_hat); + for j in 0..RATE { + let mut m_hat_j = m_hat; + for i in 0..RATE { + m_hat_j[i][j] = w[i]; + } + w_hat[j] = Self::determinant(m_hat_j) + * Option::::from(det.invert()).expect("matrix is not invertible"); + } + let m_prime = prime(m_hat); + let m_prime_prime = prime_prime(w_hat); + // row = first row of m_prime_prime.transpose() = first column of m_prime_prime + let row: [F; T] = + m_prime_prime.iter().map(|row| row[0]).collect::>().try_into().unwrap(); + // col_hat = first column of m_prime_prime.transpose() without first element = first row of m_prime_prime without first element + let col_hat: [F; RATE] = m_prime_prime[0][1..].try_into().unwrap(); + (m_prime, SparseMDSMatrix { row, col_hat }) + } +} + +impl OptimizedPoseidonSpec { + pub fn new() -> Self { + let (round_constants, mds, mds_inv) = + Poseidon128Pow5Gen::::constants(); + let mds = MDSMatrix(mds); + let inverse_mds = MDSMatrix(mds_inv); + + let constants = + Self::calculate_optimized_constants(R_F, R_P, round_constants, &inverse_mds); + let (sparse_matrices, pre_sparse_mds) = Self::calculate_sparse_matrices(R_P, &mds); + + Self { + r_f: R_F, + constants, + mds_matrices: MDSMatrices { mds, sparse_matrices, pre_sparse_mds }, + } + } + + fn calculate_optimized_constants( + r_f: usize, + r_p: usize, + constants: Vec<[F; T]>, + inverse_mds: &MDSMatrix, + ) -> OptimizedConstants { + let (number_of_rounds, r_f_half) = (r_f + r_p, r_f / 2); + assert_eq!(constants.len(), number_of_rounds); + + // Calculate optimized constants for first half of the full rounds + let mut constants_start: Vec<[F; T]> = vec![[F::zero(); T]; r_f_half]; + constants_start[0] = constants[0]; + for (optimized, constants) in + constants_start.iter_mut().skip(1).zip(constants.iter().skip(1)) + { + *optimized = inverse_mds.mul_vector(constants); + } + + // Calculate constants for partial rounds + let mut acc = constants[r_f_half + r_p]; + let mut constants_partial = vec![F::zero(); r_p]; + for (optimized, constants) in constants_partial + .iter_mut() + .rev() + .zip(constants.iter().skip(r_f_half).rev().skip(r_f_half)) + { + let mut tmp = inverse_mds.mul_vector(&acc); + *optimized = tmp[0]; + + tmp[0] = F::zero(); + for ((acc, tmp), constant) in acc.iter_mut().zip(tmp.into_iter()).zip(constants.iter()) + { + *acc = tmp + constant + } + } + constants_start.push(inverse_mds.mul_vector(&acc)); + + // Calculate optimized constants for ending half of the full rounds + let mut constants_end: Vec<[F; T]> = vec![[F::zero(); T]; r_f_half - 1]; + for (optimized, constants) in + constants_end.iter_mut().zip(constants.iter().skip(r_f_half + r_p + 1)) + { + *optimized = inverse_mds.mul_vector(constants); + } + + OptimizedConstants { + start: constants_start, + partial: constants_partial, + end: constants_end, + } + } + + fn calculate_sparse_matrices( + r_p: usize, + mds: &MDSMatrix, + ) -> (Vec>, MDSMatrix) { + let mds = mds.transpose(); + let mut acc = mds.clone(); + let mut sparse_matrices = (0..r_p) + .map(|_| { + let (m_prime, m_prime_prime) = acc.factorise(); + acc = mds.mul(&m_prime); + m_prime_prime + }) + .collect::>>(); + + sparse_matrices.reverse(); + (sparse_matrices, acc.transpose()) + } +} + +// ================ END OF CONSTRUCTION OF POSEIDON SPEC ==================== + +// now we get to actual trait based implementation of Poseidon permutation +// this works for any loader, where the two loaders used are NativeLoader (native rust) and Halo2Loader (ZK circuit) #[derive(Clone)] struct State { inner: [L; T], _marker: PhantomData, } +// the transcript hash implementation is the one suggested in the original paper https://eprint.iacr.org/2019/458.pdf +// another reference implementation is https://github.com/privacy-scaling-explorations/halo2wrong/tree/master/transcript/src impl, const T: usize, const RATE: usize> State { fn new(inner: [L; T]) -> Self { Self { inner, _marker: PhantomData } } + fn default(loader: &L::Loader) -> Self { + let mut default_state = [F::zero(); T]; + // from Section 4.2 of https://eprint.iacr.org/2019/458.pdf + // • Variable-Input-Length Hashing. The capacity value is 2^64 + (o−1) where o the output length. + // for our transcript use cases, o = 1 + default_state[0] = F::from_u128(1u128 << 64); + Self::new(default_state.map(|state| loader.load_const(&state))) + } + fn loader(&self) -> &L::Loader { self.inner[0].loader() } @@ -52,6 +376,8 @@ impl, const T: usize, const RATE: usize> State, const T: usize, const RATE: usize> State) { self.inner = iter::once( self.loader() - .sum_with_coeff(&mds.row().iter().cloned().zip(self.inner.iter()).collect_vec()), + .sum_with_coeff(&mds.row.iter().cloned().zip(self.inner.iter()).collect_vec()), ) - .chain(mds.col_hat().iter().zip(self.inner.iter().skip(1)).map(|(coeff, state)| { + .chain(mds.col_hat.iter().zip(self.inner.iter().skip(1)).map(|(coeff, state)| { self.loader().sum_with_coeff(&[(*coeff, &self.inner[0]), (F::one(), state)]) })) .collect_vec() @@ -83,27 +409,27 @@ impl, const T: usize, const RATE: usize> State { - spec: Spec, + spec: OptimizedPoseidonSpec, default_state: State, state: State, buf: Vec, } impl, const T: usize, const RATE: usize> Poseidon { - pub fn new(loader: &L::Loader, r_f: usize, r_p: usize) -> Self { - let default_state = - State::new(poseidon::State::default().words().map(|state| loader.load_const(&state))); + pub fn new( + loader: &L::Loader, + ) -> Self { + let default_state = State::default(loader); Self { - spec: Spec::new(r_f, r_p), + spec: OptimizedPoseidonSpec::new::(), state: default_state.clone(), default_state, buf: Vec::new(), } } - pub fn from_spec(loader: &L::Loader, spec: Spec) -> Self { - let default_state = - State::new(poseidon::State::default().words().map(|state| loader.load_const(&state))); + pub fn from_spec(loader: &L::Loader, spec: OptimizedPoseidonSpec) -> Self { + let default_state = State::default(loader); Self { spec, state: default_state.clone(), default_state, buf: Vec::new() } } @@ -131,13 +457,13 @@ impl, const T: usize, const RATE: usize> Poseido } fn permutation(&mut self, inputs: &[L]) { - let r_f = self.spec.r_f() / 2; - let mds = self.spec.mds_matrices().mds().rows(); - let pre_sparse_mds = self.spec.mds_matrices().pre_sparse_mds().rows(); - let sparse_matrices = self.spec.mds_matrices().sparse_matrices(); + let r_f = self.spec.r_f / 2; + let mds = self.spec.mds_matrices.mds.0; + let pre_sparse_mds = self.spec.mds_matrices.pre_sparse_mds.0; + let sparse_matrices = &self.spec.mds_matrices.sparse_matrices; // First half of the full rounds - let constants = self.spec.constants().start(); + let constants = &self.spec.constants.start; self.state.absorb_with_pre_constants(inputs, &constants[0]); for constants in constants.iter().skip(1).take(r_f - 1) { self.state.sbox_full(constants); @@ -147,14 +473,14 @@ impl, const T: usize, const RATE: usize> Poseido self.state.apply_mds(&pre_sparse_mds); // Partial rounds - let constants = self.spec.constants().partial(); + let constants = &self.spec.constants.partial; for (constant, sparse_mds) in constants.iter().zip(sparse_matrices.iter()) { self.state.sbox_part(constant); self.state.apply_sparse_mds(sparse_mds); } // Second half of the full rounds - let constants = self.spec.constants().end(); + let constants = &self.spec.constants.end; for constants in constants.iter() { self.state.sbox_full(constants); self.state.apply_mds(&mds); diff --git a/snark-verifier/src/util/hash/poseidon/tests.rs b/snark-verifier/src/util/hash/poseidon/tests.rs new file mode 100644 index 00000000..cf4712bc --- /dev/null +++ b/snark-verifier/src/util/hash/poseidon/tests.rs @@ -0,0 +1,85 @@ +use halo2_base::halo2_proofs::halo2curves::group::ff::PrimeField; + +use super::*; +use crate::{halo2_curves::bn256::Fr, loader::native::NativeLoader}; + +#[test] +fn test_mds() { + let spec = OptimizedPoseidonSpec::::new::<8, 57, 0>(); + + let mds = vec![ + vec![ + "7511745149465107256748700652201246547602992235352608707588321460060273774987", + "10370080108974718697676803824769673834027675643658433702224577712625900127200", + "19705173408229649878903981084052839426532978878058043055305024233888854471533", + ], + vec![ + "18732019378264290557468133440468564866454307626475683536618613112504878618481", + "20870176810702568768751421378473869562658540583882454726129544628203806653987", + "7266061498423634438633389053804536045105766754026813321943009179476902321146", + ], + vec![ + "9131299761947733513298312097611845208338517739621853568979632113419485819303", + "10595341252162738537912664445405114076324478519622938027420701542910180337937", + "11597556804922396090267472882856054602429588299176362916247939723151043581408", + ], + ]; + for (row1, row2) in mds.iter().zip_eq(spec.mds_matrices.mds.0.iter()) { + for (e1, e2) in row1.iter().zip_eq(row2.iter()) { + assert_eq!(Fr::from_str_vartime(e1).unwrap(), *e2); + } + } +} + +#[test] +fn test_poseidon_against_test_vectors() { + // https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt + // poseidonperm_x5_254_3 + { + const R_F: usize = 8; + const R_P: usize = 57; + const T: usize = 3; + const RATE: usize = 2; + + let mut hasher = Poseidon::::new::(&NativeLoader); + + let state = vec![0u64, 1, 2].into_iter().map(Fr::from).collect::>(); + hasher.state = State::new(state.try_into().unwrap()); + hasher.permutation(&[(); RATE].map(|_| Fr::zero())); // avoid padding + let state_0 = hasher.state.inner; + let expected = vec![ + "7853200120776062878684798364095072458815029376092732009249414926327459813530", + "7142104613055408817911962100316808866448378443474503659992478482890339429929", + "6549537674122432311777789598043107870002137484850126429160507761192163713804", + ]; + for (word, expected) in state_0.into_iter().zip(expected.iter()) { + assert_eq!(word, Fr::from_str_vartime(expected).unwrap()); + } + } + + // https://extgit.iaik.tugraz.at/krypto/hadeshash/-/blob/master/code/test_vectors.txt + // poseidonperm_x5_254_5 + { + const R_F: usize = 8; + const R_P: usize = 60; + const T: usize = 5; + const RATE: usize = 4; + + let mut hasher = Poseidon::::new::(&NativeLoader); + + let state = vec![0u64, 1, 2, 3, 4].into_iter().map(Fr::from).collect::>(); + hasher.state = State::new(state.try_into().unwrap()); + hasher.permutation(&[(); RATE].map(|_| Fr::zero())); + let state_0 = hasher.state.inner; + let expected = vec![ + "18821383157269793795438455681495246036402687001665670618754263018637548127333", + "7817711165059374331357136443537800893307845083525445872661165200086166013245", + "16733335996448830230979566039396561240864200624113062088822991822580465420551", + "6644334865470350789317807668685953492649391266180911382577082600917830417726", + "3372108894677221197912083238087960099443657816445944159266857514496320565191", + ]; + for (word, expected) in state_0.into_iter().zip(expected.iter()) { + assert_eq!(word, Fr::from_str_vartime(expected).unwrap()); + } + } +} From 53a30eb28b937b9c7468751e6032a9e215f0b900 Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Mon, 20 Feb 2023 02:03:00 -0800 Subject: [PATCH 21/73] fix: invert determinant only once in Cramer's rule --- snark-verifier/src/util/hash/poseidon.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snark-verifier/src/util/hash/poseidon.rs b/snark-verifier/src/util/hash/poseidon.rs index df167081..b1e774b4 100644 --- a/snark-verifier/src/util/hash/poseidon.rs +++ b/snark-verifier/src/util/hash/poseidon.rs @@ -206,13 +206,13 @@ impl MDSMatrix { // we avoid computing m_hat^{-1} explicitly by using Cramer's rule: https://en.wikipedia.org/wiki/Cramer%27s_rule let mut w_hat = [F::zero(); RATE]; let det = Self::determinant(m_hat); + let det_inv = Option::::from(det.invert()).expect("matrix is not invertible"); for j in 0..RATE { let mut m_hat_j = m_hat; for i in 0..RATE { m_hat_j[i][j] = w[i]; } - w_hat[j] = Self::determinant(m_hat_j) - * Option::::from(det.invert()).expect("matrix is not invertible"); + w_hat[j] = Self::determinant(m_hat_j) * det_inv; } let m_prime = prime(m_hat); let m_prime_prime = prime_prime(w_hat); From 85c68b4aca530c313edbf2d7c32077bb86425346 Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Mon, 20 Feb 2023 19:56:08 -0800 Subject: [PATCH 22/73] chore: fix doc --- snark-verifier-sdk/src/halo2/aggregation.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 97549d38..956635ba 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -249,8 +249,8 @@ impl AggregationCircuit { /// /// The user can optionally modify the circuit after calling this function to add more instances to `assigned_instances` to expose. /// - /// Warning: will fail silently if `snarks` were created using a different multi-open scheme than `MOS` - /// where `MOS` can be either [`crate::SHPLONK`] or [`crate::GWC`] (for original PLONK multi-open scheme) + /// Warning: will fail silently if `snarks` were created using a different multi-open scheme than `AS` + /// where `AS` can be either [`crate::SHPLONK`] or [`crate::GWC`] (for original PLONK multi-open scheme) pub fn new( stage: CircuitBuilderStage, break_points: Option, From efec13b776f5ae84220941b04ef95ae35ffb749d Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Mon, 20 Feb 2023 23:24:57 -0800 Subject: [PATCH 23/73] chore --- snark-verifier-sdk/src/halo2/aggregation.rs | 1 + snark-verifier/examples/evm-verifier-with-accumulator.rs | 1 + snark-verifier/examples/recursion.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 956635ba..8c98ebc5 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -475,6 +475,7 @@ impl Circuit for RangeWithInstanceCircuitBuilder { &range.lookup_advice, &range.q_lookup, &mut region, + Default::default(), ); *circuit.break_points.borrow_mut() = assignments.break_points; assigned_advices = assignments.assigned_advices; diff --git a/snark-verifier/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs index c01344ac..986972ef 100644 --- a/snark-verifier/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -478,6 +478,7 @@ mod aggregation { &range.lookup_advice, &range.q_lookup, &mut region, + Default::default(), ); *circuit.break_points.borrow_mut() = assignments.break_points; assigned_advices = assignments.assigned_advices; diff --git a/snark-verifier/examples/recursion.rs b/snark-verifier/examples/recursion.rs index f407c747..554fd073 100644 --- a/snark-verifier/examples/recursion.rs +++ b/snark-verifier/examples/recursion.rs @@ -710,6 +710,7 @@ mod recursion { &range.lookup_advice, &range.q_lookup, &mut region, + Default::default(), ); *circuit.break_points.borrow_mut() = assignments.break_points; assigned_advices = assignments.assigned_advices; From 2fd73ab738fb0000b543b7b4d06e18a1f0804840 Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Tue, 28 Feb 2023 00:42:26 -0800 Subject: [PATCH 24/73] chore: forgot to update halo2-base dependency in snark-verifier-sdk --- snark-verifier-sdk/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 0882880b..28e543c6 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -17,7 +17,7 @@ serde_json = "1.0" serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", tag = "v0.2.2", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "upgrade-v0.3.0", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } # loader_evm From 57aaba51e863897c790dd6c4fbdb87b748192878 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Wed, 19 Apr 2023 00:00:36 +0200 Subject: [PATCH 25/73] Minor update (#8) * feat(sdk): remove duplicate code in `RangeWithInstanceCircuitBuilder::synthesize` * feat(sdk): Proof caching when using feature 'halo2-pse' * chore: sync with halo2-lib * chore: switch to halo2-lib release-0.3.0 branch --- snark-verifier-sdk/Cargo.toml | 2 +- snark-verifier-sdk/benches/standard_plonk.rs | 8 +-- snark-verifier-sdk/src/halo2.rs | 16 ++++- snark-verifier-sdk/src/halo2/aggregation.rs | 66 +++----------------- snark-verifier/Cargo.toml | 4 +- snark-verifier/src/loader/halo2/loader.rs | 1 + snark-verifier/src/loader/halo2/shim.rs | 24 +++---- 7 files changed, 39 insertions(+), 82 deletions(-) diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 28e543c6..ca206bce 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -17,7 +17,7 @@ serde_json = "1.0" serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "upgrade-v0.3.0", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "upgrade-v0.3.0-fixes", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } # loader_evm diff --git a/snark-verifier-sdk/benches/standard_plonk.rs b/snark-verifier-sdk/benches/standard_plonk.rs index c435e0ca..70d600ea 100644 --- a/snark-verifier-sdk/benches/standard_plonk.rs +++ b/snark-verifier-sdk/benches/standard_plonk.rs @@ -4,7 +4,7 @@ use halo2_base::gates::builder::CircuitBuilderStage; use halo2_base::utils::fs::gen_srs; use pprof::criterion::{Output, PProfProfiler}; use rand::rngs::OsRng; - +use std::path::Path; use ark_std::{end_timer, start_timer}; use halo2_base::halo2_proofs; use halo2_proofs::halo2curves as halo2_curves; @@ -175,8 +175,8 @@ mod application { fn gen_application_snark(params: &ParamsKZG) -> Snark { let circuit = application::StandardPlonk::rand(OsRng); - let pk = gen_pk(params, &circuit, None); - gen_snark_shplonk(params, &pk, circuit, None::<&str>) + let pk = gen_pk(params, &circuit, Some(Path::new("app.pk"))); + gen_snark_shplonk(params, &pk, circuit, Some(Path::new("app.snark"))) } fn bench(c: &mut Criterion) { @@ -191,7 +191,7 @@ fn bench(c: &mut Criterion) { let agg_circuit = AggregationCircuit::keygen::(¶ms, snarks.clone()); let start0 = start_timer!(|| "gen vk & pk"); - let pk = gen_pk(¶ms, &agg_circuit, None); + let pk = gen_pk(¶ms, &agg_circuit, Some(Path::new("agg.pk"))); end_timer!(start0); let break_points = agg_circuit.break_points(); diff --git a/snark-verifier-sdk/src/halo2.rs b/snark-verifier-sdk/src/halo2.rs index 949dcee0..ed155bc8 100644 --- a/snark-verifier-sdk/src/halo2.rs +++ b/snark-verifier-sdk/src/halo2.rs @@ -190,13 +190,11 @@ where MSMAccumulator = DualMSM<'params, Bn256>, >, { + #[cfg(feature = "halo2-axiom")] if let Some(path) = &path { - #[cfg(feature = "halo2-axiom")] if let Ok(snark) = read_snark(path) { return snark; } - #[cfg(not(feature = "halo2-axiom"))] - unimplemented!("Reading SNARKs is not supported in halo2-pse because we cannot derive Serialize/Deserialize for halo2curves field elements."); } let protocol = compile( params, @@ -207,7 +205,18 @@ where ); let instances = circuit.instances(); + #[cfg(feature = "halo2-axiom")] let proof = gen_proof::(params, pk, circuit, instances.clone(), None); + // If we can't serialize the entire snark, at least serialize the proof + #[cfg(not(feature = "halo2-axiom"))] + let proof = { + let path = path.map(|path| { + let path = path.as_ref().to_str().unwrap(); + (format!("{path}.instances"), format!("{path}.proof")) + }); + let paths = path.as_ref().map(|path| (Path::new(&path.0), Path::new(&path.1))); + gen_proof::(params, pk, circuit, instances.clone(), paths) + }; let snark = Snark::new(protocol, instances, proof); #[cfg(feature = "halo2-axiom")] @@ -219,6 +228,7 @@ where #[cfg(feature = "display")] end_timer!(write_time); } + #[allow(clippy::let_and_return)] snark } diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 8c98ebc5..90bd3af7 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -3,7 +3,7 @@ use crate::{BITS, LIMBS}; use halo2_base::{ gates::{ builder::{ - assign_threads_in, CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, + CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, MultiPhaseThreadBreakPoints, RangeCircuitBuilder, }, range::RangeConfig, @@ -19,7 +19,7 @@ use halo2_base::{ }, }, utils::ScalarField, - AssignedValue, SKIP_FIRST_PASS, + AssignedValue, }; use itertools::Itertools; use rand::{rngs::StdRng, SeedableRng}; @@ -38,7 +38,6 @@ use snark_verifier::{ verifier::SnarkVerifier, }; use std::{ - collections::HashMap, env::{set_var, var}, fs::File, path::Path, @@ -137,7 +136,7 @@ where (previous_instances, accumulator) } -#[derive(Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct AggregationConfigParams { pub degree: u32, pub num_advice: usize, @@ -452,61 +451,14 @@ impl Circuit for RangeWithInstanceCircuitBuilder { let range = config.range; let circuit = &self.circuit.0; range.load_lookup_table(&mut layouter).expect("load lookup table should not fail"); - // we later `take` the builder, so we need to save this value let witness_gen_only = circuit.builder.borrow().witness_gen_only(); - let mut assigned_advices = HashMap::new(); - - let mut first_pass = SKIP_FIRST_PASS; - layouter - .assign_region( - || "RangeWithInstanceCircuitBuilder", - |mut region| { - if first_pass { - first_pass = false; - return Ok(()); - } - // only support FirstPhase in this Builder because getting challenge value requires more specialized witness generation during synthesize - if !witness_gen_only { - // clone the builder so we can re-use the circuit for both vk and pk gen - let builder = circuit.builder.borrow(); - let assignments = builder.assign_all( - &range.gate, - &range.lookup_advice, - &range.q_lookup, - &mut region, - Default::default(), - ); - *circuit.break_points.borrow_mut() = assignments.break_points; - assigned_advices = assignments.assigned_advices; - } else { - #[cfg(feature = "display")] - let start0 = std::time::Instant::now(); - let builder = circuit.builder.take(); - let break_points = circuit.break_points.take(); - for (phase, (threads, break_points)) in builder - .threads - .into_iter() - .zip(break_points.into_iter()) - .enumerate() - .take(1) - { - assign_threads_in( - phase, - threads, - &range.gate, - &range.lookup_advice[phase], - &mut region, - break_points, - ); - } - #[cfg(feature = "display")] - println!("assign threads in {:?}", start0.elapsed()); - } - Ok(()) - }, - ) - .unwrap(); + let assigned_advices = circuit.sub_synthesize( + &range.gate, + &range.lookup_advice, + &range.q_lookup, + &mut layouter, + ); if !witness_gen_only { // expose public instances diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 2f28c97f..d0eb22ec 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -15,7 +15,7 @@ rustc-hash = "1.1.0" serde = { version = "1.0", features = ["derive"] } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "upgrade-v0.3.0", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.3.0", default-features = false } # This is Scroll's audited poseidon circuit. We only use it for the Native Poseidon spec. We do not use the halo2 circuit at all (and it wouldn't even work because the halo2_proofs tag is not compatbile). poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git" } @@ -30,7 +30,7 @@ rlp = { version = "0.5.2", default-features = false, features = ["std"], optiona revm = { version = "= 2.3.1", optional = true } # loader_halo2 -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "upgrade-v0.3.0", default-features = false, optional = true } +halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.3.0", default-features = false, optional = true } [dev-dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } diff --git a/snark-verifier/src/loader/halo2/loader.rs b/snark-verifier/src/loader/halo2/loader.rs index d721cb9c..9a8410d6 100644 --- a/snark-verifier/src/loader/halo2/loader.rs +++ b/snark-verifier/src/loader/halo2/loader.rs @@ -25,6 +25,7 @@ pub struct Halo2Loader> { num_ec_point: RefCell, _marker: PhantomData, #[cfg(test)] + #[allow(dead_code)] row_meterings: RefCell>, } diff --git a/snark-verifier/src/loader/halo2/shim.rs b/snark-verifier/src/loader/halo2/shim.rs index 0509e9e9..1812f150 100644 --- a/snark-verifier/src/loader/halo2/shim.rs +++ b/snark-verifier/src/loader/halo2/shim.rs @@ -145,7 +145,7 @@ mod halo2_lib { ecc::{fixed_base::FixedEcPoint, BaseFieldEccChip, EcPoint}, fields::{FieldChip, PrimeField}, }; - use std::{ops::Deref, sync::Mutex}; + use std::ops::Deref; type AssignedInteger = CRTInteger<::ScalarExt>; type AssignedEcPoint = EcPoint<::ScalarExt, AssignedInteger>; @@ -282,7 +282,7 @@ mod halo2_lib { fn variable_base_msm( &mut self, - ctx: &mut Self::Context, + builder: &mut Self::Context, pairs: &[( impl Deref, impl Deref, @@ -292,21 +292,18 @@ mod halo2_lib { .iter() .map(|(scalar, point)| (vec![*scalar.deref()], point.deref().clone())) .unzip(); - let thread_pool = Mutex::new(std::mem::take(ctx)); - let res = BaseFieldEccChip::::variable_base_msm::( + BaseFieldEccChip::::variable_base_msm::( self, - &thread_pool, + builder, &points, scalars, C::Scalar::NUM_BITS as usize, - ); - *ctx = thread_pool.into_inner().unwrap(); - res + ) } fn fixed_base_msm( &mut self, - ctx: &mut Self::Context, + builder: &mut Self::Context, pairs: &[(impl Deref, C)], ) -> Self::AssignedEcPoint { let (scalars, points): (Vec<_>, Vec<_>) = pairs @@ -319,16 +316,13 @@ mod halo2_lib { } }) .unzip(); - let thread_pool = Mutex::new(std::mem::take(ctx)); - let res = BaseFieldEccChip::::fixed_base_msm::( + BaseFieldEccChip::::fixed_base_msm::( self, - &thread_pool, + builder, &points, scalars, C::Scalar::NUM_BITS as usize, - ); - *ctx = thread_pool.into_inner().unwrap(); - res + ) } fn assert_equal( From aecfd457530770c49519e09e5e7df71ce6f84eff Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 5 May 2023 16:45:10 -0700 Subject: [PATCH 26/73] Moved `RangeWithInstanceCircuitBuilder` to halo2-lib (#9) * chore: sync with halo2-lib * fix: clippy --- snark-verifier-sdk/src/halo2/aggregation.rs | 111 +----------------- snark-verifier/examples/recursion.rs | 10 +- snark-verifier/src/loader/evm/loader.rs | 10 +- snark-verifier/src/loader/evm/test/tui.rs | 12 +- .../src/loader/evm/util/executor.rs | 2 +- 5 files changed, 20 insertions(+), 125 deletions(-) diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 90bd3af7..1b754fa5 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -4,15 +4,15 @@ use halo2_base::{ gates::{ builder::{ CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, - MultiPhaseThreadBreakPoints, RangeCircuitBuilder, + MultiPhaseThreadBreakPoints, RangeCircuitBuilder, RangeWithInstanceCircuitBuilder, + RangeWithInstanceConfig, }, - range::RangeConfig, RangeChip, }, halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, halo2curves::bn256::{Bn256, Fr, G1Affine}, - plonk::{self, Circuit, Column, ConstraintSystem, Instance, Selector}, + plonk::{self, Circuit, ConstraintSystem, Selector}, poly::{ commitment::{Params, ParamsProver}, kzg::commitment::ParamsKZG, @@ -152,63 +152,6 @@ impl AggregationConfigParams { } } -#[derive(Clone, Debug)] -pub struct RangeWithInstanceConfig { - pub range: RangeConfig, - pub instance: Column, -} - -/// This is an extension of [`RangeCircuitBuilder`] that adds support for public instances (aka public inputs+outputs) -/// -/// The intended design is that a [`GateThreadBuilder`] is populated and then produces some assigned instances, which are supplied as `assigned_instances` to this struct. -/// The [`Circuit`] implementation for this struct will then expose these instances and constrain them using the Halo2 API. -#[derive(Clone, Debug)] -pub struct RangeWithInstanceCircuitBuilder { - pub circuit: RangeCircuitBuilder, - pub assigned_instances: Vec>, -} - -impl RangeWithInstanceCircuitBuilder { - pub fn keygen( - builder: GateThreadBuilder, - assigned_instances: Vec>, - ) -> Self { - Self { circuit: RangeCircuitBuilder::keygen(builder), assigned_instances } - } - - pub fn mock(builder: GateThreadBuilder, assigned_instances: Vec>) -> Self { - Self { circuit: RangeCircuitBuilder::mock(builder), assigned_instances } - } - - pub fn prover( - builder: GateThreadBuilder, - assigned_instances: Vec>, - break_points: MultiPhaseThreadBreakPoints, - ) -> Self { - Self { circuit: RangeCircuitBuilder::prover(builder, break_points), assigned_instances } - } - - pub fn new(circuit: RangeCircuitBuilder, assigned_instances: Vec>) -> Self { - Self { circuit, assigned_instances } - } - - pub fn config(&self, k: u32, minimum_rows: Option) -> FlexGateConfigParams { - self.circuit.0.builder.borrow().config(k as usize, minimum_rows) - } - - pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { - self.circuit.0.break_points.borrow().clone() - } - - pub fn instance_count(&self) -> usize { - self.assigned_instances.len() - } - - pub fn instance(&self) -> Vec { - self.assigned_instances.iter().map(|v| *v.value()).collect() - } -} - #[derive(Clone, Debug)] pub struct AggregationCircuit { pub inner: RangeWithInstanceCircuitBuilder, @@ -427,54 +370,6 @@ impl AggregationCircuit { } } -impl Circuit for RangeWithInstanceCircuitBuilder { - type Config = RangeWithInstanceConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - unimplemented!() - } - - fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - let range = RangeCircuitBuilder::configure(meta); - let instance = meta.instance_column(); - meta.enable_equality(instance); - RangeWithInstanceConfig { range, instance } - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), plonk::Error> { - // copied from RangeCircuitBuilder::synthesize but with extra logic to expose public instances - let range = config.range; - let circuit = &self.circuit.0; - range.load_lookup_table(&mut layouter).expect("load lookup table should not fail"); - // we later `take` the builder, so we need to save this value - let witness_gen_only = circuit.builder.borrow().witness_gen_only(); - let assigned_advices = circuit.sub_synthesize( - &range.gate, - &range.lookup_advice, - &range.q_lookup, - &mut layouter, - ); - - if !witness_gen_only { - // expose public instances - let mut layouter = layouter.namespace(|| "expose"); - for (i, instance) in self.assigned_instances.iter().enumerate() { - let cell = instance.cell.unwrap(); - let (cell, _) = assigned_advices - .get(&(cell.context_id, cell.offset)) - .expect("instance not assigned"); - layouter.constrain_instance(*cell, config.instance, i); - } - } - Ok(()) - } -} - impl CircuitExt for RangeWithInstanceCircuitBuilder { fn num_instance(&self) -> Vec { vec![self.instance_count()] diff --git a/snark-verifier/examples/recursion.rs b/snark-verifier/examples/recursion.rs index 554fd073..4301eb59 100644 --- a/snark-verifier/examples/recursion.rs +++ b/snark-verifier/examples/recursion.rs @@ -365,7 +365,7 @@ mod recursion { .flat_map(|preprocessed| { let assigned = preprocessed.assigned(); [assigned.x(), assigned.y()] - .map(|coordinate| loader.scalar_from_assigned(coordinate.native().clone())) + .map(|coordinate| loader.scalar_from_assigned(*coordinate.native())) }) .chain(protocol.transcript_initial_state.clone()) .collect_vec(); @@ -410,7 +410,7 @@ mod recursion { .iter() .zip([rhs.lhs.assigned(), rhs.rhs.assigned()].iter()) .map(|(lhs, rhs)| { - loader.ecc_chip().select(&mut loader.ctx_mut().main(0), lhs, rhs, *condition) + loader.ecc_chip().select(loader.ctx_mut().main(0), lhs, rhs, *condition) }) .collect::>() .try_into() @@ -533,8 +533,8 @@ mod recursion { let mut circuit = Self { svk, default_accumulator, - app: app.into(), - previous: previous.into(), + app: app, + previous: previous, round, instances, as_proof, @@ -570,7 +570,7 @@ mod recursion { &self.svk, &loader, &self.previous, - Some(preprocessed_digest.clone()), + Some(preprocessed_digest), ); let default_accmulator = self.load_default_accumulator(&loader).unwrap(); diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index d4dd18cd..03e8fa8b 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -39,10 +39,10 @@ impl PartialEq for Value { impl Value { fn identifier(&self) -> String { match self { - Value::Constant(_) | Value::Memory(_) => format!("{:?}", self), - Value::Negated(value) => format!("-({:?})", value), - Value::Sum(lhs, rhs) => format!("({:?} + {:?})", lhs, rhs), - Value::Product(lhs, rhs) => format!("({:?} * {:?})", lhs, rhs), + Value::Constant(_) | Value::Memory(_) => format!("{self:?}"), + Value::Negated(value) => format!("-({value:?})"), + Value::Sum(lhs, rhs) => format!("({lhs:?} + {rhs:?})"), + Value::Product(lhs, rhs) => format!("({lhs:?} * {rhs:?})"), } } } @@ -435,7 +435,7 @@ impl EvmLoader { pub fn print_gas_metering(self: &Rc, costs: Vec) { for (identifier, cost) in self.gas_metering_ids.borrow().iter().zip(costs) { - println!("{}: {}", identifier, cost); + println!("{identifier}: {cost}"); } } } diff --git a/snark-verifier/src/loader/evm/test/tui.rs b/snark-verifier/src/loader/evm/test/tui.rs index 455f308b..328082c7 100644 --- a/snark-verifier/src/loader/evm/test/tui.rs +++ b/snark-verifier/src/loader/evm/test/tui.rs @@ -574,10 +574,10 @@ impl Tui { let line_number_format = if line_number == current_step { let step: &DebugStep = &debug_steps[line_number]; - format!("{:0>max_pc_len$x}|▶", step.pc, max_pc_len = max_pc_len) + format!("{:0>max_pc_len$x}|▶", step.pc) } else if line_number < debug_steps.len() { let step: &DebugStep = &debug_steps[line_number]; - format!("{:0>max_pc_len$x}| ", step.pc, max_pc_len = max_pc_len) + format!("{:0>max_pc_len$x}| ", step.pc) } else { "END CALL".to_string() }; @@ -636,7 +636,7 @@ impl Tui { .map(|i| stack_item.byte(i)) .map(|byte| { Span::styled( - format!("{:02x} ", byte), + format!("{byte:02x} "), if affected.is_some() { Style::default().fg(Color::Cyan) } else if byte == 0 { @@ -657,7 +657,7 @@ impl Tui { } let mut spans = vec![Span::styled( - format!("{:0min_len$}| ", i, min_len = min_len), + format!("{i:0min_len$}| "), Style::default().fg(Color::White), )]; spans.extend(words); @@ -729,7 +729,7 @@ impl Tui { .iter() .map(|byte| { Span::styled( - format!("{:02x} ", byte), + format!("{byte:02x} "), if let (Some(w), Some(color)) = (word, color) { if i == w { Style::default().fg(color) @@ -748,7 +748,7 @@ impl Tui { .collect(); let mut spans = vec![Span::styled( - format!("{:0min_len$x}| ", i * 32, min_len = min_len), + format!("{:0min_len$x}| ", i * 32), Style::default().fg(Color::White), )]; spans.extend(words); diff --git a/snark-verifier/src/loader/evm/util/executor.rs b/snark-verifier/src/loader/evm/util/executor.rs index de466c08..a7697a0e 100644 --- a/snark-verifier/src/loader/evm/util/executor.rs +++ b/snark-verifier/src/loader/evm/util/executor.rs @@ -55,7 +55,7 @@ fn get_create2_address_from_hash( ] .concat(); - let hash = keccak256(&bytes); + let hash = keccak256(bytes); let mut bytes = [0u8; 20]; bytes.copy_from_slice(&hash[12..]); From 95e6b4a4b67119b64c1b60240da460191228c7f4 Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Thu, 11 May 2023 11:35:49 -0700 Subject: [PATCH 27/73] chore: fix halo2-base branch in sdk --- snark-verifier-sdk/Cargo.toml | 4 ++-- snark-verifier-sdk/src/halo2/aggregation.rs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index ca206bce..34b0f32c 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -17,7 +17,7 @@ serde_json = "1.0" serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "upgrade-v0.3.0-fixes", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.3.0", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } # loader_evm @@ -68,4 +68,4 @@ harness = false [[bench]] name = "zkevm_plus_state" required-features = ["loader_halo2", "loader_evm", "zkevm", "halo2-pse"] -harness = false \ No newline at end of file +harness = false diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 1b754fa5..9a7b2a1c 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -136,6 +136,8 @@ where (previous_instances, accumulator) } +/// Same as `FlexGateConfigParams` except we assume a single Phase and default 'Vertical' strategy. +/// Also adds `lookup_bits` field. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct AggregationConfigParams { pub degree: u32, From 739c1f74e4f07d9f3e0c772631b99f9066eea719 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 22 May 2023 14:25:09 -0500 Subject: [PATCH 28/73] feat: update to halo2-lib new types (#10) --- snark-verifier-sdk/src/halo2/aggregation.rs | 11 ++++--- .../examples/evm-verifier-with-accumulator.rs | 11 ++++--- snark-verifier/examples/recursion.rs | 17 ++++++----- snark-verifier/src/loader/halo2/shim.rs | 29 ++++++++----------- 4 files changed, 31 insertions(+), 37 deletions(-) diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 9a7b2a1c..3bff2060 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -256,13 +256,12 @@ impl AggregationCircuit { let lhs = accumulator.lhs.assigned(); let rhs = accumulator.rhs.assigned(); let assigned_instances = lhs - .x - .truncation - .limbs + .x() + .limbs() .iter() - .chain(lhs.y.truncation.limbs.iter()) - .chain(rhs.x.truncation.limbs.iter()) - .chain(rhs.y.truncation.limbs.iter()) + .chain(lhs.y().limbs().iter()) + .chain(rhs.x().limbs().iter()) + .chain(rhs.y().limbs().iter()) .copied() .collect_vec(); diff --git a/snark-verifier/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs index 986972ef..dd537880 100644 --- a/snark-verifier/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -378,13 +378,12 @@ mod aggregation { let lhs = lhs.assigned(); let rhs = rhs.assigned(); let assigned_instances = lhs - .x - .truncation - .limbs + .x() + .limbs() .iter() - .chain(lhs.y.truncation.limbs.iter()) - .chain(rhs.x.truncation.limbs.iter()) - .chain(rhs.y.truncation.limbs.iter()) + .chain(lhs.y().limbs().iter()) + .chain(rhs.x().limbs().iter()) + .chain(rhs.y().limbs().iter()) .copied() .collect_vec(); diff --git a/snark-verifier/examples/recursion.rs b/snark-verifier/examples/recursion.rs index 4301eb59..5829e1b7 100644 --- a/snark-verifier/examples/recursion.rs +++ b/snark-verifier/examples/recursion.rs @@ -333,7 +333,7 @@ mod recursion { }, AssignedValue, }; - use halo2_ecc::bn254::FpChip; + use halo2_ecc::{bn254::FpChip, ecc::EcPoint}; use halo2_proofs::plonk::{Column, Instance}; use snark_verifier::loader::halo2::{EccInstructions, IntegerInstructions}; @@ -410,7 +410,12 @@ mod recursion { .iter() .zip([rhs.lhs.assigned(), rhs.rhs.assigned()].iter()) .map(|(lhs, rhs)| { - loader.ecc_chip().select(loader.ctx_mut().main(0), lhs, rhs, *condition) + loader.ecc_chip().select( + loader.ctx_mut().main(0), + EcPoint::clone(&lhs), + EcPoint::clone(&rhs), + *condition, + ) }) .collect::>() .try_into() @@ -566,12 +571,8 @@ mod recursion { let loader = Halo2Loader::new(ecc_chip, builder); let (mut app_instances, app_accumulators) = succinct_verify(&self.svk, &loader, &self.app, None); - let (mut previous_instances, previous_accumulators) = succinct_verify( - &self.svk, - &loader, - &self.previous, - Some(preprocessed_digest), - ); + let (mut previous_instances, previous_accumulators) = + succinct_verify(&self.svk, &loader, &self.previous, Some(preprocessed_digest)); let default_accmulator = self.load_default_accumulator(&loader).unwrap(); let previous_accumulators = previous_accumulators diff --git a/snark-verifier/src/loader/halo2/shim.rs b/snark-verifier/src/loader/halo2/shim.rs index 1812f150..790c9e22 100644 --- a/snark-verifier/src/loader/halo2/shim.rs +++ b/snark-verifier/src/loader/halo2/shim.rs @@ -132,7 +132,7 @@ mod halo2_lib { use crate::halo2_proofs::halo2curves::CurveAffineExt; use crate::{ loader::halo2::{EccInstructions, IntegerInstructions}, - util::arithmetic::{CurveAffine, Field}, + util::arithmetic::CurveAffine, }; use halo2_base::{ self, @@ -140,14 +140,14 @@ mod halo2_lib { AssignedValue, QuantumCell::{Constant, Existing}, }; + use halo2_ecc::bigint::ProperCrtUint; use halo2_ecc::{ - bigint::CRTInteger, - ecc::{fixed_base::FixedEcPoint, BaseFieldEccChip, EcPoint}, + ecc::{BaseFieldEccChip, EcPoint}, fields::{FieldChip, PrimeField}, }; use std::ops::Deref; - type AssignedInteger = CRTInteger<::ScalarExt>; + type AssignedInteger = ProperCrtUint<::ScalarExt>; type AssignedEcPoint = EcPoint<::ScalarExt, AssignedInteger>; impl IntegerInstructions for GateChip { @@ -250,19 +250,11 @@ mod halo2_lib { } fn assign_constant(&self, ctx: &mut Self::Context, point: C) -> Self::AssignedEcPoint { - let fixed = FixedEcPoint::::from_curve( - point, - self.field_chip.num_limbs, - self.field_chip.limb_bits, - ); - FixedEcPoint::assign(fixed, self.field_chip(), ctx.main(0)) + self.assign_constant_point(ctx.main(0), point) } fn assign_point(&self, ctx: &mut Self::Context, point: C) -> Self::AssignedEcPoint { - let assigned = self.assign_point(ctx.main(0), point); - let is_valid = self.is_on_curve_or_infinity::(ctx.main(0), &assigned); - self.field_chip().gate().assert_is_const(ctx.main(0), &is_valid, &C::Scalar::one()); - assigned + self.assign_point(ctx.main(0), point) } fn sum_with_const( @@ -274,10 +266,13 @@ mod halo2_lib { let constant = if bool::from(constant.is_identity()) { None } else { - let constant = EccInstructions::::assign_constant(self, ctx, constant); + let constant = EccInstructions::assign_constant(self, ctx, constant); Some(constant) }; - self.sum::(ctx.main(0), constant.iter().chain(values.iter().map(Deref::deref))) + self.sum::( + ctx.main(0), + constant.into_iter().chain(values.iter().map(|v| v.deref().clone())), + ) } fn variable_base_msm( @@ -331,7 +326,7 @@ mod halo2_lib { a: &Self::AssignedEcPoint, b: &Self::AssignedEcPoint, ) { - self.assert_equal(ctx.main(0), a, b); + self.assert_equal(ctx.main(0), a.clone(), b.clone()); } } } From b38400a6ff61eee253a720ef08792b2d07a39c70 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 22 May 2023 16:09:38 -0500 Subject: [PATCH 29/73] feat: add `assert` for non-empty accumulators in `decide_all` (#11) --- snark-verifier/src/pcs/ipa/decider.rs | 1 + snark-verifier/src/pcs/kzg/decider.rs | 18 +++++------------- 2 files changed, 6 insertions(+), 13 deletions(-) diff --git a/snark-verifier/src/pcs/ipa/decider.rs b/snark-verifier/src/pcs/ipa/decider.rs index 933480f3..5235a857 100644 --- a/snark-verifier/src/pcs/ipa/decider.rs +++ b/snark-verifier/src/pcs/ipa/decider.rs @@ -58,6 +58,7 @@ mod native { dk: &Self::DecidingKey, accumulators: Vec>, ) -> Result<(), Error> { + assert!(!accumulators.is_empty()); accumulators .into_iter() .map(|accumulator| Self::decide(dk, accumulator)) diff --git a/snark-verifier/src/pcs/kzg/decider.rs b/snark-verifier/src/pcs/kzg/decider.rs index 417a39dc..59f1afbf 100644 --- a/snark-verifier/src/pcs/kzg/decider.rs +++ b/snark-verifier/src/pcs/kzg/decider.rs @@ -19,12 +19,7 @@ impl KzgDecidingKey { g2: M::G2Affine, s_g2: M::G2Affine, ) -> Self { - Self { - svk: svk.into(), - g2, - s_g2, - _marker: PhantomData, - } + Self { svk: svk.into(), g2, s_g2, _marker: PhantomData } } } @@ -67,19 +62,16 @@ mod native { KzgAccumulator { lhs, rhs }: KzgAccumulator, ) -> Result<(), Error> { let terms = [(&lhs, &dk.g2.into()), (&rhs, &(-dk.s_g2).into())]; - bool::from( - M::multi_miller_loop(&terms) - .final_exponentiation() - .is_identity(), - ) - .then_some(()) - .ok_or_else(|| Error::AssertionFailure("e(lhs, g2)·e(rhs, -s_g2) == O".to_string())) + bool::from(M::multi_miller_loop(&terms).final_exponentiation().is_identity()) + .then_some(()) + .ok_or_else(|| Error::AssertionFailure("e(lhs, g2)·e(rhs, -s_g2) == O".to_string())) } fn decide_all( dk: &Self::DecidingKey, accumulators: Vec>, ) -> Result<(), Error> { + assert!(!accumulators.is_empty()); accumulators .into_iter() .map(|accumulator| Self::decide(dk, accumulator)) From e24fa3c622f1cc18b8fc356b910b8b1737786a4d Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 22 May 2023 16:13:10 -0500 Subject: [PATCH 30/73] feat: use `zip_eq` for `Polynomial` add/sub (#12) --- snark-verifier/src/util/poly.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/snark-verifier/src/util/poly.rs b/snark-verifier/src/util/poly.rs index 88eed4fd..17a065f9 100644 --- a/snark-verifier/src/util/poly.rs +++ b/snark-verifier/src/util/poly.rs @@ -1,6 +1,7 @@ //! Polynomial. use crate::util::{arithmetic::Field, parallelize}; +use itertools::Itertools; use rand::Rng; use std::{ iter::{self, Sum}, @@ -89,7 +90,7 @@ impl<'a, F: Field> Add<&'a Polynomial> for Polynomial { fn add(mut self, rhs: &'a Polynomial) -> Polynomial { parallelize(&mut self.0, |(lhs, start)| { - for (lhs, rhs) in lhs.iter_mut().zip(rhs.0[start..].iter()) { + for (lhs, rhs) in lhs.iter_mut().zip_eq(rhs.0[start..].iter()) { *lhs += *rhs; } }); @@ -102,7 +103,7 @@ impl<'a, F: Field> Sub<&'a Polynomial> for Polynomial { fn sub(mut self, rhs: &'a Polynomial) -> Polynomial { parallelize(&mut self.0, |(lhs, start)| { - for (lhs, rhs) in lhs.iter_mut().zip(rhs.0[start..].iter()) { + for (lhs, rhs) in lhs.iter_mut().zip_eq(rhs.0[start..].iter()) { *lhs -= *rhs; } }); From f510177d5938d0cfdbd268158dd9c1f671fd4e95 Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Mon, 22 May 2023 14:19:32 -0700 Subject: [PATCH 31/73] fix: git CI turn off all features --- .github/workflows/ci.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 61c72229..634eed77 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,7 +27,7 @@ jobs: run: (hash svm 2>/dev/null || cargo install svm-rs) && svm install 0.8.17 && solc --version - name: Run test - run: cargo test --all --all-features -- --nocapture + run: cargo test --all -- --nocapture lint: @@ -51,4 +51,4 @@ jobs: run: cargo fmt --all -- --check - name: Run clippy - run: cargo clippy --all --all-features --all-targets -- -D warnings + run: cargo clippy --all --all-targets -- -D warnings From 9bbe6da660b36ac716fe6b129c5313fce3591323 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 22 May 2023 16:28:50 -0500 Subject: [PATCH 32/73] fix: `rotate_scalar` misbehaves on `i32::MIN` (#13) Should never actually be callable with such a large negative rotation --- snark-verifier/src/util/arithmetic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snark-verifier/src/util/arithmetic.rs b/snark-verifier/src/util/arithmetic.rs index 36814ab9..94964cc7 100644 --- a/snark-verifier/src/util/arithmetic.rs +++ b/snark-verifier/src/util/arithmetic.rs @@ -150,7 +150,7 @@ impl Domain { match rotation.0.cmp(&0) { Ordering::Equal => scalar, Ordering::Greater => scalar * self.gen.pow_vartime([rotation.0 as u64]), - Ordering::Less => scalar * self.gen_inv.pow_vartime([(-rotation.0) as u64]), + Ordering::Less => scalar * self.gen_inv.pow_vartime([(-(rotation.0 as i64)) as u64]), } } } From 11e0ebc91f220867d984b5c77e5acf0c5c8f51aa Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 22 May 2023 17:34:19 -0500 Subject: [PATCH 33/73] fix: cleanup code quality (#14) --- snark-verifier/src/loader/evm/loader.rs | 8 +- snark-verifier/src/system/halo2.rs | 2 +- .../src/system/halo2/aggregation.rs | 718 ------------------ .../src/system/halo2/transcript/evm.rs | 2 + 4 files changed, 9 insertions(+), 721 deletions(-) delete mode 100644 snark-verifier/src/system/halo2/aggregation.rs diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index 03e8fa8b..f6bf17b2 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -648,7 +648,9 @@ where self.ec_point(Value::Constant((x, y))) } - fn ec_point_assert_eq(&self, _: &str, _: &EcPoint, _: &EcPoint) {} + fn ec_point_assert_eq(&self, _: &str, _: &EcPoint, _: &EcPoint) { + unimplemented!() + } fn multi_scalar_multiplication( pairs: &[(&>::LoadedScalar, &EcPoint)], @@ -672,7 +674,9 @@ impl> ScalarLoader for Rc { self.scalar(Value::Constant(fe_to_u256(*value))) } - fn assert_eq(&self, _: &str, _: &Scalar, _: &Scalar) {} + fn assert_eq(&self, _: &str, _: &Scalar, _: &Scalar) { + unimplemented!() + } fn sum_with_coeff_and_const(&self, values: &[(F, &Scalar)], constant: F) -> Scalar { if values.is_empty() { diff --git a/snark-verifier/src/system/halo2.rs b/snark-verifier/src/system/halo2.rs index 561a1666..98f4488c 100644 --- a/snark-verifier/src/system/halo2.rs +++ b/snark-verifier/src/system/halo2.rs @@ -111,7 +111,7 @@ pub fn compile<'a, C: CurveAffine, P: Params<'a, C>>( .chain((0..num_proof).flat_map(move |t| polynomials.permutation_z_queries::(t))) .chain((0..num_proof).flat_map(move |t| polynomials.lookup_queries::(t))) .collect(); - + // `quotient_query()` is not needed in evaluations because the verifier can compute it itself from the other evaluations. let queries = (0..num_proof) .flat_map(|t| { iter::empty() diff --git a/snark-verifier/src/system/halo2/aggregation.rs b/snark-verifier/src/system/halo2/aggregation.rs deleted file mode 100644 index a3b09c15..00000000 --- a/snark-verifier/src/system/halo2/aggregation.rs +++ /dev/null @@ -1,718 +0,0 @@ -use super::{BITS, LIMBS}; -use crate::{ - loader::{self, native::NativeLoader, Loader}, - pcs::{ - kzg::{ - Bdfg21, Kzg, KzgAccumulator, KzgAs, KzgAsProvingKey, KzgAsVerifyingKey, - KzgSuccinctVerifyingKey, LimbsEncoding, - }, - AccumulationScheme, AccumulationSchemeProver, - }, - system::{ - self, - halo2::{ - compile, read_or_create_srs, transcript::halo2::ChallengeScalar, Config, - Halo2VerifierCircuitConfig, Halo2VerifierCircuitConfigParams, - }, - }, - util::arithmetic::fe_to_limbs, - verifier::{self, PlonkVerifier}, - Protocol, -}; -use ark_std::{end_timer, start_timer}; -use halo2_base::AssignedValue; -pub use halo2_base::{ - utils::{biguint_to_fe, fe_to_biguint}, - Context, ContextParams, -}; -use halo2_curves::bn256::{Bn256, Fr, G1Affine}; -use halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner, Value}, - plonk::{ - self, create_proof, keygen_pk, keygen_vk, verify_proof, Circuit, ProvingKey, VerifyingKey, - }, - poly::{ - commitment::{Params, ParamsProver}, - kzg::{ - commitment::{KZGCommitmentScheme, ParamsKZG}, - multiopen::{ProverSHPLONK, VerifierSHPLONK}, - strategy::AccumulatorStrategy, - }, - VerificationStrategy, - }, - transcript::{TranscriptReadBuffer, TranscriptWriterBuffer}, -}; -use itertools::Itertools; -use num_bigint::BigUint; -use num_traits::Num; -use rand_chacha::{rand_core::SeedableRng, ChaCha20Rng}; -use std::{ - fs::File, - io::{BufReader, BufWriter, Cursor, Read, Write}, - path::Path, - rc::Rc, -}; - -pub const T: usize = 3; -pub const RATE: usize = 2; -pub const R_F: usize = 8; -pub const R_P: usize = 57; - -pub type Halo2Loader<'a, 'b> = loader::halo2::Halo2Loader<'a, 'b, G1Affine>; -pub type PoseidonTranscript = - system::halo2::transcript::halo2::PoseidonTranscript; - -pub type Pcs = Kzg; -pub type Svk = KzgSuccinctVerifyingKey; -pub type As = KzgAs; -pub type AsPk = KzgAsProvingKey; -pub type AsVk = KzgAsVerifyingKey; -pub type Plonk = verifier::Plonk>; - -pub struct Snark { - protocol: Protocol, - instances: Vec>, - proof: Vec, -} - -impl Snark { - pub fn new(protocol: Protocol, instances: Vec>, proof: Vec) -> Self { - Self { protocol, instances, proof } - } - pub fn protocol(&self) -> &Protocol { - &self.protocol - } - pub fn instances(&self) -> &[Vec] { - &self.instances - } - pub fn proof(&self) -> &[u8] { - &self.proof - } -} - -impl From for SnarkWitness { - fn from(snark: Snark) -> Self { - Self { - protocol: snark.protocol, - instances: snark - .instances - .into_iter() - .map(|instances| instances.into_iter().map(Value::known).collect_vec()) - .collect(), - proof: Value::known(snark.proof), - } - } -} - -#[derive(Clone)] -pub struct SnarkWitness { - protocol: Protocol, - instances: Vec>>, - proof: Value>, -} - -impl SnarkWitness { - pub fn without_witnesses(&self) -> Self { - SnarkWitness { - protocol: self.protocol.clone(), - instances: self - .instances - .iter() - .map(|instances| vec![Value::unknown(); instances.len()]) - .collect(), - proof: Value::unknown(), - } - } - - pub fn protocol(&self) -> &Protocol { - &self.protocol - } - - pub fn instances(&self) -> &[Vec>] { - &self.instances - } - - pub fn proof(&self) -> Value<&[u8]> { - self.proof.as_ref().map(Vec::as_slice) - } -} - -pub fn aggregate<'a, 'b>( - svk: &Svk, - loader: &Rc>, - snarks: &[SnarkWitness], - as_vk: &AsVk, - as_proof: Value<&'_ [u8]>, - expose_instances: bool, -) -> Vec> { - let assign_instances = |instances: &[Vec>]| { - instances - .iter() - .map(|instances| { - instances.iter().map(|instance| loader.assign_scalar(*instance)).collect_vec() - }) - .collect_vec() - }; - - let mut instances_to_expose = vec![]; - let mut accumulators = snarks - .iter() - .flat_map(|snark| { - let instances = assign_instances(&snark.instances); - if expose_instances { - instances_to_expose.extend( - instances - .iter() - .flat_map(|instance| instance.iter().map(|scalar| scalar.assigned())), - ); - } - let mut transcript = - PoseidonTranscript::, _, _>::new(loader, snark.proof()); - let proof = - Plonk::read_proof(svk, &snark.protocol, &instances, &mut transcript).unwrap(); - Plonk::succinct_verify(svk, &snark.protocol, &instances, &proof).unwrap() - }) - .collect_vec(); - - let KzgAccumulator { lhs, rhs } = if accumulators.len() > 1 { - let mut transcript = PoseidonTranscript::, _, _>::new(loader, as_proof); - let proof = As::read_proof(as_vk, &accumulators, &mut transcript).unwrap(); - As::verify(as_vk, &accumulators, &proof).unwrap() - } else { - accumulators.pop().unwrap() - }; - - let lhs = lhs.assigned(); - let rhs = rhs.assigned(); - - lhs.x - .truncation - .limbs - .iter() - .chain(lhs.y.truncation.limbs.iter()) - .chain(rhs.x.truncation.limbs.iter()) - .chain(rhs.y.truncation.limbs.iter()) - .chain(instances_to_expose.iter()) - .cloned() - .collect_vec() -} - -pub fn recursive_aggregate<'a, 'b>( - svk: &Svk, - loader: &Rc>, - snarks: &[SnarkWitness], - recursive_snark: &SnarkWitness, - as_vk: &AsVk, - as_proof: Value<&'_ [u8]>, - use_dummy: AssignedValue, -) -> (Vec>, Vec>>) { - let assign_instances = |instances: &[Vec>]| { - instances - .iter() - .map(|instances| { - instances.iter().map(|instance| loader.assign_scalar(*instance)).collect_vec() - }) - .collect_vec() - }; - - let mut assigned_instances = vec![]; - let mut accumulators = snarks - .iter() - .flat_map(|snark| { - let instances = assign_instances(&snark.instances); - assigned_instances.push( - instances - .iter() - .flat_map(|instance| instance.iter().map(|scalar| scalar.assigned())) - .collect_vec(), - ); - let mut transcript = - PoseidonTranscript::, _, _>::new(loader, snark.proof()); - let proof = - Plonk::read_proof(svk, &snark.protocol, &instances, &mut transcript).unwrap(); - Plonk::succinct_verify(svk, &snark.protocol, &instances, &proof).unwrap() - }) - .collect_vec(); - - let use_dummy = loader.scalar_from_assigned(use_dummy); - - let prev_instances = assign_instances(&recursive_snark.instances); - let mut accs = { - let mut transcript = - PoseidonTranscript::, _, _>::new(loader, recursive_snark.proof()); - let proof = - Plonk::read_proof(svk, &recursive_snark.protocol, &prev_instances, &mut transcript) - .unwrap(); - let mut accs = Plonk::succinct_verify_or_dummy( - svk, - &recursive_snark.protocol, - &prev_instances, - &proof, - &use_dummy, - ) - .unwrap(); - for acc in accs.iter_mut() { - (*acc).lhs = - loader.ec_point_select(&accumulators[0].lhs, &acc.lhs, &use_dummy).unwrap(); - (*acc).rhs = - loader.ec_point_select(&accumulators[0].rhs, &acc.rhs, &use_dummy).unwrap(); - } - accs - }; - accumulators.append(&mut accs); - - let KzgAccumulator { lhs, rhs } = { - let mut transcript = PoseidonTranscript::, _, _>::new(loader, as_proof); - let proof = As::read_proof(as_vk, &accumulators, &mut transcript).unwrap(); - As::verify(as_vk, &accumulators, &proof).unwrap() - }; - - let lhs = lhs.assigned(); - let rhs = rhs.assigned(); - - let mut new_instances = prev_instances - .iter() - .flat_map(|instance| instance.iter().map(|scalar| scalar.assigned())) - .collect_vec(); - for (i, acc_limb) in lhs - .x - .truncation - .limbs - .iter() - .chain(lhs.y.truncation.limbs.iter()) - .chain(rhs.x.truncation.limbs.iter()) - .chain(rhs.y.truncation.limbs.iter()) - .enumerate() - { - new_instances[i] = acc_limb.clone(); - } - (new_instances, assigned_instances) -} - -#[derive(Clone)] -pub struct AggregationCircuit { - svk: Svk, - snarks: Vec, - pub instances: Vec, - as_vk: AsVk, - as_proof: Value>, - expose_target_instances: bool, -} - -impl AggregationCircuit { - pub fn new( - params: &ParamsKZG, - snarks: impl IntoIterator, - expose_target_instances: bool, - ) -> Self { - let svk = params.get_g()[0].into(); - let snarks = snarks.into_iter().collect_vec(); - - let mut accumulators = snarks - .iter() - .flat_map(|snark| { - let mut transcript = - PoseidonTranscript::::new(snark.proof.as_slice()); - let proof = - Plonk::read_proof(&svk, &snark.protocol, &snark.instances, &mut transcript) - .unwrap(); - Plonk::succinct_verify(&svk, &snark.protocol, &snark.instances, &proof).unwrap() - }) - .collect_vec(); - - let as_pk = AsPk::new(Some((params.get_g()[0], params.get_g()[1]))); - let (accumulator, as_proof) = if accumulators.len() > 1 { - let mut transcript = PoseidonTranscript::::new(Vec::new()); - let accumulator = As::create_proof( - &as_pk, - &accumulators, - &mut transcript, - ChaCha20Rng::from_seed(Default::default()), - ) - .unwrap(); - (accumulator, Value::known(transcript.finalize())) - } else { - (accumulators.pop().unwrap(), Value::unknown()) - }; - - let KzgAccumulator { lhs, rhs } = accumulator; - let mut instances = - [lhs.x, lhs.y, rhs.x, rhs.y].map(fe_to_limbs::<_, _, LIMBS, BITS>).concat(); - if expose_target_instances { - instances.extend(snarks.iter().flat_map(|snark| snark.instances.iter().flatten())); - } - - Self { - svk, - snarks: snarks.into_iter().map_into().collect(), - instances, - as_vk: as_pk.vk(), - as_proof, - expose_target_instances, - } - } - - pub fn accumulator_indices() -> Vec<(usize, usize)> { - (0..4 * LIMBS).map(|idx| (0, idx)).collect() - } - - pub fn num_instance(&self) -> Vec { - dbg!(self.instances.len()); - vec![self.instances.len()] - } - - pub fn instances(&self) -> Vec> { - vec![self.instances.clone()] - } - - pub fn as_proof(&self) -> Value<&[u8]> { - self.as_proof.as_ref().map(Vec::as_slice) - } - - pub fn synthesize_proof( - &self, - config: Halo2VerifierCircuitConfig, - layouter: &mut impl Layouter, - instance_equalities: Vec<(usize, usize)>, - ) -> Result>, plonk::Error> { - config.base_field_config.load_lookup_table(layouter)?; - - // Need to trick layouter to skip first pass in get shape mode - let using_simple_floor_planner = true; - let mut first_pass = true; - let mut assigned_instances = None; - layouter.assign_region( - || "", - |region| { - if using_simple_floor_planner && first_pass { - first_pass = false; - return Ok(()); - } - let ctx = config.base_field_config.new_context(region); - - let loader = Halo2Loader::new(&config.base_field_config, ctx); - let instances = aggregate( - &self.svk, - &loader, - &self.snarks, - &self.as_vk, - self.as_proof(), - self.expose_target_instances, - ); - - for &(i, j) in &instance_equalities { - loader - .ctx_mut() - .region - .constrain_equal(instances[i].cell(), instances[j].cell())?; - } - // REQUIRED STEP - loader.finalize(); - assigned_instances = Some(instances); - Ok(()) - }, - )?; - Ok(assigned_instances.unwrap()) - } -} - -impl Circuit for AggregationCircuit { - type Config = Halo2VerifierCircuitConfig; - type FloorPlanner = SimpleFloorPlanner; - - fn without_witnesses(&self) -> Self { - Self { - svk: self.svk, - snarks: self.snarks.iter().map(SnarkWitness::without_witnesses).collect(), - instances: Vec::new(), - as_vk: self.as_vk, - as_proof: Value::unknown(), - expose_target_instances: self.expose_target_instances, - } - } - - fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - let path = std::env::var("VERIFY_CONFIG").expect("export VERIFY_CONFIG with config path"); - let params: Halo2VerifierCircuitConfigParams = serde_json::from_reader( - File::open(path.as_str()).expect(format!("{} file should exist", path).as_str()), - ) - .unwrap(); - - Halo2VerifierCircuitConfig::configure(meta, params) - } - - fn synthesize( - &self, - config: Self::Config, - mut layouter: impl Layouter, - ) -> Result<(), plonk::Error> { - let config_instance = config.instance.clone(); - let assigned_instances = self.synthesize_proof(config, &mut layouter, vec![])?; - Ok({ - // TODO: use less instances by following Scroll's strategy of keeping only last bit of y coordinate - let mut layouter = layouter.namespace(|| "expose"); - for (i, assigned_instance) in assigned_instances.iter().enumerate() { - layouter.constrain_instance( - assigned_instance.cell().clone(), - config_instance, - i, - )?; - } - }) - } -} - -pub fn gen_srs(k: u32) -> ParamsKZG { - read_or_create_srs::(k, |k| { - ParamsKZG::::setup(k, ChaCha20Rng::from_seed(Default::default())) - }) -} - -pub fn gen_vk>( - params: &ParamsKZG, - circuit: &ConcreteCircuit, - name: &str, -) -> VerifyingKey { - let path = format!("./data/{}_{}.vkey", name, params.k()); - #[cfg(feature = "serialize")] - match File::open(path.as_str()) { - Ok(f) => { - let read_time = start_timer!(|| format!("Reading vkey from {}", path)); - let mut bufreader = BufReader::new(f); - let vk = VerifyingKey::read::<_, ConcreteCircuit>(&mut bufreader, params) - .expect("Reading vkey should not fail"); - end_timer!(read_time); - vk - } - Err(_) => { - let vk_time = start_timer!(|| "vkey"); - let vk = keygen_vk(params, circuit).unwrap(); - end_timer!(vk_time); - let mut f = BufWriter::new(File::create(path.as_str()).unwrap()); - println!("Writing vkey to {}", path); - vk.write(&mut f).unwrap(); - vk - } - } - #[cfg(not(feature = "serialize"))] - { - let vk_time = start_timer!(|| "vkey"); - let vk = keygen_vk(params, circuit).unwrap(); - end_timer!(vk_time); - vk - } -} - -pub fn gen_pk>( - params: &ParamsKZG, - circuit: &ConcreteCircuit, - name: &str, -) -> ProvingKey { - let path = format!("./data/{}_{}.pkey", name, params.k()); - #[cfg(feature = "serialize")] - match File::open(path.as_str()) { - Ok(f) => { - let read_time = start_timer!(|| format!("Reading pkey from {}", path)); - let mut bufreader = BufReader::new(f); - let pk = ProvingKey::read::<_, ConcreteCircuit>(&mut bufreader, params) - .expect("Reading pkey should not fail"); - end_timer!(read_time); - pk - } - Err(_) => { - let vk = gen_vk::(params, circuit, name); - let pk_time = start_timer!(|| "pkey"); - let pk = keygen_pk(params, vk, circuit).unwrap(); - end_timer!(pk_time); - let mut f = BufWriter::new(File::create(path.as_str()).unwrap()); - println!("Writing pkey to {}", path); - pk.write(&mut f).unwrap(); - pk - } - } - #[cfg(not(feature = "serialize"))] - { - let vk = gen_vk::(params, circuit, name); - let pk_time = start_timer!(|| "pkey"); - let pk = keygen_pk(params, vk, circuit).unwrap(); - end_timer!(pk_time); - pk - } -} - -pub fn read_bytes(path: &str) -> Vec { - let mut buf = vec![]; - let mut f = File::open(path).unwrap(); - f.read_to_end(&mut buf).unwrap(); - buf -} - -pub fn write_bytes(path: &str, buf: &Vec) { - let mut f = File::create(path).unwrap(); - f.write(buf).unwrap(); -} - -/// reads the instances for T::N_PROOFS circuits from file -pub fn read_instances(path: &str) -> Option>>> { - let f = File::open(path); - if let Err(_) = f { - return None; - } - let f = f.unwrap(); - let reader = BufReader::new(f); - let instances_str: Vec>> = serde_json::from_reader(reader).unwrap(); - let ret = instances_str - .into_iter() - .map(|circuit_instances| { - circuit_instances - .into_iter() - .map(|instance_column| { - instance_column - .iter() - .map(|str| { - biguint_to_fe::(&BigUint::from_str_radix(str.as_str(), 16).unwrap()) - }) - .collect_vec() - }) - .collect_vec() - }) - .collect_vec(); - Some(ret) -} - -pub fn write_instances(instances: &Vec>>, path: &str) { - let mut hex_strings = vec![]; - for circuit_instances in instances.iter() { - hex_strings.push( - circuit_instances - .iter() - .map(|instance_column| { - instance_column.iter().map(|x| fe_to_biguint(x).to_str_radix(16)).collect_vec() - }) - .collect_vec(), - ); - } - let f = BufWriter::new(File::create(path).unwrap()); - serde_json::to_writer(f, &hex_strings).unwrap(); -} - -pub trait TargetCircuit { - const N_PROOFS: usize; - - type Circuit: Circuit; - - fn name() -> String; -} - -// this is a toggle that should match the fork of halo2_proofs you are using -// the current default in PSE/main is `false`, before 2022_10_22 it was `true`: -// see https://github.com/privacy-scaling-explorations/halo2/pull/96/files -pub const KZG_QUERY_INSTANCE: bool = false; - -pub fn create_snark_shplonk( - params: &ParamsKZG, - circuits: Vec, - instances: Vec>>, // instances[i][j][..] is the i-th circuit's j-th instance column - accumulator_indices: Option>, -) -> Snark { - println!("CREATING SNARK FOR: {}", T::name()); - let config = if let Some(accumulator_indices) = accumulator_indices { - Config::kzg(KZG_QUERY_INSTANCE) - .set_zk(true) - .with_num_proof(T::N_PROOFS) - .with_accumulator_indices(accumulator_indices) - } else { - Config::kzg(KZG_QUERY_INSTANCE).set_zk(true).with_num_proof(T::N_PROOFS) - }; - - let pk = gen_pk(params, &circuits[0], T::name().as_str()); - // num_instance[i] is length of the i-th instance columns in circuit 0 (all circuits should have same shape of instances) - let num_instance = instances[0].iter().map(|instance_column| instance_column.len()).collect(); - let protocol = compile(params, pk.get_vk(), config.with_num_instance(num_instance)); - - // usual shenanigans to turn nested Vec into nested slice - let instances1: Vec> = instances - .iter() - .map(|instances| instances.iter().map(Vec::as_slice).collect_vec()) - .collect_vec(); - let instances2: Vec<&[&[Fr]]> = instances1.iter().map(Vec::as_slice).collect_vec(); - // TODO: need to cache the instances as well! - - let proof = { - let path = format!("./data/proof_{}_{}.dat", T::name(), params.k()); - let instance_path = format!("./data/instances_{}_{}.dat", T::name(), params.k()); - let cached_instances = read_instances::(instance_path.as_str()); - #[cfg(feature = "serialize")] - if cached_instances.is_some() - && Path::new(path.as_str()).exists() - && cached_instances.unwrap() == instances - { - let proof_time = start_timer!(|| "read proof"); - let mut file = File::open(path.as_str()).unwrap(); - let mut buf = vec![]; - file.read_to_end(&mut buf).unwrap(); - end_timer!(proof_time); - buf - } else { - let proof_time = start_timer!(|| "create proof"); - let mut transcript = PoseidonTranscript::, _>::init(Vec::new()); - create_proof::, ProverSHPLONK<_>, ChallengeScalar<_>, _, _, _>( - params, - &pk, - &circuits, - instances2.as_slice(), - &mut ChaCha20Rng::from_seed(Default::default()), - &mut transcript, - ) - .unwrap(); - let proof = transcript.finalize(); - let mut file = File::create(path.as_str()).unwrap(); - file.write_all(&proof).unwrap(); - write_instances(&instances, instance_path.as_str()); - end_timer!(proof_time); - proof - } - #[cfg(not(feature = "serialize"))] - { - let proof_time = start_timer!(|| "create proof"); - let mut transcript = PoseidonTranscript::, _>::init(Vec::new()); - create_proof::, ProverSHPLONK<_>, ChallengeScalar<_>, _, _, _>( - params, - &pk, - &circuits, - instances2.as_slice(), - &mut ChaCha20Rng::from_seed(Default::default()), - &mut transcript, - ) - .unwrap(); - let proof = transcript.finalize(); - end_timer!(proof_time); - proof - } - }; - - let verify_time = start_timer!(|| "verify proof"); - { - let verifier_params = params.verifier_params(); - let strategy = AccumulatorStrategy::new(verifier_params); - let mut transcript = - >, _> as TranscriptReadBuffer< - _, - _, - _, - >>::init(Cursor::new(proof.clone())); - assert!(VerificationStrategy::<_, VerifierSHPLONK<_>>::finalize( - verify_proof::<_, VerifierSHPLONK<_>, _, _, _>( - verifier_params, - pk.get_vk(), - strategy, - instances2.as_slice(), - &mut transcript, - ) - .unwrap() - )) - } - end_timer!(verify_time); - - Snark::new(protocol.clone(), instances.into_iter().flatten().collect_vec(), proof) -} diff --git a/snark-verifier/src/system/halo2/transcript/evm.rs b/snark-verifier/src/system/halo2/transcript/evm.rs index 5ea57189..c71c9e79 100644 --- a/snark-verifier/src/system/halo2/transcript/evm.rs +++ b/snark-verifier/src/system/halo2/transcript/evm.rs @@ -73,6 +73,8 @@ where &self.loader } + /// Does not allow the input to be a one-byte sequence, because the Transcript trait only supports writing scalars and elliptic curve points. + /// If the one-byte sequence [0x01] is a valid input to the transcript, the empty input [] will have the same transcript result as [0x01]. fn squeeze_challenge(&mut self) -> Scalar { let len = if self.buf.len() == 0x20 { assert_eq!(self.loader.ptr(), self.buf.end()); From 1820e9c39daea3fa5fc0eb431ec0b27789cb6663 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 22 May 2023 19:05:09 -0500 Subject: [PATCH 34/73] fix: `split_by_ascii_whitespace` (#15) --- snark-verifier/src/loader/evm/util.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/snark-verifier/src/loader/evm/util.rs b/snark-verifier/src/loader/evm/util.rs index 62792ee8..a84df4c3 100644 --- a/snark-verifier/src/loader/evm/util.rs +++ b/snark-verifier/src/loader/evm/util.rs @@ -114,13 +114,10 @@ pub fn compile_yul(code: &str) -> Vec { .arg("-") .spawn() .unwrap(); - cmd.stdin - .take() - .unwrap() - .write_all(code.as_bytes()) - .unwrap(); + cmd.stdin.take().unwrap().write_all(code.as_bytes()).unwrap(); let output = cmd.wait_with_output().unwrap().stdout; let binary = *split_by_ascii_whitespace(&output).last().unwrap(); + assert!(!binary.is_empty()); hex::decode(binary).unwrap() } @@ -136,5 +133,22 @@ fn split_by_ascii_whitespace(bytes: &[u8]) -> Vec<&[u8]> { start = Some(idx); } } + if let Some(last) = start { + split.push(&bytes[last..]); + } split } + +#[test] +fn test_split_by_ascii_whitespace_1() { + let bytes = b" \x01 \x02 \x03"; + let split = split_by_ascii_whitespace(bytes); + assert_eq!(split, [b"\x01", b"\x02", b"\x03"]); +} + +#[test] +fn test_split_by_ascii_whitespace_2() { + let bytes = b"123456789abc"; + let split = split_by_ascii_whitespace(bytes); + assert_eq!(split, [b"123456789abc"]); +} From 2641da5906ce877791d62d23b3229f6d62e2f578 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 22 May 2023 19:32:18 -0500 Subject: [PATCH 35/73] fix: `batch_invert_and_mul` do not allow zeros (#16) --- snark-verifier/src/util/arithmetic.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/snark-verifier/src/util/arithmetic.rs b/snark-verifier/src/util/arithmetic.rs index 94964cc7..97962e32 100644 --- a/snark-verifier/src/util/arithmetic.rs +++ b/snark-verifier/src/util/arithmetic.rs @@ -49,22 +49,23 @@ pub trait FieldOps: /// Batch invert [`PrimeField`] elements and multiply all with given coefficient. pub fn batch_invert_and_mul(values: &mut [F], coeff: &F) { + if values.is_empty() { + return; + } let products = values .iter() - .filter(|value| !value.is_zero_vartime()) .scan(F::one(), |acc, value| { *acc *= value; Some(*acc) }) .collect_vec(); - let mut all_product_inv = products.last().unwrap().invert().unwrap() * coeff; + let mut all_product_inv = Option::::from(products.last().unwrap().invert()) + .expect("Attempted to batch invert an array containing zero") + * coeff; - for (value, product) in values - .iter_mut() - .rev() - .filter(|value| !value.is_zero_vartime()) - .zip(products.into_iter().rev().skip(1).chain(Some(F::one()))) + for (value, product) in + values.iter_mut().rev().zip(products.into_iter().rev().skip(1).chain(Some(F::one()))) { let mut inv = all_product_inv * product; mem::swap(value, &mut inv); From 1e64c304669a3fb89ed38aaf65b1f418387ff9d5 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 22 May 2023 19:45:03 -0500 Subject: [PATCH 36/73] feat: verify proof in release mode (#17) Verify proof before caching it as extra safety --- snark-verifier-sdk/src/halo2.rs | 15 ++++++++------- snark-verifier-sdk/src/halo2/aggregation.rs | 3 ++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/snark-verifier-sdk/src/halo2.rs b/snark-verifier-sdk/src/halo2.rs index ed155bc8..b0710230 100644 --- a/snark-verifier-sdk/src/halo2.rs +++ b/snark-verifier-sdk/src/halo2.rs @@ -121,14 +121,10 @@ where #[cfg(feature = "display")] end_timer!(proof_time); - if let Some((instance_path, proof_path)) = path { - write_instances(&instances, instance_path); - fs::write(proof_path, &proof).unwrap(); - } - - debug_assert!({ + // validate proof before caching + assert!({ let mut transcript_read = - PoseidonTranscript::::new::(proof.as_slice()); + PoseidonTranscript::::from_spec(&proof[..], POSEIDON_SPEC.clone()); VerificationStrategy::<_, V>::finalize( verify_proof::<_, V, _, _, _>( params.verifier_params(), @@ -141,6 +137,11 @@ where ) }); + if let Some((instance_path, proof_path)) = path { + write_instances(&instances, instance_path); + fs::write(proof_path, &proof).unwrap(); + } + proof } diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 3bff2060..f361b876 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -24,6 +24,8 @@ use halo2_base::{ use itertools::Itertools; use rand::{rngs::StdRng, SeedableRng}; use serde::{Deserialize, Serialize}; +#[cfg(debug_assertions)] +use snark_verifier::util::arithmetic::fe_to_limbs; use snark_verifier::{ loader::{ self, @@ -34,7 +36,6 @@ use snark_verifier::{ kzg::{KzgAccumulator, KzgAsProvingKey, KzgAsVerifyingKey, KzgSuccinctVerifyingKey}, AccumulationScheme, AccumulationSchemeProver, PolynomialCommitmentScheme, }, - util::arithmetic::fe_to_limbs, verifier::SnarkVerifier, }; use std::{ From 7041c6f1003cd8c5357f7248c01ddfcf0eb136d4 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 22 May 2023 21:54:41 -0500 Subject: [PATCH 37/73] fix: add better error messages/docs for catching empty inputs (#18) --- snark-verifier-sdk/src/halo2/aggregation.rs | 4 ++++ snark-verifier/src/loader/evm/loader.rs | 2 +- snark-verifier/src/loader/halo2/loader.rs | 1 + snark-verifier/src/loader/native.rs | 2 +- 4 files changed, 7 insertions(+), 2 deletions(-) diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index f361b876..b5dc148d 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -57,6 +57,9 @@ pub type Halo2Loader<'chip> = loader::halo2::Halo2Loader( svk: &Svk, loader: &Rc>, @@ -76,6 +79,7 @@ where VerifyingKey = KzgAsVerifyingKey, >, { + assert!(!snarks.is_empty(), "trying to aggregate 0 snarks"); let assign_instances = |instances: &[Vec]| { instances .iter() diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index f6bf17b2..98ca5ca4 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -663,7 +663,7 @@ where _ => ec_point.loader.ec_point_scalar_mul(ec_point, scalar), }) .reduce(|acc, ec_point| acc.loader.ec_point_add(&acc, &ec_point)) - .unwrap() + .expect("pairs should not be empty") } } diff --git a/snark-verifier/src/loader/halo2/loader.rs b/snark-verifier/src/loader/halo2/loader.rs index 9a8410d6..31be9841 100644 --- a/snark-verifier/src/loader/halo2/loader.rs +++ b/snark-verifier/src/loader/halo2/loader.rs @@ -536,6 +536,7 @@ impl> EcPointLoader for Rc>::LoadedScalar, &EcPoint)], ) -> EcPoint { + assert!(!pairs.is_empty(), "multi_scalar_multiplication: pairs is empty"); let loader = &pairs[0].0.loader; let (constant, fixed_base, variable_base_non_scaled, variable_base_scaled) = diff --git a/snark-verifier/src/loader/native.rs b/snark-verifier/src/loader/native.rs index 96e7239a..783aaa89 100644 --- a/snark-verifier/src/loader/native.rs +++ b/snark-verifier/src/loader/native.rs @@ -66,7 +66,7 @@ impl EcPointLoader for NativeLoader { .cloned() .map(|(scalar, base)| *base * scalar) .reduce(|acc, value| acc + value) - .unwrap() + .expect("pairs should not be empty") .to_affine() } } From eee5ec22abb8c0aba602412898c7a67c4f21f68f Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Mon, 22 May 2023 22:04:03 -0700 Subject: [PATCH 38/73] chore: add Cargo.lock --- .gitignore | 1 - Cargo.lock | 4696 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 4696 insertions(+), 1 deletion(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index 0175c775..829691c6 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,3 @@ /target testdata -Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..44e2b188 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,4696 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug 0.3.0", +] + +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "colored", + "num-traits", + "rand", +] + +[[package]] +name = "array-init" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" + +[[package]] +name = "async-trait" +version = "0.1.68" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" + +[[package]] +name = "base58" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" + +[[package]] +name = "base58check" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ee2fe4c9a0c84515f136aaae2466744a721af6d63339c18689d9e995d74d99b" +dependencies = [ + "base58", + "sha2 0.8.2", +] + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" + +[[package]] +name = "base64ct" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" + +[[package]] +name = "bech32" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitvec" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" +dependencies = [ + "either", + "radium 0.3.0", +] + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium 0.7.0", + "tap", + "wyz", +] + +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" +dependencies = [ + "arrayref", + "byte-tools 0.2.0", +] + +[[package]] +name = "block-buffer" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" +dependencies = [ + "block-padding 0.1.5", + "byte-tools 0.3.1", + "byteorder", + "generic-array 0.12.4", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding 0.2.1", + "generic-array 0.14.7", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "block-padding" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" +dependencies = [ + "byte-tools 0.3.1", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "borsh" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bs58" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" + +[[package]] +name = "bumpalo" +version = "3.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" + +[[package]] +name = "bus-mapping" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" +dependencies = [ + "eth-types", + "ethers-core", + "ethers-providers", + "gadgets", + "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", + "itertools", + "keccak256", + "lazy_static", + "log", + "serde", + "serde_json", + "strum", + "strum_macros", +] + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "byte-tools" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" + +[[package]] +name = "byte-tools" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" + +[[package]] +name = "bytecheck" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" +dependencies = [ + "bytecheck_derive", + "ptr_meta", + "simdutf8", +] + +[[package]] +name = "bytecheck_derive" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bytemuck" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" + +[[package]] +name = "byteorder" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" + +[[package]] +name = "bytes" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" +dependencies = [ + "serde", +] + +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" +dependencies = [ + "iana-time-zone", + "num-integer", + "num-traits", + "serde", + "winapi", +] + +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "clap" +version = "3.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" +dependencies = [ + "bitflags", + "clap_lex", + "indexmap", + "textwrap", +] + +[[package]] +name = "clap_lex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "coins-bip32" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "634c509653de24b439672164bbf56f5f582a2ab0e313d3b0f6af0b7345cf2560" +dependencies = [ + "bincode", + "bs58", + "coins-core", + "digest 0.10.7", + "getrandom", + "hmac 0.12.1", + "k256", + "lazy_static", + "serde", + "sha2 0.10.6", + "thiserror", +] + +[[package]] +name = "coins-bip39" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a11892bcac83b4c6e95ab84b5b06c76d9d70ad73548dd07418269c5c7977171" +dependencies = [ + "bitvec 0.17.4", + "coins-bip32", + "getrandom", + "hex", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "rand", + "sha2 0.10.6", + "thiserror", +] + +[[package]] +name = "coins-core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94090a6663f224feae66ab01e41a2555a8296ee07b5f20dab8888bdefc9f617" +dependencies = [ + "base58check", + "base64 0.12.3", + "bech32", + "blake2", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.6", + "sha3 0.10.8", + "thiserror", +] + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "const-oid" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" + +[[package]] +name = "constant_time_eq" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" + +[[package]] +name = "convert_case" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpp_demangle" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c76f98bdfc7f66172e6c7065f981ebb576ffc903fe4c0561d9f0c2509226dc6" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" +dependencies = [ + "libc", +] + +[[package]] +name = "criterion" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" +dependencies = [ + "anes", + "atty", + "cast", + "ciborium", + "clap", + "criterion-plot", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-macro" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "288a8f36b28a19d7dbd572c76006c0a0eba1f3bf912a254dda211c6f665e7ffc" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags", + "crossterm_winapi", + "libc", + "mio", + "parking_lot 0.12.1", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" +dependencies = [ + "generic-array 0.14.7", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array 0.14.7", + "typenum", +] + +[[package]] +name = "crypto-mac" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" +dependencies = [ + "generic-array 0.14.7", + "subtle", +] + +[[package]] +name = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher", +] + +[[package]] +name = "darling" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" +dependencies = [ + "darling_core 0.13.4", + "darling_macro 0.13.4", +] + +[[package]] +name = "darling" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" +dependencies = [ + "darling_core 0.20.1", + "darling_macro 0.20.1", +] + +[[package]] +name = "darling_core" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 1.0.109", +] + +[[package]] +name = "darling_core" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.16", +] + +[[package]] +name = "darling_macro" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" +dependencies = [ + "darling_core 0.13.4", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "darling_macro" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" +dependencies = [ + "darling_core 0.20.1", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid 1.3.3", +] + +[[package]] +name = "der" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" +dependencies = [ + "generic-array 0.9.1", +] + +[[package]] +name = "digest" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" +dependencies = [ + "generic-array 0.12.4", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.7", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecc" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" +dependencies = [ + "group", + "integer", + "num-bigint", + "num-integer", + "num-traits", + "rand", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" +dependencies = [ + "ecc", + "group", + "num-bigint", + "num-integer", + "num-traits", + "rand", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.14.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" +dependencies = [ + "der", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" +dependencies = [ + "base16ct", + "crypto-bigint", + "der", + "digest 0.10.7", + "ff", + "generic-array 0.14.7", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "encoding_rs" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "env_logger" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "errno" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" +dependencies = [ + "errno-dragonfly", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "errno-dragonfly" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "eth-keystore" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f65b750ac950f2f825b36d08bef4cda4112e19a7b1a68f6e2bb499413e12440" +dependencies = [ + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "rand", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.6", + "sha3 0.10.8", + "thiserror", + "uuid 0.8.2", +] + +[[package]] +name = "eth-types" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" +dependencies = [ + "ethers-core", + "ethers-signers", + "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", + "hex", + "itertools", + "lazy_static", + "libsecp256k1", + "num", + "num-bigint", + "regex", + "serde", + "serde_json", + "serde_with 1.14.0", + "sha3 0.10.8", + "strum", + "strum_macros", + "subtle", + "uint", +] + +[[package]] +name = "ethabi" +version = "17.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" +dependencies = [ + "ethereum-types 0.13.1", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3 0.10.8", + "thiserror", + "uint", +] + +[[package]] +name = "ethbloom" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" +dependencies = [ + "crunchy", + "fixed-hash 0.7.0", + "impl-rlp", + "impl-serde", + "tiny-keccak", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash 0.8.0", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" +dependencies = [ + "ethbloom 0.12.1", + "fixed-hash 0.7.0", + "impl-rlp", + "impl-serde", + "primitive-types 0.11.1", + "uint", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom 0.13.0", + "fixed-hash 0.8.0", + "primitive-types 0.12.1", + "uint", +] + +[[package]] +name = "ethers-core" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ebdd63c828f58aa067f40f9adcbea5e114fb1f90144b3a1e2858e0c9b1ff4e8" +dependencies = [ + "arrayvec", + "bytes", + "chrono", + "convert_case", + "elliptic-curve", + "ethabi", + "fastrlp", + "generic-array 0.14.7", + "hex", + "k256", + "proc-macro2", + "rand", + "rlp", + "rlp-derive", + "rust_decimal", + "serde", + "serde_json", + "strum", + "syn 1.0.109", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-providers" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e46482e4d1e79b20c338fd9db9e166184eb387f0a4e7c05c5b5c0aa2e8c8900c" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.13.1", + "ethers-core", + "futures-channel", + "futures-core", + "futures-timer", + "futures-util", + "getrandom", + "hashers", + "hex", + "http", + "once_cell", + "parking_lot 0.11.2", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tokio-tungstenite", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-timer", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73a72ecad124e8ccd18d6a43624208cab0199e59621b1f0fa6b776b2e0529107" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "hex", + "rand", + "sha2 0.10.6", + "thiserror", +] + +[[package]] +name = "external-tracer" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" +dependencies = [ + "eth-types", + "geth-utils", + "serde", + "serde_json", +] + +[[package]] +name = "fake-simd" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" + +[[package]] +name = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "fastrlp" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "089263294bb1c38ac73649a6ad563dd9a5142c8dc0482be15b8b9acb22a1611e" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types 0.13.1", + "fastrlp-derive", +] + +[[package]] +name = "fastrlp-derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0f9d074ab623d1b388c12544bfeed759c7df36dc5c300cda053df9ba1232075" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "bitvec 1.0.1", + "rand_core", + "subtle", +] + +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + +[[package]] +name = "fixed-hash" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-macro" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-timer" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gadgets" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" +dependencies = [ + "digest 0.7.6", + "eth-types", + "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", + "sha3 0.7.3", + "strum", +] + +[[package]] +name = "generic-array" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d00328cedcac5e81c683e5620ca6a30756fc23027ebf9bff405c0e8da1fbb7e" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" +dependencies = [ + "typenum", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "geth-utils" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" +dependencies = [ + "env_logger", + "gobuild", + "log", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "gimli" +version = "0.27.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" + +[[package]] +name = "gobuild" +version = "0.1.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e156a4ddbf3deb5e8116946c111413bd9a5679bdc1536c78a60618a7a9ac9e" +dependencies = [ + "cc", +] + +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "h2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "halo2-base" +version = "0.3.0" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.3.0#238b89e7562d52166c1e08154b7c9759f65322a6" +dependencies = [ + "ff", + "halo2_proofs 0.2.0", + "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", + "itertools", + "jemallocator", + "log", + "num-bigint", + "num-integer", + "num-traits", + "rand_chacha", + "rayon", + "rustc-hash", + "serde", + "serde_json", +] + +[[package]] +name = "halo2-ecc" +version = "0.3.0" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.3.0#238b89e7562d52166c1e08154b7c9759f65322a6" +dependencies = [ + "ff", + "group", + "halo2-base", + "itertools", + "num-bigint", + "num-integer", + "num-traits", + "rand", + "rand_chacha", + "rand_core", + "rayon", + "serde", + "serde_json", +] + +[[package]] +name = "halo2_proofs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e925780549adee8364c7f2b685c753f6f3df23bde520c67416e93bf615933760" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "pasta_curves", + "rand_core", + "rayon", +] + +[[package]] +name = "halo2_proofs" +version = "0.2.0" +dependencies = [ + "blake2b_simd", + "crossbeam", + "ff", + "group", + "halo2curves 0.3.1", + "rand", + "rand_core", + "rayon", + "rustc-hash", + "sha3 0.9.1", + "tracing", +] + +[[package]] +name = "halo2_proofs" +version = "0.2.0" +source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2022_09_10#a9e99a72a65d7c98e8a4258c2c94269c834d1c10" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "halo2curves 0.2.1 (git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.2.1)", + "rand_core", + "rayon", + "tracing", +] + +[[package]] +name = "halo2_proofs" +version = "0.2.0" +source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02#0a8646b78286a13d320759b1c585262d6536dce4" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "halo2curves 0.3.1 (git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1)", + "rand_core", + "rayon", + "sha3 0.9.1", + "tracing", +] + +[[package]] +name = "halo2curves" +version = "0.2.1" +source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.2.1#f75ed26c961179186e9cec02cc3f841ca9e3fec1" +dependencies = [ + "ff", + "group", + "lazy_static", + "num-bigint", + "num-traits", + "pasta_curves", + "rand", + "rand_core", + "static_assertions", + "subtle", +] + +[[package]] +name = "halo2curves" +version = "0.2.1" +source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.0#83c72d49762343ffc9576ca11a2aa615efe1029b" +dependencies = [ + "ff", + "group", + "lazy_static", + "num-bigint", + "num-traits", + "pasta_curves", + "rand", + "rand_core", + "static_assertions", + "subtle", +] + +[[package]] +name = "halo2curves" +version = "0.3.1" +dependencies = [ + "ff", + "group", + "lazy_static", + "num-bigint", + "num-traits", + "pasta_curves", + "rand", + "rand_core", + "serde", + "static_assertions", + "subtle", +] + +[[package]] +name = "halo2curves" +version = "0.3.1" +source = "git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1#9b67e19bca30a35208b0c1b41c1723771e2c9f49" +dependencies = [ + "ff", + "group", + "lazy_static", + "num-bigint", + "num-traits", + "pasta_curves", + "rand", + "rand_core", + "static_assertions", + "subtle", +] + +[[package]] +name = "halo2wrong" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" +dependencies = [ + "group", + "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.6", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.3", +] + +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hmac" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" +dependencies = [ + "crypto-mac", + "digest 0.9.0", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "hmac-drbg" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" +dependencies = [ + "digest 0.9.0", + "generic-array 0.14.7", + "hmac 0.8.1", +] + +[[package]] +name = "http" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + +[[package]] +name = "http-body" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + +[[package]] +name = "httparse" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" + +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + +[[package]] +name = "hyper-rustls" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" +dependencies = [ + "http", + "hyper", + "rustls 0.21.1", + "tokio", + "tokio-rustls 0.24.0", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-rlp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" +dependencies = [ + "rlp", +] + +[[package]] +name = "impl-serde" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" +dependencies = [ + "serde", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "inferno" +version = "0.11.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fb7c1b80a1dfa604bb4a649a5c5aeef3d913f7c520cb42b40e534e8a61bcdfc" +dependencies = [ + "ahash 0.8.3", + "indexmap", + "is-terminal", + "itoa", + "log", + "num-format", + "once_cell", + "quick-xml", + "rgb", + "str_stack", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "integer" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" +dependencies = [ + "group", + "maingate", + "num-bigint", + "num-integer", + "num-traits", + "rand", + "subtle", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "ipnet" +version = "2.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" + +[[package]] +name = "is-terminal" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" +dependencies = [ + "hermit-abi 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "jemalloc-sys" +version = "0.5.3+5.3.0-patched" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9bd5d616ea7ed58b571b2e209a65759664d7fb021a0819d7a790afc67e47ca1" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "jemallocator" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16c2514137880c52b0b4822b563fadd38257c1f380858addb74a400889696ea6" +dependencies = [ + "jemalloc-sys", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" +dependencies = [ + "cfg-if", + "ecdsa 0.14.8", + "elliptic-curve", + "sha2 0.10.6", + "sha3 0.10.8", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "keccak256" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" +dependencies = [ + "env_logger", + "eth-types", + "halo2_proofs 0.1.0", + "itertools", + "lazy_static", + "log", + "num-bigint", + "num-traits", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "libsecp256k1" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" +dependencies = [ + "arrayref", + "base64 0.13.1", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "maingate" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" +dependencies = [ + "group", + "halo2wrong", + "num-bigint", + "num-integer", + "num-traits", + "rand", + "subtle", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "mime" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys 0.45.0", +] + +[[package]] +name = "mock" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" +dependencies = [ + "eth-types", + "ethers-core", + "ethers-signers", + "external-tracer", + "itertools", + "lazy_static", + "rand", + "rand_chacha", +] + +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "static_assertions", +] + +[[package]] +name = "num" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand", +] + +[[package]] +name = "num-complex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "itoa", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "object" +version = "0.30.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opaque-debug" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "os_str_bytes" +version = "6.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" + +[[package]] +name = "parity-scale-codec" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ddb756ca205bd108aee3c62c6d3c994e1df84a59b9d6d4a5ea42ee1fd5a9a28" +dependencies = [ + "arrayvec", + "bitvec 1.0.1", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core 0.8.6", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.7", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "winapi", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "windows-sys 0.45.0", +] + +[[package]] +name = "password-hash" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "password-hash" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + +[[package]] +name = "pasta_curves" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc65faf8e7313b4b1fbaa9f7ca917a0eed499a9663be71477f87993604341d8" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" + +[[package]] +name = "pbkdf2" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", + "password-hash 0.4.2", + "sha2 0.10.6", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version", +] + +[[package]] +name = "pin-project" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs8" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "plotters" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "poseidon" +version = "0.2.0" +source = "git+https://github.com/privacy-scaling-explorations/poseidon.git?tag=v2022_10_22#5d29df01a95e3df6334080d28e983407f56b5da3" +dependencies = [ + "group", + "halo2curves 0.2.1 (git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.0)", + "subtle", +] + +[[package]] +name = "poseidon-circuit" +version = "0.1.0" +source = "git+https://github.com/scroll-tech/poseidon-circuit.git#079e3f5bfc30d63ded672a97850e3c160504bfad" +dependencies = [ + "bitvec 1.0.1", + "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2022_09_10)", + "lazy_static", + "thiserror", +] + +[[package]] +name = "pprof" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "196ded5d4be535690899a4631cc9f18cdc41b7ebf24a79400f46f48e49a11059" +dependencies = [ + "backtrace", + "cfg-if", + "criterion", + "findshlibs", + "inferno", + "libc", + "log", + "nix", + "once_cell", + "parking_lot 0.12.1", + "smallvec", + "symbolic-demangle", + "tempfile", + "thiserror", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primitive-types" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" +dependencies = [ + "fixed-hash 0.7.0", + "impl-codec", + "impl-rlp", + "impl-serde", + "uint", +] + +[[package]] +name = "primitive-types" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" +dependencies = [ + "fixed-hash 0.8.0", + "impl-codec", + "impl-rlp", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "ptr_meta" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" +dependencies = [ + "ptr_meta_derive", +] + +[[package]] +name = "ptr_meta_derive" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "quick-xml" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" + +[[package]] +name = "rend" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" +dependencies = [ + "bytecheck", +] + +[[package]] +name = "reqwest" +version = "0.11.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" +dependencies = [ + "base64 0.21.1", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls 0.21.1", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls 0.24.0", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", +] + +[[package]] +name = "revm" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73d84c8f9836efb0f5f5f8de4700a953c4e1f3119e5cfcb0aad8e5be73daf991" +dependencies = [ + "arrayref", + "auto_impl", + "bytes", + "hashbrown 0.13.2", + "num_enum", + "primitive-types 0.12.1", + "revm_precompiles", + "rlp", + "sha3 0.10.8", +] + +[[package]] +name = "revm_precompiles" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0353d456ef3e989dc9190f42c6020f09bc2025930c37895826029304413204b5" +dependencies = [ + "bytes", + "hashbrown 0.13.2", + "num", + "once_cell", + "primitive-types 0.12.1", + "ripemd", + "secp256k1", + "sha2 0.10.6", + "sha3 0.10.8", + "substrate-bn", +] + +[[package]] +name = "rfc6979" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" +dependencies = [ + "crypto-bigint", + "hmac 0.12.1", + "zeroize", +] + +[[package]] +name = "rgb" +version = "0.8.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rkyv" +version = "0.7.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58" +dependencies = [ + "bitvec 1.0.1", + "bytecheck", + "hashbrown 0.12.3", + "ptr_meta", + "rend", + "rkyv_derive", + "seahash", + "tinyvec", + "uuid 1.3.3", +] + +[[package]] +name = "rkyv_derive" +version = "0.7.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "rust_decimal" +version = "1.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26bd36b60561ee1fb5ec2817f198b6fd09fa571c897a5e86d1487cfc2b096dfc" +dependencies = [ + "arrayvec", + "borsh", + "bytecheck", + "byteorder", + "bytes", + "num-traits", + "rand", + "rkyv", + "serde", + "serde_json", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustix" +version = "0.37.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustls" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +dependencies = [ + "log", + "ring", + "sct", + "webpki", +] + +[[package]] +name = "rustls" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + +[[package]] +name = "rustls-pemfile" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +dependencies = [ + "base64 0.21.1", +] + +[[package]] +name = "rustls-webpki" +version = "0.100.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "rustversion" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "salsa20" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0fbb5f676da676c260ba276a8f43a8dc67cf02d1438423aeb1c677a7212686" +dependencies = [ + "cipher", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "scrypt" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e73d6d7c6311ebdbd9184ad6c4447b2f36337e327bda107d3ba9e3c374f9d325" +dependencies = [ + "hmac 0.12.1", + "password-hash 0.3.2", + "pbkdf2 0.10.1", + "salsa20", + "sha2 0.10.6", +] + +[[package]] +name = "sct" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "seahash" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" + +[[package]] +name = "sec1" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" +dependencies = [ + "base16ct", + "der", + "generic-array 0.14.7", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" +dependencies = [ + "cc", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" +dependencies = [ + "serde", + "serde_with_macros 1.5.2", +] + +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "base64 0.13.1", + "chrono", + "hex", + "indexmap", + "serde", + "serde_json", + "serde_with_macros 2.3.3", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "1.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" +dependencies = [ + "darling 0.13.4", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling 0.20.1", + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "sha-1" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha2" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" +dependencies = [ + "block-buffer 0.7.3", + "digest 0.8.1", + "fake-simd", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b64dcef59ed4290b9fb562b53df07f564690d6539e8ecdd4728cf392477530bc" +dependencies = [ + "block-buffer 0.3.3", + "byte-tools 0.2.0", + "digest 0.7.6", + "keccak", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug 0.3.0", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "signal-hook" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "simdutf8" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" + +[[package]] +name = "slab" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "snark-verifier" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/snark-verifier?tag=v2023_02_02#df03d898b841f71cbc36c2fb9fa07b8196f9623e" +dependencies = [ + "ecc", + "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", + "halo2curves 0.3.1 (git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1)", + "hex", + "itertools", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "poseidon", + "rand", +] + +[[package]] +name = "snark-verifier" +version = "0.1.1" +dependencies = [ + "ark-std", + "bytes", + "crossterm", + "halo2-base", + "halo2-ecc", + "hex", + "itertools", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "paste", + "poseidon-circuit", + "primitive-types 0.12.1", + "rand", + "rand_chacha", + "rayon", + "revm", + "rlp", + "rustc-hash", + "serde", + "serde_json", + "sha3 0.10.8", + "tui", +] + +[[package]] +name = "snark-verifier-sdk" +version = "0.1.1" +dependencies = [ + "ark-std", + "bincode", + "bus-mapping", + "criterion", + "criterion-macro", + "crossterm", + "eth-types", + "ethereum-types 0.14.1", + "halo2-base", + "hex", + "itertools", + "lazy_static", + "mock", + "num-bigint", + "num-integer", + "num-traits", + "paste", + "pprof", + "rand", + "rand_chacha", + "serde", + "serde_json", + "serde_with 2.3.3", + "snark-verifier 0.1.1", + "tui", + "zkevm-circuits", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str_stack" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.24.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand", + "rustc-hex", +] + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "symbolic-common" +version = "10.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b55cdc318ede251d0957f07afe5fed912119b8c1bc5a7804151826db999e737" +dependencies = [ + "debugid", + "memmap2", + "stable_deref_trait", + "uuid 1.3.3", +] + +[[package]] +name = "symbolic-demangle" +version = "10.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79be897be8a483a81fff6a3a4e195b4ac838ef73ca42d348b3f722da9902e489" +dependencies = [ + "cpp_demangle", + "rustc-demangle", + "symbolic-common", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.45.0", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "time" +version = "0.3.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +dependencies = [ + "itoa", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" + +[[package]] +name = "time-macros" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +dependencies = [ + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "tokio" +version = "1.28.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" +dependencies = [ + "autocfg", + "bytes", + "libc", + "mio", + "pin-project-lite", + "socket2", + "windows-sys 0.48.0", +] + +[[package]] +name = "tokio-rustls" +version = "0.23.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" +dependencies = [ + "rustls 0.20.8", + "tokio", + "webpki", +] + +[[package]] +name = "tokio-rustls" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" +dependencies = [ + "rustls 0.21.1", + "tokio", +] + +[[package]] +name = "tokio-tungstenite" +version = "0.17.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" +dependencies = [ + "futures-util", + "log", + "rustls 0.20.8", + "tokio", + "tokio-rustls 0.23.4", + "tungstenite", + "webpki", + "webpki-roots", +] + +[[package]] +name = "tokio-util" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" + +[[package]] +name = "toml_edit" +version = "0.19.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d964908cec0d030b812013af25a0e57fddfadb1e066ecc6681d86253129d4f" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tower-service" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" + +[[package]] +name = "tracing" +version = "0.1.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", +] + +[[package]] +name = "tracing-core" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + +[[package]] +name = "try-lock" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" + +[[package]] +name = "tui" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" +dependencies = [ + "bitflags", + "cassowary", + "crossterm", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "tungstenite" +version = "0.17.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +dependencies = [ + "base64 0.13.1", + "byteorder", + "bytes", + "http", + "httparse", + "log", + "rand", + "rustls 0.20.8", + "sha-1", + "thiserror", + "url", + "utf-8", + "webpki", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + +[[package]] +name = "uuid" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.16", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.16", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" + +[[package]] +name = "wasm-timer" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" +dependencies = [ + "futures", + "js-sys", + "parking_lot 0.11.2", + "pin-utils", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "web-sys" +version = "0.3.63" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webpki" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +dependencies = [ + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.22.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" +dependencies = [ + "webpki", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" +dependencies = [ + "memchr", +] + +[[package]] +name = "winreg" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +dependencies = [ + "winapi", +] + +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version", + "send_wrapper", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" + +[[package]] +name = "zkevm-circuits" +version = "0.1.0" +source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" +dependencies = [ + "array-init", + "bus-mapping", + "ecc", + "ecdsa 0.1.0", + "env_logger", + "eth-types", + "ethers-core", + "ethers-signers", + "gadgets", + "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", + "integer", + "itertools", + "keccak256", + "lazy_static", + "libsecp256k1", + "log", + "maingate", + "mock", + "num", + "num-bigint", + "rand", + "rand_chacha", + "rand_xorshift", + "sha3 0.10.8", + "snark-verifier 0.1.0", + "strum", + "strum_macros", + "subtle", +] + +[[patch.unused]] +name = "poseidon" +version = "0.2.0" From 9dbe9138bb50f3bc51a84ae5e59736118e9c331c Mon Sep 17 00:00:00 2001 From: Jonathan Wang Date: Mon, 22 May 2023 22:13:08 -0700 Subject: [PATCH 39/73] chore: update Cargo dependencies --- Cargo.lock | 1 - snark-verifier-sdk/Cargo.toml | 2 +- snark-verifier/Cargo.toml | 5 ++--- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 44e2b188..0597252a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3724,7 +3724,6 @@ dependencies = [ "rayon", "revm", "rlp", - "rustc-hash", "serde", "serde_json", "sha3 0.10.8", diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 34b0f32c..7069bf26 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.1" edition = "2021" [dependencies] -itertools = "0.10.3" +itertools = "0.10.5" lazy_static = "1.4.0" num-bigint = "0.4.3" num-integer = "0.1.45" diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index d0eb22ec..ecf3c6bb 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -4,14 +4,13 @@ version = "0.1.1" edition = "2021" [dependencies] -itertools = "0.10.3" +itertools = "0.10.5" lazy_static = "1.4.0" num-bigint = "0.4.3" num-integer = "0.1.45" num-traits = "0.2.15" hex = "0.4" rand = "0.8" -rustc-hash = "1.1.0" serde = { version = "1.0", features = ["derive"] } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" @@ -20,7 +19,7 @@ halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = " poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git" } # parallel -rayon = { version = "1.5.3", optional = true } +rayon = { version = "1.7.0", optional = true } # loader_evm sha3 = { version = "0.10", optional = true } From 8d9fd64b11bcd1fa2e453d5dcd671e9eebe54ef8 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Wed, 7 Jun 2023 15:26:28 -0700 Subject: [PATCH 40/73] chore: update dependencies --- snark-verifier/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index ecf3c6bb..81248a2d 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -14,7 +14,7 @@ rand = "0.8" serde = { version = "1.0", features = ["derive"] } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.3.0", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } # This is Scroll's audited poseidon circuit. We only use it for the Native Poseidon spec. We do not use the halo2 circuit at all (and it wouldn't even work because the halo2_proofs tag is not compatbile). poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git" } @@ -29,7 +29,7 @@ rlp = { version = "0.5.2", default-features = false, features = ["std"], optiona revm = { version = "= 2.3.1", optional = true } # loader_halo2 -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.3.0", default-features = false, optional = true } +halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false, optional = true } [dev-dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } @@ -61,4 +61,4 @@ required-features = ["loader_halo2", "loader_evm"] [[example]] name = "recursion" -required-features = ["loader_halo2"] \ No newline at end of file +required-features = ["loader_halo2"] From 4c4e9e0c9f89fbbbeb8e26cab93bf5cdb9e95684 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 7 Jul 2023 01:00:30 -0700 Subject: [PATCH 41/73] Minor: merge v0.1.1 to develop (#21) Just cargo fixes --- Cargo.lock | 4695 --------------------------------- snark-verifier-sdk/Cargo.toml | 4 +- snark-verifier/Cargo.toml | 8 +- 3 files changed, 6 insertions(+), 4701 deletions(-) delete mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index 0597252a..00000000 --- a/Cargo.lock +++ /dev/null @@ -1,4695 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aes" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", - "opaque-debug 0.3.0", -] - -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if", - "getrandom", - "once_cell", - "version_check", -] - -[[package]] -name = "aho-corasick" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04" -dependencies = [ - "memchr", -] - -[[package]] -name = "android_system_properties" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" -dependencies = [ - "libc", -] - -[[package]] -name = "anes" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" - -[[package]] -name = "ark-std" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" -dependencies = [ - "colored", - "num-traits", - "rand", -] - -[[package]] -name = "array-init" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d62b7694a562cdf5a74227903507c56ab2cc8bdd1f781ed5cb4cf9c9f810bfc" - -[[package]] -name = "arrayref" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" - -[[package]] -name = "arrayvec" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" - -[[package]] -name = "async-trait" -version = "0.1.68" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.16", -] - -[[package]] -name = "async_io_stream" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" -dependencies = [ - "futures", - "pharos", - "rustc_version", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi 0.1.19", - "libc", - "winapi", -] - -[[package]] -name = "auto_impl" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" -dependencies = [ - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.67" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233d376d6d185f2a3093e58f283f60f880315b6c60075b01f36b3b85154564ca" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base16ct" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce" - -[[package]] -name = "base58" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5024ee8015f02155eee35c711107ddd9a9bf3cb689cf2a9089c97e79b6e1ae83" - -[[package]] -name = "base58check" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee2fe4c9a0c84515f136aaae2466744a721af6d63339c18689d9e995d74d99b" -dependencies = [ - "base58", - "sha2 0.8.2", -] - -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - -[[package]] -name = "base64" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f1e31e207a6b8fb791a38ea3105e6cb541f55e4d029902d3039a4ad07cc4105" - -[[package]] -name = "base64ct" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a32fd6af2b5827bce66c29053ba0e7c42b9dcab01835835058558c10851a46b" - -[[package]] -name = "bech32" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dabbe35f96fb9507f7330793dc490461b2962659ac5d427181e451a623751d1" - -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bitvec" -version = "0.17.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41262f11d771fd4a61aa3ce019fca363b4b6c282fca9da2a31186d3965a47a5c" -dependencies = [ - "either", - "radium 0.3.0", -] - -[[package]] -name = "bitvec" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" -dependencies = [ - "funty", - "radium 0.7.0", - "tap", - "wyz", -] - -[[package]] -name = "blake2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "blake2b_simd" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c2f0dc9a68c6317d884f97cc36cf5a3d20ba14ce404227df55e1af708ab04bc" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - -[[package]] -name = "block-buffer" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a076c298b9ecdb530ed9d967e74a6027d6a7478924520acddcddc24c1c8ab3ab" -dependencies = [ - "arrayref", - "byte-tools 0.2.0", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding 0.1.5", - "byte-tools 0.3.1", - "byteorder", - "generic-array 0.12.4", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "block-padding 0.2.1", - "generic-array 0.14.7", -] - -[[package]] -name = "block-buffer" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools 0.3.1", -] - -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - -[[package]] -name = "borsh" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" -dependencies = [ - "borsh-derive", - "hashbrown 0.13.2", -] - -[[package]] -name = "borsh-derive" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" -dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate 0.1.5", - "proc-macro2", - "syn 1.0.109", -] - -[[package]] -name = "borsh-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "borsh-schema-derive-internal" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "bs58" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" - -[[package]] -name = "bumpalo" -version = "3.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" - -[[package]] -name = "bus-mapping" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" -dependencies = [ - "eth-types", - "ethers-core", - "ethers-providers", - "gadgets", - "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", - "itertools", - "keccak256", - "lazy_static", - "log", - "serde", - "serde_json", - "strum", - "strum_macros", -] - -[[package]] -name = "byte-slice-cast" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" - -[[package]] -name = "byte-tools" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "560c32574a12a89ecd91f5e742165893f86e3ab98d21f8ea548658eb9eef5f40" - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "bytecheck" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6372023ac861f6e6dc89c8344a8f398fb42aaba2b5dbc649ca0c0e9dbcb627" -dependencies = [ - "bytecheck_derive", - "ptr_meta", - "simdutf8", -] - -[[package]] -name = "bytecheck_derive" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7ec4c6f261935ad534c0c22dbef2201b45918860eb1c574b972bd213a76af61" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "bytemuck" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" -dependencies = [ - "serde", -] - -[[package]] -name = "cassowary" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cc" -version = "1.0.79" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "chrono" -version = "0.4.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" -dependencies = [ - "iana-time-zone", - "num-integer", - "num-traits", - "serde", - "winapi", -] - -[[package]] -name = "ciborium" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" -dependencies = [ - "ciborium-io", - "ciborium-ll", - "serde", -] - -[[package]] -name = "ciborium-io" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" - -[[package]] -name = "ciborium-ll" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" -dependencies = [ - "ciborium-io", - "half", -] - -[[package]] -name = "cipher" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "clap" -version = "3.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "bitflags", - "clap_lex", - "indexmap", - "textwrap", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] - -[[package]] -name = "coins-bip32" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634c509653de24b439672164bbf56f5f582a2ab0e313d3b0f6af0b7345cf2560" -dependencies = [ - "bincode", - "bs58", - "coins-core", - "digest 0.10.7", - "getrandom", - "hmac 0.12.1", - "k256", - "lazy_static", - "serde", - "sha2 0.10.6", - "thiserror", -] - -[[package]] -name = "coins-bip39" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a11892bcac83b4c6e95ab84b5b06c76d9d70ad73548dd07418269c5c7977171" -dependencies = [ - "bitvec 0.17.4", - "coins-bip32", - "getrandom", - "hex", - "hmac 0.12.1", - "pbkdf2 0.11.0", - "rand", - "sha2 0.10.6", - "thiserror", -] - -[[package]] -name = "coins-core" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c94090a6663f224feae66ab01e41a2555a8296ee07b5f20dab8888bdefc9f617" -dependencies = [ - "base58check", - "base64 0.12.3", - "bech32", - "blake2", - "digest 0.10.7", - "generic-array 0.14.7", - "hex", - "ripemd", - "serde", - "serde_derive", - "sha2 0.10.6", - "sha3 0.10.8", - "thiserror", -] - -[[package]] -name = "colored" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" -dependencies = [ - "atty", - "lazy_static", - "winapi", -] - -[[package]] -name = "const-oid" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" - -[[package]] -name = "constant_time_eq" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13418e745008f7349ec7e449155f419a61b92b58a99cc3616942b926825ec76b" - -[[package]] -name = "convert_case" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" - -[[package]] -name = "core-foundation-sys" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" - -[[package]] -name = "cpp_demangle" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c76f98bdfc7f66172e6c7065f981ebb576ffc903fe4c0561d9f0c2509226dc6" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "cpufeatures" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58" -dependencies = [ - "libc", -] - -[[package]] -name = "criterion" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c76e09c1aae2bc52b3d2f29e13c6572553b30c4aa1b8a49fd70de6412654cb" -dependencies = [ - "anes", - "atty", - "cast", - "ciborium", - "clap", - "criterion-plot", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-macro" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "288a8f36b28a19d7dbd572c76006c0a0eba1f3bf912a254dda211c6f665e7ffc" -dependencies = [ - "proc-macro2", - "quote", -] - -[[package]] -name = "criterion-plot" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "crossbeam" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossterm" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" -dependencies = [ - "bitflags", - "crossterm_winapi", - "libc", - "mio", - "parking_lot 0.12.1", - "signal-hook", - "signal-hook-mio", - "winapi", -] - -[[package]] -name = "crossterm_winapi" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ae1b35a484aa10e07fe0638d02301c5ad24de82d310ccbd2f3693da5f09bf1c" -dependencies = [ - "winapi", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-bigint" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" -dependencies = [ - "generic-array 0.14.7", - "rand_core", - "subtle", - "zeroize", -] - -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array 0.14.7", - "typenum", -] - -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array 0.14.7", - "subtle", -] - -[[package]] -name = "ctr" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" -dependencies = [ - "cipher", -] - -[[package]] -name = "darling" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c" -dependencies = [ - "darling_core 0.13.4", - "darling_macro 0.13.4", -] - -[[package]] -name = "darling" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0558d22a7b463ed0241e993f76f09f30b126687447751a8638587b864e4b3944" -dependencies = [ - "darling_core 0.20.1", - "darling_macro 0.20.1", -] - -[[package]] -name = "darling_core" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 1.0.109", -] - -[[package]] -name = "darling_core" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab8bfa2e259f8ee1ce5e97824a3c55ec4404a0d772ca7fa96bf19f0752a046eb" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 2.0.16", -] - -[[package]] -name = "darling_macro" -version = "0.13.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835" -dependencies = [ - "darling_core 0.13.4", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "darling_macro" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29a358ff9f12ec09c3e61fef9b5a9902623a695a46a917b07f269bff1445611a" -dependencies = [ - "darling_core 0.20.1", - "quote", - "syn 2.0.16", -] - -[[package]] -name = "debugid" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" -dependencies = [ - "uuid 1.3.3", -] - -[[package]] -name = "der" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de" -dependencies = [ - "const-oid", - "zeroize", -] - -[[package]] -name = "digest" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03b072242a8cbaf9c145665af9d250c59af3b958f83ed6824e13533cf76d5b90" -dependencies = [ - "generic-array 0.9.1", -] - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array 0.14.7", -] - -[[package]] -name = "digest" -version = "0.10.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" -dependencies = [ - "block-buffer 0.10.4", - "crypto-common", - "subtle", -] - -[[package]] -name = "ecc" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" -dependencies = [ - "group", - "integer", - "num-bigint", - "num-integer", - "num-traits", - "rand", - "subtle", -] - -[[package]] -name = "ecdsa" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" -dependencies = [ - "ecc", - "group", - "num-bigint", - "num-integer", - "num-traits", - "rand", - "subtle", -] - -[[package]] -name = "ecdsa" -version = "0.14.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c" -dependencies = [ - "der", - "elliptic-curve", - "rfc6979", - "signature", -] - -[[package]] -name = "either" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" - -[[package]] -name = "elliptic-curve" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3" -dependencies = [ - "base16ct", - "crypto-bigint", - "der", - "digest 0.10.7", - "ff", - "generic-array 0.14.7", - "group", - "pkcs8", - "rand_core", - "sec1", - "subtle", - "zeroize", -] - -[[package]] -name = "encoding_rs" -version = "0.8.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "env_logger" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] - -[[package]] -name = "errno" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "errno-dragonfly" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "eth-keystore" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f65b750ac950f2f825b36d08bef4cda4112e19a7b1a68f6e2bb499413e12440" -dependencies = [ - "aes", - "ctr", - "digest 0.10.7", - "hex", - "hmac 0.12.1", - "pbkdf2 0.11.0", - "rand", - "scrypt", - "serde", - "serde_json", - "sha2 0.10.6", - "sha3 0.10.8", - "thiserror", - "uuid 0.8.2", -] - -[[package]] -name = "eth-types" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" -dependencies = [ - "ethers-core", - "ethers-signers", - "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", - "hex", - "itertools", - "lazy_static", - "libsecp256k1", - "num", - "num-bigint", - "regex", - "serde", - "serde_json", - "serde_with 1.14.0", - "sha3 0.10.8", - "strum", - "strum_macros", - "subtle", - "uint", -] - -[[package]] -name = "ethabi" -version = "17.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4966fba78396ff92db3b817ee71143eccd98acf0f876b8d600e585a670c5d1b" -dependencies = [ - "ethereum-types 0.13.1", - "hex", - "once_cell", - "regex", - "serde", - "serde_json", - "sha3 0.10.8", - "thiserror", - "uint", -] - -[[package]] -name = "ethbloom" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11da94e443c60508eb62cf256243a64da87304c2802ac2528847f79d750007ef" -dependencies = [ - "crunchy", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde", - "tiny-keccak", -] - -[[package]] -name = "ethbloom" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash 0.8.0", - "tiny-keccak", -] - -[[package]] -name = "ethereum-types" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2827b94c556145446fcce834ca86b7abf0c39a805883fe20e72c5bfdb5a0dc6" -dependencies = [ - "ethbloom 0.12.1", - "fixed-hash 0.7.0", - "impl-rlp", - "impl-serde", - "primitive-types 0.11.1", - "uint", -] - -[[package]] -name = "ethereum-types" -version = "0.14.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" -dependencies = [ - "ethbloom 0.13.0", - "fixed-hash 0.8.0", - "primitive-types 0.12.1", - "uint", -] - -[[package]] -name = "ethers-core" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ebdd63c828f58aa067f40f9adcbea5e114fb1f90144b3a1e2858e0c9b1ff4e8" -dependencies = [ - "arrayvec", - "bytes", - "chrono", - "convert_case", - "elliptic-curve", - "ethabi", - "fastrlp", - "generic-array 0.14.7", - "hex", - "k256", - "proc-macro2", - "rand", - "rlp", - "rlp-derive", - "rust_decimal", - "serde", - "serde_json", - "strum", - "syn 1.0.109", - "thiserror", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "ethers-providers" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e46482e4d1e79b20c338fd9db9e166184eb387f0a4e7c05c5b5c0aa2e8c8900c" -dependencies = [ - "async-trait", - "auto_impl", - "base64 0.13.1", - "ethers-core", - "futures-channel", - "futures-core", - "futures-timer", - "futures-util", - "getrandom", - "hashers", - "hex", - "http", - "once_cell", - "parking_lot 0.11.2", - "pin-project", - "reqwest", - "serde", - "serde_json", - "thiserror", - "tokio", - "tokio-tungstenite", - "tracing", - "tracing-futures", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "wasm-timer", - "web-sys", - "ws_stream_wasm", -] - -[[package]] -name = "ethers-signers" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73a72ecad124e8ccd18d6a43624208cab0199e59621b1f0fa6b776b2e0529107" -dependencies = [ - "async-trait", - "coins-bip32", - "coins-bip39", - "elliptic-curve", - "eth-keystore", - "ethers-core", - "hex", - "rand", - "sha2 0.10.6", - "thiserror", -] - -[[package]] -name = "external-tracer" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" -dependencies = [ - "eth-types", - "geth-utils", - "serde", - "serde_json", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "fastrand" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" -dependencies = [ - "instant", -] - -[[package]] -name = "fastrlp" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "089263294bb1c38ac73649a6ad563dd9a5142c8dc0482be15b8b9acb22a1611e" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types 0.13.1", - "fastrlp-derive", -] - -[[package]] -name = "fastrlp-derive" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0f9d074ab623d1b388c12544bfeed759c7df36dc5c300cda053df9ba1232075" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ff" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" -dependencies = [ - "bitvec 1.0.1", - "rand_core", - "subtle", -] - -[[package]] -name = "findshlibs" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" -dependencies = [ - "cc", - "lazy_static", - "libc", - "winapi", -] - -[[package]] -name = "fixed-hash" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fixed-hash" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" -dependencies = [ - "byteorder", - "rand", - "rustc-hex", - "static_assertions", -] - -[[package]] -name = "fnv" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" - -[[package]] -name = "form_urlencoded" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" -dependencies = [ - "percent-encoding", -] - -[[package]] -name = "funty" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" - -[[package]] -name = "futures" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" -dependencies = [ - "futures-channel", - "futures-core", - "futures-executor", - "futures-io", - "futures-sink", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-channel" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" -dependencies = [ - "futures-core", - "futures-sink", -] - -[[package]] -name = "futures-core" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" - -[[package]] -name = "futures-executor" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" -dependencies = [ - "futures-core", - "futures-task", - "futures-util", -] - -[[package]] -name = "futures-io" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" - -[[package]] -name = "futures-macro" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.16", -] - -[[package]] -name = "futures-sink" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" - -[[package]] -name = "futures-task" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" - -[[package]] -name = "futures-timer" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" - -[[package]] -name = "futures-util" -version = "0.3.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", - "futures-macro", - "futures-sink", - "futures-task", - "memchr", - "pin-project-lite", - "pin-utils", - "slab", -] - -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gadgets" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" -dependencies = [ - "digest 0.7.6", - "eth-types", - "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", - "sha3 0.7.3", - "strum", -] - -[[package]] -name = "generic-array" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d00328cedcac5e81c683e5620ca6a30756fc23027ebf9bff405c0e8da1fbb7e" -dependencies = [ - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - -[[package]] -name = "generic-array" -version = "0.14.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", -] - -[[package]] -name = "geth-utils" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" -dependencies = [ - "env_logger", - "gobuild", - "log", -] - -[[package]] -name = "getrandom" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" -dependencies = [ - "cfg-if", - "js-sys", - "libc", - "wasi", - "wasm-bindgen", -] - -[[package]] -name = "gimli" -version = "0.27.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" - -[[package]] -name = "gobuild" -version = "0.1.0-alpha.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e156a4ddbf3deb5e8116946c111413bd9a5679bdc1536c78a60618a7a9ac9e" -dependencies = [ - "cc", -] - -[[package]] -name = "group" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" -dependencies = [ - "ff", - "rand_core", - "subtle", -] - -[[package]] -name = "h2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "halo2-base" -version = "0.3.0" -source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.3.0#238b89e7562d52166c1e08154b7c9759f65322a6" -dependencies = [ - "ff", - "halo2_proofs 0.2.0", - "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", - "itertools", - "jemallocator", - "log", - "num-bigint", - "num-integer", - "num-traits", - "rand_chacha", - "rayon", - "rustc-hash", - "serde", - "serde_json", -] - -[[package]] -name = "halo2-ecc" -version = "0.3.0" -source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.3.0#238b89e7562d52166c1e08154b7c9759f65322a6" -dependencies = [ - "ff", - "group", - "halo2-base", - "itertools", - "num-bigint", - "num-integer", - "num-traits", - "rand", - "rand_chacha", - "rand_core", - "rayon", - "serde", - "serde_json", -] - -[[package]] -name = "halo2_proofs" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e925780549adee8364c7f2b685c753f6f3df23bde520c67416e93bf615933760" -dependencies = [ - "blake2b_simd", - "ff", - "group", - "pasta_curves", - "rand_core", - "rayon", -] - -[[package]] -name = "halo2_proofs" -version = "0.2.0" -dependencies = [ - "blake2b_simd", - "crossbeam", - "ff", - "group", - "halo2curves 0.3.1", - "rand", - "rand_core", - "rayon", - "rustc-hash", - "sha3 0.9.1", - "tracing", -] - -[[package]] -name = "halo2_proofs" -version = "0.2.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2022_09_10#a9e99a72a65d7c98e8a4258c2c94269c834d1c10" -dependencies = [ - "blake2b_simd", - "ff", - "group", - "halo2curves 0.2.1 (git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.2.1)", - "rand_core", - "rayon", - "tracing", -] - -[[package]] -name = "halo2_proofs" -version = "0.2.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02#0a8646b78286a13d320759b1c585262d6536dce4" -dependencies = [ - "blake2b_simd", - "ff", - "group", - "halo2curves 0.3.1 (git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1)", - "rand_core", - "rayon", - "sha3 0.9.1", - "tracing", -] - -[[package]] -name = "halo2curves" -version = "0.2.1" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.2.1#f75ed26c961179186e9cec02cc3f841ca9e3fec1" -dependencies = [ - "ff", - "group", - "lazy_static", - "num-bigint", - "num-traits", - "pasta_curves", - "rand", - "rand_core", - "static_assertions", - "subtle", -] - -[[package]] -name = "halo2curves" -version = "0.2.1" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.0#83c72d49762343ffc9576ca11a2aa615efe1029b" -dependencies = [ - "ff", - "group", - "lazy_static", - "num-bigint", - "num-traits", - "pasta_curves", - "rand", - "rand_core", - "static_assertions", - "subtle", -] - -[[package]] -name = "halo2curves" -version = "0.3.1" -dependencies = [ - "ff", - "group", - "lazy_static", - "num-bigint", - "num-traits", - "pasta_curves", - "rand", - "rand_core", - "serde", - "static_assertions", - "subtle", -] - -[[package]] -name = "halo2curves" -version = "0.3.1" -source = "git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1#9b67e19bca30a35208b0c1b41c1723771e2c9f49" -dependencies = [ - "ff", - "group", - "lazy_static", - "num-bigint", - "num-traits", - "pasta_curves", - "rand", - "rand_core", - "static_assertions", - "subtle", -] - -[[package]] -name = "halo2wrong" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" -dependencies = [ - "group", - "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -dependencies = [ - "ahash 0.7.6", -] - -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash 0.8.3", -] - -[[package]] -name = "hashers" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" -dependencies = [ - "fxhash", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" -dependencies = [ - "libc", -] - -[[package]] -name = "hermit-abi" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" - -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac", - "digest 0.9.0", -] - -[[package]] -name = "hmac" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "hmac-drbg" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" -dependencies = [ - "digest 0.9.0", - "generic-array 0.14.7", - "hmac 0.8.1", -] - -[[package]] -name = "http" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - -[[package]] -name = "http-body" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" -dependencies = [ - "bytes", - "http", - "pin-project-lite", -] - -[[package]] -name = "httparse" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" - -[[package]] -name = "httpdate" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" - -[[package]] -name = "humantime" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" - -[[package]] -name = "hyper" -version = "0.14.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2", - "tokio", - "tower-service", - "tracing", - "want", -] - -[[package]] -name = "hyper-rustls" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0646026eb1b3eea4cd9ba47912ea5ce9cc07713d105b1a14698f4e6433d348b7" -dependencies = [ - "http", - "hyper", - "rustls 0.21.1", - "tokio", - "tokio-rustls 0.24.0", -] - -[[package]] -name = "iana-time-zone" -version = "0.1.56" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0722cd7114b7de04316e7ea5456a0bbb20e4adb46fd27a3697adb812cff0f37c" -dependencies = [ - "android_system_properties", - "core-foundation-sys", - "iana-time-zone-haiku", - "js-sys", - "wasm-bindgen", - "windows", -] - -[[package]] -name = "iana-time-zone-haiku" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" -dependencies = [ - "cc", -] - -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - -[[package]] -name = "idna" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "impl-codec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" -dependencies = [ - "parity-scale-codec", -] - -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4551f042f3438e64dbd6226b20527fc84a6e1fe65688b58746a2f53623f25f5c" -dependencies = [ - "serde", -] - -[[package]] -name = "impl-trait-for-tuples" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", -] - -[[package]] -name = "inferno" -version = "0.11.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fb7c1b80a1dfa604bb4a649a5c5aeef3d913f7c520cb42b40e534e8a61bcdfc" -dependencies = [ - "ahash 0.8.3", - "indexmap", - "is-terminal", - "itoa", - "log", - "num-format", - "once_cell", - "quick-xml", - "rgb", - "str_stack", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "integer" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" -dependencies = [ - "group", - "maingate", - "num-bigint", - "num-integer", - "num-traits", - "rand", - "subtle", -] - -[[package]] -name = "io-lifetimes" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", -] - -[[package]] -name = "ipnet" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" - -[[package]] -name = "is-terminal" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" -dependencies = [ - "hermit-abi 0.3.1", - "io-lifetimes", - "rustix", - "windows-sys 0.48.0", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" - -[[package]] -name = "jemalloc-sys" -version = "0.5.3+5.3.0-patched" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9bd5d616ea7ed58b571b2e209a65759664d7fb021a0819d7a790afc67e47ca1" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "jemallocator" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16c2514137880c52b0b4822b563fadd38257c1f380858addb74a400889696ea6" -dependencies = [ - "jemalloc-sys", - "libc", -] - -[[package]] -name = "js-sys" -version = "0.3.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "k256" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b" -dependencies = [ - "cfg-if", - "ecdsa 0.14.8", - "elliptic-curve", - "sha2 0.10.6", - "sha3 0.10.8", -] - -[[package]] -name = "keccak" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" -dependencies = [ - "cpufeatures", -] - -[[package]] -name = "keccak256" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" -dependencies = [ - "env_logger", - "eth-types", - "halo2_proofs 0.1.0", - "itertools", - "lazy_static", - "log", - "num-bigint", - "num-traits", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin", -] - -[[package]] -name = "libc" -version = "0.2.144" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" - -[[package]] -name = "libsecp256k1" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b09eff1b35ed3b33b877ced3a691fc7a481919c7e29c53c906226fcf55e2a1" -dependencies = [ - "arrayref", - "base64 0.13.1", - "digest 0.9.0", - "hmac-drbg", - "libsecp256k1-core", - "libsecp256k1-gen-ecmult", - "libsecp256k1-gen-genmult", - "rand", - "serde", - "sha2 0.9.9", - "typenum", -] - -[[package]] -name = "libsecp256k1-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5be9b9bb642d8522a44d533eab56c16c738301965504753b03ad1de3425d5451" -dependencies = [ - "crunchy", - "digest 0.9.0", - "subtle", -] - -[[package]] -name = "libsecp256k1-gen-ecmult" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3038c808c55c87e8a172643a7d87187fc6c4174468159cb3090659d55bcb4809" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "libsecp256k1-gen-genmult" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8d6ba2cec9eacc40e6e8ccc98931840301f1006e95647ceb2dd5c3aa06f7c" -dependencies = [ - "libsecp256k1-core", -] - -[[package]] -name = "linux-raw-sys" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "maingate" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2wrong?tag=v2023_02_02#5905a20b62fcd9f6c269416a39c80de7ced8fb02" -dependencies = [ - "group", - "halo2wrong", - "num-bigint", - "num-integer", - "num-traits", - "rand", - "subtle", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memmap2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" -dependencies = [ - "libc", -] - -[[package]] -name = "memoffset" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" -dependencies = [ - "autocfg", -] - -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - -[[package]] -name = "miniz_oxide" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" -dependencies = [ - "adler", -] - -[[package]] -name = "mio" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" -dependencies = [ - "libc", - "log", - "wasi", - "windows-sys 0.45.0", -] - -[[package]] -name = "mock" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" -dependencies = [ - "eth-types", - "ethers-core", - "ethers-signers", - "external-tracer", - "itertools", - "lazy_static", - "rand", - "rand_chacha", -] - -[[package]] -name = "nix" -version = "0.26.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" -dependencies = [ - "bitflags", - "cfg-if", - "libc", - "static_assertions", -] - -[[package]] -name = "num" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" -dependencies = [ - "num-bigint", - "num-complex", - "num-integer", - "num-iter", - "num-rational", - "num-traits", -] - -[[package]] -name = "num-bigint" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", - "rand", -] - -[[package]] -name = "num-complex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-format" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" -dependencies = [ - "arrayvec", - "itoa", -] - -[[package]] -name = "num-integer" -version = "0.1.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" -dependencies = [ - "autocfg", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" -dependencies = [ - "autocfg", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-rational" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" -dependencies = [ - "autocfg", - "num-bigint", - "num-integer", - "num-traits", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" -dependencies = [ - "hermit-abi 0.2.6", - "libc", -] - -[[package]] -name = "num_enum" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" -dependencies = [ - "num_enum_derive", -] - -[[package]] -name = "num_enum_derive" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "object" -version = "0.30.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - -[[package]] -name = "os_str_bytes" -version = "6.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" - -[[package]] -name = "parity-scale-codec" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ddb756ca205bd108aee3c62c6d3c994e1df84a59b9d6d4a5ea42ee1fd5a9a28" -dependencies = [ - "arrayvec", - "bitvec 1.0.1", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "serde", -] - -[[package]] -name = "parity-scale-codec-derive" -version = "3.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b26a931f824dd4eca30b3e43bb4f31cd5f0d3a403c5f5ff27106b805bfde7b" -dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core 0.9.7", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "windows-sys 0.45.0", -] - -[[package]] -name = "password-hash" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d791538a6dcc1e7cb7fe6f6b58aca40e7f79403c45b2bc274008b5e647af1d8" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core", - "subtle", -] - -[[package]] -name = "pasta_curves" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc65faf8e7313b4b1fbaa9f7ca917a0eed499a9663be71477f87993604341d8" -dependencies = [ - "blake2b_simd", - "ff", - "group", - "lazy_static", - "rand", - "static_assertions", - "subtle", -] - -[[package]] -name = "paste" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" - -[[package]] -name = "pbkdf2" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271779f35b581956db91a3e55737327a03aa051e90b1c47aeb189508533adfd7" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.7", - "hmac 0.12.1", - "password-hash 0.4.2", - "sha2 0.10.6", -] - -[[package]] -name = "percent-encoding" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" - -[[package]] -name = "pharos" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" -dependencies = [ - "futures", - "rustc_version", -] - -[[package]] -name = "pin-project" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.16", -] - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pin-utils" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" - -[[package]] -name = "pkcs8" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba" -dependencies = [ - "der", - "spki", -] - -[[package]] -name = "plotters" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-svg" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "poseidon" -version = "0.2.0" -source = "git+https://github.com/privacy-scaling-explorations/poseidon.git?tag=v2022_10_22#5d29df01a95e3df6334080d28e983407f56b5da3" -dependencies = [ - "group", - "halo2curves 0.2.1 (git+https://github.com/privacy-scaling-explorations/halo2curves?tag=0.3.0)", - "subtle", -] - -[[package]] -name = "poseidon-circuit" -version = "0.1.0" -source = "git+https://github.com/scroll-tech/poseidon-circuit.git#079e3f5bfc30d63ded672a97850e3c160504bfad" -dependencies = [ - "bitvec 1.0.1", - "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2022_09_10)", - "lazy_static", - "thiserror", -] - -[[package]] -name = "pprof" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196ded5d4be535690899a4631cc9f18cdc41b7ebf24a79400f46f48e49a11059" -dependencies = [ - "backtrace", - "cfg-if", - "criterion", - "findshlibs", - "inferno", - "libc", - "log", - "nix", - "once_cell", - "parking_lot 0.12.1", - "smallvec", - "symbolic-demangle", - "tempfile", - "thiserror", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" - -[[package]] -name = "primitive-types" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e28720988bff275df1f51b171e1b2a18c30d194c4d2b61defdacecd625a5d94a" -dependencies = [ - "fixed-hash 0.7.0", - "impl-codec", - "impl-rlp", - "impl-serde", - "uint", -] - -[[package]] -name = "primitive-types" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66" -dependencies = [ - "fixed-hash 0.8.0", - "impl-codec", - "impl-rlp", - "uint", -] - -[[package]] -name = "proc-macro-crate" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" -dependencies = [ - "toml", -] - -[[package]] -name = "proc-macro-crate" -version = "1.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" -dependencies = [ - "once_cell", - "toml_edit", -] - -[[package]] -name = "proc-macro-error" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" -dependencies = [ - "proc-macro-error-attr", - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", -] - -[[package]] -name = "proc-macro-error-attr" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" -dependencies = [ - "proc-macro2", - "quote", - "version_check", -] - -[[package]] -name = "proc-macro2" -version = "1.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "ptr_meta" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0738ccf7ea06b608c10564b31debd4f5bc5e197fc8bfe088f68ae5ce81e7a4f1" -dependencies = [ - "ptr_meta_derive", -] - -[[package]] -name = "ptr_meta_derive" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b845dbfca988fa33db069c0e230574d15a3088f147a87b64c7589eb662c9ac" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "quick-xml" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" -dependencies = [ - "memchr", -] - -[[package]] -name = "quote" -version = "1.0.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "radium" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "def50a86306165861203e7f84ecffbbdfdea79f0e51039b33de1e952358c47ac" - -[[package]] -name = "radium" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rayon" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" -dependencies = [ - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "redox_syscall" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1a59b5d8e97dee33696bf13c5ba8ab85341c002922fba050069326b9c498974" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" - -[[package]] -name = "rend" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581008d2099240d37fb08d77ad713bcaec2c4d89d50b5b21a8bb1996bbab68ab" -dependencies = [ - "bytecheck", -] - -[[package]] -name = "reqwest" -version = "0.11.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55" -dependencies = [ - "base64 0.21.1", - "bytes", - "encoding_rs", - "futures-core", - "futures-util", - "h2", - "http", - "http-body", - "hyper", - "hyper-rustls", - "ipnet", - "js-sys", - "log", - "mime", - "once_cell", - "percent-encoding", - "pin-project-lite", - "rustls 0.21.1", - "rustls-pemfile", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-rustls 0.24.0", - "tower-service", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "webpki-roots", - "winreg", -] - -[[package]] -name = "revm" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73d84c8f9836efb0f5f5f8de4700a953c4e1f3119e5cfcb0aad8e5be73daf991" -dependencies = [ - "arrayref", - "auto_impl", - "bytes", - "hashbrown 0.13.2", - "num_enum", - "primitive-types 0.12.1", - "revm_precompiles", - "rlp", - "sha3 0.10.8", -] - -[[package]] -name = "revm_precompiles" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0353d456ef3e989dc9190f42c6020f09bc2025930c37895826029304413204b5" -dependencies = [ - "bytes", - "hashbrown 0.13.2", - "num", - "once_cell", - "primitive-types 0.12.1", - "ripemd", - "secp256k1", - "sha2 0.10.6", - "sha3 0.10.8", - "substrate-bn", -] - -[[package]] -name = "rfc6979" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb" -dependencies = [ - "crypto-bigint", - "hmac 0.12.1", - "zeroize", -] - -[[package]] -name = "rgb" -version = "0.8.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin", - "untrusted", - "web-sys", - "winapi", -] - -[[package]] -name = "ripemd" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" -dependencies = [ - "digest 0.10.7", -] - -[[package]] -name = "rkyv" -version = "0.7.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0200c8230b013893c0b2d6213d6ec64ed2b9be2e0e016682b7224ff82cff5c58" -dependencies = [ - "bitvec 1.0.1", - "bytecheck", - "hashbrown 0.12.3", - "ptr_meta", - "rend", - "rkyv_derive", - "seahash", - "tinyvec", - "uuid 1.3.3", -] - -[[package]] -name = "rkyv_derive" -version = "0.7.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2e06b915b5c230a17d7a736d1e2e63ee753c256a8614ef3f5147b13a4f5541d" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rlp" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" -dependencies = [ - "bytes", - "rustc-hex", -] - -[[package]] -name = "rlp-derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "rust_decimal" -version = "1.29.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26bd36b60561ee1fb5ec2817f198b6fd09fa571c897a5e86d1487cfc2b096dfc" -dependencies = [ - "arrayvec", - "borsh", - "bytecheck", - "byteorder", - "bytes", - "num-traits", - "rand", - "rkyv", - "serde", - "serde_json", -] - -[[package]] -name = "rustc-demangle" -version = "0.1.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc-hex" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "rustix" -version = "0.37.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" -dependencies = [ - "bitflags", - "errno", - "io-lifetimes", - "libc", - "linux-raw-sys", - "windows-sys 0.48.0", -] - -[[package]] -name = "rustls" -version = "0.20.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" -dependencies = [ - "log", - "ring", - "sct", - "webpki", -] - -[[package]] -name = "rustls" -version = "0.21.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" -dependencies = [ - "log", - "ring", - "rustls-webpki", - "sct", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" -dependencies = [ - "base64 0.21.1", -] - -[[package]] -name = "rustls-webpki" -version = "0.100.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustversion" -version = "1.0.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" - -[[package]] -name = "ryu" -version = "1.0.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" - -[[package]] -name = "salsa20" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0fbb5f676da676c260ba276a8f43a8dc67cf02d1438423aeb1c677a7212686" -dependencies = [ - "cipher", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "scrypt" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e73d6d7c6311ebdbd9184ad6c4447b2f36337e327bda107d3ba9e3c374f9d325" -dependencies = [ - "hmac 0.12.1", - "password-hash 0.3.2", - "pbkdf2 0.10.1", - "salsa20", - "sha2 0.10.6", -] - -[[package]] -name = "sct" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "seahash" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" - -[[package]] -name = "sec1" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" -dependencies = [ - "base16ct", - "der", - "generic-array 0.14.7", - "pkcs8", - "subtle", - "zeroize", -] - -[[package]] -name = "secp256k1" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b1629c9c557ef9b293568b338dddfc8208c98a18c59d722a9d53f859d9c9b62" -dependencies = [ - "secp256k1-sys", -] - -[[package]] -name = "secp256k1-sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83080e2c2fc1006e625be82e5d1eb6a43b7fd9578b617fcc55814daf286bba4b" -dependencies = [ - "cc", -] - -[[package]] -name = "semver" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" - -[[package]] -name = "send_wrapper" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" - -[[package]] -name = "serde" -version = "1.0.163" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.163" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.16", -] - -[[package]] -name = "serde_json" -version = "1.0.96" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_urlencoded" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" -dependencies = [ - "form_urlencoded", - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "serde_with" -version = "1.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff" -dependencies = [ - "serde", - "serde_with_macros 1.5.2", -] - -[[package]] -name = "serde_with" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" -dependencies = [ - "base64 0.13.1", - "chrono", - "hex", - "indexmap", - "serde", - "serde_json", - "serde_with_macros 2.3.3", - "time", -] - -[[package]] -name = "serde_with_macros" -version = "1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082" -dependencies = [ - "darling 0.13.4", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "serde_with_macros" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" -dependencies = [ - "darling 0.20.1", - "proc-macro2", - "quote", - "syn 2.0.16", -] - -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha2" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a256f46ea78a0c0d9ff00077504903ac881a1dafdc20da66545699e7776b3e69" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", -] - -[[package]] -name = "sha2" -version = "0.9.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" -dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - -[[package]] -name = "sha2" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", -] - -[[package]] -name = "sha3" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64dcef59ed4290b9fb562b53df07f564690d6539e8ecdd4728cf392477530bc" -dependencies = [ - "block-buffer 0.3.3", - "byte-tools 0.2.0", - "digest 0.7.6", - "keccak", -] - -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug 0.3.0", -] - -[[package]] -name = "sha3" -version = "0.10.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" -dependencies = [ - "digest 0.10.7", - "keccak", -] - -[[package]] -name = "signal-hook" -version = "0.3.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" -dependencies = [ - "libc", - "signal-hook-registry", -] - -[[package]] -name = "signal-hook-mio" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" -dependencies = [ - "libc", - "mio", - "signal-hook", -] - -[[package]] -name = "signal-hook-registry" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" -dependencies = [ - "libc", -] - -[[package]] -name = "signature" -version = "1.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" -dependencies = [ - "digest 0.10.7", - "rand_core", -] - -[[package]] -name = "simdutf8" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f27f6278552951f1f2b8cf9da965d10969b2efdea95a6ec47987ab46edfe263a" - -[[package]] -name = "slab" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" -dependencies = [ - "autocfg", -] - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "snark-verifier" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/snark-verifier?tag=v2023_02_02#df03d898b841f71cbc36c2fb9fa07b8196f9623e" -dependencies = [ - "ecc", - "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", - "halo2curves 0.3.1 (git+https://github.com/privacy-scaling-explorations/halo2curves.git?tag=0.3.1)", - "hex", - "itertools", - "lazy_static", - "num-bigint", - "num-integer", - "num-traits", - "poseidon", - "rand", -] - -[[package]] -name = "snark-verifier" -version = "0.1.1" -dependencies = [ - "ark-std", - "bytes", - "crossterm", - "halo2-base", - "halo2-ecc", - "hex", - "itertools", - "lazy_static", - "num-bigint", - "num-integer", - "num-traits", - "paste", - "poseidon-circuit", - "primitive-types 0.12.1", - "rand", - "rand_chacha", - "rayon", - "revm", - "rlp", - "serde", - "serde_json", - "sha3 0.10.8", - "tui", -] - -[[package]] -name = "snark-verifier-sdk" -version = "0.1.1" -dependencies = [ - "ark-std", - "bincode", - "bus-mapping", - "criterion", - "criterion-macro", - "crossterm", - "eth-types", - "ethereum-types 0.14.1", - "halo2-base", - "hex", - "itertools", - "lazy_static", - "mock", - "num-bigint", - "num-integer", - "num-traits", - "paste", - "pprof", - "rand", - "rand_chacha", - "serde", - "serde_json", - "serde_with 2.3.3", - "snark-verifier 0.1.1", - "tui", - "zkevm-circuits", -] - -[[package]] -name = "socket2" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "spin" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" - -[[package]] -name = "spki" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b" -dependencies = [ - "base64ct", - "der", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - -[[package]] -name = "str_stack" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" - -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - -[[package]] -name = "strum" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "063e6045c0e62079840579a7e47a355ae92f60eb74daaf156fb1e84ba164e63f" -dependencies = [ - "strum_macros", -] - -[[package]] -name = "strum_macros" -version = "0.24.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] - -[[package]] -name = "substrate-bn" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" -dependencies = [ - "byteorder", - "crunchy", - "lazy_static", - "rand", - "rustc-hex", -] - -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "symbolic-common" -version = "10.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b55cdc318ede251d0957f07afe5fed912119b8c1bc5a7804151826db999e737" -dependencies = [ - "debugid", - "memmap2", - "stable_deref_trait", - "uuid 1.3.3", -] - -[[package]] -name = "symbolic-demangle" -version = "10.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79be897be8a483a81fff6a3a4e195b4ac838ef73ca42d348b3f722da9902e489" -dependencies = [ - "cpp_demangle", - "rustc-demangle", - "symbolic-common", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "syn" -version = "2.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tap" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" - -[[package]] -name = "tempfile" -version = "3.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" -dependencies = [ - "cfg-if", - "fastrand", - "redox_syscall 0.3.5", - "rustix", - "windows-sys 0.45.0", -] - -[[package]] -name = "termcolor" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - -[[package]] -name = "thiserror" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.16", -] - -[[package]] -name = "time" -version = "0.3.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" -dependencies = [ - "itoa", - "serde", - "time-core", - "time-macros", -] - -[[package]] -name = "time-core" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" - -[[package]] -name = "time-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" -dependencies = [ - "time-core", -] - -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - -[[package]] -name = "tokio" -version = "1.28.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" -dependencies = [ - "autocfg", - "bytes", - "libc", - "mio", - "pin-project-lite", - "socket2", - "windows-sys 0.48.0", -] - -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls 0.20.8", - "tokio", - "webpki", -] - -[[package]] -name = "tokio-rustls" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" -dependencies = [ - "rustls 0.21.1", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" -dependencies = [ - "futures-util", - "log", - "rustls 0.20.8", - "tokio", - "tokio-rustls 0.23.4", - "tungstenite", - "webpki", - "webpki-roots", -] - -[[package]] -name = "tokio-util" -version = "0.7.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "pin-project-lite", - "tokio", - "tracing", -] - -[[package]] -name = "toml" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" -dependencies = [ - "serde", -] - -[[package]] -name = "toml_datetime" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" - -[[package]] -name = "toml_edit" -version = "0.19.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92d964908cec0d030b812013af25a0e57fddfadb1e066ecc6681d86253129d4f" -dependencies = [ - "indexmap", - "toml_datetime", - "winnow", -] - -[[package]] -name = "tower-service" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" - -[[package]] -name = "tracing" -version = "0.1.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.16", -] - -[[package]] -name = "tracing-core" -version = "0.1.31" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - -[[package]] -name = "try-lock" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed" - -[[package]] -name = "tui" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccdd26cbd674007e649a272da4475fb666d3aa0ad0531da7136db6fab0e5bad1" -dependencies = [ - "bitflags", - "cassowary", - "crossterm", - "unicode-segmentation", - "unicode-width", -] - -[[package]] -name = "tungstenite" -version = "0.17.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand", - "rustls 0.20.8", - "sha-1", - "thiserror", - "url", - "utf-8", - "webpki", -] - -[[package]] -name = "typenum" -version = "1.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" - -[[package]] -name = "uint" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" -dependencies = [ - "byteorder", - "crunchy", - "hex", - "static_assertions", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" - -[[package]] -name = "unicode-ident" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" - -[[package]] -name = "unicode-normalization" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-segmentation" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - -[[package]] -name = "url" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" -dependencies = [ - "form_urlencoded", - "idna", - "percent-encoding", -] - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom", - "serde", -] - -[[package]] -name = "uuid" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2" - -[[package]] -name = "version_check" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" - -[[package]] -name = "walkdir" -version = "2.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" -dependencies = [ - "same-file", - "winapi-util", -] - -[[package]] -name = "want" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" -dependencies = [ - "log", - "try-lock", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn 2.0.16", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-futures" -version = "0.4.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" -dependencies = [ - "cfg-if", - "js-sys", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.16", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.86" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" - -[[package]] -name = "wasm-timer" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f" -dependencies = [ - "futures", - "js-sys", - "parking_lot 0.11.2", - "pin-utils", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "web-sys" -version = "0.3.63" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki" -version = "0.22.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "webpki-roots" -version = "0.22.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87" -dependencies = [ - "webpki", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - -[[package]] -name = "windows-sys" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" -dependencies = [ - "windows-targets 0.48.0", -] - -[[package]] -name = "windows-targets" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" -dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", -] - -[[package]] -name = "windows-targets" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" -dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" - -[[package]] -name = "windows_i686_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" - -[[package]] -name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" - -[[package]] -name = "winnow" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" -dependencies = [ - "memchr", -] - -[[package]] -name = "winreg" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" -dependencies = [ - "winapi", -] - -[[package]] -name = "ws_stream_wasm" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" -dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version", - "send_wrapper", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - -[[package]] -name = "wyz" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" -dependencies = [ - "tap", -] - -[[package]] -name = "zeroize" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" - -[[package]] -name = "zkevm-circuits" -version = "0.1.0" -source = "git+https://github.com/privacy-scaling-explorations/zkevm-circuits.git?rev=f834e61#f834e61ed2937adfecbb5fdad9cab711871c27ac" -dependencies = [ - "array-init", - "bus-mapping", - "ecc", - "ecdsa 0.1.0", - "env_logger", - "eth-types", - "ethers-core", - "ethers-signers", - "gadgets", - "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?tag=v2023_02_02)", - "integer", - "itertools", - "keccak256", - "lazy_static", - "libsecp256k1", - "log", - "maingate", - "mock", - "num", - "num-bigint", - "rand", - "rand_chacha", - "rand_xorshift", - "sha3 0.10.8", - "snark-verifier 0.1.0", - "strum", - "strum_macros", - "subtle", -] - -[[patch.unused]] -name = "poseidon" -version = "0.2.0" diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 7069bf26..986f30eb 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -17,11 +17,11 @@ serde_json = "1.0" serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.3.0", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } # loader_evm -ethereum-types = { version = "0.14", default-features = false, features = ["std"], optional = true } +ethereum-types = { version = "0.14.1", default-features = false, features = ["std"], optional = true } # sha3 = { version = "0.10", optional = true } # revm = { version = "2.3.1", optional = true } # bytes = { version = "1.2", optional = true } diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 81248a2d..313fd038 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -16,17 +16,17 @@ serde = { version = "1.0", features = ["derive"] } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } # This is Scroll's audited poseidon circuit. We only use it for the Native Poseidon spec. We do not use the halo2 circuit at all (and it wouldn't even work because the halo2_proofs tag is not compatbile). -poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git" } +poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git", rev = "50015b7" } # parallel rayon = { version = "1.7.0", optional = true } # loader_evm -sha3 = { version = "0.10", optional = true } -bytes = { version = "1.1.0", default-features = false, optional = true } +sha3 = { version = "0.10.8", optional = true } +bytes = { version = "1.4.0", default-features = false, optional = true } primitive-types = { version = "0.12.1", default-features = false, features = ["std"], optional = true } rlp = { version = "0.5.2", default-features = false, features = ["std"], optional = true } -revm = { version = "= 2.3.1", optional = true } +revm = { version = "2.3.1", optional = true } # loader_halo2 halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false, optional = true } From 7a0fd966dd62e9f076c7631b5f541af5d44e1fac Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Thu, 20 Jul 2023 17:36:32 -0400 Subject: [PATCH 42/73] feat: remove use of env vars for circuit configuration (#22) * feat: remove use of env vars for circuit configuration This is a companion to https://github.com/axiom-crypto/halo2-lib/pull/92 * chore: remove rustfmt CI check PSE upstream uses different rustfmt configuration than us, so some files disagree in formatting --- .github/workflows/ci.yaml | 4 - snark-verifier-sdk/Cargo.toml | 2 +- snark-verifier-sdk/benches/standard_plonk.rs | 13 +- snark-verifier-sdk/src/halo2/aggregation.rs | 52 ++++--- snark-verifier/Cargo.toml | 4 +- .../examples/evm-verifier-with-accumulator.rs | 145 +++++------------- snark-verifier/examples/recursion.rs | 127 +++++---------- snark-verifier/src/loader/evm/code.rs | 4 +- 8 files changed, 111 insertions(+), 240 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 634eed77..e057f89d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -29,7 +29,6 @@ jobs: - name: Run test run: cargo test --all -- --nocapture - lint: name: Lint runs-on: ubuntu-latest @@ -47,8 +46,5 @@ jobs: with: cache-on-failure: true - - name: Run fmt - run: cargo fmt --all -- --check - - name: Run clippy run: cargo clippy --all --all-targets -- -D warnings diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 986f30eb..896dbccf 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -17,7 +17,7 @@ serde_json = "1.0" serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "feat/test_suite", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } # loader_evm diff --git a/snark-verifier-sdk/benches/standard_plonk.rs b/snark-verifier-sdk/benches/standard_plonk.rs index 70d600ea..f696f822 100644 --- a/snark-verifier-sdk/benches/standard_plonk.rs +++ b/snark-verifier-sdk/benches/standard_plonk.rs @@ -1,17 +1,16 @@ +use ark_std::{end_timer, start_timer}; use criterion::{criterion_group, criterion_main}; use criterion::{BenchmarkId, Criterion}; -use halo2_base::gates::builder::CircuitBuilderStage; -use halo2_base::utils::fs::gen_srs; -use pprof::criterion::{Output, PProfProfiler}; -use rand::rngs::OsRng; -use std::path::Path; -use ark_std::{end_timer, start_timer}; +use halo2_base::gates::builder::{CircuitBuilderStage, BASE_CONFIG_PARAMS}; use halo2_base::halo2_proofs; +use halo2_base::utils::fs::gen_srs; use halo2_proofs::halo2curves as halo2_curves; use halo2_proofs::{ halo2curves::bn256::Bn256, poly::{commitment::Params, kzg::commitment::ParamsKZG}, }; +use pprof::criterion::{Output, PProfProfiler}; +use rand::rngs::OsRng; use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; use snark_verifier_sdk::halo2::aggregation::AggregationConfigParams; use snark_verifier_sdk::{ @@ -20,6 +19,7 @@ use snark_verifier_sdk::{ Snark, }; use snark_verifier_sdk::{CircuitExt, SHPLONK}; +use std::path::Path; mod application { use super::halo2_curves::bn256::Fr; @@ -185,6 +185,7 @@ fn bench(c: &mut Criterion) { let snarks = [(); 3].map(|_| gen_application_snark(¶ms_app)); let agg_config = AggregationConfigParams::from_path(path); + BASE_CONFIG_PARAMS.with(|params| *params.borrow_mut() = agg_config.into()); let params = gen_srs(agg_config.degree); let lookup_bits = params.k() as usize - 1; diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index b5dc148d..9f9ac64a 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -3,10 +3,11 @@ use crate::{BITS, LIMBS}; use halo2_base::{ gates::{ builder::{ - CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, - MultiPhaseThreadBreakPoints, RangeCircuitBuilder, RangeWithInstanceCircuitBuilder, - RangeWithInstanceConfig, + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + PublicBaseConfig, RangeCircuitBuilder, RangeWithInstanceCircuitBuilder, + BASE_CONFIG_PARAMS, }, + flex_gate::GateStrategy, RangeChip, }, halo2_proofs::{ @@ -38,12 +39,7 @@ use snark_verifier::{ }, verifier::SnarkVerifier, }; -use std::{ - env::{set_var, var}, - fs::File, - path::Path, - rc::Rc, -}; +use std::{fs::File, path::Path, rc::Rc}; use super::{CircuitExt, PoseidonTranscript, Snark, POSEIDON_SPEC}; @@ -143,7 +139,7 @@ where /// Same as `FlexGateConfigParams` except we assume a single Phase and default 'Vertical' strategy. /// Also adds `lookup_bits` field. -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct AggregationConfigParams { pub degree: u32, pub num_advice: usize, @@ -159,6 +155,19 @@ impl AggregationConfigParams { } } +impl From for BaseConfigParams { + fn from(params: AggregationConfigParams) -> Self { + BaseConfigParams { + strategy: GateStrategy::Vertical, + k: params.degree as usize, + num_advice_per_phase: vec![params.num_advice], + num_lookup_advice_per_phase: vec![params.num_lookup_advice], + num_fixed: params.num_fixed, + lookup_bits: Some(params.lookup_bits), + } + } +} + #[derive(Clone, Debug)] pub struct AggregationCircuit { pub inner: RangeWithInstanceCircuitBuilder, @@ -314,11 +323,12 @@ impl AggregationCircuit { where AS: for<'a> Halo2KzgAccumulationScheme<'a>, { - let lookup_bits = params.k() as usize - 1; // almost always we just use the max lookup bits possible, which is k - 1 because of blinding factors + let lookup_bits = BASE_CONFIG_PARAMS + .with(|conf| conf.borrow().lookup_bits) + .unwrap_or(params.k() as usize - 1); let circuit = Self::new::(CircuitBuilderStage::Keygen, None, lookup_bits, params, snarks); circuit.config(params.k(), Some(10)); - set_var("LOOKUP_BITS", lookup_bits.to_string()); circuit } @@ -331,18 +341,16 @@ impl AggregationCircuit { where AS: for<'a> Halo2KzgAccumulationScheme<'a>, { - let lookup_bits: usize = var("LOOKUP_BITS").expect("LOOKUP_BITS not set").parse().unwrap(); - let circuit = Self::new::( + let lookup_bits = BASE_CONFIG_PARAMS + .with(|conf| conf.borrow().lookup_bits) + .unwrap_or(params.k() as usize - 1); + Self::new::( CircuitBuilderStage::Prover, Some(break_points), lookup_bits, params, snarks, - ); - let minimum_rows = var("MINIMUM_ROWS").map(|s| s.parse().unwrap_or(10)).unwrap_or(10); - circuit.config(params.k(), Some(minimum_rows)); - set_var("LOOKUP_BITS", lookup_bits.to_string()); - circuit + ) } /// Re-expose the previous public instances of aggregated snarks again. @@ -359,7 +367,7 @@ impl AggregationCircuit { &self.as_proof[..] } - pub fn config(&self, k: u32, minimum_rows: Option) -> FlexGateConfigParams { + pub fn config(&self, k: u32, minimum_rows: Option) -> BaseConfigParams { self.inner.config(k, minimum_rows) } @@ -386,12 +394,12 @@ impl CircuitExt for RangeWithInstanceCircuitBuilder { } fn selectors(config: &Self::Config) -> Vec { - config.range.gate.basic_gates[0].iter().map(|gate| gate.q_enable).collect() + config.base.gate().basic_gates[0].iter().map(|gate| gate.q_enable).collect() } } impl Circuit for AggregationCircuit { - type Config = RangeWithInstanceConfig; + type Config = PublicBaseConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 313fd038..bf8b7fd5 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -14,7 +14,7 @@ rand = "0.8" serde = { version = "1.0", features = ["derive"] } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "feat/test_suite", default-features = false } # This is Scroll's audited poseidon circuit. We only use it for the Native Poseidon spec. We do not use the halo2 circuit at all (and it wouldn't even work because the halo2_proofs tag is not compatbile). poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git", rev = "50015b7" } @@ -29,7 +29,7 @@ rlp = { version = "0.5.2", default-features = false, features = ["std"], optiona revm = { version = "2.3.1", optional = true } # loader_halo2 -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false, optional = true } +halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "feat/test_suite", default-features = false, optional = true } [dev-dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } diff --git a/snark-verifier/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs index dd537880..4ffa6459 100644 --- a/snark-verifier/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -1,5 +1,9 @@ use aggregation::{AggregationCircuit, AggregationConfigParams}; -use halo2_base::{gates::builder::CircuitBuilderStage, halo2_proofs, utils::fs::gen_srs}; +use halo2_base::{ + gates::builder::{set_lookup_bits, CircuitBuilderStage}, + halo2_proofs, + utils::fs::gen_srs, +}; use halo2_proofs::{ dev::MockProver, halo2curves::bn256::{Bn256, Fq, Fr, G1Affine}, @@ -26,7 +30,7 @@ use snark_verifier::{ system::halo2::{compile, transcript::evm::EvmTranscript, Config}, verifier::{self, SnarkVerifier}, }; -use std::{env::set_var, fs::File, io::Cursor, rc::Rc}; +use std::{fs::File, io::Cursor, rc::Rc}; const LIMBS: usize = 3; const BITS: usize = 88; @@ -200,20 +204,16 @@ mod aggregation { use super::halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, - plonk::{self, Circuit, Column, Instance}, + plonk::{self, Circuit}, }; use super::{As, BITS, LIMBS}; use super::{Fr, G1Affine}; - use halo2_base::{ - gates::{ - builder::{ - assign_threads_in, CircuitBuilderStage, FlexGateConfigParams, GateThreadBuilder, - MultiPhaseThreadBreakPoints, RangeCircuitBuilder, - }, - range::RangeConfig, - RangeChip, + use halo2_base::gates::{ + builder::{ + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, + PublicBaseConfig, RangeWithInstanceCircuitBuilder, }, - AssignedValue, SKIP_FIRST_PASS, + RangeChip, }; use halo2_ecc::bn254::FpChip; use itertools::Itertools; @@ -228,7 +228,7 @@ mod aggregation { util::arithmetic::fe_to_limbs, verifier::{plonk::PlonkProtocol, SnarkVerifier}, }; - use std::{collections::HashMap, rc::Rc}; + use std::rc::Rc; const T: usize = 3; const RATE: usize = 2; @@ -309,17 +309,10 @@ mod aggregation { pub lookup_bits: usize, } - #[derive(Clone)] - pub struct AggregationConfig { - pub range: RangeConfig, - pub instance: Column, - } - #[derive(Clone, Debug)] pub struct AggregationCircuit { - pub circuit: RangeCircuitBuilder, + pub inner: RangeWithInstanceCircuitBuilder, pub as_proof: Vec, - pub assigned_instances: Vec>, } impl AggregationCircuit { @@ -398,22 +391,28 @@ mod aggregation { } let builder = loader.take_ctx(); - let circuit = match stage { - CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder), - CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder), - CircuitBuilderStage::Prover => { - RangeCircuitBuilder::prover(builder, break_points.unwrap()) + let inner = match stage { + CircuitBuilderStage::Mock => { + RangeWithInstanceCircuitBuilder::mock(builder, assigned_instances) + } + CircuitBuilderStage::Keygen => { + RangeWithInstanceCircuitBuilder::keygen(builder, assigned_instances) } + CircuitBuilderStage::Prover => RangeWithInstanceCircuitBuilder::prover( + builder, + assigned_instances, + break_points.unwrap(), + ), }; - Self { circuit, as_proof, assigned_instances } + Self { inner, as_proof } } - pub fn config(&self, k: u32, minimum_rows: Option) -> FlexGateConfigParams { - self.circuit.0.builder.borrow().config(k as usize, minimum_rows) + pub fn config(&self, k: u32, minimum_rows: Option) -> BaseConfigParams { + self.inner.circuit.0.builder.borrow().config(k as usize, minimum_rows) } pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { - self.circuit.0.break_points.borrow().clone() + self.inner.circuit.0.break_points.borrow().clone() } pub fn num_instance() -> Vec { @@ -422,7 +421,7 @@ mod aggregation { } pub fn instances(&self) -> Vec> { - vec![self.assigned_instances.iter().map(|v| *v.value()).collect_vec()] + vec![self.inner.assigned_instances.iter().map(|v| *v.value()).collect_vec()] } pub fn accumulator_indices() -> Vec<(usize, usize)> { @@ -431,7 +430,7 @@ mod aggregation { } impl Circuit for AggregationCircuit { - type Config = AggregationConfig; + type Config = PublicBaseConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -439,89 +438,15 @@ mod aggregation { } fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - let range = RangeCircuitBuilder::configure(meta); - let instance = meta.instance_column(); - meta.enable_equality(instance); - AggregationConfig { range, instance } + RangeWithInstanceCircuitBuilder::configure(meta) } fn synthesize( &self, config: Self::Config, - mut layouter: impl Layouter, + layouter: impl Layouter, ) -> Result<(), plonk::Error> { - // copied from RangeCircuitBuilder::synthesize but with extra logic to expose public instances - let range = config.range; - let circuit = &self.circuit.0; - range.load_lookup_table(&mut layouter).expect("load lookup table should not fail"); - - // we later `take` the builder, so we need to save this value - let witness_gen_only = circuit.builder.borrow().witness_gen_only(); - let mut assigned_advices = HashMap::new(); - - let mut first_pass = SKIP_FIRST_PASS; - layouter - .assign_region( - || "AggregationCircuit", - |mut region| { - if first_pass { - first_pass = false; - return Ok(()); - } - // only support FirstPhase in this Builder because getting challenge value requires more specialized witness generation during synthesize - if !witness_gen_only { - // clone the builder so we can re-use the circuit for both vk and pk gen - let builder = circuit.builder.borrow(); - let assignments = builder.assign_all( - &range.gate, - &range.lookup_advice, - &range.q_lookup, - &mut region, - Default::default(), - ); - *circuit.break_points.borrow_mut() = assignments.break_points; - assigned_advices = assignments.assigned_advices; - } else { - #[cfg(feature = "display")] - let start0 = std::time::Instant::now(); - let builder = circuit.builder.take(); - let break_points = circuit.break_points.take(); - for (phase, (threads, break_points)) in builder - .threads - .into_iter() - .zip(break_points.into_iter()) - .enumerate() - .take(1) - { - assign_threads_in( - phase, - threads, - &range.gate, - &range.lookup_advice[phase], - &mut region, - break_points, - ); - } - #[cfg(feature = "display")] - println!("assign threads in {:?}", start0.elapsed()); - } - Ok(()) - }, - ) - .unwrap(); - - if !witness_gen_only { - // expose public instances - let mut layouter = layouter.namespace(|| "expose"); - for (i, instance) in self.assigned_instances.iter().enumerate() { - let cell = instance.cell.unwrap(); - let (cell, _) = assigned_advices - .get(&(cell.context_id, cell.offset)) - .expect("instance not assigned"); - layouter.constrain_instance(*cell, config.instance, i); - } - } - Ok(()) + self.inner.synthesize(config, layouter) } } } @@ -649,6 +574,7 @@ fn main() { File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")), ) .unwrap(); + set_lookup_bits(agg_config.lookup_bits); let agg_circuit = AggregationCircuit::new( CircuitBuilderStage::Mock, None, @@ -657,7 +583,6 @@ fn main() { snarks.clone(), ); agg_circuit.config(agg_config.degree, Some(6)); - set_var("LOOKUP_BITS", agg_config.lookup_bits.to_string()); #[cfg(debug_assertions)] { MockProver::run(agg_config.degree, &agg_circuit, agg_circuit.instances()) diff --git a/snark-verifier/examples/recursion.rs b/snark-verifier/examples/recursion.rs index 5829e1b7..7415e1ab 100644 --- a/snark-verifier/examples/recursion.rs +++ b/snark-verifier/examples/recursion.rs @@ -2,9 +2,10 @@ use ark_std::{end_timer, start_timer}; use common::*; -use halo2_base::gates::flex_gate::GateStrategy; +use halo2_base::gates::builder::BaseConfigParams; +use halo2_base::gates::{builder::BASE_CONFIG_PARAMS, flex_gate::GateStrategy}; +use halo2_base::halo2_proofs; use halo2_base::utils::fs::gen_srs; -use halo2_base::{gates::builder::FlexGateConfigParams, halo2_proofs}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, dev::MockProver, @@ -46,7 +47,7 @@ use snark_verifier::{ SnarkVerifier, }, }; -use std::{env::set_var, fs, iter, marker::PhantomData, rc::Rc}; +use std::{fs, iter, marker::PhantomData, rc::Rc}; use crate::recursion::AggregationConfigParams; @@ -323,18 +324,17 @@ mod application { } mod recursion { - use std::{collections::HashMap, env::var}; - use halo2_base::{ gates::{ - builder::{GateThreadBuilder, RangeCircuitBuilder}, - range::RangeConfig, + builder::{ + GateThreadBuilder, PublicBaseConfig, RangeWithInstanceCircuitBuilder, + BASE_CONFIG_PARAMS, + }, GateInstructions, RangeChip, RangeInstructions, }, AssignedValue, }; use halo2_ecc::{bn254::FpChip, ecc::EcPoint}; - use halo2_proofs::plonk::{Column, Instance}; use snark_verifier::loader::halo2::{EccInstructions, IntegerInstructions}; use super::*; @@ -412,8 +412,8 @@ mod recursion { .map(|(lhs, rhs)| { loader.ecc_chip().select( loader.ctx_mut().main(0), - EcPoint::clone(&lhs), - EcPoint::clone(&rhs), + EcPoint::clone(lhs), + EcPoint::clone(rhs), *condition, ) }) @@ -446,24 +446,18 @@ mod recursion { pub lookup_bits: usize, } - #[derive(Clone)] - pub struct RecursionConfig { - pub range: RangeConfig, - pub instance: Column, - } - #[derive(Clone)] pub struct RecursionCircuit { svk: Svk, default_accumulator: KzgAccumulator, app: Snark, previous: Snark, + #[allow(dead_code)] round: usize, instances: Vec, as_proof: Vec, - inner: RangeCircuitBuilder, - assigned_instances: Vec>, + inner: RangeWithInstanceCircuitBuilder, } impl RecursionCircuit { @@ -534,24 +528,16 @@ mod recursion { .collect(); let builder = GateThreadBuilder::mock(); - let inner = RangeCircuitBuilder::mock(builder); - let mut circuit = Self { - svk, - default_accumulator, - app: app, - previous: previous, - round, - instances, - as_proof, - inner, - assigned_instances: vec![], - }; + let inner = RangeWithInstanceCircuitBuilder::mock(builder, vec![]); + let mut circuit = + Self { svk, default_accumulator, app, previous, round, instances, as_proof, inner }; circuit.build(); circuit } fn build(&mut self) { - let lookup_bits = var("LOOKUP_BITS").unwrap().parse().unwrap(); + let lookup_bits = + BASE_CONFIG_PARAMS.with(|params| params.borrow().lookup_bits.unwrap()); let range = RangeChip::::default(lookup_bits); let main_gate = range.gate(); let mut builder = GateThreadBuilder::mock(); @@ -629,9 +615,9 @@ mod recursion { ] { ctx.constrain_equal(lhs, rhs); } - *self.inner.0.builder.borrow_mut() = builder; + *self.inner.circuit.0.builder.borrow_mut() = builder; - self.assigned_instances.extend( + self.inner.assigned_instances.extend( [lhs.x(), lhs.y(), rhs.x(), rhs.y()] .into_iter() .flat_map(|coordinate| coordinate.limbs()) @@ -670,7 +656,7 @@ mod recursion { } impl Circuit for RecursionCircuit { - type Config = RecursionConfig; + type Config = PublicBaseConfig; type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -678,59 +664,15 @@ mod recursion { } fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - let range = RangeCircuitBuilder::configure(meta); - let instance = meta.instance_column(); - meta.enable_equality(instance); - RecursionConfig { range, instance } + RangeWithInstanceCircuitBuilder::configure(meta) } fn synthesize( &self, config: Self::Config, - mut layouter: impl Layouter, + layouter: impl Layouter, ) -> Result<(), Error> { - let range = config.range; - range.load_lookup_table(&mut layouter).expect("load lookup table should not fail"); - let circuit = &self.inner.0; - - let mut assigned_advices = HashMap::new(); - // POC so will only do mock prover and not real prover - let mut first_pass = halo2_base::SKIP_FIRST_PASS; // assume using simple floor planner - layouter - .assign_region( - || "Recursion Circuit", - |mut region| { - if first_pass { - first_pass = false; - return Ok(()); - } - // clone the builder so we can re-use the circuit for both vk and pk gen - let builder = circuit.builder.borrow(); - let assignments = builder.assign_all( - &range.gate, - &range.lookup_advice, - &range.q_lookup, - &mut region, - Default::default(), - ); - *circuit.break_points.borrow_mut() = assignments.break_points; - assigned_advices = assignments.assigned_advices; - Ok(()) - }, - ) - .unwrap(); - - // expose public instances - let mut layouter = layouter.namespace(|| "expose"); - for (i, instance) in self.assigned_instances.iter().enumerate() { - let cell = instance.cell.unwrap(); - let (cell, _) = assigned_advices - .get(&(cell.context_id, cell.offset)) - .expect("instance not assigned"); - layouter.constrain_instance(*cell, config.instance, i); - } - - Ok(()) + self.inner.synthesize(config, layouter) } } @@ -749,7 +691,7 @@ mod recursion { } fn selectors(config: &Self::Config) -> Vec { - config.range.gate.basic_gates[0].iter().map(|gate| gate.q_enable).collect() + config.base.gate().basic_gates[0].iter().map(|gate| gate.q_enable).collect() } } @@ -805,20 +747,21 @@ mod recursion { } fn main() { - let app_params = gen_srs(3); + let app_params = gen_srs(5); let recursion_config: AggregationConfigParams = serde_json::from_reader(fs::File::open("configs/example_recursion.json").unwrap()).unwrap(); let k = recursion_config.degree; let recursion_params = gen_srs(k); - let flex_gate_config = FlexGateConfigParams { - strategy: GateStrategy::Vertical, - k: k as usize, - num_advice_per_phase: vec![recursion_config.num_advice], - num_lookup_advice_per_phase: vec![recursion_config.num_lookup_advice], - num_fixed: recursion_config.num_fixed, - }; - set_var("FLEX_GATE_CONFIG_PARAMS", serde_json::to_string(&flex_gate_config).unwrap()); - set_var("LOOKUP_BITS", recursion_config.lookup_bits.to_string()); + BASE_CONFIG_PARAMS.with(|params| { + *params.borrow_mut() = BaseConfigParams { + strategy: GateStrategy::Vertical, + k: k as usize, + num_advice_per_phase: vec![recursion_config.num_advice], + num_lookup_advice_per_phase: vec![recursion_config.num_lookup_advice], + num_fixed: recursion_config.num_fixed, + lookup_bits: Some(recursion_config.lookup_bits), + } + }); let app_pk = gen_pk(&app_params, &application::Square::default()); diff --git a/snark-verifier/src/loader/evm/code.rs b/snark-verifier/src/loader/evm/code.rs index 2fec71d2..236684d6 100644 --- a/snark-verifier/src/loader/evm/code.rs +++ b/snark-verifier/src/loader/evm/code.rs @@ -13,9 +13,7 @@ pub struct YulCode { impl YulCode { pub fn new() -> Self { - YulCode { - runtime: String::new(), - } + YulCode { runtime: String::new() } } pub fn code(&self, base_modulus: String, scalar_modulus: String) -> String { From cbf7219cbac17dc0c2d661be26484897935da425 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Thu, 20 Jul 2023 21:47:01 -0400 Subject: [PATCH 43/73] chore: fix dependencies --- snark-verifier-sdk/Cargo.toml | 2 +- snark-verifier/Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 896dbccf..986f30eb 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -17,7 +17,7 @@ serde_json = "1.0" serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "feat/test_suite", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } # loader_evm diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index bf8b7fd5..313fd038 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -14,7 +14,7 @@ rand = "0.8" serde = { version = "1.0", features = ["derive"] } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "feat/test_suite", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } # This is Scroll's audited poseidon circuit. We only use it for the Native Poseidon spec. We do not use the halo2 circuit at all (and it wouldn't even work because the halo2_proofs tag is not compatbile). poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git", rev = "50015b7" } @@ -29,7 +29,7 @@ rlp = { version = "0.5.2", default-features = false, features = ["std"], optiona revm = { version = "2.3.1", optional = true } # loader_halo2 -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "feat/test_suite", default-features = false, optional = true } +halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false, optional = true } [dev-dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } From 4aba23a69feb7bd0b8ded5d5aca112d07876519a Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Thu, 27 Jul 2023 09:55:22 -0700 Subject: [PATCH 44/73] Feat/read pk buffer capacity (#24) * feat: change default `read_pk` buffer capacity to 1MB * feat: add bench for read_pk --- snark-verifier-sdk/Cargo.toml | 5 + snark-verifier-sdk/benches/read_pk.rs | 216 ++++++++++++++++++++++++++ snark-verifier-sdk/src/lib.rs | 17 +- 3 files changed, 234 insertions(+), 4 deletions(-) create mode 100644 snark-verifier-sdk/benches/read_pk.rs diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 986f30eb..e85f614f 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -69,3 +69,8 @@ harness = false name = "zkevm_plus_state" required-features = ["loader_halo2", "loader_evm", "zkevm", "halo2-pse"] harness = false + +[[bench]] +name = "read_pk" +required-features = ["loader_halo2"] +harness = false \ No newline at end of file diff --git a/snark-verifier-sdk/benches/read_pk.rs b/snark-verifier-sdk/benches/read_pk.rs new file mode 100644 index 00000000..02d25ec6 --- /dev/null +++ b/snark-verifier-sdk/benches/read_pk.rs @@ -0,0 +1,216 @@ +use ark_std::{end_timer, start_timer}; +use criterion::Criterion; +use criterion::{criterion_group, criterion_main}; +use halo2_base::gates::builder::BASE_CONFIG_PARAMS; +use halo2_base::halo2_proofs; +use halo2_base::utils::fs::gen_srs; +use halo2_proofs::halo2curves as halo2_curves; +use halo2_proofs::{halo2curves::bn256::Bn256, poly::kzg::commitment::ParamsKZG}; +use pprof::criterion::{Output, PProfProfiler}; +use rand::rngs::OsRng; + +use snark_verifier_sdk::halo2::aggregation::AggregationConfigParams; +use snark_verifier_sdk::{ + gen_pk, + halo2::{aggregation::AggregationCircuit, gen_snark_shplonk}, + Snark, +}; +use snark_verifier_sdk::{read_pk_with_capacity, SHPLONK}; +use std::path::Path; + +mod application { + use super::halo2_curves::bn256::Fr; + use super::halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance}, + poly::Rotation, + }; + use rand::RngCore; + use snark_verifier_sdk::CircuitExt; + + #[derive(Clone, Copy)] + pub struct StandardPlonkConfig { + a: Column, + b: Column, + c: Column, + q_a: Column, + q_b: Column, + q_c: Column, + q_ab: Column, + constant: Column, + #[allow(dead_code)] + instance: Column, + } + + impl StandardPlonkConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { + let [a, b, c] = [(); 3].map(|_| meta.advice_column()); + let [q_a, q_b, q_c, q_ab, constant] = [(); 5].map(|_| meta.fixed_column()); + let instance = meta.instance_column(); + + [a, b, c].map(|column| meta.enable_equality(column)); + + meta.create_gate( + "q_a·a + q_b·b + q_c·c + q_ab·a·b + constant + instance = 0", + |meta| { + let [a, b, c] = + [a, b, c].map(|column| meta.query_advice(column, Rotation::cur())); + let [q_a, q_b, q_c, q_ab, constant] = [q_a, q_b, q_c, q_ab, constant] + .map(|column| meta.query_fixed(column, Rotation::cur())); + let instance = meta.query_instance(instance, Rotation::cur()); + Some( + q_a * a.clone() + + q_b * b.clone() + + q_c * c + + q_ab * a * b + + constant + + instance, + ) + }, + ); + + StandardPlonkConfig { a, b, c, q_a, q_b, q_c, q_ab, constant, instance } + } + } + + #[derive(Clone, Default)] + pub struct StandardPlonk(Fr); + + impl StandardPlonk { + pub fn rand(mut rng: R) -> Self { + Self(Fr::from(rng.next_u32() as u64)) + } + } + + impl CircuitExt for StandardPlonk { + fn num_instance(&self) -> Vec { + vec![1] + } + + fn instances(&self) -> Vec> { + vec![vec![self.0]] + } + } + + impl Circuit for StandardPlonk { + type Config = StandardPlonkConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + meta.set_minimum_degree(4); + StandardPlonkConfig::configure(meta) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + layouter.assign_region( + || "", + |mut region| { + #[cfg(feature = "halo2-pse")] + { + region.assign_advice(|| "", config.a, 0, || Value::known(self.0))?; + region.assign_fixed(|| "", config.q_a, 0, || Value::known(-Fr::one()))?; + region.assign_advice( + || "", + config.a, + 1, + || Value::known(-Fr::from(5u64)), + )?; + for (idx, column) in (1..).zip([ + config.q_a, + config.q_b, + config.q_c, + config.q_ab, + config.constant, + ]) { + region.assign_fixed( + || "", + column, + 1, + || Value::known(Fr::from(idx as u64)), + )?; + } + let a = + region.assign_advice(|| "", config.a, 2, || Value::known(Fr::one()))?; + a.copy_advice(|| "", &mut region, config.b, 3)?; + a.copy_advice(|| "", &mut region, config.c, 4)?; + } + #[cfg(feature = "halo2-axiom")] + { + region.assign_advice(config.a, 0, Value::known(self.0)); + region.assign_fixed(config.q_a, 0, -Fr::one()); + region.assign_advice(config.a, 1, Value::known(-Fr::from(5u64))); + for (idx, column) in (1..).zip([ + config.q_a, + config.q_b, + config.q_c, + config.q_ab, + config.constant, + ]) { + region.assign_fixed(column, 1, Fr::from(idx as u64)); + } + + let a = region.assign_advice(config.a, 2, Value::known(Fr::one())); + a.copy_advice(&mut region, config.b, 3); + a.copy_advice(&mut region, config.c, 4); + } + + Ok(()) + }, + ) + } + } +} + +fn gen_application_snark(params: &ParamsKZG) -> Snark { + let circuit = application::StandardPlonk::rand(OsRng); + + let pk = gen_pk(params, &circuit, Some(Path::new("examples/app.pk"))); + gen_snark_shplonk(params, &pk, circuit, Some(Path::new("examples/app.snark"))) +} + +fn bench(c: &mut Criterion) { + let path = "./configs/example_evm_accumulator.json"; + let params_app = gen_srs(8); + + let snarks = [(); 3].map(|_| gen_application_snark(¶ms_app)); + let agg_config = AggregationConfigParams::from_path(path); + BASE_CONFIG_PARAMS.with(|params| *params.borrow_mut() = agg_config.into()); + let params = gen_srs(agg_config.degree); + + let agg_circuit = AggregationCircuit::keygen::(¶ms, snarks); + + let start0 = start_timer!(|| "gen vk & pk"); + gen_pk(¶ms, &agg_circuit, Some(Path::new("examples/agg.pk"))); + end_timer!(start0); + + let mut group = c.benchmark_group("read-pk"); + group.sample_size(10); + group.bench_with_input("1mb", &(1024 * 1024), |b, &c| { + b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk")) + }); + group.bench_with_input("10mb", &(10 * 1024 * 1024), |b, &c| { + b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk")) + }); + group.bench_with_input("100mb", &(100 * 1024 * 1024), |b, &c| { + b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk")) + }); + group.bench_with_input("1gb", &(1024 * 1024 * 1024), |b, &c| { + b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk")) + }); + group.finish(); +} + +criterion_group! { + name = benches; + config = Criterion::default().with_profiler(PProfProfiler::new(10, Output::Flamegraph(None))); + targets = bench +} +criterion_main!(benches); diff --git a/snark-verifier-sdk/src/lib.rs b/snark-verifier-sdk/src/lib.rs index 9a5833d6..07a15bc7 100644 --- a/snark-verifier-sdk/src/lib.rs +++ b/snark-verifier-sdk/src/lib.rs @@ -33,6 +33,8 @@ pub mod halo2; pub const LIMBS: usize = 3; pub const BITS: usize = 88; +const BUFFER_SIZE: usize = 1024 * 1024; // 1MB + /// AS stands for accumulation scheme. /// AS can be either `Kzg` (the original PLONK KZG multi-open) or `Kzg` (SHPLONK) pub type PlonkVerifier = verifier::plonk::PlonkVerifier>; @@ -77,12 +79,19 @@ pub trait CircuitExt: Circuit { } pub fn read_pk>(path: &Path) -> io::Result> { - let f = File::open(path)?; + read_pk_with_capacity::(BUFFER_SIZE, path) +} + +pub fn read_pk_with_capacity>( + capacity: usize, + path: impl AsRef, +) -> io::Result> { + let f = File::open(path.as_ref())?; #[cfg(feature = "display")] - let read_time = start_timer!(|| format!("Reading pkey from {path:?}")); + let read_time = start_timer!(|| format!("Reading pkey from {:?}", path.as_ref())); // BufReader is indeed MUCH faster than Read - let mut bufreader = BufReader::new(f); + let mut bufreader = BufReader::with_capacity(capacity, f); // But it's even faster to load the whole file into memory first and then process, // HOWEVER this requires twice as much memory to initialize // let initial_buffer_size = f.metadata().map(|m| m.len() as usize + 1).unwrap_or(0); @@ -121,7 +130,7 @@ pub fn gen_pk>( let write_time = start_timer!(|| format!("Writing pkey to {path:?}")); path.parent().and_then(|dir| fs::create_dir_all(dir).ok()).unwrap(); - let mut f = BufWriter::new(File::create(path).unwrap()); + let mut f = BufWriter::with_capacity(BUFFER_SIZE, File::create(path).unwrap()); pk.write(&mut f, SerdeFormat::RawBytesUnchecked).unwrap(); #[cfg(feature = "display")] From 4eded17c17eec17626e32af00e4524127c4c79be Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Tue, 15 Aug 2023 15:57:26 -0600 Subject: [PATCH 45/73] [Update] use ff v0.13 (#28) * feat(snark-verifier): update to ff v0.13 * feat(snark-verifier): update examples * feat(snark-verifier-sdk): update to ff v0.13 * fix: conversion from BaseConfigParams to AggregationConfigParams * chore: pin poseidon rev * refactor(sdk): add `AggregationCtxBuilder` for aggregation Contains the populated builder after aggregating, without creating the `AggregationCircuit`. Doesn't need config parameters and break points. * chore: update cargo --- Cargo.toml | 1 + rust-toolchain | 2 +- snark-verifier-sdk/Cargo.toml | 4 +- snark-verifier-sdk/benches/read_pk.rs | 29 +-- snark-verifier-sdk/benches/standard_plonk.rs | 16 +- snark-verifier-sdk/src/halo2/aggregation.rs | 172 ++++++++++-------- snark-verifier-sdk/src/lib.rs | 10 +- snark-verifier/Cargo.toml | 15 +- .../examples/evm-verifier-with-accumulator.rs | 79 ++++---- snark-verifier/examples/recursion.rs | 139 +++++++++----- snark-verifier/src/loader.rs | 24 +-- snark-verifier/src/loader/evm/loader.rs | 12 +- snark-verifier/src/loader/evm/test/tui.rs | 97 +++------- snark-verifier/src/loader/evm/util.rs | 2 +- .../src/loader/evm/util/executor.rs | 98 ++-------- snark-verifier/src/loader/halo2/loader.rs | 18 +- snark-verifier/src/loader/halo2/shim.rs | 35 ++-- snark-verifier/src/pcs/ipa.rs | 2 +- snark-verifier/src/pcs/ipa/accumulation.rs | 4 +- snark-verifier/src/pcs/ipa/decider.rs | 2 +- snark-verifier/src/pcs/ipa/multiopen/bgh19.rs | 12 +- snark-verifier/src/pcs/kzg.rs | 2 +- snark-verifier/src/pcs/kzg/accumulation.rs | 4 +- snark-verifier/src/pcs/kzg/accumulator.rs | 9 +- snark-verifier/src/pcs/kzg/decider.rs | 19 +- .../src/pcs/kzg/multiopen/bdfg21.rs | 152 ++++++---------- snark-verifier/src/pcs/kzg/multiopen/gwc19.rs | 25 +-- snark-verifier/src/system/halo2.rs | 14 +- snark-verifier/src/system/halo2/transcript.rs | 23 ++- .../src/system/halo2/transcript/halo2.rs | 20 +- snark-verifier/src/util/arithmetic.rs | 27 +-- snark-verifier/src/util/hash/poseidon.rs | 82 +++++---- .../src/util/hash/poseidon/tests.rs | 4 +- snark-verifier/src/util/msm.rs | 2 +- snark-verifier/src/util/poly.rs | 12 +- snark-verifier/src/verifier/plonk/proof.rs | 2 +- snark-verifier/src/verifier/plonk/protocol.rs | 4 +- 37 files changed, 587 insertions(+), 587 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 552212b3..53c98f1a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "snark-verifier", "snark-verifier-sdk", ] +resolver = "2" [profile.dev] opt-level = 3 diff --git a/rust-toolchain b/rust-toolchain index 51ab4759..ee2d639b 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2022-10-28 \ No newline at end of file +nightly-2023-08-12 \ No newline at end of file diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index e85f614f..adf30bec 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier-sdk" -version = "0.1.1" +version = "0.1.2" edition = "2021" [dependencies] @@ -53,7 +53,7 @@ parallel = ["snark-verifier/parallel"] halo2-pse = ["snark-verifier/halo2-pse", "dep:serde_with"] halo2-axiom = ["snark-verifier/halo2-axiom"] -zkevm = ["dep:zkevm-circuits", "dep:bus-mapping", "dep:mock", "dep:eth-types"] +# zkevm = ["dep:zkevm-circuits", "dep:bus-mapping", "dep:mock", "dep:eth-types"] [[bench]] name = "standard_plonk" diff --git a/snark-verifier-sdk/benches/read_pk.rs b/snark-verifier-sdk/benches/read_pk.rs index 02d25ec6..55154a2e 100644 --- a/snark-verifier-sdk/benches/read_pk.rs +++ b/snark-verifier-sdk/benches/read_pk.rs @@ -1,7 +1,7 @@ use ark_std::{end_timer, start_timer}; use criterion::Criterion; use criterion::{criterion_group, criterion_main}; -use halo2_base::gates::builder::BASE_CONFIG_PARAMS; +use halo2_base::gates::builder::CircuitBuilderStage; use halo2_base::halo2_proofs; use halo2_base::utils::fs::gen_srs; use halo2_proofs::halo2curves as halo2_curves; @@ -182,30 +182,37 @@ fn bench(c: &mut Criterion) { let snarks = [(); 3].map(|_| gen_application_snark(¶ms_app)); let agg_config = AggregationConfigParams::from_path(path); - BASE_CONFIG_PARAMS.with(|params| *params.borrow_mut() = agg_config.into()); let params = gen_srs(agg_config.degree); - let agg_circuit = AggregationCircuit::keygen::(¶ms, snarks); + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Keygen, + agg_config, + None, + ¶ms, + snarks, + ); + std::fs::remove_file("examples/agg.pk").ok(); let start0 = start_timer!(|| "gen vk & pk"); gen_pk(¶ms, &agg_circuit, Some(Path::new("examples/agg.pk"))); end_timer!(start0); let mut group = c.benchmark_group("read-pk"); group.sample_size(10); - group.bench_with_input("1mb", &(1024 * 1024), |b, &c| { - b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk")) + group.bench_with_input("buffer 1mb capacity", &(1024 * 1024), |b, &c| { + b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk", agg_config)) }); - group.bench_with_input("10mb", &(10 * 1024 * 1024), |b, &c| { - b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk")) + group.bench_with_input("buffer 10mb capacity", &(10 * 1024 * 1024), |b, &c| { + b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk", agg_config)) }); - group.bench_with_input("100mb", &(100 * 1024 * 1024), |b, &c| { - b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk")) + group.bench_with_input("buffer 100mb capacity", &(100 * 1024 * 1024), |b, &c| { + b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk", agg_config)) }); - group.bench_with_input("1gb", &(1024 * 1024 * 1024), |b, &c| { - b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk")) + group.bench_with_input("buffer 1gb capacity", &(1024 * 1024 * 1024), |b, &c| { + b.iter(|| read_pk_with_capacity::(c, "examples/agg.pk", agg_config)) }); group.finish(); + std::fs::remove_file("examples/agg.pk").unwrap(); } criterion_group! { diff --git a/snark-verifier-sdk/benches/standard_plonk.rs b/snark-verifier-sdk/benches/standard_plonk.rs index f696f822..eecb7140 100644 --- a/snark-verifier-sdk/benches/standard_plonk.rs +++ b/snark-verifier-sdk/benches/standard_plonk.rs @@ -1,7 +1,7 @@ use ark_std::{end_timer, start_timer}; use criterion::{criterion_group, criterion_main}; use criterion::{BenchmarkId, Criterion}; -use halo2_base::gates::builder::{CircuitBuilderStage, BASE_CONFIG_PARAMS}; +use halo2_base::gates::builder::CircuitBuilderStage; use halo2_base::halo2_proofs; use halo2_base::utils::fs::gen_srs; use halo2_proofs::halo2curves as halo2_curves; @@ -185,11 +185,15 @@ fn bench(c: &mut Criterion) { let snarks = [(); 3].map(|_| gen_application_snark(¶ms_app)); let agg_config = AggregationConfigParams::from_path(path); - BASE_CONFIG_PARAMS.with(|params| *params.borrow_mut() = agg_config.into()); let params = gen_srs(agg_config.degree); - let lookup_bits = params.k() as usize - 1; - let agg_circuit = AggregationCircuit::keygen::(¶ms, snarks.clone()); + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Keygen, + agg_config, + None, + ¶ms, + snarks.clone(), + ); let start0 = start_timer!(|| "gen vk & pk"); let pk = gen_pk(¶ms, &agg_circuit, Some(Path::new("agg.pk"))); @@ -205,8 +209,8 @@ fn bench(c: &mut Criterion) { b.iter(|| { let agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Prover, + agg_config, Some(break_points.clone()), - lookup_bits, params, snarks.clone(), ); @@ -222,8 +226,8 @@ fn bench(c: &mut Criterion) { // do one more time to verify let agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Prover, + agg_config, Some(break_points), - lookup_bits, ¶ms, snarks.clone(), ); diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 9f9ac64a..2d093f7b 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -4,8 +4,7 @@ use halo2_base::{ gates::{ builder::{ BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, - PublicBaseConfig, RangeCircuitBuilder, RangeWithInstanceCircuitBuilder, - BASE_CONFIG_PARAMS, + PublicBaseConfig, RangeWithInstanceCircuitBuilder, }, flex_gate::GateStrategy, RangeChip, @@ -14,10 +13,7 @@ use halo2_base::{ circuit::{Layouter, SimpleFloorPlanner}, halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::{self, Circuit, ConstraintSystem, Selector}, - poly::{ - commitment::{Params, ParamsProver}, - kzg::commitment::ParamsKZG, - }, + poly::{commitment::ParamsProver, kzg::commitment::ParamsKZG}, }, utils::ScalarField, AssignedValue, @@ -139,7 +135,7 @@ where /// Same as `FlexGateConfigParams` except we assume a single Phase and default 'Vertical' strategy. /// Also adds `lookup_bits` field. -#[derive(Clone, Copy, Debug, Serialize, Deserialize)] +#[derive(Clone, Copy, Default, Debug, Serialize, Deserialize)] pub struct AggregationConfigParams { pub degree: u32, pub num_advice: usize, @@ -168,6 +164,40 @@ impl From for BaseConfigParams { } } +impl TryFrom<&BaseConfigParams> for AggregationConfigParams { + type Error = &'static str; + + fn try_from(params: &BaseConfigParams) -> Result { + if params.num_advice_per_phase.iter().skip(1).any(|&n| n != 0) { + return Err("AggregationConfigParams only supports 1 phase"); + } + if params.num_lookup_advice_per_phase.iter().skip(1).any(|&n| n != 0) { + return Err("AggregationConfigParams only supports 1 phase"); + } + if params.lookup_bits.is_none() { + return Err("AggregationConfigParams requires lookup_bits"); + } + Ok(Self { + degree: params.k as u32, + num_advice: params.num_advice_per_phase[0], + num_lookup_advice: params.num_lookup_advice_per_phase[0], + num_fixed: params.num_fixed, + lookup_bits: params.lookup_bits.unwrap(), + }) + } +} + +/// Holds virtual contexts for the cells used to verify a collection of snarks +#[derive(Clone, Debug)] +pub struct AggregationCtxBuilder { + /// Virtual region with virtual contexts (columns) + pub builder: GateThreadBuilder, + /// The limbs of the pair of elliptic curve points that need to be verified in a final pairing check. + pub accumulator: Vec>, + // the public instances from previous snarks that were aggregated + pub previous_instances: Vec>>, +} + #[derive(Clone, Debug)] pub struct AggregationCircuit { pub inner: RangeWithInstanceCircuitBuilder, @@ -175,7 +205,7 @@ pub struct AggregationCircuit { // the user can optionally append these to `inner.assigned_instances` to expose them pub previous_instances: Vec>>, // accumulation scheme proof, private input - pub as_proof: Vec, // not sure this needs to be stored, keeping for now + // pub as_proof: Vec, } // trait just so we can have a generic that is either SHPLONK or GWC @@ -201,17 +231,15 @@ pub trait Halo2KzgAccumulationScheme<'a> = PolynomialCommitmentScheme< VerifyingKey = KzgAsVerifyingKey, > + AccumulationSchemeProver>; -impl AggregationCircuit { - /// Given snarks, this creates a circuit and runs the `GateThreadBuilder` to verify all the snarks. - /// By default, the returned circuit has public instances equal to the limbs of the pair of elliptic curve points, referred to as the `accumulator`, that need to be verified in a final pairing check. +impl AggregationCtxBuilder { + /// Given snarks, this runs the `GateThreadBuilder` to verify all the snarks. /// - /// The user can optionally modify the circuit after calling this function to add more instances to `assigned_instances` to expose. + /// Also returns the limbs of the pair of elliptic curve points, referred to as the `accumulator`, that need to be verified in a final pairing check. /// /// Warning: will fail silently if `snarks` were created using a different multi-open scheme than `AS` /// where `AS` can be either [`crate::SHPLONK`] or [`crate::GWC`] (for original PLONK multi-open scheme) pub fn new( - stage: CircuitBuilderStage, - break_points: Option, + witness_gen_only: bool, lookup_bits: usize, params: &ParamsKZG, snarks: impl IntoIterator, @@ -254,11 +282,7 @@ impl AggregationCircuit { }; // create thread builder and run aggregation witness gen - let builder = match stage { - CircuitBuilderStage::Mock => GateThreadBuilder::mock(), - CircuitBuilderStage::Prover => GateThreadBuilder::prover(), - CircuitBuilderStage::Keygen => GateThreadBuilder::keygen(), - }; + let builder = GateThreadBuilder::new(witness_gen_only); // create halo2loader let range = RangeChip::::default(lookup_bits); let fp_chip = FpChip::::new(&range, BITS, LIMBS); @@ -269,7 +293,7 @@ impl AggregationCircuit { aggregate::(&svk, &loader, &snarks, as_proof.as_slice()); let lhs = accumulator.lhs.assigned(); let rhs = accumulator.rhs.assigned(); - let assigned_instances = lhs + let accumulator = lhs .x() .limbs() .iter() @@ -284,73 +308,65 @@ impl AggregationCircuit { let KzgAccumulator { lhs, rhs } = _accumulator; let instances = [lhs.x, lhs.y, rhs.x, rhs.y].map(fe_to_limbs::<_, Fr, LIMBS, BITS>).concat(); - for (lhs, rhs) in instances.iter().zip(assigned_instances.iter()) { + for (lhs, rhs) in instances.iter().zip(accumulator.iter()) { assert_eq!(lhs, rhs.value()); } } let builder = loader.take_ctx(); - let circuit = match stage { - CircuitBuilderStage::Mock => RangeCircuitBuilder::mock(builder), - CircuitBuilderStage::Keygen => RangeCircuitBuilder::keygen(builder), - CircuitBuilderStage::Prover => { - RangeCircuitBuilder::prover(builder, break_points.unwrap()) - } - }; - let inner = RangeWithInstanceCircuitBuilder::new(circuit, assigned_instances); - Self { inner, previous_instances, as_proof } + Self { builder, accumulator, previous_instances } } +} - pub fn public( +impl AggregationCircuit { + /// Given snarks, this creates a circuit and runs the `GateThreadBuilder` to verify all the snarks. + /// By default, the returned circuit has public instances equal to the limbs of the pair of elliptic curve points, referred to as the `accumulator`, that need to be verified in a final pairing check. + /// + /// The user can optionally modify the circuit after calling this function to add more instances to `assigned_instances` to expose. + /// + /// Warning: will fail silently if `snarks` were created using a different multi-open scheme than `AS` + /// where `AS` can be either [`crate::SHPLONK`] or [`crate::GWC`] (for original PLONK multi-open scheme) + pub fn new( stage: CircuitBuilderStage, + agg_config: AggregationConfigParams, break_points: Option, - lookup_bits: usize, params: &ParamsKZG, snarks: impl IntoIterator, - has_prev_accumulator: bool, ) -> Self where AS: for<'a> Halo2KzgAccumulationScheme<'a>, { - let mut private = Self::new::(stage, break_points, lookup_bits, params, snarks); - private.expose_previous_instances(has_prev_accumulator); - private - } - - // this function is for convenience - /// `params` should be the universal trusted setup to be used for the aggregation circuit, not the one used to generate the previous snarks, although we assume both use the same generator g[0] - pub fn keygen(params: &ParamsKZG, snarks: impl IntoIterator) -> Self - where - AS: for<'a> Halo2KzgAccumulationScheme<'a>, - { - let lookup_bits = BASE_CONFIG_PARAMS - .with(|conf| conf.borrow().lookup_bits) - .unwrap_or(params.k() as usize - 1); - let circuit = - Self::new::(CircuitBuilderStage::Keygen, None, lookup_bits, params, snarks); - circuit.config(params.k(), Some(10)); - circuit + let AggregationCtxBuilder { builder, accumulator, previous_instances } = + AggregationCtxBuilder::new::( + stage == CircuitBuilderStage::Prover, + agg_config.lookup_bits, + params, + snarks, + ); + let inner = RangeWithInstanceCircuitBuilder::from_stage( + stage, + builder, + agg_config.into(), + break_points, + accumulator, + ); + Self { inner, previous_instances } } - // this function is for convenience - pub fn prover( + pub fn public( + stage: CircuitBuilderStage, + agg_config: AggregationConfigParams, + break_points: Option, params: &ParamsKZG, snarks: impl IntoIterator, - break_points: MultiPhaseThreadBreakPoints, + has_prev_accumulator: bool, ) -> Self where AS: for<'a> Halo2KzgAccumulationScheme<'a>, { - let lookup_bits = BASE_CONFIG_PARAMS - .with(|conf| conf.borrow().lookup_bits) - .unwrap_or(params.k() as usize - 1); - Self::new::( - CircuitBuilderStage::Prover, - Some(break_points), - lookup_bits, - params, - snarks, - ) + let mut private = Self::new::(stage, agg_config, break_points, params, snarks); + private.expose_previous_instances(has_prev_accumulator); + private } /// Re-expose the previous public instances of aggregated snarks again. @@ -363,12 +379,12 @@ impl AggregationCircuit { } } - pub fn as_proof(&self) -> &[u8] { - &self.as_proof[..] - } - - pub fn config(&self, k: u32, minimum_rows: Option) -> BaseConfigParams { - self.inner.config(k, minimum_rows) + /// Auto-configure the circuit and change the circuit's internal configuration parameters. + pub fn config(&mut self, k: u32, minimum_rows: Option) -> BaseConfigParams { + let mut new_config = self.inner.circuit.0.builder.borrow().config(k as usize, minimum_rows); + new_config.lookup_bits = self.inner.circuit.0.config_params.lookup_bits; + self.inner.circuit.0.config_params = new_config.clone(); + new_config } pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { @@ -401,13 +417,25 @@ impl CircuitExt for RangeWithInstanceCircuitBuilder { impl Circuit for AggregationCircuit { type Config = PublicBaseConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = AggregationConfigParams; + + fn params(&self) -> Self::Params { + (&self.inner.circuit.0.config_params).try_into().unwrap() + } fn without_witnesses(&self) -> Self { unimplemented!() } - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - RangeWithInstanceCircuitBuilder::configure(meta) + fn configure_with_params( + meta: &mut ConstraintSystem, + params: Self::Params, + ) -> Self::Config { + RangeWithInstanceCircuitBuilder::configure_with_params(meta, params.into()) + } + + fn configure(_: &mut ConstraintSystem) -> Self::Config { + unreachable!() } fn synthesize( diff --git a/snark-verifier-sdk/src/lib.rs b/snark-verifier-sdk/src/lib.rs index 07a15bc7..40401a4c 100644 --- a/snark-verifier-sdk/src/lib.rs +++ b/snark-verifier-sdk/src/lib.rs @@ -78,13 +78,14 @@ pub trait CircuitExt: Circuit { } } -pub fn read_pk>(path: &Path) -> io::Result> { - read_pk_with_capacity::(BUFFER_SIZE, path) +pub fn read_pk>(path: &Path, params: C::Params) -> io::Result> { + read_pk_with_capacity::(BUFFER_SIZE, path, params) } pub fn read_pk_with_capacity>( capacity: usize, path: impl AsRef, + params: C::Params, ) -> io::Result> { let f = File::open(path.as_ref())?; #[cfg(feature = "display")] @@ -97,7 +98,8 @@ pub fn read_pk_with_capacity>( // let initial_buffer_size = f.metadata().map(|m| m.len() as usize + 1).unwrap_or(0); // let mut bufreader = Vec::with_capacity(initial_buffer_size); // f.read_to_end(&mut bufreader)?; - let pk = ProvingKey::read::<_, C>(&mut bufreader, SerdeFormat::RawBytesUnchecked).unwrap(); + let pk = + ProvingKey::read::<_, C>(&mut bufreader, SerdeFormat::RawBytesUnchecked, params).unwrap(); #[cfg(feature = "display")] end_timer!(read_time); @@ -112,7 +114,7 @@ pub fn gen_pk>( path: Option<&Path>, ) -> ProvingKey { if let Some(path) = path { - if let Ok(pk) = read_pk::(path) { + if let Ok(pk) = read_pk::(path, circuit.params()) { return pk; } } diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 313fd038..5606df37 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -1,25 +1,28 @@ [package] name = "snark-verifier" -version = "0.1.1" +version = "0.1.2" edition = "2021" [dependencies] -itertools = "0.10.5" -lazy_static = "1.4.0" -num-bigint = "0.4.3" +itertools = "0.11" +lazy_static = "1.4" +num-bigint = "0.4" num-integer = "0.1.45" num-traits = "0.2.15" hex = "0.4" rand = "0.8" serde = { version = "1.0", features = ["derive"] } +pairing = { version = "0.23" } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } # This is Scroll's audited poseidon circuit. We only use it for the Native Poseidon spec. We do not use the halo2 circuit at all (and it wouldn't even work because the halo2_proofs tag is not compatbile). -poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git", rev = "50015b7" } +# We forked it to upgrade to ff v0.13 and removed the circuit module +poseidon-rs = { git = "https://github.com/axiom-crypto/poseidon-circuit.git", rev = "1aee4a1" } +# poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git", rev = "50015b7" } # parallel -rayon = { version = "1.7.0", optional = true } +rayon = { version = "1.7", optional = true } # loader_evm sha3 = { version = "0.10.8", optional = true } diff --git a/snark-verifier/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs index 4ffa6459..41493efa 100644 --- a/snark-verifier/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -1,6 +1,6 @@ use aggregation::{AggregationCircuit, AggregationConfigParams}; use halo2_base::{ - gates::builder::{set_lookup_bits, CircuitBuilderStage}, + gates::builder::{BaseConfigParams, CircuitBuilderStage}, halo2_proofs, utils::fs::gen_srs, }; @@ -300,7 +300,7 @@ mod aggregation { As::verify(&Default::default(), &accumulators, &proof).unwrap() } - #[derive(serde::Serialize, serde::Deserialize)] + #[derive(serde::Serialize, serde::Deserialize, Default)] pub struct AggregationConfigParams { pub degree: u32, pub num_advice: usize, @@ -318,8 +318,8 @@ mod aggregation { impl AggregationCircuit { pub fn new( stage: CircuitBuilderStage, + config_params: BaseConfigParams, break_points: Option, - lookup_bits: usize, params_g0: G1Affine, snarks: impl IntoIterator, ) -> Self { @@ -355,13 +355,9 @@ mod aggregation { }; // create thread builder and run aggregation witness gen - let builder = match stage { - CircuitBuilderStage::Mock => GateThreadBuilder::mock(), - CircuitBuilderStage::Prover => GateThreadBuilder::prover(), - CircuitBuilderStage::Keygen => GateThreadBuilder::keygen(), - }; + let builder = GateThreadBuilder::from_stage(stage); // create halo2loader - let range = RangeChip::::default(lookup_bits); + let range = RangeChip::::default(config_params.lookup_bits.unwrap()); let fp_chip = FpChip::::new(&range, BITS, LIMBS); let ecc_chip = BaseFieldEccChip::new(&fp_chip); let loader = Halo2Loader::new(ecc_chip, builder); @@ -391,24 +387,25 @@ mod aggregation { } let builder = loader.take_ctx(); - let inner = match stage { - CircuitBuilderStage::Mock => { - RangeWithInstanceCircuitBuilder::mock(builder, assigned_instances) - } - CircuitBuilderStage::Keygen => { - RangeWithInstanceCircuitBuilder::keygen(builder, assigned_instances) - } - CircuitBuilderStage::Prover => RangeWithInstanceCircuitBuilder::prover( - builder, - assigned_instances, - break_points.unwrap(), - ), - }; + let inner = RangeWithInstanceCircuitBuilder::from_stage( + stage, + builder, + config_params, + break_points, + assigned_instances, + ); Self { inner, as_proof } } - pub fn config(&self, k: u32, minimum_rows: Option) -> BaseConfigParams { - self.inner.circuit.0.builder.borrow().config(k as usize, minimum_rows) + pub fn config( + &self, + k: u32, + minimum_rows: Option, + lookup_bits: usize, + ) -> BaseConfigParams { + let mut params = self.inner.circuit.0.builder.borrow().config(k as usize, minimum_rows); + params.lookup_bits = Some(lookup_bits); + params } pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { @@ -432,13 +429,25 @@ mod aggregation { impl Circuit for AggregationCircuit { type Config = PublicBaseConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = BaseConfigParams; + + fn params(&self) -> Self::Params { + self.inner.circuit.params() + } + + fn configure_with_params( + meta: &mut plonk::ConstraintSystem, + params: Self::Params, + ) -> Self::Config { + RangeWithInstanceCircuitBuilder::configure_with_params(meta, params) + } fn without_witnesses(&self) -> Self { unimplemented!() } - fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - RangeWithInstanceCircuitBuilder::configure(meta) + fn configure(_: &mut plonk::ConstraintSystem) -> Self::Config { + unimplemented!() } fn synthesize( @@ -574,15 +583,23 @@ fn main() { File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")), ) .unwrap(); - set_lookup_bits(agg_config.lookup_bits); - let agg_circuit = AggregationCircuit::new( + let mut config_params = BaseConfigParams { + k: agg_config.degree as usize, + strategy: Default::default(), + num_advice_per_phase: vec![agg_config.num_advice], + num_lookup_advice_per_phase: vec![agg_config.num_lookup_advice], + num_fixed: agg_config.num_fixed, + lookup_bits: Some(agg_config.lookup_bits), + }; + let mut agg_circuit = AggregationCircuit::new( CircuitBuilderStage::Mock, + config_params, None, - agg_config.lookup_bits, params_app.get_g()[0], snarks.clone(), ); - agg_circuit.config(agg_config.degree, Some(6)); + config_params = agg_circuit.config(agg_config.degree, Some(6), agg_config.lookup_bits); + agg_circuit.inner.circuit.0.config_params = config_params.clone(); #[cfg(debug_assertions)] { MockProver::run(agg_config.degree, &agg_circuit, agg_circuit.instances()) @@ -605,8 +622,8 @@ fn main() { let agg_circuit = AggregationCircuit::new( CircuitBuilderStage::Prover, + config_params, Some(break_points), - agg_config.lookup_bits, params_app.get_g()[0], snarks, ); diff --git a/snark-verifier/examples/recursion.rs b/snark-verifier/examples/recursion.rs index 7415e1ab..b469a51a 100644 --- a/snark-verifier/examples/recursion.rs +++ b/snark-verifier/examples/recursion.rs @@ -3,7 +3,7 @@ use ark_std::{end_timer, start_timer}; use common::*; use halo2_base::gates::builder::BaseConfigParams; -use halo2_base::gates::{builder::BASE_CONFIG_PARAMS, flex_gate::GateStrategy}; +use halo2_base::gates::flex_gate::GateStrategy; use halo2_base::halo2_proofs; use halo2_base::utils::fs::gen_srs; use halo2_proofs::{ @@ -12,11 +12,10 @@ use halo2_proofs::{ halo2curves::{ bn256::{Bn256, Fr, G1Affine}, group::ff::Field, - FieldExt, }, plonk::{ - self, create_proof, keygen_pk, keygen_vk, Circuit, ConstraintSystem, Error, ProvingKey, - Selector, VerifyingKey, + create_proof, keygen_pk, keygen_vk, Circuit, ConstraintSystem, Error, ProvingKey, Selector, + VerifyingKey, }, poly::{ commitment::ParamsProver, @@ -192,19 +191,38 @@ mod common { pub fn gen_dummy_snark>( params: &ParamsKZG, vk: Option<&VerifyingKey>, - ) -> Snark { - struct CsProxy(PhantomData<(F, C)>); + config_params: ConcreteCircuit::Params, + ) -> Snark + where + ConcreteCircuit::Params: Clone, + { + struct CsProxy>(C::Params, PhantomData<(F, C)>); - impl> Circuit for CsProxy { + impl> Circuit for CsProxy + where + C::Params: Clone, + { type Config = C::Config; type FloorPlanner = C::FloorPlanner; + type Params = C::Params; + + fn params(&self) -> Self::Params { + self.0.clone() + } fn without_witnesses(&self) -> Self { - CsProxy(PhantomData) + CsProxy(self.0.clone(), PhantomData) + } + + fn configure_with_params( + meta: &mut ConstraintSystem, + params: Self::Params, + ) -> Self::Config { + C::configure_with_params(meta, params) } - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - C::configure(meta) + fn configure(_: &mut ConstraintSystem) -> Self::Config { + unreachable!() } fn synthesize( @@ -227,9 +245,9 @@ mod common { } } - let dummy_vk = vk - .is_none() - .then(|| keygen_vk(params, &CsProxy::(PhantomData)).unwrap()); + let dummy_vk = vk.is_none().then(|| { + keygen_vk(params, &CsProxy::(config_params, PhantomData)).unwrap() + }); let protocol = compile( params, vk.or(dummy_vk.as_ref()).unwrap(), @@ -326,10 +344,7 @@ mod application { mod recursion { use halo2_base::{ gates::{ - builder::{ - GateThreadBuilder, PublicBaseConfig, RangeWithInstanceCircuitBuilder, - BASE_CONFIG_PARAMS, - }, + builder::{GateThreadBuilder, PublicBaseConfig, RangeWithInstanceCircuitBuilder}, GateInstructions, RangeChip, RangeInstructions, }, AssignedValue, @@ -456,6 +471,7 @@ mod recursion { round: usize, instances: Vec, as_proof: Vec, + lookup_bits: usize, inner: RangeWithInstanceCircuitBuilder, } @@ -473,6 +489,7 @@ mod recursion { initial_state: Fr, state: Fr, round: usize, + config_params: BaseConfigParams, ) -> Self { let svk = params.get_g()[0].into(); let default_accumulator = KzgAccumulator::new(params.get_g()[1], params.get_g()[0]); @@ -528,17 +545,25 @@ mod recursion { .collect(); let builder = GateThreadBuilder::mock(); - let inner = RangeWithInstanceCircuitBuilder::mock(builder, vec![]); - let mut circuit = - Self { svk, default_accumulator, app, previous, round, instances, as_proof, inner }; + let lookup_bits = config_params.lookup_bits.unwrap(); + let inner = RangeWithInstanceCircuitBuilder::mock(builder, config_params, vec![]); + let mut circuit = Self { + svk, + default_accumulator, + app, + previous, + round, + instances, + as_proof, + inner, + lookup_bits, + }; circuit.build(); circuit } fn build(&mut self) { - let lookup_bits = - BASE_CONFIG_PARAMS.with(|params| params.borrow().lookup_bits.unwrap()); - let range = RangeChip::::default(lookup_bits); + let range = RangeChip::::default(self.lookup_bits); let main_gate = range.gate(); let mut builder = GateThreadBuilder::mock(); let ctx = &mut builder; @@ -626,8 +651,12 @@ mod recursion { ); } - fn initial_snark(params: &ParamsKZG, vk: Option<&VerifyingKey>) -> Snark { - let mut snark = gen_dummy_snark::(params, vk); + fn initial_snark( + params: &ParamsKZG, + vk: Option<&VerifyingKey>, + config_params: BaseConfigParams, + ) -> Snark { + let mut snark = gen_dummy_snark::(params, vk, config_params); let g = params.get_g(); snark.instances = vec![[g[1].x, g[1].y, g[0].x, g[0].y] .into_iter() @@ -658,13 +687,25 @@ mod recursion { impl Circuit for RecursionCircuit { type Config = PublicBaseConfig; type FloorPlanner = SimpleFloorPlanner; + type Params = BaseConfigParams; + + fn params(&self) -> Self::Params { + self.inner.circuit.params() + } fn without_witnesses(&self) -> Self { unimplemented!() } - fn configure(meta: &mut plonk::ConstraintSystem) -> Self::Config { - RangeWithInstanceCircuitBuilder::configure(meta) + fn configure_with_params( + meta: &mut ConstraintSystem, + params: Self::Params, + ) -> Self::Config { + RangeWithInstanceCircuitBuilder::configure_with_params(meta, params) + } + + fn configure(_: &mut ConstraintSystem) -> Self::Config { + unreachable!() } fn synthesize( @@ -699,14 +740,20 @@ mod recursion { recursion_params: &ParamsKZG, app_params: &ParamsKZG, app_vk: &VerifyingKey, - ) -> ProvingKey { + recursion_config: BaseConfigParams, + app_config: ConcreteCircuit::Params, + ) -> ProvingKey + where + ConcreteCircuit::Params: Clone, + { let recursion = RecursionCircuit::new( recursion_params, - gen_dummy_snark::(app_params, Some(app_vk)), - RecursionCircuit::initial_snark(recursion_params, None), + gen_dummy_snark::(app_params, Some(app_vk), app_config), + RecursionCircuit::initial_snark(recursion_params, None, recursion_config.clone()), Fr::zero(), Fr::zero(), 0, + recursion_config, ); // we cannot auto-configure the circuit because dummy_snark must know the configuration beforehand // uncomment the following line only in development to test and print out the optimal configuration ahead of time @@ -721,11 +768,15 @@ mod recursion { recursion_pk: &ProvingKey, initial_state: Fr, inputs: Vec, + config_params: BaseConfigParams, ) -> (Fr, Snark) { let mut state = initial_state; let mut app = ConcreteCircuit::new(state); - let mut previous = - RecursionCircuit::initial_snark(recursion_params, Some(recursion_pk.get_vk())); + let mut previous = RecursionCircuit::initial_snark( + recursion_params, + Some(recursion_pk.get_vk()), + config_params.clone(), + ); for (round, input) in inputs.into_iter().enumerate() { state = app.state_transition(input); println!("Generate app snark"); @@ -737,6 +788,7 @@ mod recursion { initial_state, state, round, + config_params.clone(), ); println!("Generate recursion snark"); previous = gen_snark(recursion_params, recursion_pk, recursion); @@ -752,16 +804,14 @@ fn main() { serde_json::from_reader(fs::File::open("configs/example_recursion.json").unwrap()).unwrap(); let k = recursion_config.degree; let recursion_params = gen_srs(k); - BASE_CONFIG_PARAMS.with(|params| { - *params.borrow_mut() = BaseConfigParams { - strategy: GateStrategy::Vertical, - k: k as usize, - num_advice_per_phase: vec![recursion_config.num_advice], - num_lookup_advice_per_phase: vec![recursion_config.num_lookup_advice], - num_fixed: recursion_config.num_fixed, - lookup_bits: Some(recursion_config.lookup_bits), - } - }); + let config_params = BaseConfigParams { + strategy: GateStrategy::Vertical, + k: k as usize, + num_advice_per_phase: vec![recursion_config.num_advice], + num_lookup_advice_per_phase: vec![recursion_config.num_lookup_advice], + num_fixed: recursion_config.num_fixed, + lookup_bits: Some(recursion_config.lookup_bits), + }; let app_pk = gen_pk(&app_params, &application::Square::default()); @@ -770,6 +820,8 @@ fn main() { &recursion_params, &app_params, app_pk.get_vk(), + config_params.clone(), + (), ); end_timer!(pk_time); @@ -782,9 +834,10 @@ fn main() { &recursion_pk, Fr::from(2u64), vec![(); num_round], + config_params.clone(), ); end_timer!(pf_time); - assert_eq!(final_state, Fr::from(2u64).pow(&[1 << num_round, 0, 0, 0])); + assert_eq!(final_state, Fr::from(2u64).pow([1 << num_round])); { let dk = diff --git a/snark-verifier/src/loader.rs b/snark-verifier/src/loader.rs index 77a8f54b..a3637f08 100644 --- a/snark-verifier/src/loader.rs +++ b/snark-verifier/src/loader.rs @@ -122,12 +122,12 @@ pub trait ScalarLoader { /// Load `zero` as constant. fn load_zero(&self) -> Self::LoadedScalar { - self.load_const(&F::zero()) + self.load_const(&F::ZERO) } /// Load `one` as constant. fn load_one(&self) -> Self::LoadedScalar { - self.load_const(&F::one()) + self.load_const(&F::ONE) } /// Assert lhs and rhs field elements are equal. @@ -145,13 +145,13 @@ pub trait ScalarLoader { let loader = values.first().unwrap().1.loader(); iter::empty() - .chain(if constant == F::zero() { + .chain(if constant == F::ZERO { None } else { Some(Cow::Owned(loader.load_const(&constant))) }) .chain(values.iter().map(|&(coeff, value)| { - if coeff == F::one() { + if coeff == F::ONE { Cow::Borrowed(value) } else { Cow::Owned(loader.load_const(&coeff) * value) @@ -174,9 +174,9 @@ pub trait ScalarLoader { let loader = values.first().unwrap().1.loader(); iter::empty() - .chain(if constant == F::zero() { None } else { Some(loader.load_const(&constant)) }) + .chain(if constant == F::ZERO { None } else { Some(loader.load_const(&constant)) }) .chain(values.iter().map(|&(coeff, lhs, rhs)| { - if coeff == F::one() { + if coeff == F::ONE { lhs.clone() * rhs } else { loader.load_const(&coeff) * lhs * rhs @@ -188,20 +188,20 @@ pub trait ScalarLoader { /// Sum field elements with coefficients. fn sum_with_coeff(&self, values: &[(F, &Self::LoadedScalar)]) -> Self::LoadedScalar { - self.sum_with_coeff_and_const(values, F::zero()) + self.sum_with_coeff_and_const(values, F::ZERO) } /// Sum field elements and constant. fn sum_with_const(&self, values: &[&Self::LoadedScalar], constant: F) -> Self::LoadedScalar { self.sum_with_coeff_and_const( - &values.iter().map(|&value| (F::one(), value)).collect_vec(), + &values.iter().map(|&value| (F::ONE, value)).collect_vec(), constant, ) } /// Sum field elements. fn sum(&self, values: &[&Self::LoadedScalar]) -> Self::LoadedScalar { - self.sum_with_const(values, F::zero()) + self.sum_with_const(values, F::ZERO) } /// Sum product of field elements with coefficients. @@ -209,7 +209,7 @@ pub trait ScalarLoader { &self, values: &[(F, &Self::LoadedScalar, &Self::LoadedScalar)], ) -> Self::LoadedScalar { - self.sum_products_with_coeff_and_const(values, F::zero()) + self.sum_products_with_coeff_and_const(values, F::ZERO) } /// Sum product of field elements and constant. @@ -219,7 +219,7 @@ pub trait ScalarLoader { constant: F, ) -> Self::LoadedScalar { self.sum_products_with_coeff_and_const( - &values.iter().map(|&(lhs, rhs)| (F::one(), lhs, rhs)).collect_vec(), + &values.iter().map(|&(lhs, rhs)| (F::ONE, lhs, rhs)).collect_vec(), constant, ) } @@ -229,7 +229,7 @@ pub trait ScalarLoader { &self, values: &[(&Self::LoadedScalar, &Self::LoadedScalar)], ) -> Self::LoadedScalar { - self.sum_products_with_const(values, F::zero()) + self.sum_products_with_const(values, F::ZERO) } /// Product of field elements. diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index 98ca5ca4..bfb37c8c 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -684,8 +684,8 @@ impl> ScalarLoader for Rc { } let push_addend = |(coeff, value): &(F, &Scalar)| { - assert_ne!(*coeff, F::zero()); - match (*coeff == F::one(), &value.value) { + assert_ne!(*coeff, F::ZERO); + match (*coeff == F::ONE, &value.value) { (true, _) => self.push(value), (false, Value::Constant(value)) => self.push( &self.scalar(Value::Constant(fe_to_u256(*coeff * u256_to_fe::(*value)))), @@ -699,7 +699,7 @@ impl> ScalarLoader for Rc { }; let mut values = values.iter(); - let initial_value = if constant == F::zero() { + let initial_value = if constant == F::ZERO { push_addend(values.next().unwrap()) } else { self.push(&self.scalar(Value::Constant(fe_to_u256(constant)))) @@ -733,8 +733,8 @@ impl> ScalarLoader for Rc { } let push_addend = |(coeff, lhs, rhs): &(F, &Scalar, &Scalar)| { - assert_ne!(*coeff, F::zero()); - match (*coeff == F::one(), &lhs.value, &rhs.value) { + assert_ne!(*coeff, F::ZERO); + match (*coeff == F::ONE, &lhs.value, &rhs.value) { (_, Value::Constant(lhs), Value::Constant(rhs)) => { self.push(&self.scalar(Value::Constant(fe_to_u256( *coeff * u256_to_fe::(*lhs) * u256_to_fe::(*rhs), @@ -764,7 +764,7 @@ impl> ScalarLoader for Rc { }; let mut values = values.iter(); - let initial_value = if constant == F::zero() { + let initial_value = if constant == F::ZERO { push_addend(values.next().unwrap()) } else { self.push(&self.scalar(Value::Constant(fe_to_u256(constant)))) diff --git a/snark-verifier/src/loader/evm/test/tui.rs b/snark-verifier/src/loader/evm/test/tui.rs index 328082c7..9bd68bb9 100644 --- a/snark-verifier/src/loader/evm/test/tui.rs +++ b/snark-verifier/src/loader/evm/test/tui.rs @@ -45,12 +45,7 @@ impl Tui { let backend = CrosstermBackend::new(stdout); let mut terminal = Terminal::new(backend).unwrap(); terminal.hide_cursor().unwrap(); - Tui { - debug_arena, - terminal, - key_buffer: String::new(), - current_step, - } + Tui { debug_arena, terminal, key_buffer: String::new(), current_step } } pub fn start(mut self) { @@ -91,11 +86,8 @@ impl Tui { let mut draw_memory: DrawMemory = DrawMemory::default(); let debug_call = &self.debug_arena; - let mut opcode_list: Vec = debug_call[0] - .1 - .iter() - .map(|step| step.pretty_opcode()) - .collect(); + let mut opcode_list: Vec = + debug_call[0].1.iter().map(|step| step.pretty_opcode()).collect(); let mut last_index = 0; let mut stack_labels = false; @@ -385,12 +377,8 @@ impl Tui { if let [op_pane, stack_pane, memory_pane] = Layout::default() .direction(Direction::Vertical) .constraints( - [ - Constraint::Ratio(1, 3), - Constraint::Ratio(1, 3), - Constraint::Ratio(1, 3), - ] - .as_ref(), + [Constraint::Ratio(1, 3), Constraint::Ratio(1, 3), Constraint::Ratio(1, 3)] + .as_ref(), ) .split(app)[..] { @@ -412,14 +400,7 @@ impl Tui { stack_labels, draw_memory, ); - Tui::draw_memory( - f, - debug_steps, - current_step, - memory_pane, - mem_utf, - draw_memory, - ); + Tui::draw_memory(f, debug_steps, current_step, memory_pane, mem_utf, draw_memory); } else { panic!("unable to create vertical panes") } @@ -536,15 +517,11 @@ impl Tui { let prev_start = draw_memory.current_startline; let abs_min_start = 0; let abs_max_start = (opcode_list.len() as i32 - 1) - (height / 2); - let mut min_start = max( - current_step as i32 - height + extra_top_lines, - abs_min_start, - ) as usize; + let mut min_start = + max(current_step as i32 - height + extra_top_lines, abs_min_start) as usize; - let mut max_start = max( - min(current_step as i32 - extra_top_lines, abs_max_start), - abs_min_start, - ) as usize; + let mut max_start = + max(min(current_step as i32 - extra_top_lines, abs_max_start), abs_min_start) as usize; if min_start > max_start { std::mem::swap(&mut min_start, &mut max_start); @@ -559,18 +536,11 @@ impl Tui { } draw_memory.current_startline = display_start; - let max_pc_len = debug_steps - .iter() - .fold(0, |max_val, val| val.pc.max(max_val)) - .to_string() - .len(); + let max_pc_len = + debug_steps.iter().fold(0, |max_val, val| val.pc.max(max_val)).to_string().len(); let mut add_new_line = |line_number| { - let bg_color = if line_number == current_step { - Color::DarkGray - } else { - Color::Reset - }; + let bg_color = if line_number == current_step { Color::DarkGray } else { Color::Reset }; let line_number_format = if line_number == current_step { let step: &DebugStep = &debug_steps[line_number]; @@ -598,9 +568,8 @@ impl Tui { add_new_line(number); } add_new_line(opcode_list.len()); - let paragraph = Paragraph::new(text_output) - .block(block_source_code) - .wrap(Wrap { trim: true }); + let paragraph = + Paragraph::new(text_output).block(block_source_code).wrap(Wrap { trim: true }); f.render_widget(paragraph, area); } @@ -610,12 +579,11 @@ impl Tui { current_step: usize, area: Rect, stack_labels: bool, - draw_memory: &mut DrawMemory, + draw_memory: &DrawMemory, ) { let stack = &debug_steps[current_step].stack; - let stack_space = Block::default() - .title(format!("Stack: {}", stack.len())) - .borders(Borders::ALL); + let stack_space = + Block::default().title(format!("Stack: {}", stack.len())).borders(Borders::ALL); let min_len = usize::max(format!("{}", stack.len()).len(), 2); let indices_affected = stack_indices_affected(debug_steps[current_step].instruction.0); @@ -626,12 +594,10 @@ impl Tui { .enumerate() .skip(draw_memory.current_stack_startline) .map(|(i, stack_item)| { - let affected = indices_affected - .iter() - .find(|(affected_index, _name)| *affected_index == i); + let affected = + indices_affected.iter().find(|(affected_index, _name)| *affected_index == i); let mut words: Vec = (0..32) - .into_iter() .rev() .map(|i| stack_item.byte(i)) .map(|byte| { @@ -667,9 +633,7 @@ impl Tui { }) .collect(); - let paragraph = Paragraph::new(text) - .block(stack_space) - .wrap(Wrap { trim: true }); + let paragraph = Paragraph::new(text).block(stack_space).wrap(Wrap { trim: true }); f.render_widget(paragraph, area); } @@ -679,14 +643,11 @@ impl Tui { current_step: usize, area: Rect, mem_utf8: bool, - draw_mem: &mut DrawMemory, + draw_mem: &DrawMemory, ) { let memory = &debug_steps[current_step].memory; let stack_space = Block::default() - .title(format!( - "Memory (max expansion: {} bytes)", - memory.effective_len() - )) + .title(format!("Memory (max expansion: {} bytes)", memory.effective_len())) .borders(Borders::ALL); let memory = memory.data(); let max_i = memory.len() / 32; @@ -773,9 +734,7 @@ impl Tui { Spans::from(spans) }) .collect(); - let paragraph = Paragraph::new(text) - .block(stack_space) - .wrap(Wrap { trim: true }); + let paragraph = Paragraph::new(text).block(stack_space).wrap(Wrap { trim: true }); f.render_widget(paragraph, area); } } @@ -884,13 +843,7 @@ fn stack_indices_affected(op: u8) -> Vec<(usize, &'static str)> { 0xa0 => vec![(0, "offset"), (1, "length")], 0xa1 => vec![(0, "offset"), (1, "length"), (2, "topic")], 0xa2 => vec![(0, "offset"), (1, "length"), (2, "topic1"), (3, "topic2")], - 0xa3 => vec![ - (0, "offset"), - (1, "length"), - (2, "topic1"), - (3, "topic2"), - (4, "topic3"), - ], + 0xa3 => vec![(0, "offset"), (1, "length"), (2, "topic1"), (3, "topic2"), (4, "topic3")], 0xa4 => vec![ (0, "offset"), (1, "length"), diff --git a/snark-verifier/src/loader/evm/util.rs b/snark-verifier/src/loader/evm/util.rs index a84df4c3..5df077f6 100644 --- a/snark-verifier/src/loader/evm/util.rs +++ b/snark-verifier/src/loader/evm/util.rs @@ -74,7 +74,7 @@ pub fn modulus() -> U256 where F: PrimeField, { - U256::from_little_endian((-F::one()).to_repr().as_ref()) + 1 + U256::from_little_endian((-F::ONE).to_repr().as_ref()) + 1 } /// Encode instances and proof into calldata. diff --git a/snark-verifier/src/loader/evm/util/executor.rs b/snark-verifier/src/loader/evm/util/executor.rs index a7697a0e..17062028 100644 --- a/snark-verifier/src/loader/evm/util/executor.rs +++ b/snark-verifier/src/loader/evm/util/executor.rs @@ -47,13 +47,8 @@ fn get_create2_address_from_hash( salt: [u8; 32], init_code_hash: impl Into, ) -> Address { - let bytes = [ - &[0xff], - from.into().as_bytes(), - salt.as_slice(), - init_code_hash.into().as_ref(), - ] - .concat(); + let bytes = + [&[0xff], from.into().as_bytes(), salt.as_slice(), init_code_hash.into().as_ref()].concat(); let hash = keccak256(bytes); @@ -87,11 +82,7 @@ struct LogCollector { impl Inspector for LogCollector { fn log(&mut self, _: &mut EVMData<'_, DB>, address: &Address, topics: &[H256], data: &Bytes) { - self.logs.push(Log { - address: *address, - topics: topics.to_vec(), - data: data.clone(), - }); + self.logs.push(Log { address: *address, topics: topics.to_vec(), data: data.clone() }); } fn call( @@ -114,6 +105,7 @@ pub enum CallKind { Create2, } +#[allow(clippy::derivable_impls)] impl Default for CallKind { fn default() -> Self { CallKind::Call @@ -284,29 +276,15 @@ impl Debugger { fn enter(&mut self, depth: usize, address: Address, kind: CallKind) { self.context = address; - self.head = self.arena.push_node(DebugNode { - depth, - address, - kind, - ..Default::default() - }); + self.head = self.arena.push_node(DebugNode { depth, address, kind, ..Default::default() }); } fn exit(&mut self) { if let Some(parent_id) = self.arena.arena[self.head].parent { - let DebugNode { - depth, - address, - kind, - .. - } = self.arena.arena[parent_id]; + let DebugNode { depth, address, kind, .. } = self.arena.arena[parent_id]; self.context = address; - self.head = self.arena.push_node(DebugNode { - depth, - address, - kind, - ..Default::default() - }); + self.head = + self.arena.push_node(DebugNode { depth, address, kind, ..Default::default() }); } } } @@ -324,11 +302,7 @@ impl Inspector for Debugger { let opcode_infos = spec_opcode_gas(data.env.cfg.spec_id); let opcode_info = &opcode_infos[op as usize]; - let push_size = if opcode_info.is_push() { - (op - opcode::PUSH1 + 1) as usize - } else { - 0 - }; + let push_size = if opcode_info.is_push() { (op - opcode::PUSH1 + 1) as usize } else { 0 }; let push_bytes = match push_size { 0 => None, n => { @@ -394,12 +368,7 @@ impl Inspector for Debugger { CallKind::Create, ); - ( - Return::Continue, - None, - Gas::new(call.gas_limit), - Bytes::new(), - ) + (Return::Continue, None, Gas::new(call.gas_limit), Bytes::new()) } fn create_end( @@ -619,12 +588,7 @@ impl Inspector for InspectorStack { } ); - ( - Return::Continue, - None, - Gas::new(call.gas_limit), - Bytes::new(), - ) + (Return::Continue, None, Gas::new(call.gas_limit), Bytes::new()) } fn create_end( @@ -741,11 +705,7 @@ pub struct Executor { impl Executor { fn new(debugger: bool, gas_limit: U256) -> Self { - Executor { - db: InMemoryDB::default(), - debugger, - gas_limit, - } + Executor { db: InMemoryDB::default(), debugger, gas_limit } } pub fn db_mut(&mut self) -> &mut InMemoryDB { @@ -757,16 +717,8 @@ impl Executor { let result = self.call_raw_with_env(env); self.commit(&result); - let RawCallResult { - exit_reason, - out, - gas_used, - gas_refunded, - logs, - debug, - env, - .. - } = result; + let RawCallResult { exit_reason, out, gas_used, gas_refunded, logs, debug, env, .. } = + result; let address = match (exit_reason, out) { (return_ok!(), TransactOut::Create(_, Some(address))) => Some(address), @@ -801,13 +753,7 @@ impl Executor { let result = evm_inner::<_, true>(&mut env, &mut self.db.clone(), &mut inspector).transact(); let (exec_result, state_changeset) = result; - let ExecutionResult { - exit_reason, - gas_refunded, - gas_used, - out, - .. - } = exec_result; + let ExecutionResult { exit_reason, gas_refunded, gas_used, out, .. } = exec_result; let result = match out { TransactOut::Call(ref data) => data.to_owned(), @@ -831,16 +777,13 @@ impl Executor { fn commit(&mut self, result: &RawCallResult) { if let Some(state_changeset) = result.state_changeset.as_ref() { - self.db - .commit(state_changeset.clone().into_iter().collect()); + self.db.commit(state_changeset.clone().into_iter().collect()); } } fn inspector(&self) -> InspectorStack { - let mut stack = InspectorStack { - logs: Some(LogCollector::default()), - ..Default::default() - }; + let mut stack = + InspectorStack { logs: Some(LogCollector::default()), ..Default::default() }; if self.debugger { let gas_inspector = Rc::new(RefCell::new(GasInspector::default())); stack.gas = Some(gas_inspector.clone()); @@ -857,10 +800,7 @@ impl Executor { value: U256, ) -> Env { Env { - block: BlockEnv { - gas_limit: self.gas_limit, - ..BlockEnv::default() - }, + block: BlockEnv { gas_limit: self.gas_limit, ..BlockEnv::default() }, tx: TxEnv { caller, transact_to, diff --git a/snark-verifier/src/loader/halo2/loader.rs b/snark-verifier/src/loader/halo2/loader.rs index 31be9841..105972c0 100644 --- a/snark-verifier/src/loader/halo2/loader.rs +++ b/snark-verifier/src/loader/halo2/loader.rs @@ -136,15 +136,15 @@ impl> Halo2Loader { | (Value::Constant(constant), Value::Assigned(assigned)) => { Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( &mut self.ctx_mut(), - &[(C::Scalar::one(), assigned)], + &[(C::Scalar::ONE, assigned)], *constant, )) } (Value::Assigned(lhs), Value::Assigned(rhs)) => { Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( &mut self.ctx_mut(), - &[(C::Scalar::one(), lhs), (C::Scalar::one(), rhs)], - C::Scalar::zero(), + &[(C::Scalar::ONE, lhs), (C::Scalar::ONE, rhs)], + C::Scalar::ZERO, )) } }; @@ -161,14 +161,14 @@ impl> Halo2Loader { (Value::Constant(constant), Value::Assigned(assigned)) => { Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( &mut self.ctx_mut(), - &[(-C::Scalar::one(), assigned)], + &[(-C::Scalar::ONE, assigned)], *constant, )) } (Value::Assigned(assigned), Value::Constant(constant)) => { Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( &mut self.ctx_mut(), - &[(C::Scalar::one(), assigned)], + &[(C::Scalar::ONE, assigned)], -*constant, )) } @@ -191,14 +191,14 @@ impl> Halo2Loader { Value::Assigned(self.scalar_chip().sum_with_coeff_and_const( &mut self.ctx_mut(), &[(*constant, assigned)], - C::Scalar::zero(), + C::Scalar::ZERO, )) } (Value::Assigned(lhs), Value::Assigned(rhs)) => { Value::Assigned(self.scalar_chip().sum_products_with_coeff_and_const( &mut self.ctx_mut(), - &[(C::Scalar::one(), lhs, rhs)], - C::Scalar::zero(), + &[(C::Scalar::ONE, lhs, rhs)], + C::Scalar::ZERO, )) } }; @@ -557,7 +557,7 @@ impl> EcPointLoader for Rc + if scalar.eq(&C::Scalar::ONE) => { variable_base_non_scaled.push(base); } diff --git a/snark-verifier/src/loader/halo2/shim.rs b/snark-verifier/src/loader/halo2/shim.rs index 790c9e22..9d010d2b 100644 --- a/snark-verifier/src/loader/halo2/shim.rs +++ b/snark-verifier/src/loader/halo2/shim.rs @@ -1,8 +1,8 @@ -use crate::util::arithmetic::{CurveAffine, FieldExt}; +use crate::util::arithmetic::{CurveAffine, PrimeField}; use std::{fmt::Debug, ops::Deref}; /// Instructions to handle field element operations. -pub trait IntegerInstructions: Clone + Debug { +pub trait IntegerInstructions: Clone + Debug { /// Context (either enhanced `region` or some kind of builder). type Context: Debug; /// Assigned cell. @@ -24,8 +24,8 @@ pub trait IntegerInstructions: Clone + Debug { fn sum_with_coeff_and_const( &self, ctx: &mut Self::Context, - values: &[(F::Scalar, impl Deref)], - constant: F::Scalar, + values: &[(F, impl Deref)], + constant: F, ) -> Self::AssignedInteger; /// Sum product of integers with coefficients and constant. @@ -33,11 +33,11 @@ pub trait IntegerInstructions: Clone + Debug { &self, ctx: &mut Self::Context, values: &[( - F::Scalar, + F, impl Deref, impl Deref, )], - constant: F::Scalar, + constant: F, ) -> Self::AssignedInteger; /// Returns `lhs - rhs`. @@ -132,25 +132,26 @@ mod halo2_lib { use crate::halo2_proofs::halo2curves::CurveAffineExt; use crate::{ loader::halo2::{EccInstructions, IntegerInstructions}, - util::arithmetic::CurveAffine, + util::arithmetic::{CurveAffine, PrimeField}, }; use halo2_base::{ self, gates::{builder::GateThreadBuilder, GateChip, GateInstructions, RangeInstructions}, + utils::BigPrimeField, AssignedValue, QuantumCell::{Constant, Existing}, }; use halo2_ecc::bigint::ProperCrtUint; use halo2_ecc::{ ecc::{BaseFieldEccChip, EcPoint}, - fields::{FieldChip, PrimeField}, + fields::FieldChip, }; use std::ops::Deref; type AssignedInteger = ProperCrtUint<::ScalarExt>; type AssignedEcPoint = EcPoint<::ScalarExt, AssignedInteger>; - impl IntegerInstructions for GateChip { + impl IntegerInstructions for GateChip { type Context = GateThreadBuilder; type AssignedCell = AssignedValue; type AssignedInteger = AssignedValue; @@ -166,14 +167,14 @@ mod halo2_lib { fn sum_with_coeff_and_const( &self, ctx: &mut Self::Context, - values: &[(F::Scalar, impl Deref)], + values: &[(F, impl Deref)], constant: F, ) -> Self::AssignedInteger { let mut a = Vec::with_capacity(values.len() + 1); let mut b = Vec::with_capacity(values.len() + 1); - if constant != F::zero() { + if constant != F::ZERO { a.push(Constant(constant)); - b.push(Constant(F::one())); + b.push(Constant(F::ONE)); } a.extend(values.iter().map(|(_, a)| Existing(*a.deref()))); b.extend(values.iter().map(|(c, _)| Constant(*c))); @@ -184,7 +185,7 @@ mod halo2_lib { &self, ctx: &mut Self::Context, values: &[( - F::Scalar, + F, impl Deref, impl Deref, )], @@ -220,8 +221,8 @@ mod halo2_lib { ) -> Self::AssignedInteger { // make sure scalar != 0 let is_zero = self.is_zero(ctx.main(0), *a); - self.assert_is_const(ctx.main(0), &is_zero, &F::zero()); - GateInstructions::div_unsafe(self, ctx.main(0), Constant(F::one()), Existing(*a)) + self.assert_is_const(ctx.main(0), &is_zero, &F::ZERO); + GateInstructions::div_unsafe(self, ctx.main(0), Constant(F::ONE), Existing(*a)) } fn assert_equal( @@ -236,8 +237,8 @@ mod halo2_lib { impl<'chip, C: CurveAffineExt> EccInstructions for BaseFieldEccChip<'chip, C> where - C::ScalarExt: PrimeField, - C::Base: PrimeField, + C::ScalarExt: BigPrimeField, + C::Base: BigPrimeField, { type Context = GateThreadBuilder; type ScalarChip = GateChip; diff --git a/snark-verifier/src/pcs/ipa.rs b/snark-verifier/src/pcs/ipa.rs index 6358e15d..288745d7 100644 --- a/snark-verifier/src/pcs/ipa.rs +++ b/snark-verifier/src/pcs/ipa.rs @@ -379,7 +379,7 @@ fn h_eval>(xi: &[T], z: &T) -> T { fn h_coeffs(xi: &[F], scalar: F) -> Vec { assert!(!xi.is_empty()); - let mut coeffs = vec![F::zero(); 1 << xi.len()]; + let mut coeffs = vec![F::ZERO; 1 << xi.len()]; coeffs[0] = scalar; for (len, xi) in xi.iter().rev().enumerate().map(|(i, xi)| (1 << i, xi)) { diff --git a/snark-verifier/src/pcs/ipa/accumulation.rs b/snark-verifier/src/pcs/ipa/accumulation.rs index 56d61aa7..51434541 100644 --- a/snark-verifier/src/pcs/ipa/accumulation.rs +++ b/snark-verifier/src/pcs/ipa/accumulation.rs @@ -186,13 +186,13 @@ where let (u, h) = instances .iter() - .map(|IpaAccumulator { u, xi }| (*u, h_coeffs(xi, C::Scalar::one()))) + .map(|IpaAccumulator { u, xi }| (*u, h_coeffs(xi, C::Scalar::ONE))) .chain(a_b_u.map(|(a, b, u)| { ( u, iter::empty() .chain([b, a]) - .chain(iter::repeat_with(C::Scalar::zero).take(pk.domain.n - 2)) + .chain(iter::repeat(C::Scalar::ZERO).take(pk.domain.n - 2)) .collect(), ) })) diff --git a/snark-verifier/src/pcs/ipa/decider.rs b/snark-verifier/src/pcs/ipa/decider.rs index 5235a857..6fd7026b 100644 --- a/snark-verifier/src/pcs/ipa/decider.rs +++ b/snark-verifier/src/pcs/ipa/decider.rs @@ -48,7 +48,7 @@ mod native { dk: &Self::DecidingKey, IpaAccumulator { u, xi }: IpaAccumulator, ) -> Result<(), Error> { - let h = h_coeffs(&xi, C::Scalar::one()); + let h = h_coeffs(&xi, C::Scalar::ONE); (u == multi_scalar_multiplication(&h, &dk.g).to_affine()) .then_some(()) .ok_or_else(|| Error::AssertionFailure("U == commit(G, h)".to_string())) diff --git a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs index cae77a5f..538aa4fb 100644 --- a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs +++ b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs @@ -5,7 +5,7 @@ use crate::{ PolynomialCommitmentScheme, Query, }, util::{ - arithmetic::{CurveAffine, FieldExt, Fraction}, + arithmetic::{CurveAffine, Fraction, PrimeField}, msm::Msm, transcript::TranscriptRead, Itertools, @@ -159,7 +159,7 @@ where fn query_sets(queries: &[Query]) -> Vec> where - F: FieldExt, + F: PrimeField + Ord, T: Clone, { let poly_shifts = @@ -203,7 +203,7 @@ where fn query_set_coeffs(sets: &[QuerySet], x: &T, x_3: &T) -> Vec> where - F: FieldExt, + F: PrimeField + Ord, T: LoadedScalar, { let loader = x.loader(); @@ -236,7 +236,7 @@ struct QuerySet<'a, F, T> { impl<'a, F, T> QuerySet<'a, F, T> where - F: FieldExt, + F: PrimeField, T: LoadedScalar, { fn msm>( @@ -288,7 +288,7 @@ struct QuerySetCoeff { impl QuerySetCoeff where - F: FieldExt, + F: PrimeField + Ord, T: LoadedScalar, { fn new(shifts: &[F], powers_of_x: &[T], x_3: &T, x_3_minus_x_shift_i: &BTreeMap) -> Self { @@ -303,7 +303,7 @@ where .filter(|&(i, _)| i != j) .map(|(_, shift_i)| (*shift_j - shift_i)) .reduce(|acc, value| acc * value) - .unwrap_or_else(|| F::one()) + .unwrap_or(F::ONE) }) .collect_vec(); diff --git a/snark-verifier/src/pcs/kzg.rs b/snark-verifier/src/pcs/kzg.rs index 8f416ee3..387a108c 100644 --- a/snark-verifier/src/pcs/kzg.rs +++ b/snark-verifier/src/pcs/kzg.rs @@ -18,7 +18,7 @@ pub use accumulator::LimbsEncodingInstructions; /// KZG succinct verifying key. #[derive(Clone, Copy, Debug)] -pub struct KzgSuccinctVerifyingKey { +pub struct KzgSuccinctVerifyingKey { /// Generator. pub g: C, } diff --git a/snark-verifier/src/pcs/kzg/accumulation.rs b/snark-verifier/src/pcs/kzg/accumulation.rs index 1f901568..d71e366e 100644 --- a/snark-verifier/src/pcs/kzg/accumulation.rs +++ b/snark-verifier/src/pcs/kzg/accumulation.rs @@ -19,6 +19,7 @@ pub struct KzgAs(PhantomData<(M, MOS)>); impl AccumulationScheme for KzgAs where M: MultiMillerLoop, + M::G1Affine: CurveAffine, L: Loader, MOS: Clone + Debug, { @@ -139,6 +140,7 @@ where impl AccumulationSchemeProver for KzgAs where M: MultiMillerLoop, + M::G1Affine: CurveAffine, MOS: Clone + Debug, { type ProvingKey = KzgAsProvingKey; @@ -163,7 +165,7 @@ where let blind = pk .zk() .then(|| { - let s = M::Scalar::random(rng); + let s = M::Fr::random(rng); let (g, s_g) = pk.0.unwrap(); let lhs = (s_g * s).to_affine(); let rhs = (g * s).to_affine(); diff --git a/snark-verifier/src/pcs/kzg/accumulator.rs b/snark-verifier/src/pcs/kzg/accumulator.rs index 82d1454b..423ae7d5 100644 --- a/snark-verifier/src/pcs/kzg/accumulator.rs +++ b/snark-verifier/src/pcs/kzg/accumulator.rs @@ -59,7 +59,6 @@ mod native { let [lhs_x, lhs_y, rhs_x, rhs_y]: [_; 4] = limbs .chunks(LIMBS) - .into_iter() .map(|limbs| { fe_from_limbs::<_, _, LIMBS, BITS>( limbs.iter().map(|limb| **limb).collect_vec().try_into().unwrap(), @@ -109,7 +108,6 @@ mod evm { let [lhs_x, lhs_y, rhs_x, rhs_y]: [[_; LIMBS]; 4] = limbs .chunks(LIMBS) - .into_iter() .map(|limbs| limbs.to_vec().try_into().unwrap()) .collect_vec() .try_into() @@ -204,14 +202,15 @@ mod halo2 { mod halo2_lib { use super::*; use halo2_base::halo2_proofs::halo2curves::CurveAffineExt; - use halo2_ecc::{ecc::BaseFieldEccChip, fields::PrimeField}; + use halo2_base::utils::BigPrimeField; + use halo2_ecc::ecc::BaseFieldEccChip; impl<'chip, C, const LIMBS: usize, const BITS: usize> LimbsEncodingInstructions for BaseFieldEccChip<'chip, C> where C: CurveAffineExt, - C::ScalarExt: PrimeField, - C::Base: PrimeField, + C::ScalarExt: BigPrimeField, + C::Base: BigPrimeField, { fn assign_ec_point_from_limbs( &self, diff --git a/snark-verifier/src/pcs/kzg/decider.rs b/snark-verifier/src/pcs/kzg/decider.rs index 59f1afbf..04f2caaf 100644 --- a/snark-verifier/src/pcs/kzg/decider.rs +++ b/snark-verifier/src/pcs/kzg/decider.rs @@ -1,4 +1,7 @@ -use crate::{pcs::kzg::KzgSuccinctVerifyingKey, util::arithmetic::MultiMillerLoop}; +use crate::{ + pcs::kzg::KzgSuccinctVerifyingKey, + util::arithmetic::{CurveAffine, MultiMillerLoop}, +}; use std::marker::PhantomData; /// KZG deciding key. @@ -23,7 +26,10 @@ impl KzgDecidingKey { } } -impl From<(M::G1Affine, M::G2Affine, M::G2Affine)> for KzgDecidingKey { +impl From<(M::G1Affine, M::G2Affine, M::G2Affine)> for KzgDecidingKey +where + M::G1Affine: CurveAffine, +{ fn from((g1, g2, s_g2): (M::G1Affine, M::G2Affine, M::G2Affine)) -> KzgDecidingKey { KzgDecidingKey::new(g1, g2, s_g2) } @@ -43,7 +49,7 @@ mod native { AccumulationDecider, }, util::{ - arithmetic::{Group, MillerLoopResult, MultiMillerLoop}, + arithmetic::{CurveAffine, Group, MillerLoopResult, MultiMillerLoop}, Itertools, }, Error, @@ -53,6 +59,7 @@ mod native { impl AccumulationDecider for KzgAs where M: MultiMillerLoop, + M::G1Affine: CurveAffine, MOS: Clone + Debug, { type DecidingKey = KzgDecidingKey; @@ -103,7 +110,9 @@ mod evm { impl AccumulationDecider> for KzgAs where M: MultiMillerLoop, - M::Scalar: PrimeField, + M::G1Affine: CurveAffine, + M::G2Affine: CurveAffine, + M::Fr: PrimeField, MOS: Clone + Debug, { type DecidingKey = KzgDecidingKey; @@ -152,7 +161,7 @@ mod evm { loader.code_mut().runtime_append(code); let challenge = loader.scalar(Value::Memory(challenge_ptr)); - let powers_of_challenge = LoadedScalar::::powers(&challenge, lhs.len()); + let powers_of_challenge = LoadedScalar::::powers(&challenge, lhs.len()); let [lhs, rhs] = [lhs, rhs].map(|msms| { msms.iter() .zip(powers_of_challenge.iter()) diff --git a/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs index 3a448056..d1398ebb 100644 --- a/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs @@ -6,7 +6,7 @@ use crate::{ PolynomialCommitmentScheme, Query, }, util::{ - arithmetic::{CurveAffine, FieldExt, Fraction, MultiMillerLoop}, + arithmetic::{CurveAffine, Fraction, MultiMillerLoop, PrimeField}, msm::Msm, transcript::TranscriptRead, Itertools, @@ -27,6 +27,8 @@ pub struct Bdfg21; impl PolynomialCommitmentScheme for KzgAs where M: MultiMillerLoop, + M::G1Affine: CurveAffine, + M::Fr: Ord, L: Loader, { type VerifyingKey = KzgSuccinctVerifyingKey; @@ -35,7 +37,7 @@ where fn read_proof( _: &KzgSuccinctVerifyingKey, - _: &[Query], + _: &[Query], transcript: &mut T, ) -> Result, Error> where @@ -48,22 +50,21 @@ where svk: &KzgSuccinctVerifyingKey, commitments: &[Msm], z: &L::LoadedScalar, - queries: &[Query], + queries: &[Query], proof: &Bdfg21Proof, ) -> Result { let sets = query_sets(queries); let f = { let coeffs = query_set_coeffs(&sets, z, &proof.z_prime); - let powers_of_mu = proof - .mu - .powers(sets.iter().map(|set| set.polys.len()).max().unwrap()); + let powers_of_mu = + proof.mu.powers(sets.iter().map(|set| set.polys.len()).max().unwrap()); let msms = sets .iter() .zip(coeffs.iter()) .map(|(set, coeff)| set.msm(coeff, commitments, &powers_of_mu)); - msms.zip(proof.gamma.powers(sets.len()).into_iter()) + msms.zip(proof.gamma.powers(sets.len())) .map(|(msm, power_of_gamma)| msm * &power_of_gamma) .sum::>() - Msm::base(&proof.w) * &coeffs[0].z_s @@ -72,10 +73,7 @@ where let rhs = Msm::base(&proof.w_prime); let lhs = f + rhs.clone() * &proof.z_prime; - Ok(KzgAccumulator::new( - lhs.evaluate(Some(svk.g)), - rhs.evaluate(Some(svk.g)), - )) + Ok(KzgAccumulator::new(lhs.evaluate(Some(svk.g)), rhs.evaluate(Some(svk.g)))) } } @@ -104,24 +102,14 @@ where let w = transcript.read_ec_point()?; let z_prime = transcript.squeeze_challenge(); let w_prime = transcript.read_ec_point()?; - Ok(Bdfg21Proof { - mu, - gamma, - w, - z_prime, - w_prime, - }) + Ok(Bdfg21Proof { mu, gamma, w, z_prime, w_prime }) } } -fn query_sets(queries: &[Query]) -> Vec> { - let poly_shifts = queries.iter().fold( - Vec::<(usize, Vec, Vec<&T>)>::new(), - |mut poly_shifts, query| { - if let Some(pos) = poly_shifts - .iter() - .position(|(poly, _, _)| *poly == query.poly) - { +fn query_sets(queries: &[Query]) -> Vec> { + let poly_shifts = + queries.iter().fold(Vec::<(usize, Vec, Vec<&T>)>::new(), |mut poly_shifts, query| { + if let Some(pos) = poly_shifts.iter().position(|(poly, _, _)| *poly == query.poly) { let (_, shifts, evals) = &mut poly_shifts[pos]; if !shifts.contains(&query.shift) { shifts.push(query.shift); @@ -131,67 +119,47 @@ fn query_sets(queries: &[Query]) -> Vec>::new(), - |mut sets, (poly, shifts, evals)| { - if let Some(pos) = sets.iter().position(|set| { - BTreeSet::from_iter(set.shifts.iter()) == BTreeSet::from_iter(shifts.iter()) - }) { - let set = &mut sets[pos]; - if !set.polys.contains(&poly) { - set.polys.push(poly); - set.evals.push( - set.shifts - .iter() - .map(|lhs| { - let idx = shifts.iter().position(|rhs| lhs == rhs).unwrap(); - evals[idx] - }) - .collect(), - ); - } - } else { - let set = QuerySet { - shifts, - polys: vec![poly], - evals: vec![evals], - }; - sets.push(set); + }); + + poly_shifts.into_iter().fold(Vec::>::new(), |mut sets, (poly, shifts, evals)| { + if let Some(pos) = sets.iter().position(|set| { + BTreeSet::from_iter(set.shifts.iter()) == BTreeSet::from_iter(shifts.iter()) + }) { + let set = &mut sets[pos]; + if !set.polys.contains(&poly) { + set.polys.push(poly); + set.evals.push( + set.shifts + .iter() + .map(|lhs| { + let idx = shifts.iter().position(|rhs| lhs == rhs).unwrap(); + evals[idx] + }) + .collect(), + ); } - sets - }, - ) + } else { + let set = QuerySet { shifts, polys: vec![poly], evals: vec![evals] }; + sets.push(set); + } + sets + }) } -fn query_set_coeffs<'a, F: FieldExt, T: LoadedScalar>( - sets: &[QuerySet<'a, F, T>], +fn query_set_coeffs>( + sets: &[QuerySet], z: &T, z_prime: &T, ) -> Vec> { let loader = z.loader(); - let superset = sets - .iter() - .flat_map(|set| set.shifts.clone()) - .sorted() - .dedup(); + let superset = sets.iter().flat_map(|set| set.shifts.clone()).sorted().dedup(); - let size = sets - .iter() - .map(|set| set.shifts.len()) - .chain(Some(2)) - .max() - .unwrap(); + let size = sets.iter().map(|set| set.shifts.len()).chain(Some(2)).max().unwrap(); let powers_of_z = z.powers(size); - let z_prime_minus_z_shift_i = BTreeMap::from_iter(superset.map(|shift| { - ( - shift, - z_prime.clone() - z.clone() * loader.load_const(&shift), - ) - })); + let z_prime_minus_z_shift_i = BTreeMap::from_iter( + superset.map(|shift| (shift, z_prime.clone() - z.clone() * loader.load_const(&shift))), + ); let mut z_s_1 = None; let mut coeffs = sets @@ -225,7 +193,7 @@ struct QuerySet<'a, F, T> { evals: Vec>, } -impl<'a, F: FieldExt, T: LoadedScalar> QuerySet<'a, F, T> { +impl<'a, F: PrimeField, T: LoadedScalar> QuerySet<'a, F, T> { fn msm>( &self, coeff: &QuerySetCoeff, @@ -270,7 +238,7 @@ struct QuerySetCoeff { impl QuerySetCoeff where - F: FieldExt, + F: PrimeField + Ord, T: LoadedScalar, { fn new( @@ -292,7 +260,7 @@ where .filter(|&(i, _)| i != j) .map(|(_, shift_i)| (*shift_j - shift_i)) .reduce(|acc, value| acc * value) - .unwrap_or_else(|| F::one()) + .unwrap_or(F::ONE) }) .collect_vec(); @@ -312,10 +280,7 @@ where .collect_vec(); let z_s = loader.product( - &shifts - .iter() - .map(|shift| z_prime_minus_z_shift_i.get(shift).unwrap()) - .collect_vec(), + &shifts.iter().map(|shift| z_prime_minus_z_shift_i.get(shift).unwrap()).collect_vec(), ); let z_s_1_over_z_s = z_s_1.clone().map(|z_s_1| Fraction::new(z_s_1, z_s.clone())); @@ -344,13 +309,8 @@ where .iter_mut() .chain(self.commitment_coeff.as_mut()) .for_each(Fraction::evaluate); - let barycentric_weights_sum = loader.sum( - &self - .eval_coeffs - .iter() - .map(Fraction::evaluated) - .collect_vec(), - ); + let barycentric_weights_sum = + loader.sum(&self.eval_coeffs.iter().map(Fraction::evaluated).collect_vec()); self.r_eval_coeff = Some(match self.commitment_coeff.as_ref() { Some(coeff) => Fraction::new(coeff.evaluated().clone(), barycentric_weights_sum), None => Fraction::one_over(barycentric_weights_sum), @@ -370,13 +330,9 @@ impl CostEstimation for KzgAs where M: MultiMillerLoop, { - type Input = Vec>; + type Input = Vec>; - fn estimate_cost(_: &Vec>) -> Cost { - Cost { - num_commitment: 2, - num_msm: 2, - ..Default::default() - } + fn estimate_cost(_: &Vec>) -> Cost { + Cost { num_commitment: 2, num_msm: 2, ..Default::default() } } } diff --git a/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs index e5741163..da5d51a6 100644 --- a/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs @@ -23,6 +23,7 @@ pub struct Gwc19; impl PolynomialCommitmentScheme for KzgAs where M: MultiMillerLoop, + M::G1Affine: CurveAffine, L: Loader, { type VerifyingKey = KzgSuccinctVerifyingKey; @@ -31,7 +32,7 @@ where fn read_proof( _: &Self::VerifyingKey, - queries: &[Query], + queries: &[Query], transcript: &mut T, ) -> Result where @@ -44,15 +45,13 @@ where svk: &Self::VerifyingKey, commitments: &[Msm], z: &L::LoadedScalar, - queries: &[Query], + queries: &[Query], proof: &Self::Proof, ) -> Result { let sets = query_sets(queries); let powers_of_u = &proof.u.powers(sets.len()); let f = { - let powers_of_v = proof - .v - .powers(sets.iter().map(|set| set.polys.len()).max().unwrap()); + let powers_of_v = proof.v.powers(sets.iter().map(|set| set.polys.len()).max().unwrap()); sets.iter() .map(|set| set.msm(commitments, &powers_of_v)) .zip(powers_of_u.iter()) @@ -67,11 +66,7 @@ where .zip(powers_of_u.iter()) .map(|(w, power_of_u)| Msm::base(w) * power_of_u) .collect_vec(); - let lhs = f + rhs - .iter() - .zip(z_omegas) - .map(|(uw, z_omega)| uw.clone() * &z_omega) - .sum(); + let lhs = f + rhs.iter().zip(z_omegas).map(|(uw, z_omega)| uw.clone() * &z_omega).sum(); Ok(KzgAccumulator::new( lhs.evaluate(Some(svk.g)), @@ -161,14 +156,10 @@ impl CostEstimation for KzgAs where M: MultiMillerLoop, { - type Input = Vec>; + type Input = Vec>; - fn estimate_cost(queries: &Vec>) -> Cost { + fn estimate_cost(queries: &Vec>) -> Cost { let num_w = query_sets(queries).len(); - Cost { - num_commitment: num_w, - num_msm: num_w, - ..Default::default() - } + Cost { num_commitment: num_w, num_msm: num_w, ..Default::default() } } } diff --git a/snark-verifier/src/system/halo2.rs b/snark-verifier/src/system/halo2.rs index 98f4488c..2dc5751d 100644 --- a/snark-verifier/src/system/halo2.rs +++ b/snark-verifier/src/system/halo2.rs @@ -7,7 +7,7 @@ use crate::halo2_proofs::{ }; use crate::{ util::{ - arithmetic::{root_of_unity, CurveAffine, Domain, FieldExt, Rotation}, + arithmetic::{root_of_unity, CurveAffine, Domain, PrimeField, Rotation}, Itertools, }, verifier::plonk::protocol::{ @@ -161,7 +161,7 @@ impl From for Rotation { } } -struct Polynomials<'a, F: FieldExt> { +struct Polynomials<'a, F: PrimeField> { cs: &'a ConstraintSystem, zk: bool, query_instance: bool, @@ -179,7 +179,7 @@ struct Polynomials<'a, F: FieldExt> { num_lookup_z: usize, } -impl<'a, F: FieldExt> Polynomials<'a, F> { +impl<'a, F: PrimeField> Polynomials<'a, F> { fn new( cs: &'a ConstraintSystem, zk: bool, @@ -474,7 +474,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { } fn l_active(&self) -> Expression { - Expression::Constant(F::one()) - self.l_last() - self.l_blind() + Expression::Constant(F::ONE) - self.l_last() - self.l_blind() } fn system_challenge_offset(&self) -> usize { @@ -499,7 +499,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { } fn permutation_constraints(&'a self, t: usize) -> impl IntoIterator> + 'a { - let one = &Expression::Constant(F::one()); + let one = &Expression::Constant(F::ONE); let l_0 = &Expression::::CommonPolynomial(CommonPolynomial::Lagrange(0)); let l_last = &self.l_last(); let l_active = &self.l_active(); @@ -591,7 +591,7 @@ impl<'a, F: FieldExt> Polynomials<'a, F> { } fn lookup_constraints(&'a self, t: usize) -> impl IntoIterator> + 'a { - let one = &Expression::Constant(F::one()); + let one = &Expression::Constant(F::ONE); let l_0 = &Expression::::CommonPolynomial(CommonPolynomial::Lagrange(0)); let l_last = &self.l_last(); let l_active = &self.l_active(); @@ -698,7 +698,7 @@ impl EncodedChallenge for MockChallenge { } #[derive(Default)] -struct MockTranscript(F); +struct MockTranscript(F); impl Transcript for MockTranscript { fn squeeze_challenge(&mut self) -> MockChallenge { diff --git a/snark-verifier/src/system/halo2/transcript.rs b/snark-verifier/src/system/halo2/transcript.rs index 9cfd6b89..10da3a22 100644 --- a/snark-verifier/src/system/halo2/transcript.rs +++ b/snark-verifier/src/system/halo2/transcript.rs @@ -1,7 +1,6 @@ //! Transcripts implemented with both `halo2_proofs::transcript` and //! `crate::util::transcript`. use crate::halo2_proofs; -use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite, Challenge255}; use crate::{ loader::native::{self, NativeLoader}, util::{ @@ -10,6 +9,8 @@ use crate::{ }, Error, }; +use halo2_proofs::transcript::{Blake2bRead, Blake2bWrite, Challenge255}; +use pairing::group::ff::FromUniformBytes; use std::io::{Read, Write}; #[cfg(feature = "loader_evm")] @@ -18,7 +19,10 @@ pub mod evm; #[cfg(feature = "loader_halo2")] pub mod halo2; -impl Transcript for Blake2bRead> { +impl Transcript for Blake2bRead> +where + C::Scalar: FromUniformBytes<64>, +{ fn loader(&self) -> &NativeLoader { &native::LOADER } @@ -38,8 +42,9 @@ impl Transcript for Blake2bRead TranscriptRead - for Blake2bRead> +impl TranscriptRead for Blake2bRead> +where + C::Scalar: FromUniformBytes<64>, { fn read_scalar(&mut self) -> Result { halo2_proofs::transcript::TranscriptRead::read_scalar(self) @@ -52,7 +57,10 @@ impl TranscriptRead } } -impl Transcript for Blake2bWrite> { +impl Transcript for Blake2bWrite> +where + C::Scalar: FromUniformBytes<64>, +{ fn loader(&self) -> &NativeLoader { &native::LOADER } @@ -72,7 +80,10 @@ impl Transcript for Blake2bWrite TranscriptWrite for Blake2bWrite, C, Challenge255> { +impl TranscriptWrite for Blake2bWrite, C, Challenge255> +where + C::Scalar: FromUniformBytes<64>, +{ fn write_scalar(&mut self, scalar: C::Scalar) -> Result<(), Error> { halo2_proofs::transcript::TranscriptWrite::write_scalar(self, scalar) .map_err(|err| Error::Transcript(err.kind(), err.to_string())) diff --git a/snark-verifier/src/system/halo2/transcript/halo2.rs b/snark-verifier/src/system/halo2/transcript/halo2.rs index 86b1929c..8a0ce6d4 100644 --- a/snark-verifier/src/system/halo2/transcript/halo2.rs +++ b/snark-verifier/src/system/halo2/transcript/halo2.rs @@ -1,6 +1,7 @@ //! Transcript for verifier in [`halo2_proofs`] circuit. use crate::halo2_proofs; +use crate::util::arithmetic::FieldExt; use crate::{ loader::{ halo2::{EcPoint, EccInstructions, Halo2Loader, Scalar}, @@ -64,7 +65,10 @@ where { /// Initialize [`PoseidonTranscript`] given readable or writeable stream for /// verifying or proving with [`NativeLoader`]. - pub fn new(loader: &Rc>, stream: R) -> Self { + pub fn new(loader: &Rc>, stream: R) -> Self + where + C::Scalar: FieldExt, + { let buf = Poseidon::new::(loader); Self { loader: loader.clone(), stream, buf } } @@ -165,7 +169,10 @@ impl(stream: S) -> Self { + pub fn new(stream: S) -> Self + where + C::Scalar: FieldExt, + { Self { loader: NativeLoader, stream, @@ -375,6 +382,7 @@ impl where C: CurveAffine, + C::Scalar: FieldExt, R: Read, { fn init(reader: R) -> Self { @@ -409,6 +417,7 @@ impl where C: CurveAffine, + C::Scalar: FieldExt, W: Write, { fn init(writer: W) -> Self { @@ -423,12 +432,13 @@ where mod halo2_lib { use crate::halo2_curves::CurveAffineExt; use crate::system::halo2::transcript::halo2::NativeEncoding; - use halo2_ecc::{ecc::BaseFieldEccChip, fields::PrimeField}; + use halo2_base::utils::BigPrimeField; + use halo2_ecc::ecc::BaseFieldEccChip; impl<'chip, C: CurveAffineExt> NativeEncoding for BaseFieldEccChip<'chip, C> where - C::Scalar: PrimeField, - C::Base: PrimeField, + C::Scalar: BigPrimeField, + C::Base: BigPrimeField, { fn encode( &self, diff --git a/snark-verifier/src/util/arithmetic.rs b/snark-verifier/src/util/arithmetic.rs index 97962e32..070277a5 100644 --- a/snark-verifier/src/util/arithmetic.rs +++ b/snark-verifier/src/util/arithmetic.rs @@ -4,15 +4,15 @@ use crate::halo2_curves; use crate::util::Itertools; pub use halo2_curves::{ group::{ - ff::{BatchInvert, Field, PrimeField}, + ff::{BatchInvert, Field, FromUniformBytes, PrimeField}, prime::PrimeCurveAffine, Curve, Group, GroupEncoding, }, - pairing::MillerLoopResult, - Coordinates, CurveAffine, CurveExt, FieldExt, + Coordinates, CurveAffine, CurveExt, }; use num_bigint::BigUint; use num_traits::One; +pub use pairing::MillerLoopResult; use serde::{Deserialize, Serialize}; use std::{ cmp::Ordering, @@ -22,9 +22,14 @@ use std::{ }; /// [`halo2_curves::pairing::MultiMillerLoop`] with [`std::fmt::Debug`]. -pub trait MultiMillerLoop: halo2_curves::pairing::MultiMillerLoop + Debug {} +pub trait MultiMillerLoop: pairing::MultiMillerLoop + Debug {} -impl MultiMillerLoop for M {} +impl MultiMillerLoop for M {} + +/// Trait for fields that can implement Poseidon hash +pub trait FieldExt: PrimeField + FromUniformBytes<64> + Ord {} + +impl + Ord> FieldExt for F {} /// Operations that could be done with field elements. pub trait FieldOps: @@ -54,7 +59,7 @@ pub fn batch_invert_and_mul(values: &mut [F], coeff: &F) { } let products = values .iter() - .scan(F::one(), |acc, value| { + .scan(F::ONE, |acc, value| { *acc *= value; Some(*acc) }) @@ -65,7 +70,7 @@ pub fn batch_invert_and_mul(values: &mut [F], coeff: &F) { * coeff; for (value, product) in - values.iter_mut().rev().zip(products.into_iter().rev().skip(1).chain(Some(F::one()))) + values.iter_mut().rev().zip(products.into_iter().rev().skip(1).chain(Some(F::ONE))) { let mut inv = all_product_inv * product; mem::swap(value, &mut inv); @@ -75,7 +80,7 @@ pub fn batch_invert_and_mul(values: &mut [F], coeff: &F) { /// Batch invert [`PrimeField`] elements. pub fn batch_invert(values: &mut [F]) { - batch_invert_and_mul(values, &F::one()) + batch_invert_and_mul(values, &F::ONE) } /// Root of unity of 2^k-sized multiplicative subgroup of [`PrimeField`] by @@ -88,7 +93,7 @@ pub fn batch_invert(values: &mut [F]) { pub fn root_of_unity(k: usize) -> F { assert!(k <= F::S as usize); - iter::successors(Some(F::root_of_unity()), |acc| Some(acc.square())) + iter::successors(Some(F::ROOT_OF_UNITY), |acc| Some(acc.square())) .take(F::S as usize - k + 1) .last() .unwrap() @@ -230,7 +235,7 @@ impl Fraction { /// Modulus of a [`PrimeField`] pub fn modulus() -> BigUint { - fe_to_big(-F::one()) + 1usize + fe_to_big(-F::ONE) + 1usize } /// Convert a [`BigUint`] into a [`PrimeField`] . @@ -286,7 +291,7 @@ pub fn fe_to_limbs(scalar: F) -> impl Iterator { - iter::successors(Some(F::one()), move |power| Some(scalar * power)) + iter::successors(Some(F::ONE), move |power| Some(scalar * power)) } /// Compute inner product of 2 slice of [`Field`]. diff --git a/snark-verifier/src/util/hash/poseidon.rs b/snark-verifier/src/util/hash/poseidon.rs index 1ff06ab9..e826ac52 100644 --- a/snark-verifier/src/util/hash/poseidon.rs +++ b/snark-verifier/src/util/hash/poseidon.rs @@ -1,9 +1,12 @@ #![allow(clippy::needless_range_loop)] // for clarity of matrix operations use crate::{ loader::{LoadedScalar, ScalarLoader}, - util::{arithmetic::FieldExt, Itertools}, + util::{ + arithmetic::{FieldExt, PrimeField}, + Itertools, + }, }; -use poseidon_circuit::poseidon::primitives::Spec as PoseidonSpec; // trait +use poseidon_rs::poseidon::primitives::Spec as PoseidonSpec; // trait use std::{iter, marker::PhantomData, mem}; #[cfg(test)] @@ -12,7 +15,7 @@ mod tests; // struct so we can use PoseidonSpec trait to generate round constants and MDS matrix #[derive(Debug)] pub struct Poseidon128Pow5Gen< - F: FieldExt, + F: PrimeField, const T: usize, const RATE: usize, const R_F: usize, @@ -23,7 +26,7 @@ pub struct Poseidon128Pow5Gen< } impl< - F: FieldExt, + F: PrimeField, const T: usize, const RATE: usize, const R_F: usize, @@ -57,7 +60,7 @@ impl< /// `OptimizedPoseidonSpec` holds construction parameters as well as constants that are used in /// permutation step. #[derive(Debug, Clone)] -pub struct OptimizedPoseidonSpec { +pub struct OptimizedPoseidonSpec { pub(crate) r_f: usize, pub(crate) mds_matrices: MDSMatrices, pub(crate) constants: OptimizedConstants, @@ -67,7 +70,7 @@ pub struct OptimizedPoseidonSpec /// full rounds has T sized constants there is a single constant for each /// partial round #[derive(Debug, Clone)] -pub struct OptimizedConstants { +pub struct OptimizedConstants { pub(crate) start: Vec<[F; T]>, pub(crate) partial: Vec, pub(crate) end: Vec<[F; T]>, @@ -80,7 +83,7 @@ pub(crate) type Mds = [[F; T]; T]; /// also called `pre_sparse_mds` and sparse matrices that enables us to reduce /// number of multiplications in apply MDS step #[derive(Debug, Clone)] -pub struct MDSMatrices { +pub struct MDSMatrices { pub(crate) mds: MDSMatrix, pub(crate) pre_sparse_mds: MDSMatrix, pub(crate) sparse_matrices: Vec>, @@ -89,18 +92,18 @@ pub struct MDSMatrices { /// `SparseMDSMatrix` are in `[row], [hat | identity]` form and used in linear /// layer of partial rounds instead of the original MDS #[derive(Debug, Clone)] -pub struct SparseMDSMatrix { +pub struct SparseMDSMatrix { pub(crate) row: [F; T], pub(crate) col_hat: [F; RATE], } /// `MDSMatrix` is applied to `State` to achive linear layer of Poseidon #[derive(Clone, Debug)] -pub struct MDSMatrix(pub(crate) Mds); +pub struct MDSMatrix(pub(crate) Mds); -impl MDSMatrix { +impl MDSMatrix { pub(crate) fn mul_vector(&self, v: &[F; T]) -> [F; T] { - let mut res = [F::zero(); T]; + let mut res = [F::ZERO; T]; for i in 0..T { for j in 0..T { res[i] += self.0[i][j] * v[j]; @@ -110,16 +113,16 @@ impl MDSMatrix { } fn identity() -> Mds { - let mut mds = [[F::zero(); T]; T]; + let mut mds = [[F::ZERO; T]; T]; for i in 0..T { - mds[i][i] = F::one(); + mds[i][i] = F::ONE; } mds } /// Multiplies two MDS matrices. Used in sparse matrix calculations fn mul(&self, other: &Self) -> Self { - let mut res = [[F::zero(); T]; T]; + let mut res = [[F::ZERO; T]; T]; for i in 0..T { for j in 0..T { for k in 0..T { @@ -131,7 +134,7 @@ impl MDSMatrix { } fn transpose(&self) -> Self { - let mut res = [[F::zero(); T]; T]; + let mut res = [[F::ZERO; T]; T]; for i in 0..T { for j in 0..T { res[i][j] = self.0[j][i]; @@ -141,11 +144,11 @@ impl MDSMatrix { } fn determinant(m: [[F; N]; N]) -> F { - let mut res = F::one(); + let mut res = F::ONE; let mut m = m; for i in 0..N { let mut pivot = i; - while m[pivot][i] == F::zero() { + while m[pivot][i] == F::ZERO { pivot += 1; assert!(pivot < N, "matrix is not invertible"); } @@ -196,7 +199,7 @@ impl MDSMatrix { let w = self.0.iter().skip(1).map(|row| row[0]).collect::>(); // m_hat is the `(t-1 * t-1)` right bottom sub-matrix of m := self.0 - let mut m_hat = [[F::zero(); RATE]; RATE]; + let mut m_hat = [[F::ZERO; RATE]; RATE]; for i in 0..RATE { for j in 0..RATE { m_hat[i][j] = self.0[i + 1][j + 1]; @@ -204,7 +207,7 @@ impl MDSMatrix { } // w_hat = m_hat^{-1} * w, where m_hat^{-1} is matrix inverse and * is matrix mult // we avoid computing m_hat^{-1} explicitly by using Cramer's rule: https://en.wikipedia.org/wiki/Cramer%27s_rule - let mut w_hat = [F::zero(); RATE]; + let mut w_hat = [F::ZERO; RATE]; let det = Self::determinant(m_hat); let det_inv = Option::::from(det.invert()).expect("matrix is not invertible"); for j in 0..RATE { @@ -225,9 +228,12 @@ impl MDSMatrix { } } -impl OptimizedPoseidonSpec { +impl OptimizedPoseidonSpec { /// Generate new spec with specific number of full and partial rounds. `SECURE_MDS` is usually 0, but may need to be specified because insecure matrices may sometimes be generated - pub fn new() -> Self { + pub fn new() -> Self + where + F: FieldExt, + { let (round_constants, mds, mds_inv) = Poseidon128Pow5Gen::::constants(); let mds = MDSMatrix(mds); @@ -254,7 +260,7 @@ impl OptimizedPoseidonSpec = vec![[F::zero(); T]; r_f_half]; + let mut constants_start: Vec<[F; T]> = vec![[F::ZERO; T]; r_f_half]; constants_start[0] = constants[0]; for (optimized, constants) in constants_start.iter_mut().skip(1).zip(constants.iter().skip(1)) @@ -264,7 +270,7 @@ impl OptimizedPoseidonSpec OptimizedPoseidonSpec = vec![[F::zero(); T]; r_f_half - 1]; + let mut constants_end: Vec<[F; T]> = vec![[F::ZERO; T]; r_f_half - 1]; for (optimized, constants) in constants_end.iter_mut().zip(constants.iter().skip(r_f_half + r_p + 1)) { @@ -320,20 +325,20 @@ impl OptimizedPoseidonSpec { +struct State { inner: [L; T], _marker: PhantomData, } // the transcript hash implementation is the one suggested in the original paper https://eprint.iacr.org/2019/458.pdf // another reference implementation is https://github.com/privacy-scaling-explorations/halo2wrong/tree/master/transcript/src -impl, const T: usize, const RATE: usize> State { +impl, const T: usize, const RATE: usize> State { fn new(inner: [L; T]) -> Self { Self { inner, _marker: PhantomData } } fn default(loader: &L::Loader) -> Self { - let mut default_state = [F::zero(); T]; + let mut default_state = [F::ZERO; T]; // from Section 4.2 of https://eprint.iacr.org/2019/458.pdf // • Variable-Input-Length Hashing. The capacity value is 2^64 + (o−1) where o the output length. // for our transcript use cases, o = 1 @@ -376,8 +381,8 @@ impl, const T: usize, const RATE: usize> State, const T: usize, const RATE: usize> State, const T: usize, const RATE: usize> State { +pub struct Poseidon { spec: OptimizedPoseidonSpec, default_state: State, state: State, buf: Vec, } -impl, const T: usize, const RATE: usize> Poseidon { +impl, const T: usize, const RATE: usize> Poseidon { /// Initialize a poseidon hasher. /// Generates a new spec with specific number of full and partial rounds. `SECURE_MDS` is usually 0, but may need to be specified because insecure matrices may sometimes be generated pub fn new( loader: &L::Loader, - ) -> Self { + ) -> Self + where + F: FieldExt, + { let default_state = State::default(loader); Self { spec: OptimizedPoseidonSpec::new::(), @@ -495,7 +503,7 @@ impl, const T: usize, const RATE: usize> Poseido self.state.sbox_full(constants); self.state.apply_mds(&mds); } - self.state.sbox_full(&[F::zero(); T]); + self.state.sbox_full(&[F::ZERO; T]); self.state.apply_mds(&mds); } } diff --git a/snark-verifier/src/util/hash/poseidon/tests.rs b/snark-verifier/src/util/hash/poseidon/tests.rs index cf4712bc..76793c91 100644 --- a/snark-verifier/src/util/hash/poseidon/tests.rs +++ b/snark-verifier/src/util/hash/poseidon/tests.rs @@ -47,7 +47,7 @@ fn test_poseidon_against_test_vectors() { hasher.state = State::new(state.try_into().unwrap()); hasher.permutation(&[(); RATE].map(|_| Fr::zero())); // avoid padding let state_0 = hasher.state.inner; - let expected = vec![ + let expected = [ "7853200120776062878684798364095072458815029376092732009249414926327459813530", "7142104613055408817911962100316808866448378443474503659992478482890339429929", "6549537674122432311777789598043107870002137484850126429160507761192163713804", @@ -71,7 +71,7 @@ fn test_poseidon_against_test_vectors() { hasher.state = State::new(state.try_into().unwrap()); hasher.permutation(&[(); RATE].map(|_| Fr::zero())); let state_0 = hasher.state.inner; - let expected = vec![ + let expected = [ "18821383157269793795438455681495246036402687001665670618754263018637548127333", "7817711165059374331357136443537800893307845083525445872661165200086166013245", "16733335996448830230979566039396561240864200624113062088822991822580465420551", diff --git a/snark-verifier/src/util/msm.rs b/snark-verifier/src/util/msm.rs index 8d18cdf8..fef53e59 100644 --- a/snark-verifier/src/util/msm.rs +++ b/snark-verifier/src/util/msm.rs @@ -71,7 +71,7 @@ where let gen = gen.map(|gen| self.bases.first().unwrap().loader().ec_point_load_const(&gen)); let pairs = iter::empty() .chain(self.constant.as_ref().map(|constant| (constant, gen.as_ref().unwrap()))) - .chain(self.scalars.iter().zip(self.bases.into_iter())) + .chain(self.scalars.iter().zip(self.bases)) .collect_vec(); L::multi_scalar_multiplication(&pairs) } diff --git a/snark-verifier/src/util/poly.rs b/snark-verifier/src/util/poly.rs index 17a065f9..9d688a4e 100644 --- a/snark-verifier/src/util/poly.rs +++ b/snark-verifier/src/util/poly.rs @@ -55,7 +55,7 @@ impl Polynomial { /// Returns evaluation at given `x`. pub fn evaluate(&self, x: F) -> F { let evaluate_serial = - |coeffs: &[F]| coeffs.iter().rev().fold(F::zero(), |acc, coeff| acc * x + coeff); + |coeffs: &[F]| coeffs.iter().rev().fold(F::ZERO, |acc, coeff| acc * x + coeff); #[cfg(feature = "parallel")] { @@ -68,7 +68,7 @@ impl Polynomial { } let chunk_size = Integer::div_ceil(&self.len(), &num_threads); - let mut results = vec![F::zero(); num_threads]; + let mut results = vec![F::ZERO; num_threads]; parallelize_iter( results.iter_mut().zip(self.0.chunks(chunk_size)).zip(powers(x.pow_vartime(&[ chunk_size as u64, @@ -78,7 +78,7 @@ impl Polynomial { ]))), |((result, coeffs), scalar)| *result = evaluate_serial(coeffs) * scalar, ); - results.iter().fold(F::zero(), |acc, result| acc + result) + results.iter().fold(F::ZERO, |acc, result| acc + result) } #[cfg(not(feature = "parallel"))] evaluate_serial(&self.0) @@ -133,10 +133,10 @@ impl Mul for Polynomial { type Output = Polynomial; fn mul(mut self, rhs: F) -> Polynomial { - if rhs == F::zero() { - return Polynomial::new(vec![F::zero(); self.len()]); + if rhs == F::ZERO { + return Polynomial::new(vec![F::ZERO; self.len()]); } - if rhs == F::one() { + if rhs == F::ONE { return self; } parallelize(&mut self.0, |(lhs, _)| { diff --git a/snark-verifier/src/verifier/plonk/proof.rs b/snark-verifier/src/verifier/plonk/proof.rs index 7adba7ac..a42a56ae 100644 --- a/snark-verifier/src/verifier/plonk/proof.rs +++ b/snark-verifier/src/verifier/plonk/proof.rs @@ -158,7 +158,7 @@ where .queries .iter() .map(|query| { - let shift = protocol.domain.rotate_scalar(C::Scalar::one(), query.rotation); + let shift = protocol.domain.rotate_scalar(C::Scalar::ONE, query.rotation); pcs::Query::new(query.poly, shift) }) .collect() diff --git a/snark-verifier/src/verifier/plonk/protocol.rs b/snark-verifier/src/verifier/plonk/protocol.rs index a3a84346..97f6f336 100644 --- a/snark-verifier/src/verifier/plonk/protocol.rs +++ b/snark-verifier/src/verifier/plonk/protocol.rs @@ -219,7 +219,7 @@ where let numer = zn_minus_one.clone() * &n_inv; let omegas = langranges .iter() - .map(|&i| loader.load_const(&domain.rotate_scalar(C::Scalar::one(), Rotation(i)))) + .map(|&i| loader.load_const(&domain.rotate_scalar(C::Scalar::ONE, Rotation(i)))) .collect_vec(); let lagrange_evals = omegas .iter() @@ -478,7 +478,7 @@ impl Sum for Expression { impl One for Expression { fn one() -> Self { - Expression::Constant(F::one()) + Expression::Constant(F::ONE) } } From f1d12e52dff42cd9784ac874587c3e563cf94d80 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 18 Aug 2023 09:00:27 -0600 Subject: [PATCH 46/73] [Feat] Universal verifier circuit (#26) * feat: add example with different vkey as private witness Same aggregation circuit, verifies different snarks with different vkeys (same standard plonk gate, but different selectors / copy constraints) * fix: save break points when generating agg circuit for first time (#23) * fix: save break points when generating agg circuit for first time * chore: add circuit files to gitignore * feat: halo2-lib universal verifier example * chore: cargo fix * feat: allow circuit size (number of rows) to be loaded as witness * chore: clippy fix * fix(n_as_witness): computation of shifts depends on `omega` `omega` which changes when `k` changes, so all shift computations need to be done as witness. Current implementation is likely not the most optimal. Instead of storing `shift` as `omega^i`, we store just `Rotation(i)`. We de-duplicate when possible using `BTreeMap` of `Rotation`. Note you must use `Rotation` instead of `F` for `BTreeMap` because the ordering of `omega^i` may change depending on `omega`. * fix: temp remove pow_var * add universal verifier range check test * chore: do not serialize domain_as_witness if none * Revert "fix: temp remove pow_var" This reverts commit 69f648e12a850a1d16235fc33acebfb5f8b2f290. * fix: halo2_lib example * test: halo2_lib with variable lookup table passes * Bump version to 0.1.3 --------- Co-authored-by: Roshan --- .gitignore | 4 + snark-verifier-sdk/Cargo.toml | 2 +- snark-verifier-sdk/benches/read_pk.rs | 3 +- snark-verifier-sdk/benches/standard_plonk.rs | 5 +- snark-verifier-sdk/examples/n_as_witness.rs | 188 ++++++++++++++++++ snark-verifier-sdk/examples/range_check.rs | 90 +++++++++ .../examples/vkey_as_witness.rs | 184 +++++++++++++++++ snark-verifier-sdk/src/halo2.rs | 34 ++-- snark-verifier-sdk/src/halo2/aggregation.rs | 152 ++++++++++++-- snark-verifier/Cargo.toml | 2 +- snark-verifier/examples/recursion.rs | 2 +- snark-verifier/src/loader.rs | 6 + snark-verifier/src/loader/evm/loader.rs | 4 + snark-verifier/src/loader/halo2/loader.rs | 8 + snark-verifier/src/loader/halo2/shim.rs | 19 ++ snark-verifier/src/loader/native.rs | 7 +- snark-verifier/src/pcs.rs | 24 ++- snark-verifier/src/pcs/ipa/multiopen/bgh19.rs | 90 +++++---- .../src/pcs/kzg/multiopen/bdfg21.rs | 77 ++++--- snark-verifier/src/pcs/kzg/multiopen/gwc19.rs | 35 ++-- snark-verifier/src/system/halo2.rs | 1 + snark-verifier/src/verifier/plonk.rs | 17 +- snark-verifier/src/verifier/plonk/proof.rs | 43 ++-- snark-verifier/src/verifier/plonk/protocol.rs | 94 +++++++-- 24 files changed, 926 insertions(+), 165 deletions(-) create mode 100644 snark-verifier-sdk/examples/n_as_witness.rs create mode 100644 snark-verifier-sdk/examples/range_check.rs create mode 100644 snark-verifier-sdk/examples/vkey_as_witness.rs diff --git a/.gitignore b/.gitignore index 829691c6..ec2971fb 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ /target testdata +Cargo.lock +params +agg.pk +break_points.json \ No newline at end of file diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index adf30bec..fa423daf 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier-sdk" -version = "0.1.2" +version = "0.1.3" edition = "2021" [dependencies] diff --git a/snark-verifier-sdk/benches/read_pk.rs b/snark-verifier-sdk/benches/read_pk.rs index 55154a2e..f87f52c8 100644 --- a/snark-verifier-sdk/benches/read_pk.rs +++ b/snark-verifier-sdk/benches/read_pk.rs @@ -9,7 +9,7 @@ use halo2_proofs::{halo2curves::bn256::Bn256, poly::kzg::commitment::ParamsKZG}; use pprof::criterion::{Output, PProfProfiler}; use rand::rngs::OsRng; -use snark_verifier_sdk::halo2::aggregation::AggregationConfigParams; +use snark_verifier_sdk::halo2::aggregation::{AggregationConfigParams, VerifierUniversality}; use snark_verifier_sdk::{ gen_pk, halo2::{aggregation::AggregationCircuit, gen_snark_shplonk}, @@ -190,6 +190,7 @@ fn bench(c: &mut Criterion) { None, ¶ms, snarks, + VerifierUniversality::None, ); std::fs::remove_file("examples/agg.pk").ok(); diff --git a/snark-verifier-sdk/benches/standard_plonk.rs b/snark-verifier-sdk/benches/standard_plonk.rs index eecb7140..873f77cb 100644 --- a/snark-verifier-sdk/benches/standard_plonk.rs +++ b/snark-verifier-sdk/benches/standard_plonk.rs @@ -12,7 +12,7 @@ use halo2_proofs::{ use pprof::criterion::{Output, PProfProfiler}; use rand::rngs::OsRng; use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; -use snark_verifier_sdk::halo2::aggregation::AggregationConfigParams; +use snark_verifier_sdk::halo2::aggregation::{AggregationConfigParams, VerifierUniversality}; use snark_verifier_sdk::{ gen_pk, halo2::{aggregation::AggregationCircuit, gen_proof_shplonk, gen_snark_shplonk}, @@ -193,6 +193,7 @@ fn bench(c: &mut Criterion) { None, ¶ms, snarks.clone(), + VerifierUniversality::None, ); let start0 = start_timer!(|| "gen vk & pk"); @@ -213,6 +214,7 @@ fn bench(c: &mut Criterion) { Some(break_points.clone()), params, snarks.clone(), + VerifierUniversality::None, ); let instances = agg_circuit.instances(); gen_proof_shplonk(params, pk, agg_circuit, instances, None) @@ -230,6 +232,7 @@ fn bench(c: &mut Criterion) { Some(break_points), ¶ms, snarks.clone(), + VerifierUniversality::None, ); let num_instances = agg_circuit.num_instance(); let instances = agg_circuit.instances(); diff --git a/snark-verifier-sdk/examples/n_as_witness.rs b/snark-verifier-sdk/examples/n_as_witness.rs new file mode 100644 index 00000000..3ee25f23 --- /dev/null +++ b/snark-verifier-sdk/examples/n_as_witness.rs @@ -0,0 +1,188 @@ +use halo2_base::gates::builder::CircuitBuilderStage; +use halo2_base::halo2_proofs; +use halo2_base::halo2_proofs::arithmetic::Field; +use halo2_base::halo2_proofs::halo2curves::bn256::Fr; +use halo2_base::halo2_proofs::poly::commitment::Params; +use halo2_base::utils::fs::gen_srs; +use halo2_proofs::halo2curves as halo2_curves; + +use rand::rngs::StdRng; +use rand::SeedableRng; +use snark_verifier_sdk::halo2::aggregation::{AggregationConfigParams, VerifierUniversality}; +use snark_verifier_sdk::SHPLONK; +use snark_verifier_sdk::{ + gen_pk, + halo2::{aggregation::AggregationCircuit, gen_snark_shplonk}, + Snark, +}; + +mod application { + use super::halo2_curves::bn256::Fr; + use super::halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance}, + poly::Rotation, + }; + + use snark_verifier_sdk::CircuitExt; + + #[derive(Clone, Copy)] + pub struct StandardPlonkConfig { + a: Column, + b: Column, + c: Column, + q_a: Column, + q_b: Column, + q_c: Column, + q_ab: Column, + constant: Column, + #[allow(dead_code)] + instance: Column, + } + + impl StandardPlonkConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { + let [a, b, c] = [(); 3].map(|_| meta.advice_column()); + let [q_a, q_b, q_c, q_ab, constant] = [(); 5].map(|_| meta.fixed_column()); + let instance = meta.instance_column(); + + [a, b, c].map(|column| meta.enable_equality(column)); + + meta.create_gate( + "q_a·a + q_b·b + q_c·c + q_ab·a·b + constant + instance = 0", + |meta| { + let [a, b, c] = + [a, b, c].map(|column| meta.query_advice(column, Rotation::cur())); + let [q_a, q_b, q_c, q_ab, constant] = [q_a, q_b, q_c, q_ab, constant] + .map(|column| meta.query_fixed(column, Rotation::cur())); + let instance = meta.query_instance(instance, Rotation::cur()); + Some( + q_a * a.clone() + + q_b * b.clone() + + q_c * c + + q_ab * a * b + + constant + + instance, + ) + }, + ); + + StandardPlonkConfig { a, b, c, q_a, q_b, q_c, q_ab, constant, instance } + } + } + + #[derive(Clone)] + pub struct StandardPlonk(pub Fr, pub usize); + + impl CircuitExt for StandardPlonk { + fn num_instance(&self) -> Vec { + vec![1] + } + + fn instances(&self) -> Vec> { + vec![vec![self.0]] + } + } + + impl Circuit for StandardPlonk { + type Config = StandardPlonkConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self(Fr::zero(), self.1) + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + meta.set_minimum_degree(4); + StandardPlonkConfig::configure(meta) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + layouter.assign_region( + || "", + |mut region| { + region.assign_advice(config.a, 0, Value::known(self.0)); + region.assign_fixed(config.q_a, 0, -Fr::one()); + region.assign_advice(config.a, 1, Value::known(-Fr::from(5u64))); + for (idx, column) in (1..).zip([ + config.q_a, + config.q_b, + config.q_c, + config.q_ab, + config.constant, + ]) { + region.assign_fixed(column, 1, Fr::from(idx as u64)); + } + let a = region.assign_advice(config.a, 2, Value::known(Fr::one())); + a.copy_advice(&mut region, config.b, 3); + a.copy_advice(&mut region, config.c, 4); + + // assuming <= 10 blinding factors + // fill in most of circuit with a computation + let n = self.1; + for offset in 5..n - 10 { + region.assign_advice(config.a, offset, Value::known(-Fr::from(5u64))); + for (idx, column) in (1..).zip([ + config.q_a, + config.q_b, + config.q_c, + config.q_ab, + config.constant, + ]) { + region.assign_fixed(column, offset, Fr::from(idx as u64)); + } + } + + Ok(()) + }, + ) + } + } +} + +fn gen_application_snark(k: u32) -> Snark { + let rng = StdRng::seed_from_u64(0); + let params = gen_srs(k); + let circuit = application::StandardPlonk(Fr::random(rng), params.n() as usize); + + let pk = gen_pk(¶ms, &circuit, None); + gen_snark_shplonk(¶ms, &pk, circuit, None::<&str>) +} + +fn main() { + let dummy_snark = gen_application_snark(8); + + let k = 15u32; + let params = gen_srs(k); + let lookup_bits = k as usize - 1; + let mut agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Keygen, + AggregationConfigParams { degree: k, lookup_bits, ..Default::default() }, + None, + ¶ms, + vec![dummy_snark], + VerifierUniversality::Full, + ); + let agg_config = agg_circuit.config(Some(10)); + + let pk = gen_pk(¶ms, &agg_circuit, None); + let break_points = agg_circuit.break_points(); + + let snarks = [8, 12, 15, 20].map(|k| (k, gen_application_snark(k))); + for (k, snark) in snarks { + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + agg_config, + Some(break_points.clone()), + ¶ms, + vec![snark], + VerifierUniversality::Full, + ); + let _snark = gen_snark_shplonk(¶ms, &pk, agg_circuit, None::<&str>); + println!("snark with k = {k} success"); + } +} diff --git a/snark-verifier-sdk/examples/range_check.rs b/snark-verifier-sdk/examples/range_check.rs new file mode 100644 index 00000000..c9200df7 --- /dev/null +++ b/snark-verifier-sdk/examples/range_check.rs @@ -0,0 +1,90 @@ +use ark_std::{end_timer, start_timer}; +use halo2_base::gates::builder::{ + BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, RangeWithInstanceCircuitBuilder, +}; +use halo2_base::gates::flex_gate::GateStrategy; +use halo2_base::halo2_proofs::halo2curves::bn256::Fr; +use halo2_base::halo2_proofs::plonk::Circuit; +use halo2_base::safe_types::{GateInstructions, RangeChip, RangeInstructions}; +use halo2_base::utils::fs::gen_srs; + +use itertools::Itertools; +use snark_verifier_sdk::halo2::aggregation::{AggregationConfigParams, VerifierUniversality}; +use snark_verifier_sdk::SHPLONK; +use snark_verifier_sdk::{ + gen_pk, + halo2::{aggregation::AggregationCircuit, gen_snark_shplonk}, + Snark, +}; + +fn generate_circuit(k: u32) -> Snark { + let mut builder = GateThreadBuilder::new(false); + let ctx = builder.main(0); + let lookup_bits = k as usize - 1; + let range = RangeChip::::default(lookup_bits); + + let x = ctx.load_witness(Fr::from(14)); + range.range_check(ctx, x, 2 * lookup_bits + 1); + range.gate().add(ctx, x, x); + + let circuit = RangeWithInstanceCircuitBuilder::::keygen( + builder.clone(), + BaseConfigParams { + strategy: GateStrategy::Vertical, + k: k as usize, + num_advice_per_phase: vec![1], + num_lookup_advice_per_phase: vec![1], + num_fixed: 1, + lookup_bits: Some(lookup_bits), + }, + vec![], + ); + let params = gen_srs(k); + + let pk = gen_pk(¶ms, &circuit, None); + let breakpoints = circuit.break_points(); + + let circuit = RangeWithInstanceCircuitBuilder::::prover( + builder.clone(), + circuit.params(), + breakpoints, + vec![], + ); + gen_snark_shplonk(¶ms, &pk, circuit, None::<&str>) +} + +fn main() { + let dummy_snark = generate_circuit(13); + + let k = 14u32; + let lookup_bits = k as usize - 1; + let params = gen_srs(k); + let mut agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Keygen, + AggregationConfigParams { degree: k, lookup_bits, ..Default::default() }, + None, + ¶ms, + vec![dummy_snark], + VerifierUniversality::Full, + ); + let agg_config = agg_circuit.config(Some(10)); + + let start0 = start_timer!(|| "gen vk & pk"); + let pk = gen_pk(¶ms, &agg_circuit, None); + end_timer!(start0); + let break_points = agg_circuit.break_points(); + + let snarks = (14..17).map(generate_circuit).collect_vec(); + for (i, snark) in snarks.into_iter().enumerate() { + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + agg_config, + Some(break_points.clone()), + ¶ms, + vec![snark], + VerifierUniversality::Full, + ); + let _snark = gen_snark_shplonk(¶ms, &pk, agg_circuit, None::<&str>); + println!("snark {i} success"); + } +} diff --git a/snark-verifier-sdk/examples/vkey_as_witness.rs b/snark-verifier-sdk/examples/vkey_as_witness.rs new file mode 100644 index 00000000..a0eb30d2 --- /dev/null +++ b/snark-verifier-sdk/examples/vkey_as_witness.rs @@ -0,0 +1,184 @@ +use application::ComputeFlag; + +use halo2_base::gates::builder::CircuitBuilderStage; +use halo2_base::halo2_proofs; +use halo2_base::halo2_proofs::arithmetic::Field; +use halo2_base::halo2_proofs::halo2curves::bn256::Fr; +use halo2_base::utils::fs::gen_srs; +use halo2_proofs::halo2curves as halo2_curves; + +use halo2_proofs::{halo2curves::bn256::Bn256, poly::kzg::commitment::ParamsKZG}; +use rand::rngs::OsRng; +use snark_verifier_sdk::halo2::aggregation::{AggregationConfigParams, VerifierUniversality}; +use snark_verifier_sdk::SHPLONK; +use snark_verifier_sdk::{ + gen_pk, + halo2::{aggregation::AggregationCircuit, gen_snark_shplonk}, + Snark, +}; + +mod application { + use super::halo2_curves::bn256::Fr; + use super::halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance}, + poly::Rotation, + }; + + use snark_verifier_sdk::CircuitExt; + + #[derive(Clone, Copy)] + pub struct StandardPlonkConfig { + a: Column, + b: Column, + c: Column, + q_a: Column, + q_b: Column, + q_c: Column, + q_ab: Column, + constant: Column, + #[allow(dead_code)] + instance: Column, + } + + impl StandardPlonkConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { + let [a, b, c] = [(); 3].map(|_| meta.advice_column()); + let [q_a, q_b, q_c, q_ab, constant] = [(); 5].map(|_| meta.fixed_column()); + let instance = meta.instance_column(); + + [a, b, c].map(|column| meta.enable_equality(column)); + + meta.create_gate( + "q_a·a + q_b·b + q_c·c + q_ab·a·b + constant + instance = 0", + |meta| { + let [a, b, c] = + [a, b, c].map(|column| meta.query_advice(column, Rotation::cur())); + let [q_a, q_b, q_c, q_ab, constant] = [q_a, q_b, q_c, q_ab, constant] + .map(|column| meta.query_fixed(column, Rotation::cur())); + let instance = meta.query_instance(instance, Rotation::cur()); + Some( + q_a * a.clone() + + q_b * b.clone() + + q_c * c + + q_ab * a * b + + constant + + instance, + ) + }, + ); + + StandardPlonkConfig { a, b, c, q_a, q_b, q_c, q_ab, constant, instance } + } + } + + #[derive(Clone, Copy, PartialEq, Eq)] + pub enum ComputeFlag { + All, + SkipFixed, + SkipCopy, + } + + #[derive(Clone)] + pub struct StandardPlonk(pub Fr, pub ComputeFlag); + + impl CircuitExt for StandardPlonk { + fn num_instance(&self) -> Vec { + vec![1] + } + + fn instances(&self) -> Vec> { + vec![vec![self.0]] + } + } + + impl Circuit for StandardPlonk { + type Config = StandardPlonkConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self(Fr::zero(), self.1) + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + meta.set_minimum_degree(4); + StandardPlonkConfig::configure(meta) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + layouter.assign_region( + || "", + |mut region| { + region.assign_advice(config.a, 0, Value::known(self.0)); + region.assign_fixed(config.q_a, 0, -Fr::one()); + region.assign_advice(config.a, 1, Value::known(-Fr::from(5u64))); + if self.1 != ComputeFlag::SkipFixed { + for (idx, column) in (1..).zip([ + config.q_a, + config.q_b, + config.q_c, + config.q_ab, + config.constant, + ]) { + region.assign_fixed(column, 1, Fr::from(idx as u64)); + } + } + let a = region.assign_advice(config.a, 2, Value::known(Fr::one())); + if self.1 != ComputeFlag::SkipCopy { + a.copy_advice(&mut region, config.b, 3); + a.copy_advice(&mut region, config.c, 4); + } + + Ok(()) + }, + ) + } + } +} + +fn gen_application_snark(params: &ParamsKZG, flag: ComputeFlag) -> Snark { + let circuit = application::StandardPlonk(Fr::random(OsRng), flag); + + let pk = gen_pk(params, &circuit, None); + gen_snark_shplonk(params, &pk, circuit, None::<&str>) +} + +fn main() { + let params_app = gen_srs(8); + let dummy_snark = gen_application_snark(¶ms_app, ComputeFlag::All); + + let k = 15u32; + let params = gen_srs(k); + let lookup_bits = k as usize - 1; + let mut agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Keygen, + AggregationConfigParams { degree: k, lookup_bits, ..Default::default() }, + None, + ¶ms, + vec![dummy_snark], + VerifierUniversality::PreprocessedAsWitness, + ); + let agg_config = agg_circuit.config(Some(10)); + + let pk = gen_pk(¶ms, &agg_circuit, None); + let break_points = agg_circuit.break_points(); + + let snarks = [ComputeFlag::All, ComputeFlag::SkipFixed, ComputeFlag::SkipCopy] + .map(|flag| gen_application_snark(¶ms_app, flag)); + for (i, snark) in snarks.into_iter().enumerate() { + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + agg_config, + Some(break_points.clone()), + ¶ms, + vec![snark], + VerifierUniversality::PreprocessedAsWitness, + ); + let _snark = gen_snark_shplonk(¶ms, &pk, agg_circuit, None::<&str>); + println!("snark {i} success"); + } +} diff --git a/snark-verifier-sdk/src/halo2.rs b/snark-verifier-sdk/src/halo2.rs index b0710230..06d5e622 100644 --- a/snark-verifier-sdk/src/halo2.rs +++ b/snark-verifier-sdk/src/halo2.rs @@ -35,6 +35,7 @@ use snark_verifier::{ AccumulationScheme, PolynomialCommitmentScheme, Query, }, system::halo2::{compile, Config}, + util::arithmetic::Rotation, util::transcript::TranscriptWrite, verifier::plonk::PlonkProof, }; @@ -122,20 +123,25 @@ where end_timer!(proof_time); // validate proof before caching - assert!({ - let mut transcript_read = - PoseidonTranscript::::from_spec(&proof[..], POSEIDON_SPEC.clone()); - VerificationStrategy::<_, V>::finalize( - verify_proof::<_, V, _, _, _>( - params.verifier_params(), - pk.get_vk(), - AccumulatorStrategy::new(params.verifier_params()), - &[instances.as_slice()], - &mut transcript_read, + assert!( + { + let mut transcript_read = PoseidonTranscript::::from_spec( + &proof[..], + POSEIDON_SPEC.clone(), + ); + VerificationStrategy::<_, V>::finalize( + verify_proof::<_, V, _, _, _>( + params.verifier_params(), + pk.get_vk(), + AccumulatorStrategy::new(params.verifier_params()), + &[instances.as_slice()], + &mut transcript_read, + ) + .unwrap(), ) - .unwrap(), - ) - }); + }, + "SNARK proof failed to verify" + ); if let Some((instance_path, proof_path)) = path { write_instances(&instances, instance_path); @@ -286,7 +292,7 @@ where NativeLoader, Accumulator = KzgAccumulator, VerifyingKey = KzgAsVerifyingKey, - > + CostEstimation>>, + > + CostEstimation>>, { struct CsProxy(PhantomData<(F, C)>); diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 2d093f7b..0063a599 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -43,6 +43,37 @@ pub type Svk = KzgSuccinctVerifyingKey; pub type BaseFieldEccChip<'chip> = halo2_ecc::ecc::BaseFieldEccChip<'chip, G1Affine>; pub type Halo2Loader<'chip> = loader::halo2::Halo2Loader>; +pub struct SnarkAggregationWitness<'a> { + pub previous_instances: Vec>>, + pub accumulator: KzgAccumulator>>, + /// This returns the assigned `preprocessed` and `transcript_initial_state` values as a vector of assigned values, one for each aggregated snark. + /// These can then be exposed as public instances. + /// + /// This is only useful if preprocessed digest is loaded as witness (i.e., `preprocessed_as_witness` is true in `aggregate`), so we set it to `None` otherwise. + pub preprocessed_digests: Option>>>, +} + +/// Different possible stages of universality the aggregation circuit can support +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum VerifierUniversality { + /// Default: verifier is specific to a single circuit + None, + /// Preprocessed digest (commitments to fixed columns) is loaded as witness + PreprocessedAsWitness, + /// Preprocessed as witness and number of rows in the circuit `n` loaded as witness + Full, +} + +impl VerifierUniversality { + pub fn preprocessed_as_witness(&self) -> bool { + self != &VerifierUniversality::None + } + + pub fn n_as_witness(&self) -> bool { + self == &VerifierUniversality::Full + } +} + #[allow(clippy::type_complexity)] /// Core function used in `synthesize` to aggregate multiple `snarks`. /// @@ -50,6 +81,9 @@ pub type Halo2Loader<'chip> = loader::halo2::Halo2Loader( @@ -57,7 +91,8 @@ pub fn aggregate<'a, AS>( loader: &Rc>, snarks: &[Snark], as_proof: &[u8], -) -> (Vec>>, KzgAccumulator>>) + universality: VerifierUniversality, +) -> SnarkAggregationWitness<'a> where AS: PolynomialCommitmentScheme< G1Affine, @@ -82,6 +117,7 @@ where }; let mut previous_instances = Vec::with_capacity(snarks.len()); + let mut preprocessed_digests = Vec::with_capacity(snarks.len()); // to avoid re-loading the spec each time, we create one transcript and clear the stream let mut transcript = PoseidonTranscript::>, &[u8]>::from_spec( loader, @@ -89,10 +125,42 @@ where POSEIDON_SPEC.clone(), ); + let preprocessed_as_witness = universality.preprocessed_as_witness(); let mut accumulators = snarks .iter() - .flat_map(|snark| { - let protocol = snark.protocol.loaded(loader); + .flat_map(|snark: &Snark| { + let protocol = if preprocessed_as_witness { + // always load `domain.n` as witness if vkey is witness + snark.protocol.loaded_preprocessed_as_witness(loader, universality.n_as_witness()) + } else { + snark.protocol.loaded(loader) + }; + let inputs = protocol + .preprocessed + .iter() + .flat_map(|preprocessed| { + let assigned = preprocessed.assigned(); + [assigned.x(), assigned.y()] + .into_iter() + .flat_map(|coordinate| coordinate.limbs().to_vec()) + .collect_vec() + }) + .chain( + protocol.transcript_initial_state.clone().map(|scalar| scalar.into_assigned()), + ) + .chain( + protocol + .domain_as_witness + .as_ref() + .map(|domain| domain.n.clone().into_assigned()), + ) // If `n` is witness, add it as part of input + .chain( + protocol + .domain_as_witness + .as_ref() + .map(|domain| domain.gen.clone().into_assigned()), + ) // If `n` is witness, add the generator of the order `n` subgroup as part of input + .collect_vec(); let instances = assign_instances(&snark.instances); // read the transcript and perform Fiat-Shamir @@ -111,6 +179,7 @@ where previous_instances.push( instances.into_iter().flatten().map(|scalar| scalar.into_assigned()).collect(), ); + preprocessed_digests.push(inputs); accumulator }) @@ -129,8 +198,9 @@ where } else { accumulators.pop().unwrap() }; + let preprocessed_digests = preprocessed_as_witness.then_some(preprocessed_digests); - (previous_instances, accumulator) + SnarkAggregationWitness { previous_instances, accumulator, preprocessed_digests } } /// Same as `FlexGateConfigParams` except we assume a single Phase and default 'Vertical' strategy. @@ -187,6 +257,14 @@ impl TryFrom<&BaseConfigParams> for AggregationConfigParams { } } +impl TryFrom for AggregationConfigParams { + type Error = &'static str; + + fn try_from(value: BaseConfigParams) -> Result { + Self::try_from(&value) + } +} + /// Holds virtual contexts for the cells used to verify a collection of snarks #[derive(Clone, Debug)] pub struct AggregationCtxBuilder { @@ -196,6 +274,11 @@ pub struct AggregationCtxBuilder { pub accumulator: Vec>, // the public instances from previous snarks that were aggregated pub previous_instances: Vec>>, + /// This returns the assigned `preprocessed_digest` (vkey), optional `transcript_initial_state`, `domain.n` (optional), and `omega` (optional) values as a vector of assigned values, one for each aggregated snark. + /// These can then be exposed as public instances. + /// + /// This is only useful if preprocessed digest is loaded as witness (i.e., `universality != None`), so we set it to `None` if `universality == None`. + pub preprocessed_digests: Option>>>, } #[derive(Clone, Debug)] @@ -204,6 +287,11 @@ pub struct AggregationCircuit { // the public instances from previous snarks that were aggregated, now collected as PRIVATE assigned values // the user can optionally append these to `inner.assigned_instances` to expose them pub previous_instances: Vec>>, + /// This returns the assigned `preprocessed_digest` (vkey), optional `transcript_initial_state`, `domain.n` (optional), and `omega` (optional) values as a vector of assigned values, one for each aggregated snark. + /// These can then be exposed as public instances. + /// + /// This is only useful if preprocessed digest is loaded as witness (i.e., `universality != None`), so we set it to `None` if `universality == None`. + pub preprocessed_digests: Option>>>, // accumulation scheme proof, private input // pub as_proof: Vec, } @@ -236,13 +324,21 @@ impl AggregationCtxBuilder { /// /// Also returns the limbs of the pair of elliptic curve points, referred to as the `accumulator`, that need to be verified in a final pairing check. /// - /// Warning: will fail silently if `snarks` were created using a different multi-open scheme than `AS` + /// # Universality + /// - If `universality` is not `None`, then the verifying keys of each snark in `snarks` is loaded as a witness in the circuit. + /// - Moreover, if `universality` is `Full`, then the number of rows `n` of each snark in `snarks` is also loaded as a witness. In this case the generator `omega` of the order `n` multiplicative subgroup of `F` is also loaded as a witness. + /// - By default, these witnesses are _private_ and returned in `self.preprocessed_ + /// - The user can optionally modify the circuit after calling this function to add more instances to `assigned_instances` to expose. + /// + /// # Warning + /// Will fail silently if `snarks` were created using a different multi-open scheme than `AS` /// where `AS` can be either [`crate::SHPLONK`] or [`crate::GWC`] (for original PLONK multi-open scheme) pub fn new( witness_gen_only: bool, lookup_bits: usize, params: &ParamsKZG, snarks: impl IntoIterator, + universality: VerifierUniversality, ) -> Self where AS: for<'a> Halo2KzgAccumulationScheme<'a>, @@ -289,8 +385,8 @@ impl AggregationCtxBuilder { let ecc_chip = BaseFieldEccChip::new(&fp_chip); let loader = Halo2Loader::new(ecc_chip, builder); - let (previous_instances, accumulator) = - aggregate::(&svk, &loader, &snarks, as_proof.as_slice()); + let SnarkAggregationWitness { previous_instances, accumulator, preprocessed_digests } = + aggregate::(&svk, &loader, &snarks, as_proof.as_slice(), universality); let lhs = accumulator.lhs.assigned(); let rhs = accumulator.rhs.assigned(); let accumulator = lhs @@ -314,7 +410,7 @@ impl AggregationCtxBuilder { } let builder = loader.take_ctx(); - Self { builder, accumulator, previous_instances } + Self { builder, accumulator, previous_instances, preprocessed_digests } } } @@ -322,6 +418,8 @@ impl AggregationCircuit { /// Given snarks, this creates a circuit and runs the `GateThreadBuilder` to verify all the snarks. /// By default, the returned circuit has public instances equal to the limbs of the pair of elliptic curve points, referred to as the `accumulator`, that need to be verified in a final pairing check. /// + /// See [`AggregationCtxBuilder`] for more details. + /// /// The user can optionally modify the circuit after calling this function to add more instances to `assigned_instances` to expose. /// /// Warning: will fail silently if `snarks` were created using a different multi-open scheme than `AS` @@ -332,17 +430,23 @@ impl AggregationCircuit { break_points: Option, params: &ParamsKZG, snarks: impl IntoIterator, + universality: VerifierUniversality, ) -> Self where AS: for<'a> Halo2KzgAccumulationScheme<'a>, { - let AggregationCtxBuilder { builder, accumulator, previous_instances } = - AggregationCtxBuilder::new::( - stage == CircuitBuilderStage::Prover, - agg_config.lookup_bits, - params, - snarks, - ); + let AggregationCtxBuilder { + builder, + accumulator, + previous_instances, + preprocessed_digests, + } = AggregationCtxBuilder::new::( + stage == CircuitBuilderStage::Prover, + agg_config.lookup_bits, + params, + snarks, + universality, + ); let inner = RangeWithInstanceCircuitBuilder::from_stage( stage, builder, @@ -350,7 +454,7 @@ impl AggregationCircuit { break_points, accumulator, ); - Self { inner, previous_instances } + Self { inner, previous_instances, preprocessed_digests } } pub fn public( @@ -364,7 +468,14 @@ impl AggregationCircuit { where AS: for<'a> Halo2KzgAccumulationScheme<'a>, { - let mut private = Self::new::(stage, agg_config, break_points, params, snarks); + let mut private = Self::new::( + stage, + agg_config, + break_points, + params, + snarks, + VerifierUniversality::None, + ); private.expose_previous_instances(has_prev_accumulator); private } @@ -380,11 +491,8 @@ impl AggregationCircuit { } /// Auto-configure the circuit and change the circuit's internal configuration parameters. - pub fn config(&mut self, k: u32, minimum_rows: Option) -> BaseConfigParams { - let mut new_config = self.inner.circuit.0.builder.borrow().config(k as usize, minimum_rows); - new_config.lookup_bits = self.inner.circuit.0.config_params.lookup_bits; - self.inner.circuit.0.config_params = new_config.clone(); - new_config + pub fn config(&mut self, minimum_rows: Option) -> AggregationConfigParams { + self.inner.config(minimum_rows).try_into().unwrap() } pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 5606df37..ebbf283b 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier" -version = "0.1.2" +version = "0.1.3" edition = "2021" [dependencies] diff --git a/snark-verifier/examples/recursion.rs b/snark-verifier/examples/recursion.rs index b469a51a..9c9b169a 100644 --- a/snark-verifier/examples/recursion.rs +++ b/snark-verifier/examples/recursion.rs @@ -373,7 +373,7 @@ mod recursion { ) -> (Vec>>, Vec>>>) { let protocol = if let Some(preprocessed_digest) = preprocessed_digest { let preprocessed_digest = loader.scalar_from_assigned(preprocessed_digest); - let protocol = snark.protocol.loaded_preprocessed_as_witness(loader); + let protocol = snark.protocol.loaded_preprocessed_as_witness(loader, false); let inputs = protocol .preprocessed .iter() diff --git a/snark-verifier/src/loader.rs b/snark-verifier/src/loader.rs index a3637f08..26450e1a 100644 --- a/snark-verifier/src/loader.rs +++ b/snark-verifier/src/loader.rs @@ -67,6 +67,12 @@ pub trait LoadedScalar: Clone + Debug + PartialEq + FieldOps { acc } + /// Returns power to exponent, where exponent is also [`LoadedScalar`]. + /// If `Loader` is for Halo2, then `exp` must have at most `exp_max_bits` bits (otherwise constraints will fail). + /// + /// Currently **unimplemented** for EvmLoader + fn pow_var(&self, exp: &Self, exp_max_bits: usize) -> Self; + /// Returns powers up to exponent `n-1`. fn powers(&self, n: usize) -> Vec { iter::once(self.loader().load_one()) diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index bfb37c8c..ba304f2b 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -632,6 +632,10 @@ impl> LoadedScalar for Scalar { fn loader(&self) -> &Self::Loader { &self.loader } + + fn pow_var(&self, _exp: &Self, _exp_max_bits: usize) -> Self { + todo!() + } } impl EcPointLoader for Rc diff --git a/snark-verifier/src/loader/halo2/loader.rs b/snark-verifier/src/loader/halo2/loader.rs index 105972c0..f8e1da7d 100644 --- a/snark-verifier/src/loader/halo2/loader.rs +++ b/snark-verifier/src/loader/halo2/loader.rs @@ -306,6 +306,14 @@ impl> LoadedScalar for Sc fn loader(&self) -> &Self::Loader { &self.loader } + + fn pow_var(&self, exp: &Self, max_bits: usize) -> Self { + let loader = self.loader(); + let base = self.clone().into_assigned(); + let exp = exp.clone().into_assigned(); + let res = loader.scalar_chip().pow_var(&mut loader.ctx_mut(), &base, &exp, max_bits); + loader.scalar_from_assigned(res) + } } impl> Debug for Scalar { diff --git a/snark-verifier/src/loader/halo2/shim.rs b/snark-verifier/src/loader/halo2/shim.rs index 9d010d2b..49bbad41 100644 --- a/snark-verifier/src/loader/halo2/shim.rs +++ b/snark-verifier/src/loader/halo2/shim.rs @@ -65,6 +65,15 @@ pub trait IntegerInstructions: Clone + Debug { lhs: &Self::AssignedInteger, rhs: &Self::AssignedInteger, ); + + /// Returns `base^exponent` and constrains that `exponent` has at most `max_bits` bits. + fn pow_var( + &self, + ctx: &mut Self::Context, + base: &Self::AssignedInteger, + exponent: &Self::AssignedInteger, + max_bits: usize, + ) -> Self::AssignedInteger; } /// Instructions to handle elliptic curve point operations. @@ -233,6 +242,16 @@ mod halo2_lib { ) { ctx.main(0).constrain_equal(a, b); } + + fn pow_var( + &self, + ctx: &mut Self::Context, + base: &Self::AssignedInteger, + exponent: &Self::AssignedInteger, + max_bits: usize, + ) -> Self::AssignedInteger { + GateInstructions::pow_var(self, ctx.main(0), *base, *exponent, max_bits) + } } impl<'chip, C: CurveAffineExt> EccInstructions for BaseFieldEccChip<'chip, C> diff --git a/snark-verifier/src/loader/native.rs b/snark-verifier/src/loader/native.rs index 783aaa89..a9aa86ff 100644 --- a/snark-verifier/src/loader/native.rs +++ b/snark-verifier/src/loader/native.rs @@ -2,7 +2,7 @@ use crate::{ loader::{EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader}, - util::arithmetic::{Curve, CurveAffine, FieldOps, PrimeField}, + util::arithmetic::{fe_to_big, Curve, CurveAffine, FieldOps, PrimeField}, Error, }; use lazy_static::lazy_static; @@ -38,6 +38,11 @@ impl LoadedScalar for F { fn loader(&self) -> &NativeLoader { &LOADER } + + fn pow_var(&self, exp: &Self, _: usize) -> Self { + let exp = fe_to_big(*exp).to_u64_digits(); + self.pow_vartime(exp) + } } impl EcPointLoader for NativeLoader { diff --git a/snark-verifier/src/pcs.rs b/snark-verifier/src/pcs.rs index 65b1325b..1ca9eedc 100644 --- a/snark-verifier/src/pcs.rs +++ b/snark-verifier/src/pcs.rs @@ -3,7 +3,7 @@ use crate::{ loader::{native::NativeLoader, Loader}, util::{ - arithmetic::{CurveAffine, PrimeField}, + arithmetic::{CurveAffine, Rotation}, msm::Msm, transcript::{TranscriptRead, TranscriptWrite}, }, @@ -18,24 +18,26 @@ pub mod kzg; /// Query to an oracle. /// It assumes all queries are based on the same point, but with some `shift`. #[derive(Clone, Debug)] -pub struct Query { +pub struct Query { /// Index of polynomial to query pub poly: usize, /// Shift of the query point. - pub shift: F, + pub shift: S, + /// Shift loaded as either constant or witness. It is user's job to ensure this is correctly constrained to have value equal to `shift` + pub loaded_shift: T, /// Evaluation read from transcript. pub eval: T, } -impl Query { +impl Query { /// Initialize [`Query`] without evaluation. - pub fn new(poly: usize, shift: F) -> Self { - Self { poly, shift, eval: () } + pub fn new(poly: usize, shift: S) -> Self { + Self { poly, shift, loaded_shift: (), eval: () } } - /// Returns [`Query`] with evaluation. - pub fn with_evaluation(self, eval: T) -> Query { - Query { poly: self.poly, shift: self.shift, eval } + /// Returns [`Query`] with evaluation and optionally the shift are loaded as. + pub fn with_evaluation(self, loaded_shift: T, eval: T) -> Query { + Query { poly: self.poly, shift: self.shift, loaded_shift, eval } } } @@ -55,7 +57,7 @@ where /// Read [`PolynomialCommitmentScheme::Proof`] from transcript. fn read_proof( vk: &Self::VerifyingKey, - queries: &[Query], + queries: &[Query], transcript: &mut T, ) -> Result where @@ -66,7 +68,7 @@ where vk: &Self::VerifyingKey, commitments: &[Msm], point: &L::LoadedScalar, - queries: &[Query], + queries: &[Query], proof: &Self::Proof, ) -> Result; } diff --git a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs index 538aa4fb..e2cb87ab 100644 --- a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs +++ b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs @@ -5,7 +5,7 @@ use crate::{ PolynomialCommitmentScheme, Query, }, util::{ - arithmetic::{CurveAffine, Fraction, PrimeField}, + arithmetic::{CurveAffine, Fraction, PrimeField, Rotation}, msm::Msm, transcript::TranscriptRead, Itertools, @@ -35,7 +35,7 @@ where fn read_proof( svk: &Self::VerifyingKey, - queries: &[Query], + queries: &[Query], transcript: &mut T, ) -> Result where @@ -48,7 +48,7 @@ where svk: &Self::VerifyingKey, commitments: &[Msm], x: &L::LoadedScalar, - queries: &[Query], + queries: &[Query], proof: &Self::Proof, ) -> Result { let loader = x.loader(); @@ -119,7 +119,7 @@ where { fn read>( svk: &IpaSuccinctVerifyingKey, - queries: &[Query], + queries: &[Query], transcript: &mut T, ) -> Result { // Multiopen @@ -157,28 +157,33 @@ where } } -fn query_sets(queries: &[Query]) -> Vec> +fn query_sets(queries: &[Query]) -> Vec> where - F: PrimeField + Ord, + S: PartialEq + Ord + Copy, T: Clone, { let poly_shifts = - queries.iter().fold(Vec::<(usize, Vec, Vec<&T>)>::new(), |mut poly_shifts, query| { + queries.iter().fold(Vec::<(usize, Vec<_>, Vec<&T>)>::new(), |mut poly_shifts, query| { if let Some(pos) = poly_shifts.iter().position(|(poly, _, _)| *poly == query.poly) { let (_, shifts, evals) = &mut poly_shifts[pos]; - if !shifts.contains(&query.shift) { - shifts.push(query.shift); + if !shifts.iter().map(|(shift, _)| shift).contains(&query.shift) { + shifts.push((query.shift, query.loaded_shift.clone())); evals.push(&query.eval); } } else { - poly_shifts.push((query.poly, vec![query.shift], vec![&query.eval])); + poly_shifts.push(( + query.poly, + vec![(query.shift, query.loaded_shift.clone())], + vec![&query.eval], + )); } poly_shifts }); - poly_shifts.into_iter().fold(Vec::>::new(), |mut sets, (poly, shifts, evals)| { + poly_shifts.into_iter().fold(Vec::>::new(), |mut sets, (poly, shifts, evals)| { if let Some(pos) = sets.iter().position(|set| { - BTreeSet::from_iter(set.shifts.iter()) == BTreeSet::from_iter(shifts.iter()) + BTreeSet::from_iter(set.shifts.iter().map(|(shift, _)| shift)) + == BTreeSet::from_iter(shifts.iter().map(|(shift, _)| shift)) }) { let set = &mut sets[pos]; if !set.polys.contains(&poly) { @@ -187,7 +192,7 @@ where set.shifts .iter() .map(|lhs| { - let idx = shifts.iter().position(|rhs| lhs == rhs).unwrap(); + let idx = shifts.iter().position(|rhs| lhs.0 == rhs.0).unwrap(); evals[idx] }) .collect(), @@ -201,18 +206,23 @@ where }) } -fn query_set_coeffs(sets: &[QuerySet], x: &T, x_3: &T) -> Vec> +fn query_set_coeffs( + sets: &[QuerySet], + x: &T, + x_3: &T, +) -> Vec> where F: PrimeField + Ord, T: LoadedScalar, { - let loader = x.loader(); - let superset = sets.iter().flat_map(|set| set.shifts.clone()).sorted().dedup(); + let superset = BTreeMap::from_iter(sets.iter().flat_map(|set| set.shifts.clone())); let size = sets.iter().map(|set| set.shifts.len()).chain(Some(2)).max().unwrap(); let powers_of_x = x.powers(size); let x_3_minus_x_shift_i = BTreeMap::from_iter( - superset.map(|shift| (shift, x_3.clone() - x.clone() * loader.load_const(&shift))), + superset + .into_iter() + .map(|(shift, loaded_shift)| (shift, x_3.clone() - x.clone() * loaded_shift)), ); let mut coeffs = sets @@ -228,23 +238,22 @@ where } #[derive(Clone, Debug)] -struct QuerySet<'a, F, T> { - shifts: Vec, +struct QuerySet<'a, S, T> { + shifts: Vec<(S, T)>, polys: Vec, evals: Vec>, } -impl<'a, F, T> QuerySet<'a, F, T> -where - F: PrimeField, - T: LoadedScalar, -{ +impl<'a, S, T> QuerySet<'a, S, T> { fn msm>( &self, commitments: &[Msm<'a, C, L>], q_eval: &T, powers_of_x_1: &[T], - ) -> Msm { + ) -> Msm + where + T: LoadedScalar, + { self.polys .iter() .rev() @@ -254,7 +263,15 @@ where - Msm::constant(q_eval.clone()) } - fn f_eval(&self, coeff: &QuerySetCoeff, q_eval: &T, powers_of_x_1: &[T]) -> T { + fn f_eval( + &self, + coeff: &QuerySetCoeff, + q_eval: &T, + powers_of_x_1: &[T], + ) -> T + where + T: LoadedScalar, + { let loader = q_eval.loader(); let r_eval = { let r_evals = self @@ -291,7 +308,12 @@ where F: PrimeField + Ord, T: LoadedScalar, { - fn new(shifts: &[F], powers_of_x: &[T], x_3: &T, x_3_minus_x_shift_i: &BTreeMap) -> Self { + fn new( + shifts: &[(Rotation, T)], + powers_of_x: &[T], + x_3: &T, + x_3_minus_x_shift_i: &BTreeMap, + ) -> Self { let loader = x_3.loader(); let normalized_ell_primes = shifts .iter() @@ -301,9 +323,9 @@ where .iter() .enumerate() .filter(|&(i, _)| i != j) - .map(|(_, shift_i)| (*shift_j - shift_i)) + .map(|(_, shift_i)| (shift_j.1.clone() - &shift_i.1)) .reduce(|acc, value| acc * value) - .unwrap_or(F::ONE) + .unwrap_or_else(|| loader.load_const(&F::ONE)) }) .collect_vec(); @@ -313,17 +335,15 @@ where let barycentric_weights = shifts .iter() .zip(normalized_ell_primes.iter()) - .map(|(shift, normalized_ell_prime)| { - loader.sum_products_with_coeff(&[ - (*normalized_ell_prime, x_pow_k_minus_one, x_3), - (-(*normalized_ell_prime * shift), x_pow_k_minus_one, x), - ]) + .map(|((_, loaded_shift), normalized_ell_prime)| { + let tmp = normalized_ell_prime.clone() * x_pow_k_minus_one; + loader.sum_products(&[(&tmp, x_3), (&-(tmp.clone() * loaded_shift), x)]) }) .map(Fraction::one_over) .collect_vec(); let f_eval_coeff = Fraction::one_over(loader.product( - &shifts.iter().map(|shift| x_3_minus_x_shift_i.get(shift).unwrap()).collect_vec(), + &shifts.iter().map(|(shift, _)| x_3_minus_x_shift_i.get(shift).unwrap()).collect_vec(), )); Self { diff --git a/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs index d1398ebb..e13e09cc 100644 --- a/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs @@ -6,7 +6,7 @@ use crate::{ PolynomialCommitmentScheme, Query, }, util::{ - arithmetic::{CurveAffine, Fraction, MultiMillerLoop, PrimeField}, + arithmetic::{CurveAffine, Fraction, MultiMillerLoop, PrimeField, Rotation}, msm::Msm, transcript::TranscriptRead, Itertools, @@ -37,7 +37,7 @@ where fn read_proof( _: &KzgSuccinctVerifyingKey, - _: &[Query], + _: &[Query], transcript: &mut T, ) -> Result, Error> where @@ -50,7 +50,7 @@ where svk: &KzgSuccinctVerifyingKey, commitments: &[Msm], z: &L::LoadedScalar, - queries: &[Query], + queries: &[Query], proof: &Bdfg21Proof, ) -> Result { let sets = query_sets(queries); @@ -106,24 +106,29 @@ where } } -fn query_sets(queries: &[Query]) -> Vec> { +fn query_sets(queries: &[Query]) -> Vec> { let poly_shifts = - queries.iter().fold(Vec::<(usize, Vec, Vec<&T>)>::new(), |mut poly_shifts, query| { + queries.iter().fold(Vec::<(usize, Vec<_>, Vec<&T>)>::new(), |mut poly_shifts, query| { if let Some(pos) = poly_shifts.iter().position(|(poly, _, _)| *poly == query.poly) { let (_, shifts, evals) = &mut poly_shifts[pos]; - if !shifts.contains(&query.shift) { - shifts.push(query.shift); + if !shifts.iter().map(|(shift, _)| shift).contains(&query.shift) { + shifts.push((query.shift, query.loaded_shift.clone())); evals.push(&query.eval); } } else { - poly_shifts.push((query.poly, vec![query.shift], vec![&query.eval])); + poly_shifts.push(( + query.poly, + vec![(query.shift, query.loaded_shift.clone())], + vec![&query.eval], + )); } poly_shifts }); - poly_shifts.into_iter().fold(Vec::>::new(), |mut sets, (poly, shifts, evals)| { + poly_shifts.into_iter().fold(Vec::>::new(), |mut sets, (poly, shifts, evals)| { if let Some(pos) = sets.iter().position(|set| { - BTreeSet::from_iter(set.shifts.iter()) == BTreeSet::from_iter(shifts.iter()) + BTreeSet::from_iter(set.shifts.iter().map(|(shift, _)| shift)) + == BTreeSet::from_iter(shifts.iter().map(|(shift, _)| shift)) }) { let set = &mut sets[pos]; if !set.polys.contains(&poly) { @@ -132,7 +137,7 @@ fn query_sets(queries: &[Query]) -> Vec(queries: &[Query]) -> Vec>( - sets: &[QuerySet], + sets: &[QuerySet], z: &T, z_prime: &T, ) -> Vec> { - let loader = z.loader(); - - let superset = sets.iter().flat_map(|set| set.shifts.clone()).sorted().dedup(); + // map of shift => loaded_shift, removing duplicate `shift` values + // shift is the rotation, not omega^rotation, to ensure BTreeMap does not depend on omega (otherwise ordering can change) + let superset = BTreeMap::from_iter(sets.iter().flat_map(|set| set.shifts.clone())); let size = sets.iter().map(|set| set.shifts.len()).chain(Some(2)).max().unwrap(); let powers_of_z = z.powers(size); let z_prime_minus_z_shift_i = BTreeMap::from_iter( - superset.map(|shift| (shift, z_prime.clone() - z.clone() * loader.load_const(&shift))), + superset + .into_iter() + .map(|(shift, loaded_shift)| (shift, z_prime.clone() - z.clone() * loaded_shift)), ); let mut z_s_1 = None; @@ -187,19 +194,22 @@ fn query_set_coeffs>( } #[derive(Clone, Debug)] -struct QuerySet<'a, F, T> { - shifts: Vec, +struct QuerySet<'a, S, T> { + shifts: Vec<(S, T)>, // vec of (shift, loaded_shift) polys: Vec, evals: Vec>, } -impl<'a, F: PrimeField, T: LoadedScalar> QuerySet<'a, F, T> { +impl<'a, S, T> QuerySet<'a, S, T> { fn msm>( &self, - coeff: &QuerySetCoeff, + coeff: &QuerySetCoeff, commitments: &[Msm<'a, C, L>], powers_of_mu: &[T], - ) -> Msm { + ) -> Msm + where + T: LoadedScalar, + { self.polys .iter() .zip(self.evals.iter()) @@ -242,10 +252,10 @@ where T: LoadedScalar, { fn new( - shifts: &[F], + shifts: &[(Rotation, T)], powers_of_z: &[T], z_prime: &T, - z_prime_minus_z_shift_i: &BTreeMap, + z_prime_minus_z_shift_i: &BTreeMap, z_s_1: &Option, ) -> Self { let loader = z_prime.loader(); @@ -258,9 +268,9 @@ where .iter() .enumerate() .filter(|&(i, _)| i != j) - .map(|(_, shift_i)| (*shift_j - shift_i)) + .map(|(_, shift_i)| (shift_j.1.clone() - &shift_i.1)) .reduce(|acc, value| acc * value) - .unwrap_or(F::ONE) + .unwrap_or_else(|| loader.load_const(&F::ONE)) }) .collect_vec(); @@ -270,17 +280,18 @@ where let barycentric_weights = shifts .iter() .zip(normalized_ell_primes.iter()) - .map(|(shift, normalized_ell_prime)| { - loader.sum_products_with_coeff(&[ - (*normalized_ell_prime, z_pow_k_minus_one, z_prime), - (-(*normalized_ell_prime * shift), z_pow_k_minus_one, z), - ]) + .map(|((_, loaded_shift), normalized_ell_prime)| { + let tmp = normalized_ell_prime.clone() * z_pow_k_minus_one; + loader.sum_products(&[(&tmp, z_prime), (&-(tmp.clone() * loaded_shift), z)]) }) .map(Fraction::one_over) .collect_vec(); let z_s = loader.product( - &shifts.iter().map(|shift| z_prime_minus_z_shift_i.get(shift).unwrap()).collect_vec(), + &shifts + .iter() + .map(|(shift, _)| z_prime_minus_z_shift_i.get(shift).unwrap()) + .collect_vec(), ); let z_s_1_over_z_s = z_s_1.clone().map(|z_s_1| Fraction::new(z_s_1, z_s.clone())); @@ -330,9 +341,9 @@ impl CostEstimation for KzgAs where M: MultiMillerLoop, { - type Input = Vec>; + type Input = Vec>; - fn estimate_cost(_: &Vec>) -> Cost { + fn estimate_cost(_: &Vec>) -> Cost { Cost { num_commitment: 2, num_msm: 2, ..Default::default() } } } diff --git a/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs index da5d51a6..e8114d09 100644 --- a/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs @@ -6,7 +6,7 @@ use crate::{ PolynomialCommitmentScheme, Query, }, util::{ - arithmetic::{CurveAffine, MultiMillerLoop, PrimeField}, + arithmetic::{CurveAffine, MultiMillerLoop, Rotation}, msm::Msm, transcript::TranscriptRead, Itertools, @@ -32,7 +32,7 @@ where fn read_proof( _: &Self::VerifyingKey, - queries: &[Query], + queries: &[Query], transcript: &mut T, ) -> Result where @@ -45,7 +45,7 @@ where svk: &Self::VerifyingKey, commitments: &[Msm], z: &L::LoadedScalar, - queries: &[Query], + queries: &[Query], proof: &Self::Proof, ) -> Result { let sets = query_sets(queries); @@ -58,7 +58,10 @@ where .map(|(msm, power_of_u)| msm * power_of_u) .sum::>() }; - let z_omegas = sets.iter().map(|set| z.loader().load_const(&set.shift) * z); + let z_omegas = sets.iter().map(|set| { + let loaded_shift = set.loaded_shift.clone(); + loaded_shift * z + }); let rhs = proof .ws @@ -92,7 +95,7 @@ where C: CurveAffine, L: Loader, { - fn read(queries: &[Query], transcript: &mut T) -> Result + fn read(queries: &[Query], transcript: &mut T) -> Result where T: TranscriptRead, { @@ -103,22 +106,25 @@ where } } -struct QuerySet<'a, F, T> { - shift: F, +struct QuerySet<'a, S, T> { + shift: S, + loaded_shift: T, polys: Vec, evals: Vec<&'a T>, } -impl<'a, F, T> QuerySet<'a, F, T> +impl<'a, S, T> QuerySet<'a, S, T> where - F: PrimeField, T: Clone, { fn msm>( &self, commitments: &[Msm<'a, C, L>], powers_of_v: &[L::LoadedScalar], - ) -> Msm { + ) -> Msm + where + T: LoadedScalar, + { self.polys .iter() .zip(self.evals.iter().cloned()) @@ -132,9 +138,9 @@ where } } -fn query_sets(queries: &[Query]) -> Vec> +fn query_sets(queries: &[Query]) -> Vec> where - F: PrimeField, + S: PartialEq + Copy, T: Clone + PartialEq, { queries.iter().fold(Vec::new(), |mut sets, query| { @@ -144,6 +150,7 @@ where } else { sets.push(QuerySet { shift: query.shift, + loaded_shift: query.loaded_shift.clone(), polys: vec![query.poly], evals: vec![&query.eval], }); @@ -156,9 +163,9 @@ impl CostEstimation for KzgAs where M: MultiMillerLoop, { - type Input = Vec>; + type Input = Vec>; - fn estimate_cost(queries: &Vec>) -> Cost { + fn estimate_cost(queries: &Vec>) -> Cost { let num_w = query_sets(queries).len(); Cost { num_commitment: num_w, num_msm: num_w, ..Default::default() } } diff --git a/snark-verifier/src/system/halo2.rs b/snark-verifier/src/system/halo2.rs index 2dc5751d..74824361 100644 --- a/snark-verifier/src/system/halo2.rs +++ b/snark-verifier/src/system/halo2.rs @@ -141,6 +141,7 @@ pub fn compile<'a, C: CurveAffine, P: Params<'a, C>>( PlonkProtocol { domain, + domain_as_witness: None, preprocessed, num_instance: polynomials.num_instance(), num_witness: polynomials.num_witness(), diff --git a/snark-verifier/src/verifier/plonk.rs b/snark-verifier/src/verifier/plonk.rs index d5937ab8..9c910400 100644 --- a/snark-verifier/src/verifier/plonk.rs +++ b/snark-verifier/src/verifier/plonk.rs @@ -15,7 +15,10 @@ use crate::{ AccumulationDecider, AccumulationScheme, AccumulatorEncoding, PolynomialCommitmentScheme, Query, }, - util::{arithmetic::CurveAffine, transcript::TranscriptRead}, + util::{ + arithmetic::{CurveAffine, Rotation}, + transcript::TranscriptRead, + }, verifier::{plonk::protocol::CommonPolynomialEvaluation, SnarkVerifier}, Error, }; @@ -62,8 +65,12 @@ where proof: &Self::Proof, ) -> Result { let common_poly_eval = { - let mut common_poly_eval = - CommonPolynomialEvaluation::new(&protocol.domain, protocol.langranges(), &proof.z); + let mut common_poly_eval = CommonPolynomialEvaluation::new( + &protocol.domain, + protocol.langranges(), + &proof.z, + &protocol.domain_as_witness, + ); L::batch_invert(common_poly_eval.denoms()); common_poly_eval.evaluate(); @@ -140,7 +147,7 @@ where L: Loader, AS: AccumulationScheme + PolynomialCommitmentScheme - + CostEstimation>>, + + CostEstimation>>, { type Input = PlonkProtocol; @@ -168,7 +175,7 @@ where L: Loader, AS: AccumulationScheme + PolynomialCommitmentScheme - + CostEstimation>>, + + CostEstimation>>, { type Input = PlonkProtocol; diff --git a/snark-verifier/src/verifier/plonk/proof.rs b/snark-verifier/src/verifier/plonk/proof.rs index a42a56ae..459027ba 100644 --- a/snark-verifier/src/verifier/plonk/proof.rs +++ b/snark-verifier/src/verifier/plonk/proof.rs @@ -13,7 +13,10 @@ use crate::{ }, Error, }; -use std::{collections::HashMap, iter}; +use std::{ + collections::{BTreeMap, HashMap}, + iter, +}; /// Proof of PLONK with [`PolynomialCommitmentScheme`] that has /// [`AccumulationScheme`]. @@ -153,26 +156,42 @@ where } /// Empty queries - pub fn empty_queries(protocol: &PlonkProtocol) -> Vec> { - protocol - .queries - .iter() - .map(|query| { - let shift = protocol.domain.rotate_scalar(C::Scalar::ONE, query.rotation); - pcs::Query::new(query.poly, shift) - }) - .collect() + pub fn empty_queries(protocol: &PlonkProtocol) -> Vec> { + // `preprocessed` should always be non-empty, unless the circuit has no constraints or constants + protocol.queries.iter().map(|query| pcs::Query::new(query.poly, query.rotation)).collect() } pub(super) fn queries( &self, protocol: &PlonkProtocol, mut evaluations: HashMap, - ) -> Vec> { + ) -> Vec> { + if protocol.queries.is_empty() { + return vec![]; + } + let loader = evaluations[&protocol.queries[0]].loader(); + let rotations = + protocol.queries.iter().map(|query| query.rotation).sorted().dedup().collect_vec(); + let loaded_shifts = if let Some(domain) = protocol.domain_as_witness.as_ref() { + // the `rotation`s are still constants, it is only generator `omega` that might be witness + BTreeMap::from_iter( + rotations.into_iter().map(|rotation| (rotation, domain.rotate_one(rotation))), + ) + } else { + BTreeMap::from_iter(rotations.into_iter().map(|rotation| { + ( + rotation, + loader.load_const(&protocol.domain.rotate_scalar(C::Scalar::ONE, rotation)), + ) + })) + }; Self::empty_queries(protocol) .into_iter() .zip(protocol.queries.iter().map(|query| evaluations.remove(query).unwrap())) - .map(|(query, eval)| query.with_evaluation(eval)) + .map(|(query, eval)| { + let shift = loaded_shifts[&query.shift].clone(); + query.with_evaluation(shift, eval) + }) .collect() } diff --git a/snark-verifier/src/verifier/plonk/protocol.rs b/snark-verifier/src/verifier/plonk/protocol.rs index 97f6f336..098e7de9 100644 --- a/snark-verifier/src/verifier/plonk/protocol.rs +++ b/snark-verifier/src/verifier/plonk/protocol.rs @@ -1,7 +1,7 @@ use crate::{ loader::{native::NativeLoader, LoadedScalar, Loader}, util::{ - arithmetic::{CurveAffine, Domain, Field, Fraction, Rotation}, + arithmetic::{CurveAffine, Domain, Field, Fraction, PrimeField, Rotation}, Itertools, }, }; @@ -9,13 +9,44 @@ use num_integer::Integer; use num_traits::One; use serde::{Deserialize, Serialize}; use std::{ - cmp::max, + cmp::{max, Ordering}, collections::{BTreeMap, BTreeSet}, fmt::Debug, iter::{self, Sum}, ops::{Add, Mul, Neg, Sub}, }; +/// Domain parameters to be optionally loaded as witnesses +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct DomainAsWitness +where + C: CurveAffine, + L: Loader, +{ + /// Number of rows in the domain + pub n: L::LoadedScalar, + /// Generator of the domain + pub gen: L::LoadedScalar, + /// Inverse generator of the domain + pub gen_inv: L::LoadedScalar, +} + +impl DomainAsWitness +where + C: CurveAffine, + L: Loader, +{ + /// Rotate `F::one()` to given `rotation`. + pub fn rotate_one(&self, rotation: Rotation) -> L::LoadedScalar { + let loader = self.gen.loader(); + match rotation.0.cmp(&0) { + Ordering::Equal => loader.load_one(), + Ordering::Greater => self.gen.pow_const(rotation.0 as u64), + Ordering::Less => self.gen_inv.pow_const(-rotation.0 as u64), + } + } +} + /// Protocol specifying configuration of a PLONK. #[derive(Clone, Debug, Serialize, Deserialize)] pub struct PlonkProtocol @@ -29,6 +60,15 @@ where ))] /// Working domain. pub domain: Domain, + + #[serde(bound( + serialize = "L::LoadedScalar: Serialize", + deserialize = "L::LoadedScalar: Deserialize<'de>" + ))] + #[serde(skip_serializing_if = "Option::is_none")] + /// Optional: load `domain.n` and `domain.gen` as a witness + pub domain_as_witness: Option>, + #[serde(bound( serialize = "L::LoadedEcPoint: Serialize", deserialize = "L::LoadedEcPoint: Deserialize<'de>" @@ -115,6 +155,7 @@ where .map(|transcript_initial_state| loader.load_const(transcript_initial_state)); PlonkProtocol { domain: self.domain.clone(), + domain_as_witness: None, preprocessed, num_instance: self.num_instance.clone(), num_witness: self.num_witness.clone(), @@ -133,12 +174,17 @@ where #[cfg(feature = "loader_halo2")] mod halo2 { use crate::{ - loader::halo2::{EccInstructions, Halo2Loader}, + loader::{ + halo2::{EccInstructions, Halo2Loader}, + LoadedScalar, + }, util::arithmetic::CurveAffine, verifier::plonk::PlonkProtocol, }; use std::rc::Rc; + use super::DomainAsWitness; + impl PlonkProtocol where C: CurveAffine, @@ -149,7 +195,15 @@ mod halo2 { pub fn loaded_preprocessed_as_witness>( &self, loader: &Rc>, + load_n_as_witness: bool, ) -> PlonkProtocol>> { + let domain_as_witness = load_n_as_witness.then(|| { + let n = loader.assign_scalar(C::Scalar::from(self.domain.n as u64)); + let gen = loader.assign_scalar(self.domain.gen); + let gen_inv = gen.invert().expect("subgroup generation is invertible"); + DomainAsWitness { n, gen, gen_inv } + }); + let preprocessed = self .preprocessed .iter() @@ -161,6 +215,7 @@ mod halo2 { .map(|transcript_initial_state| loader.assign_scalar(*transcript_initial_state)); PlonkProtocol { domain: self.domain.clone(), + domain_as_witness, preprocessed, num_instance: self.num_instance.clone(), num_witness: self.num_witness.clone(), @@ -201,26 +256,39 @@ where C: CurveAffine, L: Loader, { + // if `n_as_witness` is Some, then we assume `n_as_witness` has value equal to `domain.n` (i.e., number of rows in the circuit) + // and is loaded as a witness instead of a constant. + // The generator of `domain` also depends on `n`. pub fn new( domain: &Domain, - langranges: impl IntoIterator, + lagranges: impl IntoIterator, z: &L::LoadedScalar, + domain_as_witness: &Option>, ) -> Self { let loader = z.loader(); - let zn = z.pow_const(domain.n as u64); - let langranges = langranges.into_iter().sorted().dedup().collect_vec(); - + let lagranges = lagranges.into_iter().sorted().dedup().collect_vec(); let one = loader.load_one(); + + let (zn, n_inv, omegas) = if let Some(domain) = domain_as_witness.as_ref() { + let zn = z.pow_var(&domain.n, C::Scalar::S as usize + 1); + let n_inv = domain.n.invert().expect("n is not zero"); + let omegas = lagranges.iter().map(|&i| domain.rotate_one(Rotation(i))).collect_vec(); + (zn, n_inv, omegas) + } else { + let zn = z.pow_const(domain.n as u64); + let n_inv = loader.load_const(&domain.n_inv); + let omegas = lagranges + .iter() + .map(|&i| loader.load_const(&domain.rotate_scalar(C::Scalar::ONE, Rotation(i)))) + .collect_vec(); + (zn, n_inv, omegas) + }; + let zn_minus_one = zn.clone() - &one; let zn_minus_one_inv = Fraction::one_over(zn_minus_one.clone()); - let n_inv = loader.load_const(&domain.n_inv); let numer = zn_minus_one.clone() * &n_inv; - let omegas = langranges - .iter() - .map(|&i| loader.load_const(&domain.rotate_scalar(C::Scalar::ONE, Rotation(i)))) - .collect_vec(); let lagrange_evals = omegas .iter() .map(|omega| Fraction::new(numer.clone() * omega, z.clone() - omega)) @@ -231,7 +299,7 @@ where zn_minus_one, zn_minus_one_inv, identity: z.clone(), - lagrange: langranges.into_iter().zip(lagrange_evals).collect(), + lagrange: lagranges.into_iter().zip(lagrange_evals).collect(), } } From 9d981455c04717e7338cf3a17b19e016121608c5 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 18 Aug 2023 10:18:30 -0700 Subject: [PATCH 47/73] chore: derive Default for VerifierUniversality --- snark-verifier-sdk/src/halo2/aggregation.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 0063a599..60674a6c 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -54,9 +54,10 @@ pub struct SnarkAggregationWitness<'a> { } /// Different possible stages of universality the aggregation circuit can support -#[derive(PartialEq, Eq, Clone, Copy, Debug)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Default)] pub enum VerifierUniversality { /// Default: verifier is specific to a single circuit + #[default] None, /// Preprocessed digest (commitments to fixed columns) is loaded as witness PreprocessedAsWitness, From f309edea16ed483cf828dd843fabb1b02aabc65a Mon Sep 17 00:00:00 2001 From: Han Date: Fri, 2 Jun 2023 14:41:37 +0800 Subject: [PATCH 48/73] feat: upgrade `revm` to support lastest hardfork (#40) --- .github/workflows/ci.yaml | 2 +- rust-toolchain | 2 +- snark-verifier-sdk/src/evm.rs | 17 +- snark-verifier/Cargo.toml | 9 +- .../examples/evm-verifier-with-accumulator.rs | 16 +- snark-verifier/examples/evm-verifier.rs | 16 +- snark-verifier/src/loader/evm.rs | 10 +- snark-verifier/src/loader/evm/loader.rs | 44 +- snark-verifier/src/loader/evm/test.rs | 48 - snark-verifier/src/loader/evm/test/tui.rs | 896 ------------------ snark-verifier/src/loader/evm/util.rs | 13 +- .../src/loader/evm/util/executor.rs | 854 +---------------- snark-verifier/src/pcs/kzg/decider.rs | 8 +- .../src/system/halo2/transcript/evm.rs | 4 +- snark-verifier/src/util/arithmetic.rs | 2 +- snark-verifier/src/util/poly.rs | 10 +- 16 files changed, 97 insertions(+), 1854 deletions(-) delete mode 100644 snark-verifier/src/loader/evm/test.rs delete mode 100644 snark-verifier/src/loader/evm/test/tui.rs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e057f89d..7261444e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,7 +24,7 @@ jobs: cache-on-failure: true - name: Install solc - run: (hash svm 2>/dev/null || cargo install svm-rs) && svm install 0.8.17 && solc --version + run: (hash svm 2>/dev/null || cargo install --version 0.2.23 svm-rs) && svm install 0.8.20 && solc --version - name: Run test run: cargo test --all -- --nocapture diff --git a/rust-toolchain b/rust-toolchain index ee2d639b..6f6d7b39 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2023-08-12 \ No newline at end of file +nightly-2023-08-12 diff --git a/snark-verifier-sdk/src/evm.rs b/snark-verifier-sdk/src/evm.rs index f423d327..97b1b96e 100644 --- a/snark-verifier-sdk/src/evm.rs +++ b/snark-verifier-sdk/src/evm.rs @@ -3,7 +3,6 @@ use crate::{GWC, SHPLONK}; use super::{CircuitExt, PlonkVerifier}; #[cfg(feature = "display")] use ark_std::{end_timer, start_timer}; -use ethereum_types::Address; use halo2_base::halo2_proofs::{ halo2curves::bn256::{Bn256, Fq, Fr, G1Affine}, plonk::{create_proof, verify_proof, Circuit, ProvingKey, VerifyingKey}, @@ -23,7 +22,7 @@ use itertools::Itertools; use rand::{rngs::StdRng, SeedableRng}; pub use snark_verifier::loader::evm::encode_calldata; use snark_verifier::{ - loader::evm::{compile_yul, EvmLoader, ExecutorBuilder}, + loader::evm::{compile_yul, deploy_and_call, EvmLoader}, pcs::{ kzg::{KzgAccumulator, KzgAsVerifyingKey, KzgDecidingKey, KzgSuccinctVerifyingKey}, AccumulationDecider, AccumulationScheme, PolynomialCommitmentScheme, @@ -177,18 +176,8 @@ pub fn gen_evm_verifier_shplonk>( pub fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { let calldata = encode_calldata(&instances, &proof); - let success = { - let mut evm = ExecutorBuilder::default().with_gas_limit(u64::MAX.into()).build(); - - let caller = Address::from_low_u64_be(0xfe); - let verifier = evm.deploy(caller, deployment_code.into(), 0.into()).address.unwrap(); - let result = evm.call_raw(caller, verifier, calldata.into(), 0.into()); - - dbg!(result.gas_used); - - !result.reverted - }; - assert!(success); + let gas_cost = deploy_and_call(deployment_code, calldata).unwrap(); + dbg!(gas_cost); } pub fn write_calldata(instances: &[Vec], proof: &[u8], path: &Path) -> io::Result { diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index ebbf283b..f4c4f4af 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -25,11 +25,8 @@ poseidon-rs = { git = "https://github.com/axiom-crypto/poseidon-circuit.git", re rayon = { version = "1.7", optional = true } # loader_evm -sha3 = { version = "0.10.8", optional = true } -bytes = { version = "1.4.0", default-features = false, optional = true } -primitive-types = { version = "0.12.1", default-features = false, features = ["std"], optional = true } -rlp = { version = "0.5.2", default-features = false, features = ["std"], optional = true } -revm = { version = "2.3.1", optional = true } +sha3 = { version = "0.10", optional = true } +revm = { version = "3.3.0", optional = true } # loader_halo2 halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false, optional = true } @@ -47,7 +44,7 @@ tui = { version = "0.19", default-features = false, features = ["crossterm"] } [features] default = ["loader_evm", "loader_halo2", "halo2-axiom", "display"] display = ["halo2-base/display", "halo2-ecc?/display"] -loader_evm = ["dep:primitive-types", "dep:sha3", "dep:revm", "dep:bytes", "dep:rlp"] +loader_evm = ["dep:sha3", "dep:revm"] loader_halo2 = ["halo2-ecc"] parallel = ["dep:rayon"] # EXACTLY one of halo2-pse / halo2-axiom should always be turned on; not sure how to enforce this with Cargo diff --git a/snark-verifier/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs index 41493efa..650598aa 100644 --- a/snark-verifier/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -23,7 +23,7 @@ use itertools::Itertools; use rand::rngs::OsRng; use snark_verifier::{ loader::{ - evm::{self, encode_calldata, Address, EvmLoader, ExecutorBuilder}, + evm::{self, deploy_and_call, encode_calldata, EvmLoader}, native::NativeLoader, }, pcs::kzg::{Gwc19, KzgAs, LimbsEncoding}, @@ -559,18 +559,8 @@ fn gen_aggregation_evm_verifier( fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { let calldata = encode_calldata(&instances, &proof); - let success = { - let mut evm = ExecutorBuilder::default().with_gas_limit(u64::MAX.into()).build(); - - let caller = Address::from_low_u64_be(0xfe); - let verifier = evm.deploy(caller, deployment_code.into(), 0.into()).address.unwrap(); - let result = evm.call_raw(caller, verifier, calldata.into(), 0.into()); - - dbg!(result.gas_used); - - !result.reverted - }; - assert!(success); + let gas_cost = deploy_and_call(deployment_code, calldata).unwrap(); + dbg!(gas_cost); } fn main() { diff --git a/snark-verifier/examples/evm-verifier.rs b/snark-verifier/examples/evm-verifier.rs index 5b2aa802..c7f206b1 100644 --- a/snark-verifier/examples/evm-verifier.rs +++ b/snark-verifier/examples/evm-verifier.rs @@ -21,7 +21,7 @@ use halo2_proofs::{ use itertools::Itertools; use rand::{rngs::OsRng, RngCore}; use snark_verifier::{ - loader::evm::{self, encode_calldata, Address, EvmLoader, ExecutorBuilder}, + loader::evm::{self, deploy_and_call, encode_calldata, EvmLoader}, pcs::kzg::{Gwc19, KzgAs}, system::halo2::{compile, transcript::evm::EvmTranscript, Config}, verifier::{self, SnarkVerifier}, @@ -242,18 +242,8 @@ fn gen_evm_verifier( fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { let calldata = encode_calldata(&instances, &proof); - let success = { - let mut evm = ExecutorBuilder::default().with_gas_limit(u64::MAX.into()).build(); - - let caller = Address::from_low_u64_be(0xfe); - let verifier = evm.deploy(caller, deployment_code.into(), 0.into()).address.unwrap(); - let result = evm.call_raw(caller, verifier, calldata.into(), 0.into()); - - dbg!(result.gas_used); - - !result.reverted - }; - assert!(success); + let gas_cost = deploy_and_call(deployment_code, calldata).unwrap(); + dbg!(gas_cost); } fn main() { diff --git a/snark-verifier/src/loader/evm.rs b/snark-verifier/src/loader/evm.rs index e942b4a3..74ed0f4e 100644 --- a/snark-verifier/src/loader/evm.rs +++ b/snark-verifier/src/loader/evm.rs @@ -4,14 +4,8 @@ mod code; pub(crate) mod loader; pub(crate) mod util; -#[cfg(test)] -mod test; - pub use loader::{EcPoint, EvmLoader, Scalar}; pub use util::{ - compile_yul, encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, Address, - ExecutorBuilder, H256, U256, U512, + compile_yul, deploy_and_call, encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, + Address, B256, U256, U512, }; - -#[cfg(test)] -pub use test::execute; diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index ba304f2b..127cc7e4 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -55,14 +55,10 @@ pub struct EvmLoader { code: RefCell, ptr: RefCell, cache: RefCell>, - #[cfg(test)] - gas_metering_ids: RefCell>, } fn hex_encode_u256(value: &U256) -> String { - let mut bytes = [0; 32]; - value.to_big_endian(&mut bytes); - format!("0x{}", hex::encode(bytes)) + format!("0x{}", hex::encode(value.to_be_bytes::<32>())) } impl EvmLoader { @@ -82,8 +78,6 @@ impl EvmLoader { code: RefCell::new(code), ptr: Default::default(), cache: Default::default(), - #[cfg(test)] - gas_metering_ids: RefCell::new(Vec::new()), }) } @@ -308,11 +302,11 @@ impl EvmLoader { fn invert(self: &Rc, scalar: &Scalar) -> Scalar { let rd_ptr = self.allocate(0x20); let [cd_ptr, ..] = [ - &self.scalar(Value::Constant(0x20.into())), - &self.scalar(Value::Constant(0x20.into())), - &self.scalar(Value::Constant(0x20.into())), + &self.scalar(Value::Constant(U256::from(0x20))), + &self.scalar(Value::Constant(U256::from(0x20))), + &self.scalar(Value::Constant(U256::from(0x20))), scalar, - &self.scalar(Value::Constant(self.scalar_modulus - 2)), + &self.scalar(Value::Constant(self.scalar_modulus - U256::from(2))), &self.scalar(Value::Constant(self.scalar_modulus)), ] .map(|value| self.dup_scalar(value).ptr()); @@ -383,8 +377,8 @@ impl EvmLoader { fn add(self: &Rc, lhs: &Scalar, rhs: &Scalar) -> Scalar { if let (Value::Constant(lhs), Value::Constant(rhs)) = (&lhs.value, &rhs.value) { - let out = (U512::from(lhs) + U512::from(rhs)) % U512::from(self.scalar_modulus); - return self.scalar(Value::Constant(out.try_into().unwrap())); + let out = (U512::from(*lhs) + U512::from(*rhs)) % U512::from(self.scalar_modulus); + return self.scalar(Value::Constant(U256::from(out))); } self.scalar(Value::Sum(Box::new(lhs.value.clone()), Box::new(rhs.value.clone()))) @@ -403,8 +397,8 @@ impl EvmLoader { fn mul(self: &Rc, lhs: &Scalar, rhs: &Scalar) -> Scalar { if let (Value::Constant(lhs), Value::Constant(rhs)) = (&lhs.value, &rhs.value) { - let out = (U512::from(lhs) * U512::from(rhs)) % U512::from(self.scalar_modulus); - return self.scalar(Value::Constant(out.try_into().unwrap())); + let out = (U512::from(*lhs) * U512::from(*rhs)) % U512::from(self.scalar_modulus); + return self.scalar(Value::Constant(U256::from(out))); } self.scalar(Value::Product(Box::new(lhs.value.clone()), Box::new(rhs.value.clone()))) @@ -421,22 +415,16 @@ impl EvmLoader { #[cfg(test)] impl EvmLoader { - fn start_gas_metering(self: &Rc, identifier: &str) { - self.gas_metering_ids.borrow_mut().push(identifier.to_string()); - let code = format!("let {identifier} := gas()"); - self.code.borrow_mut().runtime_append(code); + fn start_gas_metering(self: &Rc, _: &str) { + // unimplemented } fn end_gas_metering(self: &Rc) { - let code = - format!("log1(0, 0, sub({}, gas()))", self.gas_metering_ids.borrow().last().unwrap()); - self.code.borrow_mut().runtime_append(code); + // unimplemented } - pub fn print_gas_metering(self: &Rc, costs: Vec) { - for (identifier, cost) in self.gas_metering_ids.borrow().iter().zip(costs) { - println!("{identifier}: {cost}"); - } + pub fn print_gas_metering(self: &Rc, _: Vec) { + // unimplemented } } @@ -648,7 +636,7 @@ where fn ec_point_load_const(&self, value: &C) -> EcPoint { let coordinates = value.coordinates().unwrap(); let [x, y] = [coordinates.x(), coordinates.y()] - .map(|coordinate| U256::from_little_endian(coordinate.to_repr().as_ref())); + .map(|coordinate| U256::try_from_le_slice(coordinate.to_repr().as_ref()).unwrap()); self.ec_point(Value::Constant((x, y))) } @@ -663,7 +651,7 @@ where .iter() .cloned() .map(|(scalar, ec_point)| match scalar.value { - Value::Constant(constant) if U256::one() == constant => ec_point.clone(), + Value::Constant(constant) if U256::from(1) == constant => ec_point.clone(), _ => ec_point.loader.ec_point_scalar_mul(ec_point, scalar), }) .reduce(|acc, ec_point| acc.loader.ec_point_add(&acc, &ec_point)) diff --git a/snark-verifier/src/loader/evm/test.rs b/snark-verifier/src/loader/evm/test.rs deleted file mode 100644 index e3467408..00000000 --- a/snark-verifier/src/loader/evm/test.rs +++ /dev/null @@ -1,48 +0,0 @@ -use crate::{ - loader::evm::{test::tui::Tui, Address, ExecutorBuilder, U256}, - util::Itertools, -}; -use std::env::var_os; - -mod tui; - -fn debug() -> bool { - matches!( - var_os("DEBUG"), - Some(value) if value.to_str() == Some("1") - ) -} - -pub fn execute(deployment_code: Vec, calldata: Vec) -> (bool, u64, Vec) { - assert!( - deployment_code.len() <= 0x6000, - "Contract size {} exceeds the limit 24576", - deployment_code.len() - ); - - let debug = debug(); - let caller = Address::from_low_u64_be(0xfe); - - let mut evm = ExecutorBuilder::default() - .with_gas_limit(u64::MAX.into()) - .set_debugger(debug) - .build(); - - let contract = evm - .deploy(caller, deployment_code.into(), 0.into()) - .address - .unwrap(); - let result = evm.call_raw(caller, contract, calldata.into(), 0.into()); - - let costs = result - .logs - .into_iter() - .map(|log| U256::from_big_endian(log.topics[0].as_bytes()).as_u64()) - .collect_vec(); - - if debug { - Tui::new(result.debug.unwrap().flatten(0), 0).start(); - } - - (!result.reverted, result.gas_used, costs) -} diff --git a/snark-verifier/src/loader/evm/test/tui.rs b/snark-verifier/src/loader/evm/test/tui.rs deleted file mode 100644 index 9bd68bb9..00000000 --- a/snark-verifier/src/loader/evm/test/tui.rs +++ /dev/null @@ -1,896 +0,0 @@ -//! Copied and modified from https://github.com/foundry-rs/foundry/blob/master/ui/src/lib.rs - -use crate::loader::evm::{ - util::executor::{CallKind, DebugStep}, - Address, -}; -use crossterm::{ - event::{ - self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEvent, KeyModifiers, - MouseEvent, MouseEventKind, - }, - execute, - terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, -}; -use revm::opcode; -use std::{ - cmp::{max, min}, - io, - sync::mpsc, - thread, - time::{Duration, Instant}, -}; -use tui::{ - backend::{Backend, CrosstermBackend}, - layout::{Alignment, Constraint, Direction, Layout, Rect}, - style::{Color, Modifier, Style}, - terminal::Frame, - text::{Span, Spans, Text}, - widgets::{Block, Borders, Paragraph, Wrap}, - Terminal, -}; - -pub struct Tui { - debug_arena: Vec<(Address, Vec, CallKind)>, - terminal: Terminal>, - key_buffer: String, - current_step: usize, -} - -impl Tui { - pub fn new(debug_arena: Vec<(Address, Vec, CallKind)>, current_step: usize) -> Self { - enable_raw_mode().unwrap(); - let mut stdout = io::stdout(); - execute!(stdout, EnterAlternateScreen, EnableMouseCapture).unwrap(); - let backend = CrosstermBackend::new(stdout); - let mut terminal = Terminal::new(backend).unwrap(); - terminal.hide_cursor().unwrap(); - Tui { debug_arena, terminal, key_buffer: String::new(), current_step } - } - - pub fn start(mut self) { - std::panic::set_hook(Box::new(|e| { - disable_raw_mode().expect("Unable to disable raw mode"); - execute!(io::stdout(), LeaveAlternateScreen, DisableMouseCapture) - .expect("unable to execute disable mouse capture"); - println!("{e}"); - })); - let tick_rate = Duration::from_millis(60); - - let (tx, rx) = mpsc::channel(); - thread::spawn(move || { - let mut last_tick = Instant::now(); - loop { - if event::poll(tick_rate - last_tick.elapsed()).unwrap() { - let event = event::read().unwrap(); - if let Event::Key(key) = event { - if tx.send(Interrupt::KeyPressed(key)).is_err() { - return; - } - } else if let Event::Mouse(mouse) = event { - if tx.send(Interrupt::MouseEvent(mouse)).is_err() { - return; - } - } - } - if last_tick.elapsed() > tick_rate { - if tx.send(Interrupt::IntervalElapsed).is_err() { - return; - } - last_tick = Instant::now(); - } - } - }); - - self.terminal.clear().unwrap(); - let mut draw_memory: DrawMemory = DrawMemory::default(); - - let debug_call = &self.debug_arena; - let mut opcode_list: Vec = - debug_call[0].1.iter().map(|step| step.pretty_opcode()).collect(); - let mut last_index = 0; - - let mut stack_labels = false; - let mut mem_utf = false; - loop { - if last_index != draw_memory.inner_call_index { - opcode_list = debug_call[draw_memory.inner_call_index] - .1 - .iter() - .map(|step| step.pretty_opcode()) - .collect(); - last_index = draw_memory.inner_call_index; - } - match rx.recv().unwrap() { - Interrupt::KeyPressed(event) => match event.code { - KeyCode::Char('q') => { - disable_raw_mode().unwrap(); - execute!( - self.terminal.backend_mut(), - LeaveAlternateScreen, - DisableMouseCapture - ) - .unwrap(); - return; - } - KeyCode::Char('j') | KeyCode::Down => { - for _ in 0..Tui::buffer_as_number(&self.key_buffer, 1) { - if event.modifiers.contains(KeyModifiers::CONTROL) { - let max_mem = (debug_call[draw_memory.inner_call_index].1 - [self.current_step] - .memory - .len() - / 32) - .saturating_sub(1); - let step = if event.modifiers.contains(KeyModifiers::ALT) { - 20 - } else { - 1 - }; - if draw_memory.current_mem_startline + step < max_mem { - draw_memory.current_mem_startline += step; - } - } else if self.current_step < opcode_list.len() - 1 { - self.current_step += 1; - } else if draw_memory.inner_call_index < debug_call.len() - 1 { - draw_memory.inner_call_index += 1; - self.current_step = 0; - } - } - self.key_buffer.clear(); - } - KeyCode::Char('J') => { - for _ in 0..Tui::buffer_as_number(&self.key_buffer, 1) { - let max_stack = debug_call[draw_memory.inner_call_index].1 - [self.current_step] - .stack - .len() - .saturating_sub(1); - if draw_memory.current_stack_startline < max_stack { - draw_memory.current_stack_startline += 1; - } - } - self.key_buffer.clear(); - } - KeyCode::Char('k') | KeyCode::Up => { - for _ in 0..Tui::buffer_as_number(&self.key_buffer, 1) { - if event.modifiers.contains(KeyModifiers::CONTROL) { - draw_memory.current_mem_startline = - draw_memory.current_mem_startline.saturating_sub(1); - } else if self.current_step > 0 { - self.current_step -= 1; - } else if draw_memory.inner_call_index > 0 { - draw_memory.inner_call_index -= 1; - self.current_step = - debug_call[draw_memory.inner_call_index].1.len() - 1; - } - } - self.key_buffer.clear(); - } - KeyCode::Char('K') => { - for _ in 0..Tui::buffer_as_number(&self.key_buffer, 1) { - draw_memory.current_stack_startline = - draw_memory.current_stack_startline.saturating_sub(1); - } - self.key_buffer.clear(); - } - KeyCode::Char('g') => { - draw_memory.inner_call_index = 0; - self.current_step = 0; - self.key_buffer.clear(); - } - KeyCode::Char('G') => { - draw_memory.inner_call_index = debug_call.len() - 1; - self.current_step = debug_call[draw_memory.inner_call_index].1.len() - 1; - self.key_buffer.clear(); - } - KeyCode::Char('c') => { - draw_memory.inner_call_index = - draw_memory.inner_call_index.saturating_sub(1); - self.current_step = debug_call[draw_memory.inner_call_index].1.len() - 1; - self.key_buffer.clear(); - } - KeyCode::Char('C') => { - if debug_call.len() > draw_memory.inner_call_index + 1 { - draw_memory.inner_call_index += 1; - self.current_step = 0; - } - self.key_buffer.clear(); - } - KeyCode::Char('s') => { - for _ in 0..Tui::buffer_as_number(&self.key_buffer, 1) { - let remaining_ops = &opcode_list[self.current_step..]; - self.current_step += remaining_ops - .iter() - .enumerate() - .find_map(|(i, op)| { - if i < remaining_ops.len() - 1 { - match ( - op.contains("JUMP") && op != "JUMPDEST", - &*remaining_ops[i + 1], - ) { - (true, "JUMPDEST") => Some(i + 1), - _ => None, - } - } else { - None - } - }) - .unwrap_or(opcode_list.len() - 1); - if self.current_step > opcode_list.len() { - self.current_step = opcode_list.len() - 1 - }; - } - self.key_buffer.clear(); - } - KeyCode::Char('a') => { - for _ in 0..Tui::buffer_as_number(&self.key_buffer, 1) { - let prev_ops = &opcode_list[..self.current_step]; - self.current_step = prev_ops - .iter() - .enumerate() - .rev() - .find_map(|(i, op)| { - if i > 0 { - match ( - prev_ops[i - 1].contains("JUMP") - && prev_ops[i - 1] != "JUMPDEST", - &**op, - ) { - (true, "JUMPDEST") => Some(i - 1), - _ => None, - } - } else { - None - } - }) - .unwrap_or_default(); - } - self.key_buffer.clear(); - } - KeyCode::Char('t') => { - stack_labels = !stack_labels; - } - KeyCode::Char('m') => { - mem_utf = !mem_utf; - } - KeyCode::Char(other) => match other { - '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' => { - self.key_buffer.push(other); - } - _ => { - self.key_buffer.clear(); - } - }, - _ => { - self.key_buffer.clear(); - } - }, - Interrupt::MouseEvent(event) => match event.kind { - MouseEventKind::ScrollUp => { - if self.current_step > 0 { - self.current_step -= 1; - } else if draw_memory.inner_call_index > 0 { - draw_memory.inner_call_index -= 1; - draw_memory.current_mem_startline = 0; - draw_memory.current_stack_startline = 0; - self.current_step = - debug_call[draw_memory.inner_call_index].1.len() - 1; - } - } - MouseEventKind::ScrollDown => { - if self.current_step < opcode_list.len() - 1 { - self.current_step += 1; - } else if draw_memory.inner_call_index < debug_call.len() - 1 { - draw_memory.inner_call_index += 1; - draw_memory.current_mem_startline = 0; - draw_memory.current_stack_startline = 0; - self.current_step = 0; - } - } - _ => {} - }, - Interrupt::IntervalElapsed => {} - } - let current_step = self.current_step; - self.terminal - .draw(|f| { - Tui::draw_layout( - f, - debug_call[draw_memory.inner_call_index].0, - &debug_call[draw_memory.inner_call_index].1[..], - &opcode_list, - current_step, - &mut draw_memory, - stack_labels, - mem_utf, - ) - }) - .unwrap(); - } - } - - fn buffer_as_number(buffer: &str, default_value: usize) -> usize { - if let Ok(num) = buffer.parse() { - if num >= 1 { - num - } else { - default_value - } - } else { - default_value - } - } - - fn draw_layout( - f: &mut Frame, - address: Address, - debug_steps: &[DebugStep], - opcode_list: &[String], - current_step: usize, - draw_memory: &mut DrawMemory, - stack_labels: bool, - mem_utf: bool, - ) { - let total_size = f.size(); - if total_size.width < 225 { - Tui::vertical_layout( - f, - address, - debug_steps, - opcode_list, - current_step, - draw_memory, - stack_labels, - mem_utf, - ); - } else { - Tui::square_layout( - f, - address, - debug_steps, - opcode_list, - current_step, - draw_memory, - stack_labels, - mem_utf, - ); - } - } - - fn vertical_layout( - f: &mut Frame, - address: Address, - debug_steps: &[DebugStep], - opcode_list: &[String], - current_step: usize, - draw_memory: &mut DrawMemory, - stack_labels: bool, - mem_utf: bool, - ) { - let total_size = f.size(); - if let [app, footer] = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Ratio(98, 100), Constraint::Ratio(2, 100)].as_ref()) - .split(total_size)[..] - { - if let [op_pane, stack_pane, memory_pane] = Layout::default() - .direction(Direction::Vertical) - .constraints( - [Constraint::Ratio(1, 3), Constraint::Ratio(1, 3), Constraint::Ratio(1, 3)] - .as_ref(), - ) - .split(app)[..] - { - Tui::draw_footer(f, footer); - Tui::draw_op_list( - f, - address, - debug_steps, - opcode_list, - current_step, - draw_memory, - op_pane, - ); - Tui::draw_stack( - f, - debug_steps, - current_step, - stack_pane, - stack_labels, - draw_memory, - ); - Tui::draw_memory(f, debug_steps, current_step, memory_pane, mem_utf, draw_memory); - } else { - panic!("unable to create vertical panes") - } - } else { - panic!("unable to create footer / app") - } - } - - fn square_layout( - f: &mut Frame, - address: Address, - debug_steps: &[DebugStep], - opcode_list: &[String], - current_step: usize, - draw_memory: &mut DrawMemory, - stack_labels: bool, - mem_utf: bool, - ) { - let total_size = f.size(); - - if let [app, footer] = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Ratio(98, 100), Constraint::Ratio(2, 100)].as_ref()) - .split(total_size)[..] - { - if let [left_pane, right_pane] = Layout::default() - .direction(Direction::Horizontal) - .constraints([Constraint::Ratio(1, 2), Constraint::Ratio(1, 2)].as_ref()) - .split(app)[..] - { - if let [stack_pane, memory_pane] = Layout::default() - .direction(Direction::Vertical) - .constraints([Constraint::Ratio(2, 5), Constraint::Ratio(3, 5)].as_ref()) - .split(right_pane)[..] - { - Tui::draw_footer(f, footer); - Tui::draw_op_list( - f, - address, - debug_steps, - opcode_list, - current_step, - draw_memory, - left_pane, - ); - Tui::draw_stack( - f, - debug_steps, - current_step, - stack_pane, - stack_labels, - draw_memory, - ); - Tui::draw_memory( - f, - debug_steps, - current_step, - memory_pane, - mem_utf, - draw_memory, - ); - } else { - panic!("Couldn't generate horizontal split layout 1:2."); - } - } else { - panic!("Couldn't generate vertical split layout 1:2."); - } - } else { - panic!("Couldn't generate application & footer") - } - } - - fn draw_footer(f: &mut Frame, area: Rect) { - let block_controls = Block::default(); - - let text_output = Text::from(Span::styled( - "[q]: quit | [k/j]: prev/next op | [a/s]: prev/next jump | [c/C]: prev/next call | [g/G]: start/end | [t]: toggle stack labels | [m]: toggle memory decoding | [shift + j/k]: scroll stack | [ctrl + j/k]: scroll memory", - Style::default().add_modifier(Modifier::DIM) - )); - let paragraph = Paragraph::new(text_output) - .block(block_controls) - .alignment(Alignment::Center) - .wrap(Wrap { trim: false }); - f.render_widget(paragraph, area); - } - - fn draw_op_list( - f: &mut Frame, - address: Address, - debug_steps: &[DebugStep], - opcode_list: &[String], - current_step: usize, - draw_memory: &mut DrawMemory, - area: Rect, - ) { - let block_source_code = Block::default() - .title(format!( - "Address: {:?} | PC: {} | Gas used in call: {}", - address, - if let Some(step) = debug_steps.get(current_step) { - step.pc.to_string() - } else { - "END".to_string() - }, - debug_steps[current_step].total_gas_used, - )) - .borders(Borders::ALL); - let mut text_output: Vec = Vec::new(); - - let display_start; - - let height = area.height as i32; - let extra_top_lines = height / 2; - let prev_start = draw_memory.current_startline; - let abs_min_start = 0; - let abs_max_start = (opcode_list.len() as i32 - 1) - (height / 2); - let mut min_start = - max(current_step as i32 - height + extra_top_lines, abs_min_start) as usize; - - let mut max_start = - max(min(current_step as i32 - extra_top_lines, abs_max_start), abs_min_start) as usize; - - if min_start > max_start { - std::mem::swap(&mut min_start, &mut max_start); - } - - if prev_start < min_start { - display_start = min_start; - } else if prev_start > max_start { - display_start = max_start; - } else { - display_start = prev_start; - } - draw_memory.current_startline = display_start; - - let max_pc_len = - debug_steps.iter().fold(0, |max_val, val| val.pc.max(max_val)).to_string().len(); - - let mut add_new_line = |line_number| { - let bg_color = if line_number == current_step { Color::DarkGray } else { Color::Reset }; - - let line_number_format = if line_number == current_step { - let step: &DebugStep = &debug_steps[line_number]; - format!("{:0>max_pc_len$x}|▶", step.pc) - } else if line_number < debug_steps.len() { - let step: &DebugStep = &debug_steps[line_number]; - format!("{:0>max_pc_len$x}| ", step.pc) - } else { - "END CALL".to_string() - }; - - if let Some(op) = opcode_list.get(line_number) { - text_output.push(Spans::from(Span::styled( - format!("{line_number_format}{op}"), - Style::default().fg(Color::White).bg(bg_color), - ))); - } else { - text_output.push(Spans::from(Span::styled( - line_number_format, - Style::default().fg(Color::White).bg(bg_color), - ))); - } - }; - for number in display_start..opcode_list.len() { - add_new_line(number); - } - add_new_line(opcode_list.len()); - let paragraph = - Paragraph::new(text_output).block(block_source_code).wrap(Wrap { trim: true }); - f.render_widget(paragraph, area); - } - - fn draw_stack( - f: &mut Frame, - debug_steps: &[DebugStep], - current_step: usize, - area: Rect, - stack_labels: bool, - draw_memory: &DrawMemory, - ) { - let stack = &debug_steps[current_step].stack; - let stack_space = - Block::default().title(format!("Stack: {}", stack.len())).borders(Borders::ALL); - let min_len = usize::max(format!("{}", stack.len()).len(), 2); - - let indices_affected = stack_indices_affected(debug_steps[current_step].instruction.0); - - let text: Vec = stack - .iter() - .rev() - .enumerate() - .skip(draw_memory.current_stack_startline) - .map(|(i, stack_item)| { - let affected = - indices_affected.iter().find(|(affected_index, _name)| *affected_index == i); - - let mut words: Vec = (0..32) - .rev() - .map(|i| stack_item.byte(i)) - .map(|byte| { - Span::styled( - format!("{byte:02x} "), - if affected.is_some() { - Style::default().fg(Color::Cyan) - } else if byte == 0 { - Style::default().add_modifier(Modifier::DIM) - } else { - Style::default().fg(Color::White) - }, - ) - }) - .collect(); - - if stack_labels { - if let Some((_, name)) = affected { - words.push(Span::raw(format!("| {name}"))); - } else { - words.push(Span::raw("| ".to_string())); - } - } - - let mut spans = vec![Span::styled( - format!("{i:0min_len$}| "), - Style::default().fg(Color::White), - )]; - spans.extend(words); - spans.push(Span::raw("\n")); - - Spans::from(spans) - }) - .collect(); - - let paragraph = Paragraph::new(text).block(stack_space).wrap(Wrap { trim: true }); - f.render_widget(paragraph, area); - } - - fn draw_memory( - f: &mut Frame, - debug_steps: &[DebugStep], - current_step: usize, - area: Rect, - mem_utf8: bool, - draw_mem: &DrawMemory, - ) { - let memory = &debug_steps[current_step].memory; - let stack_space = Block::default() - .title(format!("Memory (max expansion: {} bytes)", memory.effective_len())) - .borders(Borders::ALL); - let memory = memory.data(); - let max_i = memory.len() / 32; - let min_len = format!("{:x}", max_i * 32).len(); - - let mut word = None; - let mut color = None; - let stack_len = debug_steps[current_step].stack.len(); - if stack_len > 0 { - let w = debug_steps[current_step].stack[stack_len - 1]; - match debug_steps[current_step].instruction.0 { - opcode::MLOAD => { - word = Some(w.as_usize() / 32); - color = Some(Color::Cyan); - } - opcode::MSTORE => { - word = Some(w.as_usize() / 32); - color = Some(Color::Red); - } - _ => {} - } - } - - if current_step > 0 { - let prev_step = current_step - 1; - let stack_len = debug_steps[prev_step].stack.len(); - if debug_steps[prev_step].instruction.0 == opcode::MSTORE { - let prev_top = debug_steps[prev_step].stack[stack_len - 1]; - word = Some(prev_top.as_usize() / 32); - color = Some(Color::Green); - } - } - - let text: Vec = memory - .chunks(32) - .enumerate() - .skip(draw_mem.current_mem_startline) - .map(|(i, mem_word)| { - let words: Vec = mem_word - .iter() - .map(|byte| { - Span::styled( - format!("{byte:02x} "), - if let (Some(w), Some(color)) = (word, color) { - if i == w { - Style::default().fg(color) - } else if *byte == 0 { - Style::default().add_modifier(Modifier::DIM) - } else { - Style::default().fg(Color::White) - } - } else if *byte == 0 { - Style::default().add_modifier(Modifier::DIM) - } else { - Style::default().fg(Color::White) - }, - ) - }) - .collect(); - - let mut spans = vec![Span::styled( - format!("{:0min_len$x}| ", i * 32), - Style::default().fg(Color::White), - )]; - spans.extend(words); - - if mem_utf8 { - let chars: Vec = mem_word - .chunks(4) - .map(|utf| { - if let Ok(utf_str) = std::str::from_utf8(utf) { - Span::raw(utf_str.replace(char::from(0), ".")) - } else { - Span::raw(".") - } - }) - .collect(); - spans.push(Span::raw("|")); - spans.extend(chars); - } - - spans.push(Span::raw("\n")); - - Spans::from(spans) - }) - .collect(); - let paragraph = Paragraph::new(text).block(stack_space).wrap(Wrap { trim: true }); - f.render_widget(paragraph, area); - } -} - -enum Interrupt { - KeyPressed(KeyEvent), - MouseEvent(MouseEvent), - IntervalElapsed, -} - -struct DrawMemory { - pub current_startline: usize, - pub inner_call_index: usize, - pub current_mem_startline: usize, - pub current_stack_startline: usize, -} - -impl DrawMemory { - fn default() -> Self { - DrawMemory { - current_startline: 0, - inner_call_index: 0, - current_mem_startline: 0, - current_stack_startline: 0, - } - } -} - -fn stack_indices_affected(op: u8) -> Vec<(usize, &'static str)> { - match op { - 0x01 => vec![(0, "a"), (1, "b")], - 0x02 => vec![(0, "a"), (1, "b")], - 0x03 => vec![(0, "a"), (1, "b")], - 0x04 => vec![(0, "a"), (1, "b")], - 0x05 => vec![(0, "a"), (1, "b")], - 0x06 => vec![(0, "a"), (1, "b")], - 0x07 => vec![(0, "a"), (1, "b")], - 0x08 => vec![(0, "a"), (1, "b"), (2, "mod")], - 0x09 => vec![(0, "a"), (1, "b"), (2, "mod")], - 0x0a => vec![(0, "base"), (1, "exp")], - 0x0b => vec![(0, "i"), (1, "a")], - 0x10 => vec![(0, "a"), (1, "b")], - 0x11 => vec![(0, "a"), (1, "b")], - 0x12 => vec![(0, "a"), (1, "b")], - 0x13 => vec![(0, "a"), (1, "b")], - 0x14 => vec![(0, "a"), (1, "b")], - 0x15 => vec![(0, "a")], - 0x16 => vec![(0, "a"), (1, "b")], - 0x17 => vec![(0, "a"), (1, "b")], - 0x18 => vec![(0, "a"), (1, "b")], - 0x19 => vec![(0, "a")], - 0x1a => vec![(0, "i"), (1, "a")], - 0x1b => vec![(0, "shift"), (1, "a")], - 0x1c => vec![(0, "shift"), (1, "a")], - 0x1d => vec![(0, "shift"), (1, "a")], - 0x20 => vec![(0, "offset"), (1, "length")], - 0x31 => vec![(0, "address")], - 0x35 => vec![(0, "offset")], - 0x37 => vec![(0, "dst"), (1, "src"), (2, "length")], - 0x39 => vec![(0, "dst"), (1, "src"), (2, "length")], - 0x3b => vec![(0, "address")], - 0x3c => vec![(0, "address"), (1, "dst"), (2, "src"), (3, "length")], - 0x3e => vec![(0, "dst"), (1, "src"), (2, "length")], - 0x3f => vec![(0, "address")], - 0x40 => vec![(0, "number")], - 0x50 => vec![(0, "a")], - 0x51 => vec![(0, "offset")], - 0x52 => vec![(0, "offset"), (1, "a")], - 0x53 => vec![(0, "offset"), (1, "a")], - 0x54 => vec![(0, "key")], - 0x55 => vec![(0, "key"), (1, "a")], - 0x56 => vec![(0, "dst")], - 0x57 => vec![(0, "dst"), (1, "cond")], - 0x80 => vec![(0, "a")], - 0x81 => vec![(1, "a")], - 0x82 => vec![(2, "a")], - 0x83 => vec![(3, "a")], - 0x84 => vec![(4, "a")], - 0x85 => vec![(5, "a")], - 0x86 => vec![(6, "a")], - 0x87 => vec![(7, "a")], - 0x88 => vec![(8, "a")], - 0x89 => vec![(9, "a")], - 0x8a => vec![(10, "a")], - 0x8b => vec![(11, "a")], - 0x8c => vec![(12, "a")], - 0x8d => vec![(13, "a")], - 0x8e => vec![(14, "a")], - 0x8f => vec![(15, "a")], - 0x90 => vec![(0, "a"), (1, "a")], - 0x91 => vec![(0, "a"), (2, "a")], - 0x92 => vec![(0, "a"), (3, "a")], - 0x93 => vec![(0, "a"), (4, "a")], - 0x94 => vec![(0, "a"), (5, "a")], - 0x95 => vec![(0, "a"), (6, "a")], - 0x96 => vec![(0, "a"), (7, "a")], - 0x97 => vec![(0, "a"), (8, "a")], - 0x98 => vec![(0, "a"), (9, "a")], - 0x99 => vec![(0, "a"), (10, "a")], - 0x9a => vec![(0, "a"), (11, "a")], - 0x9b => vec![(0, "a"), (12, "a")], - 0x9c => vec![(0, "a"), (13, "a")], - 0x9d => vec![(0, "a"), (14, "a")], - 0x9e => vec![(0, "a"), (15, "a")], - 0x9f => vec![(0, "a"), (16, "a")], - 0xa0 => vec![(0, "offset"), (1, "length")], - 0xa1 => vec![(0, "offset"), (1, "length"), (2, "topic")], - 0xa2 => vec![(0, "offset"), (1, "length"), (2, "topic1"), (3, "topic2")], - 0xa3 => vec![(0, "offset"), (1, "length"), (2, "topic1"), (3, "topic2"), (4, "topic3")], - 0xa4 => vec![ - (0, "offset"), - (1, "length"), - (2, "topic1"), - (3, "topic2"), - (4, "topic3"), - (5, "topic4"), - ], - 0xf0 => vec![(0, "value"), (1, "offset"), (2, "length")], - 0xf1 => vec![ - (0, "gas"), - (1, "address"), - (2, "value"), - (3, "cd_offset"), - (4, "cd_length"), - (5, "rd_offset"), - (6, "rd_length"), - ], - 0xf2 => vec![ - (0, "gas"), - (1, "address"), - (2, "value"), - (3, "cd_offset"), - (4, "cd_length"), - (5, "rd_offset"), - (6, "rd_length"), - ], - 0xf3 => vec![(0, "offset"), (1, "length")], - 0xf4 => vec![ - (0, "gas"), - (1, "address"), - (2, "cd_offset"), - (3, "cd_length"), - (4, "rd_offset"), - (5, "rd_length"), - ], - 0xf5 => vec![(0, "value"), (1, "offset"), (2, "length"), (3, "salt")], - 0xfa => vec![ - (0, "gas"), - (1, "address"), - (2, "cd_offset"), - (3, "cd_length"), - (4, "rd_offset"), - (5, "rd_length"), - ], - 0xfd => vec![(0, "offset"), (1, "length")], - 0xff => vec![(0, "address")], - _ => vec![], - } -} diff --git a/snark-verifier/src/loader/evm/util.rs b/snark-verifier/src/loader/evm/util.rs index 5df077f6..747849d4 100644 --- a/snark-verifier/src/loader/evm/util.rs +++ b/snark-verifier/src/loader/evm/util.rs @@ -8,12 +8,11 @@ use std::{ process::{Command, Stdio}, }; -pub use primitive_types::{H160 as Address, H256, U256, U512}; +pub use executor::deploy_and_call; +pub use revm::primitives::ruint::aliases::{B160 as Address, B256, U256, U512}; pub(crate) mod executor; -pub use executor::ExecutorBuilder; - /// Memory chunk in EVM. #[derive(Debug)] pub struct MemoryChunk { @@ -55,7 +54,7 @@ pub fn fe_to_u256(f: F) -> U256 where F: PrimeField, { - U256::from_little_endian(f.to_repr().as_ref()) + U256::from_le_bytes(f.to_repr()) } /// Convert a [`U256`] into a [`PrimeField`]. @@ -64,9 +63,7 @@ where F: PrimeField, { let value = value % modulus::(); - let mut repr = F::Repr::default(); - value.to_little_endian(repr.as_mut()); - F::from_repr(repr).unwrap() + F::from_repr(value.to_le_bytes::<32>()).unwrap() } /// Returns modulus of [`PrimeField`] as [`U256`]. @@ -74,7 +71,7 @@ pub fn modulus() -> U256 where F: PrimeField, { - U256::from_little_endian((-F::ONE).to_repr().as_ref()) + 1 + U256::from_le_bytes((-F::ONE).to_repr()) + U256::from(1) } /// Encode instances and proof into calldata. diff --git a/snark-verifier/src/loader/evm/util/executor.rs b/snark-verifier/src/loader/evm/util/executor.rs index 17062028..e2c5bb2c 100644 --- a/snark-verifier/src/loader/evm/util/executor.rs +++ b/snark-verifier/src/loader/evm/util/executor.rs @@ -1,815 +1,59 @@ -//! Copied and modified from -//! - -use crate::loader::evm::{Address, H256, U256}; -use bytes::Bytes; use revm::{ - evm_inner, opcode, spec_opcode_gas, Account, BlockEnv, CallInputs, CallScheme, CreateInputs, - CreateScheme, Database, DatabaseCommit, EVMData, Env, ExecutionResult, Gas, GasInspector, - InMemoryDB, Inspector, Interpreter, Memory, OpCode, Return, TransactOut, TransactTo, TxEnv, + primitives::{CreateScheme, ExecutionResult, Output, TransactTo, TxEnv}, + InMemoryDB, EVM, }; -use sha3::{Digest, Keccak256}; -use std::{cell::RefCell, collections::HashMap, fmt::Display, rc::Rc}; -macro_rules! return_ok { - () => { - Return::Continue | Return::Stop | Return::Return | Return::SelfDestruct +/// Deploy contract and then call with calldata. +/// Returns gas_used of call to deployed contract if both transactions are successful. +pub fn deploy_and_call(deployment_code: Vec, calldata: Vec) -> Result { + let mut evm = EVM { + env: Default::default(), + db: Some(InMemoryDB::default()), }; -} - -fn keccak256(data: impl AsRef<[u8]>) -> [u8; 32] { - Keccak256::digest(data.as_ref()).into() -} - -fn get_contract_address(sender: impl Into
, nonce: impl Into) -> Address { - let mut stream = rlp::RlpStream::new(); - stream.begin_list(2); - stream.append(&sender.into()); - stream.append(&nonce.into()); - - let hash = keccak256(&stream.out()); - - let mut bytes = [0u8; 20]; - bytes.copy_from_slice(&hash[12..]); - Address::from(bytes) -} - -fn get_create2_address( - from: impl Into
, - salt: [u8; 32], - init_code: impl Into, -) -> Address { - get_create2_address_from_hash(from, salt, keccak256(init_code.into().as_ref()).to_vec()) -} - -fn get_create2_address_from_hash( - from: impl Into
, - salt: [u8; 32], - init_code_hash: impl Into, -) -> Address { - let bytes = - [&[0xff], from.into().as_bytes(), salt.as_slice(), init_code_hash.into().as_ref()].concat(); - - let hash = keccak256(bytes); - - let mut bytes = [0u8; 20]; - bytes.copy_from_slice(&hash[12..]); - Address::from(bytes) -} - -fn get_create_address(call: &CreateInputs, nonce: u64) -> Address { - match call.scheme { - CreateScheme::Create => get_contract_address(call.caller, nonce), - CreateScheme::Create2 { salt } => { - let mut buffer: [u8; 4 * 8] = [0; 4 * 8]; - salt.to_big_endian(&mut buffer); - get_create2_address(call.caller, buffer, call.init_code.clone()) - } - } -} - -#[derive(Clone, Debug, Default)] -pub struct Log { - pub address: Address, - pub topics: Vec, - pub data: Bytes, -} - -#[derive(Clone, Debug, Default)] -struct LogCollector { - logs: Vec, -} - -impl Inspector for LogCollector { - fn log(&mut self, _: &mut EVMData<'_, DB>, address: &Address, topics: &[H256], data: &Bytes) { - self.logs.push(Log { address: *address, topics: topics.to_vec(), data: data.clone() }); - } - - fn call( - &mut self, - _: &mut EVMData<'_, DB>, - call: &mut CallInputs, - _: bool, - ) -> (Return, Gas, Bytes) { - (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) - } -} - -#[derive(Clone, Debug, Copy)] -pub enum CallKind { - Call, - StaticCall, - CallCode, - DelegateCall, - Create, - Create2, -} - -#[allow(clippy::derivable_impls)] -impl Default for CallKind { - fn default() -> Self { - CallKind::Call - } -} - -impl From for CallKind { - fn from(scheme: CallScheme) -> Self { - match scheme { - CallScheme::Call => CallKind::Call, - CallScheme::StaticCall => CallKind::StaticCall, - CallScheme::CallCode => CallKind::CallCode, - CallScheme::DelegateCall => CallKind::DelegateCall, - } - } -} - -impl From for CallKind { - fn from(create: CreateScheme) -> Self { - match create { - CreateScheme::Create => CallKind::Create, - CreateScheme::Create2 { .. } => CallKind::Create2, - } - } -} - -#[derive(Clone, Debug, Default)] -pub struct DebugArena { - pub arena: Vec, -} - -impl DebugArena { - fn push_node(&mut self, mut new_node: DebugNode) -> usize { - fn recursively_push( - arena: &mut Vec, - entry: usize, - mut new_node: DebugNode, - ) -> usize { - match new_node.depth { - _ if arena[entry].depth == new_node.depth - 1 => { - let id = arena.len(); - new_node.location = arena[entry].children.len(); - new_node.parent = Some(entry); - arena[entry].children.push(id); - arena.push(new_node); - id - } - _ => { - let child = *arena[entry].children.last().unwrap(); - recursively_push(arena, child, new_node) - } - } - } - - if self.arena.is_empty() { - self.arena.push(new_node); - 0 - } else if new_node.depth == 0 { - let id = self.arena.len(); - new_node.location = self.arena[0].children.len(); - new_node.parent = Some(0); - self.arena[0].children.push(id); - self.arena.push(new_node); - id - } else { - recursively_push(&mut self.arena, 0, new_node) - } - } - - #[cfg(test)] - pub fn flatten(&self, entry: usize) -> Vec<(Address, Vec, CallKind)> { - let node = &self.arena[entry]; - - let mut flattened = vec![]; - if !node.steps.is_empty() { - flattened.push((node.address, node.steps.clone(), node.kind)); - } - flattened.extend(node.children.iter().flat_map(|child| self.flatten(*child))); - - flattened - } -} - -#[derive(Clone, Debug, Default)] -pub struct DebugNode { - pub parent: Option, - pub children: Vec, - pub location: usize, - pub address: Address, - pub kind: CallKind, - pub depth: usize, - pub steps: Vec, -} - -#[derive(Clone, Debug)] -pub struct DebugStep { - pub stack: Vec, - pub memory: Memory, - pub instruction: Instruction, - pub push_bytes: Option>, - pub pc: usize, - pub total_gas_used: u64, -} - -impl Default for DebugStep { - fn default() -> Self { - Self { - stack: vec![], - memory: Memory::new(), - instruction: Instruction(revm::opcode::INVALID), - push_bytes: None, - pc: 0, - total_gas_used: 0, - } - } -} - -impl DebugStep { - #[cfg(test)] - pub fn pretty_opcode(&self) -> String { - if let Some(push_bytes) = &self.push_bytes { - format!("{}(0x{})", self.instruction, hex::encode(push_bytes)) - } else { - self.instruction.to_string() - } - } -} - -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub struct Instruction(pub u8); - -impl From for Instruction { - fn from(op: u8) -> Instruction { - Instruction(op) - } -} - -impl Display for Instruction { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!( - f, - "{}", - OpCode::try_from_u8(self.0).map_or_else( - || format!("UNDEFINED(0x{:02x})", self.0), - |opcode| opcode.as_str().to_string(), - ) - ) - } -} - -#[derive(Clone, Debug)] -struct Debugger { - arena: DebugArena, - head: usize, - context: Address, - gas_inspector: Rc>, -} - -impl Debugger { - fn new(gas_inspector: Rc>) -> Self { - Self { - arena: Default::default(), - head: Default::default(), - context: Default::default(), - gas_inspector, - } - } - - fn enter(&mut self, depth: usize, address: Address, kind: CallKind) { - self.context = address; - self.head = self.arena.push_node(DebugNode { depth, address, kind, ..Default::default() }); - } - - fn exit(&mut self) { - if let Some(parent_id) = self.arena.arena[self.head].parent { - let DebugNode { depth, address, kind, .. } = self.arena.arena[parent_id]; - self.context = address; - self.head = - self.arena.push_node(DebugNode { depth, address, kind, ..Default::default() }); - } - } -} - -impl Inspector for Debugger { - fn step( - &mut self, - interpreter: &mut Interpreter, - data: &mut EVMData<'_, DB>, - _is_static: bool, - ) -> Return { - let pc = interpreter.program_counter(); - let op = interpreter.contract.bytecode.bytecode()[pc]; - - let opcode_infos = spec_opcode_gas(data.env.cfg.spec_id); - let opcode_info = &opcode_infos[op as usize]; - - let push_size = if opcode_info.is_push() { (op - opcode::PUSH1 + 1) as usize } else { 0 }; - let push_bytes = match push_size { - 0 => None, - n => { - let start = pc + 1; - let end = start + n; - Some(interpreter.contract.bytecode.bytecode()[start..end].to_vec()) - } - }; - - let spent = interpreter.gas.limit() - self.gas_inspector.borrow().gas_remaining(); - let total_gas_used = spent - (interpreter.gas.refunded() as u64).min(spent / 5); - - self.arena.arena[self.head].steps.push(DebugStep { - pc, - stack: interpreter.stack().data().clone(), - memory: interpreter.memory.clone(), - instruction: Instruction(op), - push_bytes, - total_gas_used, - }); - - Return::Continue - } - - fn call( - &mut self, - data: &mut EVMData<'_, DB>, - call: &mut CallInputs, - _: bool, - ) -> (Return, Gas, Bytes) { - self.enter( - data.journaled_state.depth() as usize, - call.context.code_address, - call.context.scheme.into(), - ); - - (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) - } - fn call_end( - &mut self, - _: &mut EVMData<'_, DB>, - _: &CallInputs, - gas: Gas, - status: Return, - retdata: Bytes, - _: bool, - ) -> (Return, Gas, Bytes) { - self.exit(); - - (status, gas, retdata) - } - - fn create( - &mut self, - data: &mut EVMData<'_, DB>, - call: &mut CreateInputs, - ) -> (Return, Option
, Gas, Bytes) { - let nonce = data.journaled_state.account(call.caller).info.nonce; - self.enter( - data.journaled_state.depth() as usize, - get_create_address(call, nonce), - CallKind::Create, - ); - - (Return::Continue, None, Gas::new(call.gas_limit), Bytes::new()) - } - - fn create_end( - &mut self, - _: &mut EVMData<'_, DB>, - _: &CreateInputs, - status: Return, - address: Option
, - gas: Gas, - retdata: Bytes, - ) -> (Return, Option
, Gas, Bytes) { - self.exit(); - - (status, address, gas, retdata) - } -} - -macro_rules! call_inspectors { - ($id:ident, [ $($inspector:expr),+ ], $call:block) => { - $({ - if let Some($id) = $inspector { - $call; - } - })+ - } -} - -struct InspectorData { - logs: Vec, - debug: Option, -} - -#[derive(Default)] -struct InspectorStack { - gas: Option>>, - logs: Option, - debugger: Option, -} - -impl InspectorStack { - fn collect_inspector_states(self) -> InspectorData { - InspectorData { - logs: self.logs.map(|logs| logs.logs).unwrap_or_default(), - debug: self.debugger.map(|debugger| debugger.arena), - } - } -} - -impl Inspector for InspectorStack { - fn initialize_interp( - &mut self, - interpreter: &mut Interpreter, - data: &mut EVMData<'_, DB>, - is_static: bool, - ) -> Return { - call_inspectors!( - inspector, - [ - &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), - &mut self.logs, - &mut self.debugger - ], - { - let status = inspector.initialize_interp(interpreter, data, is_static); - - if status != Return::Continue { - return status; - } - } - ); - - Return::Continue - } - - fn step( - &mut self, - interpreter: &mut Interpreter, - data: &mut EVMData<'_, DB>, - is_static: bool, - ) -> Return { - call_inspectors!( - inspector, - [ - &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), - &mut self.logs, - &mut self.debugger - ], - { - let status = inspector.step(interpreter, data, is_static); - - if status != Return::Continue { - return status; - } - } - ); - - Return::Continue - } - - fn log( - &mut self, - evm_data: &mut EVMData<'_, DB>, - address: &Address, - topics: &[H256], - data: &Bytes, - ) { - call_inspectors!(inspector, [&mut self.logs], { - inspector.log(evm_data, address, topics, data); - }); - } - - fn step_end( - &mut self, - interpreter: &mut Interpreter, - data: &mut EVMData<'_, DB>, - is_static: bool, - status: Return, - ) -> Return { - call_inspectors!( - inspector, - [ - &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), - &mut self.logs, - &mut self.debugger - ], - { - let status = inspector.step_end(interpreter, data, is_static, status); - - if status != Return::Continue { - return status; - } - } - ); - - Return::Continue - } - - fn call( - &mut self, - data: &mut EVMData<'_, DB>, - call: &mut CallInputs, - is_static: bool, - ) -> (Return, Gas, Bytes) { - call_inspectors!( - inspector, - [ - &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), - &mut self.logs, - &mut self.debugger - ], - { - let (status, gas, retdata) = inspector.call(data, call, is_static); - - if status != Return::Continue { - return (status, gas, retdata); - } - } - ); - - (Return::Continue, Gas::new(call.gas_limit), Bytes::new()) - } - - fn call_end( - &mut self, - data: &mut EVMData<'_, DB>, - call: &CallInputs, - remaining_gas: Gas, - status: Return, - retdata: Bytes, - is_static: bool, - ) -> (Return, Gas, Bytes) { - call_inspectors!( - inspector, - [ - &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), - &mut self.logs, - &mut self.debugger - ], - { - let (new_status, new_gas, new_retdata) = inspector.call_end( - data, - call, - remaining_gas, - status, - retdata.clone(), - is_static, - ); - - if new_status != status || (new_status == Return::Revert && new_retdata != retdata) - { - return (new_status, new_gas, new_retdata); - } - } - ); - - (status, remaining_gas, retdata) - } - - fn create( - &mut self, - data: &mut EVMData<'_, DB>, - call: &mut CreateInputs, - ) -> (Return, Option
, Gas, Bytes) { - call_inspectors!( - inspector, - [ - &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), - &mut self.logs, - &mut self.debugger - ], - { - let (status, addr, gas, retdata) = inspector.create(data, call); - - if status != Return::Continue { - return (status, addr, gas, retdata); - } - } - ); - - (Return::Continue, None, Gas::new(call.gas_limit), Bytes::new()) - } - - fn create_end( - &mut self, - data: &mut EVMData<'_, DB>, - call: &CreateInputs, - status: Return, - address: Option
, - remaining_gas: Gas, - retdata: Bytes, - ) -> (Return, Option
, Gas, Bytes) { - call_inspectors!( - inspector, - [ - &mut self.gas.as_deref().map(|gas| gas.borrow_mut()), - &mut self.logs, - &mut self.debugger - ], - { - let (new_status, new_address, new_gas, new_retdata) = inspector.create_end( - data, - call, - status, - address, - remaining_gas, - retdata.clone(), - ); - - if new_status != status { - return (new_status, new_address, new_gas, new_retdata); - } - } - ); - - (status, address, remaining_gas, retdata) - } - - fn selfdestruct(&mut self) { - call_inspectors!(inspector, [&mut self.logs, &mut self.debugger], { - Inspector::::selfdestruct(inspector); - }); - } -} - -/// Call result. -#[derive(Debug)] -pub struct RawCallResult { - /// Exit reason - pub exit_reason: Return, - /// If the call is reverted or not. - pub reverted: bool, - /// Returndata - pub result: Bytes, - /// Gas used - pub gas_used: u64, - /// Gas refunded - pub gas_refunded: u64, - /// Logs emitted during the call - pub logs: Vec, - /// Debug information if any - pub debug: Option, - /// State changes if any - pub state_changeset: Option>, - /// Environment - pub env: Env, - /// Output - pub out: TransactOut, -} - -#[derive(Clone, Debug)] -pub struct DeployResult { - pub exit_reason: Return, - pub reverted: bool, - pub address: Option
, - pub gas_used: u64, - pub gas_refunded: u64, - pub logs: Vec, - pub debug: Option, - pub env: Env, -} - -/// Executor builder. -#[derive(Debug, Default)] -pub struct ExecutorBuilder { - debugger: bool, - gas_limit: Option, -} - -impl ExecutorBuilder { - /// Set `debugger`. - pub fn set_debugger(mut self, enable: bool) -> Self { - self.debugger = enable; - self - } - - /// Set `gas_limit`. - pub fn with_gas_limit(mut self, gas_limit: U256) -> Self { - self.gas_limit = Some(gas_limit); - self - } - - /// Initialize an `Executor`. - pub fn build(self) -> Executor { - Executor::new(self.debugger, self.gas_limit.unwrap_or(U256::MAX)) - } -} - -#[derive(Clone, Debug)] -pub struct Executor { - db: InMemoryDB, - debugger: bool, - gas_limit: U256, -} - -impl Executor { - fn new(debugger: bool, gas_limit: U256) -> Self { - Executor { db: InMemoryDB::default(), debugger, gas_limit } - } - - pub fn db_mut(&mut self) -> &mut InMemoryDB { - &mut self.db - } - - pub fn deploy(&mut self, from: Address, code: Bytes, value: U256) -> DeployResult { - let env = self.build_test_env(from, TransactTo::Create(CreateScheme::Create), code, value); - let result = self.call_raw_with_env(env); - self.commit(&result); - - let RawCallResult { exit_reason, out, gas_used, gas_refunded, logs, debug, env, .. } = - result; - - let address = match (exit_reason, out) { - (return_ok!(), TransactOut::Create(_, Some(address))) => Some(address), - _ => None, - }; - - DeployResult { - exit_reason, - reverted: !matches!(exit_reason, return_ok!()), - address, - gas_used, - gas_refunded, - logs, - debug, - env, - } - } - - pub fn call_raw( - &self, - from: Address, - to: Address, - calldata: Bytes, - value: U256, - ) -> RawCallResult { - let env = self.build_test_env(from, TransactTo::Call(to), calldata, value); - self.call_raw_with_env(env) - } - - fn call_raw_with_env(&self, mut env: Env) -> RawCallResult { - let mut inspector = self.inspector(); - let result = - evm_inner::<_, true>(&mut env, &mut self.db.clone(), &mut inspector).transact(); - let (exec_result, state_changeset) = result; - let ExecutionResult { exit_reason, gas_refunded, gas_used, out, .. } = exec_result; - - let result = match out { - TransactOut::Call(ref data) => data.to_owned(), - _ => Bytes::default(), - }; - let InspectorData { logs, debug } = inspector.collect_inspector_states(); - - RawCallResult { - exit_reason, - reverted: !matches!(exit_reason, return_ok!()), - result, - gas_used, - gas_refunded, - logs: logs.to_vec(), - debug, - state_changeset: Some(state_changeset.into_iter().collect()), - env, - out, - } - } + evm.env.tx = TxEnv { + gas_limit: u64::MAX, + transact_to: TransactTo::Create(CreateScheme::Create), + data: deployment_code.into(), + ..Default::default() + }; - fn commit(&mut self, result: &RawCallResult) { - if let Some(state_changeset) = result.state_changeset.as_ref() { - self.db.commit(state_changeset.clone().into_iter().collect()); - } - } + let result = evm.transact_commit().unwrap(); + let contract = match result { + ExecutionResult::Success { + output: Output::Create(_, Some(contract)), + .. + } => contract, + ExecutionResult::Revert { gas_used, output } => { + return Err(format!( + "Contract deployment transaction reverts with gas_used {gas_used} and output {:#x}", + output + )) + } + ExecutionResult::Halt { reason, gas_used } => return Err(format!( + "Contract deployment transaction halts unexpectedly with gas_used {gas_used} and reason {:?}", + reason + )), + _ => unreachable!(), + }; - fn inspector(&self) -> InspectorStack { - let mut stack = - InspectorStack { logs: Some(LogCollector::default()), ..Default::default() }; - if self.debugger { - let gas_inspector = Rc::new(RefCell::new(GasInspector::default())); - stack.gas = Some(gas_inspector.clone()); - stack.debugger = Some(Debugger::new(gas_inspector)); - } - stack - } + evm.env.tx = TxEnv { + gas_limit: u64::MAX, + transact_to: TransactTo::Call(contract), + data: calldata.into(), + ..Default::default() + }; - fn build_test_env( - &self, - caller: Address, - transact_to: TransactTo, - data: Bytes, - value: U256, - ) -> Env { - Env { - block: BlockEnv { gas_limit: self.gas_limit, ..BlockEnv::default() }, - tx: TxEnv { - caller, - transact_to, - data, - value, - gas_limit: self.gas_limit.as_u64(), - ..TxEnv::default() - }, - ..Env::default() - } + let result = evm.transact_commit().unwrap(); + match result { + ExecutionResult::Success { gas_used, .. } => Ok(gas_used), + ExecutionResult::Revert { gas_used, output } => Err(format!( + "Contract call transaction reverts with gas_used {gas_used} and output {:#x}", + output + )), + ExecutionResult::Halt { reason, gas_used } => Err(format!( + "Contract call transaction halts unexpectedly with gas_used {gas_used} and reason {:?}", + reason + )), } } diff --git a/snark-verifier/src/pcs/kzg/decider.rs b/snark-verifier/src/pcs/kzg/decider.rs index 04f2caaf..d55e0a57 100644 --- a/snark-verifier/src/pcs/kzg/decider.rs +++ b/snark-verifier/src/pcs/kzg/decider.rs @@ -127,10 +127,10 @@ mod evm { let x = coordinates.x().to_repr(); let y = coordinates.y().to_repr(); ( - U256::from_little_endian(&x.as_ref()[32..]), - U256::from_little_endian(&x.as_ref()[..32]), - U256::from_little_endian(&y.as_ref()[32..]), - U256::from_little_endian(&y.as_ref()[..32]), + U256::try_from_le_slice(&x.as_ref()[32..]).unwrap(), + U256::try_from_le_slice(&x.as_ref()[..32]).unwrap(), + U256::try_from_le_slice(&y.as_ref()[32..]).unwrap(), + U256::try_from_le_slice(&y.as_ref()[..32]).unwrap(), ) }); loader.pairing(&lhs, g2, &rhs, minus_s_g2); diff --git a/snark-verifier/src/system/halo2/transcript/evm.rs b/snark-verifier/src/system/halo2/transcript/evm.rs index c71c9e79..da2c09c2 100644 --- a/snark-verifier/src/system/halo2/transcript/evm.rs +++ b/snark-verifier/src/system/halo2/transcript/evm.rs @@ -178,7 +178,7 @@ where .collect_vec(); let hash: [u8; 32] = Keccak256::digest(data).into(); self.buf = hash.to_vec(); - u256_to_fe(U256::from_big_endian(hash.as_slice())) + u256_to_fe(U256::from_be_bytes(hash)) } fn common_ec_point(&mut self, ec_point: &C) -> Result<(), Error> { @@ -274,7 +274,7 @@ where type Input = [u8; 32]; fn new(challenge_input: &[u8; 32]) -> Self { - ChallengeEvm(u256_to_fe(U256::from_big_endian(challenge_input))) + ChallengeEvm(u256_to_fe(U256::from_be_bytes(*challenge_input))) } fn get_scalar(&self) -> C::Scalar { diff --git a/snark-verifier/src/util/arithmetic.rs b/snark-verifier/src/util/arithmetic.rs index 070277a5..c34daef8 100644 --- a/snark-verifier/src/util/arithmetic.rs +++ b/snark-verifier/src/util/arithmetic.rs @@ -156,7 +156,7 @@ impl Domain { match rotation.0.cmp(&0) { Ordering::Equal => scalar, Ordering::Greater => scalar * self.gen.pow_vartime([rotation.0 as u64]), - Ordering::Less => scalar * self.gen_inv.pow_vartime([(-(rotation.0 as i64)) as u64]), + Ordering::Less => scalar * self.gen_inv.pow_vartime([(-rotation.0) as u64]), } } } diff --git a/snark-verifier/src/util/poly.rs b/snark-verifier/src/util/poly.rs index 9d688a4e..86271af4 100644 --- a/snark-verifier/src/util/poly.rs +++ b/snark-verifier/src/util/poly.rs @@ -70,12 +70,10 @@ impl Polynomial { let chunk_size = Integer::div_ceil(&self.len(), &num_threads); let mut results = vec![F::ZERO; num_threads]; parallelize_iter( - results.iter_mut().zip(self.0.chunks(chunk_size)).zip(powers(x.pow_vartime(&[ - chunk_size as u64, - 0, - 0, - 0, - ]))), + results + .iter_mut() + .zip(self.0.chunks(chunk_size)) + .zip(powers(x.pow_vartime([chunk_size as u64]))), |((result, coeffs), scalar)| *result = evaluate_serial(coeffs) * scalar, ); results.iter().fold(F::ZERO, |acc, result| acc + result) From 3aadbdf006642db370ec280d0cb9049ad0cf47ad Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 28 Aug 2023 17:14:40 -0600 Subject: [PATCH 49/73] Update: use `halo2-lib` v0.4.0 (#29) * feat: update snark-verifier * update: use `halo2-lib` v0.4.0 --- snark-verifier-sdk/Cargo.toml | 3 +- snark-verifier-sdk/benches/read_pk.rs | 7 +- snark-verifier-sdk/benches/standard_plonk.rs | 19 +- snark-verifier-sdk/examples/n_as_witness.rs | 9 +- snark-verifier-sdk/examples/range_check.rs | 62 ++--- .../examples/vkey_as_witness.rs | 9 +- snark-verifier-sdk/src/halo2/aggregation.rs | 225 +++++++----------- snark-verifier/Cargo.toml | 2 +- .../examples/evm-verifier-with-accumulator.rs | 116 +++------ snark-verifier/examples/recursion.rs | 75 +++--- snark-verifier/src/loader/halo2/shim.rs | 39 +-- snark-verifier/src/pcs/kzg/accumulator.rs | 4 +- 12 files changed, 222 insertions(+), 348 deletions(-) diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index fa423daf..a62b3b0c 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier-sdk" -version = "0.1.3" +version = "0.1.4" edition = "2021" [dependencies] @@ -19,6 +19,7 @@ bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } +getset = "0.1.2" # loader_evm ethereum-types = { version = "0.14.1", default-features = false, features = ["std"], optional = true } diff --git a/snark-verifier-sdk/benches/read_pk.rs b/snark-verifier-sdk/benches/read_pk.rs index f87f52c8..4adc42fd 100644 --- a/snark-verifier-sdk/benches/read_pk.rs +++ b/snark-verifier-sdk/benches/read_pk.rs @@ -1,7 +1,7 @@ use ark_std::{end_timer, start_timer}; use criterion::Criterion; use criterion::{criterion_group, criterion_main}; -use halo2_base::gates::builder::CircuitBuilderStage; +use halo2_base::gates::circuit::CircuitBuilderStage; use halo2_base::halo2_proofs; use halo2_base::utils::fs::gen_srs; use halo2_proofs::halo2curves as halo2_curves; @@ -172,8 +172,8 @@ mod application { fn gen_application_snark(params: &ParamsKZG) -> Snark { let circuit = application::StandardPlonk::rand(OsRng); - let pk = gen_pk(params, &circuit, Some(Path::new("examples/app.pk"))); - gen_snark_shplonk(params, &pk, circuit, Some(Path::new("examples/app.snark"))) + let pk = gen_pk(params, &circuit, None); + gen_snark_shplonk(params, &pk, circuit, None::<&str>) } fn bench(c: &mut Criterion) { @@ -187,7 +187,6 @@ fn bench(c: &mut Criterion) { let agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Keygen, agg_config, - None, ¶ms, snarks, VerifierUniversality::None, diff --git a/snark-verifier-sdk/benches/standard_plonk.rs b/snark-verifier-sdk/benches/standard_plonk.rs index 873f77cb..9f566999 100644 --- a/snark-verifier-sdk/benches/standard_plonk.rs +++ b/snark-verifier-sdk/benches/standard_plonk.rs @@ -1,7 +1,7 @@ use ark_std::{end_timer, start_timer}; use criterion::{criterion_group, criterion_main}; use criterion::{BenchmarkId, Criterion}; -use halo2_base::gates::builder::CircuitBuilderStage; +use halo2_base::gates::circuit::CircuitBuilderStage; use halo2_base::halo2_proofs; use halo2_base::utils::fs::gen_srs; use halo2_proofs::halo2curves as halo2_curves; @@ -19,7 +19,6 @@ use snark_verifier_sdk::{ Snark, }; use snark_verifier_sdk::{CircuitExt, SHPLONK}; -use std::path::Path; mod application { use super::halo2_curves::bn256::Fr; @@ -175,8 +174,8 @@ mod application { fn gen_application_snark(params: &ParamsKZG) -> Snark { let circuit = application::StandardPlonk::rand(OsRng); - let pk = gen_pk(params, &circuit, Some(Path::new("app.pk"))); - gen_snark_shplonk(params, &pk, circuit, Some(Path::new("app.snark"))) + let pk = gen_pk(params, &circuit, None); + gen_snark_shplonk(params, &pk, circuit, None::<&str>) } fn bench(c: &mut Criterion) { @@ -190,16 +189,16 @@ fn bench(c: &mut Criterion) { let agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Keygen, agg_config, - None, ¶ms, snarks.clone(), VerifierUniversality::None, ); let start0 = start_timer!(|| "gen vk & pk"); - let pk = gen_pk(¶ms, &agg_circuit, Some(Path::new("agg.pk"))); + let pk = gen_pk(¶ms, &agg_circuit, None); end_timer!(start0); let break_points = agg_circuit.break_points(); + drop(agg_circuit); let mut group = c.benchmark_group("plonk-prover"); group.sample_size(10); @@ -211,11 +210,11 @@ fn bench(c: &mut Criterion) { let agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Prover, agg_config, - Some(break_points.clone()), params, snarks.clone(), VerifierUniversality::None, - ); + ) + .use_break_points(break_points.clone()); let instances = agg_circuit.instances(); gen_proof_shplonk(params, pk, agg_circuit, instances, None) }) @@ -229,11 +228,11 @@ fn bench(c: &mut Criterion) { let agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Prover, agg_config, - Some(break_points), ¶ms, snarks.clone(), VerifierUniversality::None, - ); + ) + .use_break_points(break_points); let num_instances = agg_circuit.num_instance(); let instances = agg_circuit.instances(); let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); diff --git a/snark-verifier-sdk/examples/n_as_witness.rs b/snark-verifier-sdk/examples/n_as_witness.rs index 3ee25f23..3561447f 100644 --- a/snark-verifier-sdk/examples/n_as_witness.rs +++ b/snark-verifier-sdk/examples/n_as_witness.rs @@ -1,4 +1,4 @@ -use halo2_base::gates::builder::CircuitBuilderStage; +use halo2_base::gates::circuit::CircuitBuilderStage; use halo2_base::halo2_proofs; use halo2_base::halo2_proofs::arithmetic::Field; use halo2_base::halo2_proofs::halo2curves::bn256::Fr; @@ -162,12 +162,11 @@ fn main() { let mut agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Keygen, AggregationConfigParams { degree: k, lookup_bits, ..Default::default() }, - None, ¶ms, vec![dummy_snark], VerifierUniversality::Full, ); - let agg_config = agg_circuit.config(Some(10)); + let agg_config = agg_circuit.calculate_params(Some(10)); let pk = gen_pk(¶ms, &agg_circuit, None); let break_points = agg_circuit.break_points(); @@ -177,11 +176,11 @@ fn main() { let agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Prover, agg_config, - Some(break_points.clone()), ¶ms, vec![snark], VerifierUniversality::Full, - ); + ) + .use_break_points(break_points.clone()); let _snark = gen_snark_shplonk(¶ms, &pk, agg_circuit, None::<&str>); println!("snark with k = {k} success"); } diff --git a/snark-verifier-sdk/examples/range_check.rs b/snark-verifier-sdk/examples/range_check.rs index c9200df7..2beb5a78 100644 --- a/snark-verifier-sdk/examples/range_check.rs +++ b/snark-verifier-sdk/examples/range_check.rs @@ -1,11 +1,8 @@ use ark_std::{end_timer, start_timer}; -use halo2_base::gates::builder::{ - BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, RangeWithInstanceCircuitBuilder, -}; -use halo2_base::gates::flex_gate::GateStrategy; +use halo2_base::gates::circuit::builder::BaseCircuitBuilder; +use halo2_base::gates::circuit::{BaseCircuitParams, CircuitBuilderStage}; +use halo2_base::gates::{GateInstructions, RangeInstructions}; use halo2_base::halo2_proofs::halo2curves::bn256::Fr; -use halo2_base::halo2_proofs::plonk::Circuit; -use halo2_base::safe_types::{GateInstructions, RangeChip, RangeInstructions}; use halo2_base::utils::fs::gen_srs; use itertools::Itertools; @@ -18,43 +15,33 @@ use snark_verifier_sdk::{ }; fn generate_circuit(k: u32) -> Snark { - let mut builder = GateThreadBuilder::new(false); - let ctx = builder.main(0); let lookup_bits = k as usize - 1; - let range = RangeChip::::default(lookup_bits); + let circuit_params = BaseCircuitParams { + k: k as usize, + num_advice_per_phase: vec![10], + num_lookup_advice_per_phase: vec![5], + num_fixed: 1, + lookup_bits: Some(lookup_bits), + num_instance_columns: 1, + }; + let mut builder = BaseCircuitBuilder::new(false).use_params(circuit_params); + let range = builder.range_chip(); + + let ctx = builder.main(0); let x = ctx.load_witness(Fr::from(14)); range.range_check(ctx, x, 2 * lookup_bits + 1); range.gate().add(ctx, x, x); - let circuit = RangeWithInstanceCircuitBuilder::::keygen( - builder.clone(), - BaseConfigParams { - strategy: GateStrategy::Vertical, - k: k as usize, - num_advice_per_phase: vec![1], - num_lookup_advice_per_phase: vec![1], - num_fixed: 1, - lookup_bits: Some(lookup_bits), - }, - vec![], - ); let params = gen_srs(k); - - let pk = gen_pk(¶ms, &circuit, None); - let breakpoints = circuit.break_points(); - - let circuit = RangeWithInstanceCircuitBuilder::::prover( - builder.clone(), - circuit.params(), - breakpoints, - vec![], - ); - gen_snark_shplonk(¶ms, &pk, circuit, None::<&str>) + // do not call calculate_params, we want to use fixed params + let pk = gen_pk(¶ms, &builder, None); + // builder now has break_point set + gen_snark_shplonk(¶ms, &pk, builder, None::<&str>) } fn main() { - let dummy_snark = generate_circuit(13); + let dummy_snark = generate_circuit(9); let k = 14u32; let lookup_bits = k as usize - 1; @@ -62,28 +49,27 @@ fn main() { let mut agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Keygen, AggregationConfigParams { degree: k, lookup_bits, ..Default::default() }, - None, ¶ms, vec![dummy_snark], VerifierUniversality::Full, ); - let agg_config = agg_circuit.config(Some(10)); + let agg_config = agg_circuit.calculate_params(Some(10)); let start0 = start_timer!(|| "gen vk & pk"); let pk = gen_pk(¶ms, &agg_circuit, None); end_timer!(start0); let break_points = agg_circuit.break_points(); - let snarks = (14..17).map(generate_circuit).collect_vec(); + let snarks = (10..16).map(generate_circuit).collect_vec(); for (i, snark) in snarks.into_iter().enumerate() { let agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Prover, agg_config, - Some(break_points.clone()), ¶ms, vec![snark], VerifierUniversality::Full, - ); + ) + .use_break_points(break_points.clone()); let _snark = gen_snark_shplonk(¶ms, &pk, agg_circuit, None::<&str>); println!("snark {i} success"); } diff --git a/snark-verifier-sdk/examples/vkey_as_witness.rs b/snark-verifier-sdk/examples/vkey_as_witness.rs index a0eb30d2..ca066d80 100644 --- a/snark-verifier-sdk/examples/vkey_as_witness.rs +++ b/snark-verifier-sdk/examples/vkey_as_witness.rs @@ -1,6 +1,6 @@ use application::ComputeFlag; -use halo2_base::gates::builder::CircuitBuilderStage; +use halo2_base::gates::circuit::CircuitBuilderStage; use halo2_base::halo2_proofs; use halo2_base::halo2_proofs::arithmetic::Field; use halo2_base::halo2_proofs::halo2curves::bn256::Fr; @@ -157,12 +157,11 @@ fn main() { let mut agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Keygen, AggregationConfigParams { degree: k, lookup_bits, ..Default::default() }, - None, ¶ms, vec![dummy_snark], VerifierUniversality::PreprocessedAsWitness, ); - let agg_config = agg_circuit.config(Some(10)); + let agg_config = agg_circuit.calculate_params(Some(10)); let pk = gen_pk(¶ms, &agg_circuit, None); let break_points = agg_circuit.break_points(); @@ -173,11 +172,11 @@ fn main() { let agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Prover, agg_config, - Some(break_points.clone()), ¶ms, vec![snark], VerifierUniversality::PreprocessedAsWitness, - ); + ) + .use_break_points(break_points.clone()); let _snark = gen_snark_shplonk(¶ms, &pk, agg_circuit, None::<&str>); println!("snark {i} success"); } diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 60674a6c..f24dc96e 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -1,13 +1,12 @@ use super::PlonkSuccinctVerifier; use crate::{BITS, LIMBS}; +use getset::Getters; use halo2_base::{ gates::{ - builder::{ - BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, - PublicBaseConfig, RangeWithInstanceCircuitBuilder, + circuit::{ + builder::BaseCircuitBuilder, BaseCircuitParams, BaseConfig, CircuitBuilderStage, }, - flex_gate::GateStrategy, - RangeChip, + flex_gate::MultiPhaseThreadBreakPoints, }, halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, @@ -35,7 +34,7 @@ use snark_verifier::{ }, verifier::SnarkVerifier, }; -use std::{fs::File, path::Path, rc::Rc}; +use std::{fs::File, mem, path::Path, rc::Rc}; use super::{CircuitExt, PoseidonTranscript, Snark, POSEIDON_SPEC}; @@ -222,23 +221,23 @@ impl AggregationConfigParams { } } -impl From for BaseConfigParams { +impl From for BaseCircuitParams { fn from(params: AggregationConfigParams) -> Self { - BaseConfigParams { - strategy: GateStrategy::Vertical, + BaseCircuitParams { k: params.degree as usize, num_advice_per_phase: vec![params.num_advice], num_lookup_advice_per_phase: vec![params.num_lookup_advice], num_fixed: params.num_fixed, lookup_bits: Some(params.lookup_bits), + num_instance_columns: 1, } } } -impl TryFrom<&BaseConfigParams> for AggregationConfigParams { +impl TryFrom<&BaseCircuitParams> for AggregationConfigParams { type Error = &'static str; - fn try_from(params: &BaseConfigParams) -> Result { + fn try_from(params: &BaseCircuitParams) -> Result { if params.num_advice_per_phase.iter().skip(1).any(|&n| n != 0) { return Err("AggregationConfigParams only supports 1 phase"); } @@ -248,6 +247,9 @@ impl TryFrom<&BaseConfigParams> for AggregationConfigParams { if params.lookup_bits.is_none() { return Err("AggregationConfigParams requires lookup_bits"); } + if params.num_instance_columns != 1 { + return Err("AggregationConfigParams only supports 1 instance column"); + } Ok(Self { degree: params.k as u32, num_advice: params.num_advice_per_phase[0], @@ -258,42 +260,29 @@ impl TryFrom<&BaseConfigParams> for AggregationConfigParams { } } -impl TryFrom for AggregationConfigParams { +impl TryFrom for AggregationConfigParams { type Error = &'static str; - fn try_from(value: BaseConfigParams) -> Result { + fn try_from(value: BaseCircuitParams) -> Result { Self::try_from(&value) } } -/// Holds virtual contexts for the cells used to verify a collection of snarks -#[derive(Clone, Debug)] -pub struct AggregationCtxBuilder { - /// Virtual region with virtual contexts (columns) - pub builder: GateThreadBuilder, - /// The limbs of the pair of elliptic curve points that need to be verified in a final pairing check. - pub accumulator: Vec>, - // the public instances from previous snarks that were aggregated - pub previous_instances: Vec>>, - /// This returns the assigned `preprocessed_digest` (vkey), optional `transcript_initial_state`, `domain.n` (optional), and `omega` (optional) values as a vector of assigned values, one for each aggregated snark. - /// These can then be exposed as public instances. - /// - /// This is only useful if preprocessed digest is loaded as witness (i.e., `universality != None`), so we set it to `None` if `universality == None`. - pub preprocessed_digests: Option>>>, -} - -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Getters)] pub struct AggregationCircuit { - pub inner: RangeWithInstanceCircuitBuilder, + /// Circuit builder consisting of virtual region managers + pub builder: BaseCircuitBuilder, // the public instances from previous snarks that were aggregated, now collected as PRIVATE assigned values // the user can optionally append these to `inner.assigned_instances` to expose them - pub previous_instances: Vec>>, + #[getset(get = "pub")] + previous_instances: Vec>>, /// This returns the assigned `preprocessed_digest` (vkey), optional `transcript_initial_state`, `domain.n` (optional), and `omega` (optional) values as a vector of assigned values, one for each aggregated snark. /// These can then be exposed as public instances. /// /// This is only useful if preprocessed digest is loaded as witness (i.e., `universality != None`), so we set it to `None` if `universality == None`. - pub preprocessed_digests: Option>>>, - // accumulation scheme proof, private input + #[getset(get = "pub")] + preprocessed_digests: Option>>>, + // accumulation scheme proof, no longer used // pub as_proof: Vec, } @@ -320,23 +309,23 @@ pub trait Halo2KzgAccumulationScheme<'a> = PolynomialCommitmentScheme< VerifyingKey = KzgAsVerifyingKey, > + AccumulationSchemeProver>; -impl AggregationCtxBuilder { - /// Given snarks, this runs the `GateThreadBuilder` to verify all the snarks. +impl AggregationCircuit { + /// Given snarks, this creates `BaseCircuitBuilder` and populates the circuit builder with the virtual cells and constraints necessary to verify all the snarks. /// - /// Also returns the limbs of the pair of elliptic curve points, referred to as the `accumulator`, that need to be verified in a final pairing check. + /// By default, the returned circuit has public instances equal to the limbs of the pair of elliptic curve points, referred to as the `accumulator`, that need to be verified in a final pairing check. /// /// # Universality /// - If `universality` is not `None`, then the verifying keys of each snark in `snarks` is loaded as a witness in the circuit. /// - Moreover, if `universality` is `Full`, then the number of rows `n` of each snark in `snarks` is also loaded as a witness. In this case the generator `omega` of the order `n` multiplicative subgroup of `F` is also loaded as a witness. - /// - By default, these witnesses are _private_ and returned in `self.preprocessed_ + /// - By default, these witnesses are _private_ and returned in `self.preprocessed_digests /// - The user can optionally modify the circuit after calling this function to add more instances to `assigned_instances` to expose. /// /// # Warning /// Will fail silently if `snarks` were created using a different multi-open scheme than `AS` /// where `AS` can be either [`crate::SHPLONK`] or [`crate::GWC`] (for original PLONK multi-open scheme) pub fn new( - witness_gen_only: bool, - lookup_bits: usize, + stage: CircuitBuilderStage, + config_params: AggregationConfigParams, params: &ParamsKZG, snarks: impl IntoIterator, universality: VerifierUniversality, @@ -378,14 +367,19 @@ impl AggregationCtxBuilder { (accumulator, transcript_write.finalize()) }; - // create thread builder and run aggregation witness gen - let builder = GateThreadBuilder::new(witness_gen_only); + let mut builder = BaseCircuitBuilder::from_stage(stage).use_params(config_params.into()); // create halo2loader - let range = RangeChip::::default(lookup_bits); + let range = builder.range_chip(); let fp_chip = FpChip::::new(&range, BITS, LIMBS); let ecc_chip = BaseFieldEccChip::new(&fp_chip); - let loader = Halo2Loader::new(ecc_chip, builder); - + // Take the phase 0 pool from `builder`; it needs to be owned by loader. + // We put it back later (below), so it should have same effect as just mutating `builder.pool(0)`. + let pool = mem::take(builder.pool(0)); + // range_chip has shared reference to LookupAnyManager, with shared CopyConstraintManager + // pool has shared reference to CopyConstraintManager + let loader = Halo2Loader::new(ecc_chip, pool); + + // run witness and copy constraint generation let SnarkAggregationWitness { previous_instances, accumulator, preprocessed_digests } = aggregate::(&svk, &loader, &snarks, as_proof.as_slice(), universality); let lhs = accumulator.lhs.assigned(); @@ -409,76 +403,16 @@ impl AggregationCtxBuilder { assert_eq!(lhs, rhs.value()); } } - - let builder = loader.take_ctx(); - Self { builder, accumulator, previous_instances, preprocessed_digests } - } -} - -impl AggregationCircuit { - /// Given snarks, this creates a circuit and runs the `GateThreadBuilder` to verify all the snarks. - /// By default, the returned circuit has public instances equal to the limbs of the pair of elliptic curve points, referred to as the `accumulator`, that need to be verified in a final pairing check. - /// - /// See [`AggregationCtxBuilder`] for more details. - /// - /// The user can optionally modify the circuit after calling this function to add more instances to `assigned_instances` to expose. - /// - /// Warning: will fail silently if `snarks` were created using a different multi-open scheme than `AS` - /// where `AS` can be either [`crate::SHPLONK`] or [`crate::GWC`] (for original PLONK multi-open scheme) - pub fn new( - stage: CircuitBuilderStage, - agg_config: AggregationConfigParams, - break_points: Option, - params: &ParamsKZG, - snarks: impl IntoIterator, - universality: VerifierUniversality, - ) -> Self - where - AS: for<'a> Halo2KzgAccumulationScheme<'a>, - { - let AggregationCtxBuilder { - builder, - accumulator, - previous_instances, - preprocessed_digests, - } = AggregationCtxBuilder::new::( - stage == CircuitBuilderStage::Prover, - agg_config.lookup_bits, - params, - snarks, - universality, + // put back `pool` into `builder` + *builder.pool(0) = loader.take_ctx(); + assert_eq!( + builder.assigned_instances.len(), + 1, + "AggregationCircuit must have exactly 1 instance column" ); - let inner = RangeWithInstanceCircuitBuilder::from_stage( - stage, - builder, - agg_config.into(), - break_points, - accumulator, - ); - Self { inner, previous_instances, preprocessed_digests } - } - - pub fn public( - stage: CircuitBuilderStage, - agg_config: AggregationConfigParams, - break_points: Option, - params: &ParamsKZG, - snarks: impl IntoIterator, - has_prev_accumulator: bool, - ) -> Self - where - AS: for<'a> Halo2KzgAccumulationScheme<'a>, - { - let mut private = Self::new::( - stage, - agg_config, - break_points, - params, - snarks, - VerifierUniversality::None, - ); - private.expose_previous_instances(has_prev_accumulator); - private + // expose accumulator as public instances + builder.assigned_instances[0] = accumulator; + Self { builder, previous_instances, preprocessed_digests } } /// Re-expose the previous public instances of aggregated snarks again. @@ -487,49 +421,72 @@ impl AggregationCircuit { pub fn expose_previous_instances(&mut self, has_prev_accumulator: bool) { let start = (has_prev_accumulator as usize) * 4 * LIMBS; for prev in self.previous_instances.iter() { - self.inner.assigned_instances.extend_from_slice(&prev[start..]); + self.builder.assigned_instances[0].extend_from_slice(&prev[start..]); } } - /// Auto-configure the circuit and change the circuit's internal configuration parameters. - pub fn config(&mut self, minimum_rows: Option) -> AggregationConfigParams { - self.inner.config(minimum_rows).try_into().unwrap() + /// The log_2 size of the lookup table + pub fn lookup_bits(&self) -> usize { + self.builder.config_params.lookup_bits.unwrap() + } + + /// Set config params + pub fn set_params(&mut self, params: AggregationConfigParams) { + self.builder.set_params(params.into()); } + /// Returns new with config params + pub fn use_params(mut self, params: AggregationConfigParams) -> Self { + self.set_params(params); + self + } + + /// The break points of the circuit. pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { - self.inner.break_points() + self.builder.break_points() + } + + /// Sets the break points of the circuit. + pub fn set_break_points(&mut self, break_points: MultiPhaseThreadBreakPoints) { + self.builder.set_break_points(break_points); } - pub fn instance_count(&self) -> usize { - self.inner.instance_count() + /// Returns new with break points + pub fn use_break_points(mut self, break_points: MultiPhaseThreadBreakPoints) -> Self { + self.set_break_points(break_points); + self } - pub fn instance(&self) -> Vec { - self.inner.instance() + /// Auto-configure the circuit and change the circuit's internal configuration parameters. + pub fn calculate_params(&mut self, minimum_rows: Option) -> AggregationConfigParams { + self.builder.calculate_params(minimum_rows).try_into().unwrap() } } -impl CircuitExt for RangeWithInstanceCircuitBuilder { +impl CircuitExt for BaseCircuitBuilder { fn num_instance(&self) -> Vec { - vec![self.instance_count()] + self.assigned_instances.iter().map(|instances| instances.len()).collect() } fn instances(&self) -> Vec> { - vec![self.instance()] + self.assigned_instances + .iter() + .map(|instances| instances.iter().map(|v| *v.value()).collect()) + .collect() } fn selectors(config: &Self::Config) -> Vec { - config.base.gate().basic_gates[0].iter().map(|gate| gate.q_enable).collect() + config.gate().basic_gates[0].iter().map(|gate| gate.q_enable).collect() } } impl Circuit for AggregationCircuit { - type Config = PublicBaseConfig; + type Config = BaseConfig; type FloorPlanner = SimpleFloorPlanner; type Params = AggregationConfigParams; fn params(&self) -> Self::Params { - (&self.inner.circuit.0.config_params).try_into().unwrap() + (&self.builder.config_params).try_into().unwrap() } fn without_witnesses(&self) -> Self { @@ -540,7 +497,7 @@ impl Circuit for AggregationCircuit { meta: &mut ConstraintSystem, params: Self::Params, ) -> Self::Config { - RangeWithInstanceCircuitBuilder::configure_with_params(meta, params.into()) + BaseCircuitBuilder::configure_with_params(meta, params.into()) } fn configure(_: &mut ConstraintSystem) -> Self::Config { @@ -552,17 +509,17 @@ impl Circuit for AggregationCircuit { config: Self::Config, layouter: impl Layouter, ) -> Result<(), plonk::Error> { - self.inner.synthesize(config, layouter) + self.builder.synthesize(config, layouter) } } impl CircuitExt for AggregationCircuit { fn num_instance(&self) -> Vec { - self.inner.num_instance() + self.builder.num_instance() } fn instances(&self) -> Vec> { - self.inner.instances() + self.builder.instances() } fn accumulator_indices() -> Option> { @@ -570,7 +527,7 @@ impl CircuitExt for AggregationCircuit { } fn selectors(config: &Self::Config) -> Vec { - RangeWithInstanceCircuitBuilder::selectors(config) + BaseCircuitBuilder::selectors(config) } } diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index f4c4f4af..fbc40c85 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier" -version = "0.1.3" +version = "0.1.4" edition = "2021" [dependencies] diff --git a/snark-verifier/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs index 650598aa..645c71fd 100644 --- a/snark-verifier/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -1,6 +1,6 @@ use aggregation::{AggregationCircuit, AggregationConfigParams}; use halo2_base::{ - gates::builder::{BaseConfigParams, CircuitBuilderStage}, + gates::circuit::{BaseCircuitParams, CircuitBuilderStage}, halo2_proofs, utils::fs::gen_srs, }; @@ -202,18 +202,11 @@ mod application { mod aggregation { use crate::PlonkSuccinctVerifier; - use super::halo2_proofs::{ - circuit::{Layouter, SimpleFloorPlanner}, - plonk::{self, Circuit}, - }; use super::{As, BITS, LIMBS}; use super::{Fr, G1Affine}; use halo2_base::gates::{ - builder::{ - BaseConfigParams, CircuitBuilderStage, GateThreadBuilder, MultiPhaseThreadBreakPoints, - PublicBaseConfig, RangeWithInstanceCircuitBuilder, - }, - RangeChip, + circuit::{builder::BaseCircuitBuilder, BaseCircuitParams, CircuitBuilderStage}, + flex_gate::MultiPhaseThreadBreakPoints, }; use halo2_ecc::bn254::FpChip; use itertools::Itertools; @@ -228,7 +221,7 @@ mod aggregation { util::arithmetic::fe_to_limbs, verifier::{plonk::PlonkProtocol, SnarkVerifier}, }; - use std::rc::Rc; + use std::{mem, rc::Rc}; const T: usize = 3; const RATE: usize = 2; @@ -311,14 +304,14 @@ mod aggregation { #[derive(Clone, Debug)] pub struct AggregationCircuit { - pub inner: RangeWithInstanceCircuitBuilder, + pub inner: BaseCircuitBuilder, pub as_proof: Vec, } impl AggregationCircuit { pub fn new( stage: CircuitBuilderStage, - config_params: BaseConfigParams, + circuit_params: BaseCircuitParams, break_points: Option, params_g0: G1Affine, snarks: impl IntoIterator, @@ -354,14 +347,15 @@ mod aggregation { (accumulator, transcript.finalize()) }; - // create thread builder and run aggregation witness gen - let builder = GateThreadBuilder::from_stage(stage); + let mut builder = BaseCircuitBuilder::from_stage(stage).use_params(circuit_params); // create halo2loader - let range = RangeChip::::default(config_params.lookup_bits.unwrap()); + let range = builder.range_chip(); let fp_chip = FpChip::::new(&range, BITS, LIMBS); let ecc_chip = BaseFieldEccChip::new(&fp_chip); - let loader = Halo2Loader::new(ecc_chip, builder); + let pool = mem::take(builder.pool(0)); + let loader = Halo2Loader::new(ecc_chip, pool); + // witness generation let KzgAccumulator { lhs, rhs } = aggregate(&svk, &loader, &snarks, as_proof.as_slice()); let lhs = lhs.assigned(); @@ -386,30 +380,12 @@ mod aggregation { } } - let builder = loader.take_ctx(); - let inner = RangeWithInstanceCircuitBuilder::from_stage( - stage, - builder, - config_params, - break_points, - assigned_instances, - ); - Self { inner, as_proof } - } - - pub fn config( - &self, - k: u32, - minimum_rows: Option, - lookup_bits: usize, - ) -> BaseConfigParams { - let mut params = self.inner.circuit.0.builder.borrow().config(k as usize, minimum_rows); - params.lookup_bits = Some(lookup_bits); - params - } - - pub fn break_points(&self) -> MultiPhaseThreadBreakPoints { - self.inner.circuit.0.break_points.borrow().clone() + *builder.pool(0) = loader.take_ctx(); + builder.assigned_instances[0] = assigned_instances; + if let Some(break_points) = break_points { + builder.set_break_points(break_points); + } + Self { inner: builder, as_proof } } pub fn num_instance() -> Vec { @@ -418,46 +394,17 @@ mod aggregation { } pub fn instances(&self) -> Vec> { - vec![self.inner.assigned_instances.iter().map(|v| *v.value()).collect_vec()] + self.inner + .assigned_instances + .iter() + .map(|v| v.iter().map(|v| *v.value()).collect_vec()) + .collect() } pub fn accumulator_indices() -> Vec<(usize, usize)> { (0..4 * LIMBS).map(|idx| (0, idx)).collect() } } - - impl Circuit for AggregationCircuit { - type Config = PublicBaseConfig; - type FloorPlanner = SimpleFloorPlanner; - type Params = BaseConfigParams; - - fn params(&self) -> Self::Params { - self.inner.circuit.params() - } - - fn configure_with_params( - meta: &mut plonk::ConstraintSystem, - params: Self::Params, - ) -> Self::Config { - RangeWithInstanceCircuitBuilder::configure_with_params(meta, params) - } - - fn without_witnesses(&self) -> Self { - unimplemented!() - } - - fn configure(_: &mut plonk::ConstraintSystem) -> Self::Config { - unimplemented!() - } - - fn synthesize( - &self, - config: Self::Config, - layouter: impl Layouter, - ) -> Result<(), plonk::Error> { - self.inner.synthesize(config, layouter) - } - } } fn gen_pk>(params: &ParamsKZG, circuit: &C) -> ProvingKey { @@ -573,33 +520,32 @@ fn main() { File::open(path).unwrap_or_else(|e| panic!("{path} does not exist: {e:?}")), ) .unwrap(); - let mut config_params = BaseConfigParams { + let mut circuit_params = BaseCircuitParams { k: agg_config.degree as usize, - strategy: Default::default(), num_advice_per_phase: vec![agg_config.num_advice], num_lookup_advice_per_phase: vec![agg_config.num_lookup_advice], num_fixed: agg_config.num_fixed, lookup_bits: Some(agg_config.lookup_bits), + num_instance_columns: 1, }; let mut agg_circuit = AggregationCircuit::new( CircuitBuilderStage::Mock, - config_params, + circuit_params, None, params_app.get_g()[0], snarks.clone(), ); - config_params = agg_circuit.config(agg_config.degree, Some(6), agg_config.lookup_bits); - agg_circuit.inner.circuit.0.config_params = config_params.clone(); + circuit_params = agg_circuit.inner.calculate_params(Some(9)); #[cfg(debug_assertions)] { - MockProver::run(agg_config.degree, &agg_circuit, agg_circuit.instances()) + MockProver::run(agg_config.degree, &agg_circuit.inner, agg_circuit.instances()) .unwrap() .assert_satisfied(); println!("mock prover passed"); } let params = gen_srs(agg_config.degree); - let pk = gen_pk(¶ms, &agg_circuit); + let pk = gen_pk(¶ms, &agg_circuit.inner); let deployment_code = gen_aggregation_evm_verifier( ¶ms, pk.get_vk(), @@ -607,12 +553,12 @@ fn main() { aggregation::AggregationCircuit::accumulator_indices(), ); - let break_points = agg_circuit.break_points(); + let break_points = agg_circuit.inner.break_points(); drop(agg_circuit); let agg_circuit = AggregationCircuit::new( CircuitBuilderStage::Prover, - config_params, + circuit_params, Some(break_points), params_app.get_g()[0], snarks, @@ -621,7 +567,7 @@ fn main() { let proof = gen_proof::<_, _, EvmTranscript, EvmTranscript>( ¶ms, &pk, - agg_circuit, + agg_circuit.inner, instances.clone(), ); evm_verify(deployment_code, instances, proof); diff --git a/snark-verifier/examples/recursion.rs b/snark-verifier/examples/recursion.rs index 9c9b169a..da34cb82 100644 --- a/snark-verifier/examples/recursion.rs +++ b/snark-verifier/examples/recursion.rs @@ -2,10 +2,8 @@ use ark_std::{end_timer, start_timer}; use common::*; -use halo2_base::gates::builder::BaseConfigParams; -use halo2_base::gates::flex_gate::GateStrategy; -use halo2_base::halo2_proofs; use halo2_base::utils::fs::gen_srs; +use halo2_base::{gates::circuit::BaseCircuitParams, halo2_proofs}; use halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, dev::MockProver, @@ -342,10 +340,12 @@ mod application { } mod recursion { + use std::mem; + use halo2_base::{ gates::{ - builder::{GateThreadBuilder, PublicBaseConfig, RangeWithInstanceCircuitBuilder}, - GateInstructions, RangeChip, RangeInstructions, + circuit::{builder::BaseCircuitBuilder, BaseCircuitParams, BaseConfig}, + GateInstructions, RangeInstructions, }, AssignedValue, }; @@ -426,7 +426,7 @@ mod recursion { .zip([rhs.lhs.assigned(), rhs.rhs.assigned()].iter()) .map(|(lhs, rhs)| { loader.ecc_chip().select( - loader.ctx_mut().main(0), + loader.ctx_mut().main(), EcPoint::clone(lhs), EcPoint::clone(rhs), *condition, @@ -471,9 +471,8 @@ mod recursion { round: usize, instances: Vec, as_proof: Vec, - lookup_bits: usize, - inner: RangeWithInstanceCircuitBuilder, + inner: BaseCircuitBuilder, } impl RecursionCircuit { @@ -489,7 +488,7 @@ mod recursion { initial_state: Fr, state: Fr, round: usize, - config_params: BaseConfigParams, + config_params: BaseCircuitParams, ) -> Self { let svk = params.get_g()[0].into(); let default_accumulator = KzgAccumulator::new(params.get_g()[1], params.get_g()[0]); @@ -544,42 +543,30 @@ mod recursion { .chain([preprocessed_digest, initial_state, state, Fr::from(round as u64)]) .collect(); - let builder = GateThreadBuilder::mock(); - let lookup_bits = config_params.lookup_bits.unwrap(); - let inner = RangeWithInstanceCircuitBuilder::mock(builder, config_params, vec![]); - let mut circuit = Self { - svk, - default_accumulator, - app, - previous, - round, - instances, - as_proof, - inner, - lookup_bits, - }; + let inner = BaseCircuitBuilder::new(false).use_params(config_params); + let mut circuit = + Self { svk, default_accumulator, app, previous, round, instances, as_proof, inner }; circuit.build(); circuit } fn build(&mut self) { - let range = RangeChip::::default(self.lookup_bits); + let range = self.inner.range_chip(); let main_gate = range.gate(); - let mut builder = GateThreadBuilder::mock(); - let ctx = &mut builder; + let pool = self.inner.pool(0); let [preprocessed_digest, initial_state, state, round] = [ self.instances[Self::PREPROCESSED_DIGEST_ROW], self.instances[Self::INITIAL_STATE_ROW], self.instances[Self::STATE_ROW], self.instances[Self::ROUND_ROW], ] - .map(|instance| main_gate.assign_integer(ctx, instance)); - let first_round = main_gate.is_zero(ctx.main(0), round); - let not_first_round = main_gate.not(ctx.main(0), first_round); + .map(|instance| main_gate.assign_integer(pool, instance)); + let first_round = main_gate.is_zero(pool.main(), round); + let not_first_round = main_gate.not(pool.main(), first_round); let fp_chip = FpChip::::new(&range, BITS, LIMBS); let ecc_chip = BaseFieldEccChip::new(&fp_chip); - let loader = Halo2Loader::new(ecc_chip, builder); + let loader = Halo2Loader::new(ecc_chip, mem::take(self.inner.pool(0))); let (mut app_instances, app_accumulators) = succinct_verify(&self.svk, &loader, &self.app, None); let (mut previous_instances, previous_accumulators) = @@ -610,8 +597,8 @@ mod recursion { let app_instances = app_instances.pop().unwrap(); let previous_instances = previous_instances.pop().unwrap(); - let mut builder = loader.take_ctx(); - let ctx = builder.main(0); + let mut pool = loader.take_ctx(); + let ctx = pool.main(); for (lhs, rhs) in [ // Propagate preprocessed_digest ( @@ -640,9 +627,9 @@ mod recursion { ] { ctx.constrain_equal(lhs, rhs); } - *self.inner.circuit.0.builder.borrow_mut() = builder; + *self.inner.pool(0) = pool; - self.inner.assigned_instances.extend( + self.inner.assigned_instances[0].extend( [lhs.x(), lhs.y(), rhs.x(), rhs.y()] .into_iter() .flat_map(|coordinate| coordinate.limbs()) @@ -654,7 +641,7 @@ mod recursion { fn initial_snark( params: &ParamsKZG, vk: Option<&VerifyingKey>, - config_params: BaseConfigParams, + config_params: BaseCircuitParams, ) -> Snark { let mut snark = gen_dummy_snark::(params, vk, config_params); let g = params.get_g(); @@ -685,12 +672,12 @@ mod recursion { } impl Circuit for RecursionCircuit { - type Config = PublicBaseConfig; + type Config = BaseConfig; type FloorPlanner = SimpleFloorPlanner; - type Params = BaseConfigParams; + type Params = BaseCircuitParams; fn params(&self) -> Self::Params { - self.inner.circuit.params() + self.inner.params() } fn without_witnesses(&self) -> Self { @@ -701,7 +688,7 @@ mod recursion { meta: &mut ConstraintSystem, params: Self::Params, ) -> Self::Config { - RangeWithInstanceCircuitBuilder::configure_with_params(meta, params) + BaseCircuitBuilder::configure_with_params(meta, params) } fn configure(_: &mut ConstraintSystem) -> Self::Config { @@ -732,7 +719,7 @@ mod recursion { } fn selectors(config: &Self::Config) -> Vec { - config.base.gate().basic_gates[0].iter().map(|gate| gate.q_enable).collect() + config.gate().basic_gates[0].iter().map(|gate| gate.q_enable).collect() } } @@ -740,7 +727,7 @@ mod recursion { recursion_params: &ParamsKZG, app_params: &ParamsKZG, app_vk: &VerifyingKey, - recursion_config: BaseConfigParams, + recursion_config: BaseCircuitParams, app_config: ConcreteCircuit::Params, ) -> ProvingKey where @@ -768,7 +755,7 @@ mod recursion { recursion_pk: &ProvingKey, initial_state: Fr, inputs: Vec, - config_params: BaseConfigParams, + config_params: BaseCircuitParams, ) -> (Fr, Snark) { let mut state = initial_state; let mut app = ConcreteCircuit::new(state); @@ -804,13 +791,13 @@ fn main() { serde_json::from_reader(fs::File::open("configs/example_recursion.json").unwrap()).unwrap(); let k = recursion_config.degree; let recursion_params = gen_srs(k); - let config_params = BaseConfigParams { - strategy: GateStrategy::Vertical, + let config_params = BaseCircuitParams { k: k as usize, num_advice_per_phase: vec![recursion_config.num_advice], num_lookup_advice_per_phase: vec![recursion_config.num_lookup_advice], num_fixed: recursion_config.num_fixed, lookup_bits: Some(recursion_config.lookup_bits), + num_instance_columns: 1, }; let app_pk = gen_pk(&app_params, &application::Square::default()); diff --git a/snark-verifier/src/loader/halo2/shim.rs b/snark-verifier/src/loader/halo2/shim.rs index 49bbad41..80d5eae2 100644 --- a/snark-verifier/src/loader/halo2/shim.rs +++ b/snark-verifier/src/loader/halo2/shim.rs @@ -143,9 +143,10 @@ mod halo2_lib { loader::halo2::{EccInstructions, IntegerInstructions}, util::arithmetic::{CurveAffine, PrimeField}, }; + use halo2_base::gates::flex_gate::threads::SinglePhaseCoreManager; use halo2_base::{ self, - gates::{builder::GateThreadBuilder, GateChip, GateInstructions, RangeInstructions}, + gates::{GateChip, GateInstructions, RangeInstructions}, utils::BigPrimeField, AssignedValue, QuantumCell::{Constant, Existing}, @@ -161,16 +162,16 @@ mod halo2_lib { type AssignedEcPoint = EcPoint<::ScalarExt, AssignedInteger>; impl IntegerInstructions for GateChip { - type Context = GateThreadBuilder; + type Context = SinglePhaseCoreManager; type AssignedCell = AssignedValue; type AssignedInteger = AssignedValue; fn assign_integer(&self, ctx: &mut Self::Context, integer: F) -> Self::AssignedInteger { - ctx.main(0).load_witness(integer) + ctx.main().load_witness(integer) } fn assign_constant(&self, ctx: &mut Self::Context, integer: F) -> Self::AssignedInteger { - ctx.main(0).load_constant(integer) + ctx.main().load_constant(integer) } fn sum_with_coeff_and_const( @@ -187,7 +188,7 @@ mod halo2_lib { } a.extend(values.iter().map(|(_, a)| Existing(*a.deref()))); b.extend(values.iter().map(|(c, _)| Constant(*c))); - self.inner_product(ctx.main(0), a, b) + self.inner_product(ctx.main(), a, b) } fn sum_products_with_coeff_and_const( @@ -201,9 +202,9 @@ mod halo2_lib { constant: F, ) -> Self::AssignedInteger { match values.len() { - 0 => ctx.main(0).load_constant(constant), + 0 => ctx.main().load_constant(constant), _ => self.sum_products_with_coeff_and_var( - ctx.main(0), + ctx.main(), values.iter().map(|(c, a, b)| (*c, Existing(*a.deref()), Existing(*b.deref()))), Constant(constant), ), @@ -216,11 +217,11 @@ mod halo2_lib { a: &Self::AssignedInteger, b: &Self::AssignedInteger, ) -> Self::AssignedInteger { - GateInstructions::sub(self, ctx.main(0), Existing(*a), Existing(*b)) + GateInstructions::sub(self, ctx.main(), Existing(*a), Existing(*b)) } fn neg(&self, ctx: &mut Self::Context, a: &Self::AssignedInteger) -> Self::AssignedInteger { - GateInstructions::neg(self, ctx.main(0), Existing(*a)) + GateInstructions::neg(self, ctx.main(), Existing(*a)) } fn invert( @@ -229,9 +230,9 @@ mod halo2_lib { a: &Self::AssignedInteger, ) -> Self::AssignedInteger { // make sure scalar != 0 - let is_zero = self.is_zero(ctx.main(0), *a); - self.assert_is_const(ctx.main(0), &is_zero, &F::ZERO); - GateInstructions::div_unsafe(self, ctx.main(0), Constant(F::ONE), Existing(*a)) + let is_zero = self.is_zero(ctx.main(), *a); + self.assert_is_const(ctx.main(), &is_zero, &F::ZERO); + GateInstructions::div_unsafe(self, ctx.main(), Constant(F::ONE), Existing(*a)) } fn assert_equal( @@ -240,7 +241,7 @@ mod halo2_lib { a: &Self::AssignedInteger, b: &Self::AssignedInteger, ) { - ctx.main(0).constrain_equal(a, b); + ctx.main().constrain_equal(a, b); } fn pow_var( @@ -250,7 +251,7 @@ mod halo2_lib { exponent: &Self::AssignedInteger, max_bits: usize, ) -> Self::AssignedInteger { - GateInstructions::pow_var(self, ctx.main(0), *base, *exponent, max_bits) + GateInstructions::pow_var(self, ctx.main(), *base, *exponent, max_bits) } } @@ -259,7 +260,7 @@ mod halo2_lib { C::ScalarExt: BigPrimeField, C::Base: BigPrimeField, { - type Context = GateThreadBuilder; + type Context = SinglePhaseCoreManager; type ScalarChip = GateChip; type AssignedCell = AssignedValue; type AssignedScalar = AssignedValue; @@ -270,11 +271,11 @@ mod halo2_lib { } fn assign_constant(&self, ctx: &mut Self::Context, point: C) -> Self::AssignedEcPoint { - self.assign_constant_point(ctx.main(0), point) + self.assign_constant_point(ctx.main(), point) } fn assign_point(&self, ctx: &mut Self::Context, point: C) -> Self::AssignedEcPoint { - self.assign_point(ctx.main(0), point) + self.assign_point(ctx.main(), point) } fn sum_with_const( @@ -290,7 +291,7 @@ mod halo2_lib { Some(constant) }; self.sum::( - ctx.main(0), + ctx.main(), constant.into_iter().chain(values.iter().map(|v| v.deref().clone())), ) } @@ -346,7 +347,7 @@ mod halo2_lib { a: &Self::AssignedEcPoint, b: &Self::AssignedEcPoint, ) { - self.assert_equal(ctx.main(0), a.clone(), b.clone()); + self.assert_equal(ctx.main(), a.clone(), b.clone()); } } } diff --git a/snark-verifier/src/pcs/kzg/accumulator.rs b/snark-verifier/src/pcs/kzg/accumulator.rs index 423ae7d5..37cb493f 100644 --- a/snark-verifier/src/pcs/kzg/accumulator.rs +++ b/snark-verifier/src/pcs/kzg/accumulator.rs @@ -220,7 +220,7 @@ mod halo2 { assert_eq!(limbs.len(), 2 * LIMBS); let ec_point = self.assign_point::( - ctx.main(0), + ctx.main(), ec_point_from_limbs::<_, LIMBS, BITS>( &limbs.iter().map(|limb| limb.value()).collect_vec(), ), @@ -230,7 +230,7 @@ mod halo2 { .iter() .zip_eq(iter::empty().chain(ec_point.x().limbs()).chain(ec_point.y().limbs())) { - ctx.main(0).constrain_equal(src, dst); + ctx.main().constrain_equal(src, dst); } ec_point From 10ef300fbaebaad80d9e71b74cff4ad1d6c6e476 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 1 Sep 2023 11:28:40 -0600 Subject: [PATCH 50/73] feat: load `k` as witness and compute `n = 2^k` and `omega` from `k` (#30) * feat: load `k` as witness and compute `n = 2^k` and `omega` from `k` Removes need to make `omega` a public output in universal verifier. * fix: bit_length --- .../{n_as_witness.rs => k_as_witness.rs} | 0 snark-verifier-sdk/src/halo2/aggregation.rs | 61 ++++++++++--------- snark-verifier/src/verifier/plonk/protocol.rs | 28 ++++++--- 3 files changed, 52 insertions(+), 37 deletions(-) rename snark-verifier-sdk/examples/{n_as_witness.rs => k_as_witness.rs} (100%) diff --git a/snark-verifier-sdk/examples/n_as_witness.rs b/snark-verifier-sdk/examples/k_as_witness.rs similarity index 100% rename from snark-verifier-sdk/examples/n_as_witness.rs rename to snark-verifier-sdk/examples/k_as_witness.rs diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index f24dc96e..690a64fc 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -42,14 +42,20 @@ pub type Svk = KzgSuccinctVerifyingKey; pub type BaseFieldEccChip<'chip> = halo2_ecc::ecc::BaseFieldEccChip<'chip, G1Affine>; pub type Halo2Loader<'chip> = loader::halo2::Halo2Loader>; +#[derive(Clone, Debug)] +pub struct PreprocessedAndDomainAsWitness { + // this is basically the vkey + pub preprocessed: Vec>, + pub k: AssignedValue, +} + +#[derive(Clone, Debug)] pub struct SnarkAggregationWitness<'a> { pub previous_instances: Vec>>, pub accumulator: KzgAccumulator>>, /// This returns the assigned `preprocessed` and `transcript_initial_state` values as a vector of assigned values, one for each aggregated snark. /// These can then be exposed as public instances. - /// - /// This is only useful if preprocessed digest is loaded as witness (i.e., `preprocessed_as_witness` is true in `aggregate`), so we set it to `None` otherwise. - pub preprocessed_digests: Option>>>, + pub preprocessed: Vec, } /// Different possible stages of universality the aggregation circuit can support @@ -60,7 +66,7 @@ pub enum VerifierUniversality { None, /// Preprocessed digest (commitments to fixed columns) is loaded as witness PreprocessedAsWitness, - /// Preprocessed as witness and number of rows in the circuit `n` loaded as witness + /// Preprocessed as witness and log_2(number of rows in the circuit) = k loaded as witness Full, } @@ -69,7 +75,7 @@ impl VerifierUniversality { self != &VerifierUniversality::None } - pub fn n_as_witness(&self) -> bool { + pub fn k_as_witness(&self) -> bool { self == &VerifierUniversality::Full } } @@ -117,7 +123,7 @@ where }; let mut previous_instances = Vec::with_capacity(snarks.len()); - let mut preprocessed_digests = Vec::with_capacity(snarks.len()); + let mut preprocessed_witnesses = Vec::with_capacity(snarks.len()); // to avoid re-loading the spec each time, we create one transcript and clear the stream let mut transcript = PoseidonTranscript::>, &[u8]>::from_spec( loader, @@ -131,11 +137,11 @@ where .flat_map(|snark: &Snark| { let protocol = if preprocessed_as_witness { // always load `domain.n` as witness if vkey is witness - snark.protocol.loaded_preprocessed_as_witness(loader, universality.n_as_witness()) + snark.protocol.loaded_preprocessed_as_witness(loader, universality.k_as_witness()) } else { snark.protocol.loaded(loader) }; - let inputs = protocol + let preprocessed = protocol .preprocessed .iter() .flat_map(|preprocessed| { @@ -148,19 +154,18 @@ where .chain( protocol.transcript_initial_state.clone().map(|scalar| scalar.into_assigned()), ) - .chain( - protocol - .domain_as_witness - .as_ref() - .map(|domain| domain.n.clone().into_assigned()), - ) // If `n` is witness, add it as part of input - .chain( - protocol - .domain_as_witness - .as_ref() - .map(|domain| domain.gen.clone().into_assigned()), - ) // If `n` is witness, add the generator of the order `n` subgroup as part of input .collect_vec(); + // Store `k` as witness. If `k` was fixed, assign it as a constant. + let k = protocol + .domain_as_witness + .as_ref() + .map(|domain| domain.k.clone().into_assigned()) + .unwrap_or_else(|| { + loader.ctx_mut().main().load_constant(Fr::from(protocol.domain.k as u64)) + }); + let preprocessed_and_k = PreprocessedAndDomainAsWitness { preprocessed, k }; + preprocessed_witnesses.push(preprocessed_and_k); + let instances = assign_instances(&snark.instances); // read the transcript and perform Fiat-Shamir @@ -179,7 +184,6 @@ where previous_instances.push( instances.into_iter().flatten().map(|scalar| scalar.into_assigned()).collect(), ); - preprocessed_digests.push(inputs); accumulator }) @@ -198,9 +202,12 @@ where } else { accumulators.pop().unwrap() }; - let preprocessed_digests = preprocessed_as_witness.then_some(preprocessed_digests); - SnarkAggregationWitness { previous_instances, accumulator, preprocessed_digests } + SnarkAggregationWitness { + previous_instances, + accumulator, + preprocessed: preprocessed_witnesses, + } } /// Same as `FlexGateConfigParams` except we assume a single Phase and default 'Vertical' strategy. @@ -278,10 +285,8 @@ pub struct AggregationCircuit { previous_instances: Vec>>, /// This returns the assigned `preprocessed_digest` (vkey), optional `transcript_initial_state`, `domain.n` (optional), and `omega` (optional) values as a vector of assigned values, one for each aggregated snark. /// These can then be exposed as public instances. - /// - /// This is only useful if preprocessed digest is loaded as witness (i.e., `universality != None`), so we set it to `None` if `universality == None`. #[getset(get = "pub")] - preprocessed_digests: Option>>>, + preprocessed: Vec, // accumulation scheme proof, no longer used // pub as_proof: Vec, } @@ -380,7 +385,7 @@ impl AggregationCircuit { let loader = Halo2Loader::new(ecc_chip, pool); // run witness and copy constraint generation - let SnarkAggregationWitness { previous_instances, accumulator, preprocessed_digests } = + let SnarkAggregationWitness { previous_instances, accumulator, preprocessed } = aggregate::(&svk, &loader, &snarks, as_proof.as_slice(), universality); let lhs = accumulator.lhs.assigned(); let rhs = accumulator.rhs.assigned(); @@ -412,7 +417,7 @@ impl AggregationCircuit { ); // expose accumulator as public instances builder.assigned_instances[0] = accumulator; - Self { builder, previous_instances, preprocessed_digests } + Self { builder, previous_instances, preprocessed } } /// Re-expose the previous public instances of aggregated snarks again. diff --git a/snark-verifier/src/verifier/plonk/protocol.rs b/snark-verifier/src/verifier/plonk/protocol.rs index 098e7de9..9260e572 100644 --- a/snark-verifier/src/verifier/plonk/protocol.rs +++ b/snark-verifier/src/verifier/plonk/protocol.rs @@ -23,7 +23,9 @@ where C: CurveAffine, L: Loader, { - /// Number of rows in the domain + /// 2k is the number of rows in the domain + pub k: L::LoadedScalar, + /// n = 2k is the number of rows in the domain pub n: L::LoadedScalar, /// Generator of the domain pub gen: L::LoadedScalar, @@ -65,7 +67,6 @@ where serialize = "L::LoadedScalar: Serialize", deserialize = "L::LoadedScalar: Deserialize<'de>" ))] - #[serde(skip_serializing_if = "Option::is_none")] /// Optional: load `domain.n` and `domain.gen` as a witness pub domain_as_witness: Option>, @@ -176,14 +177,15 @@ mod halo2 { use crate::{ loader::{ halo2::{EccInstructions, Halo2Loader}, - LoadedScalar, + LoadedScalar, ScalarLoader, }, util::arithmetic::CurveAffine, verifier::plonk::PlonkProtocol, }; + use halo2_base::utils::bit_length; use std::rc::Rc; - use super::DomainAsWitness; + use super::{DomainAsWitness, PrimeField}; impl PlonkProtocol where @@ -195,13 +197,21 @@ mod halo2 { pub fn loaded_preprocessed_as_witness>( &self, loader: &Rc>, - load_n_as_witness: bool, + load_k_as_witness: bool, ) -> PlonkProtocol>> { - let domain_as_witness = load_n_as_witness.then(|| { - let n = loader.assign_scalar(C::Scalar::from(self.domain.n as u64)); - let gen = loader.assign_scalar(self.domain.gen); + let domain_as_witness = load_k_as_witness.then(|| { + let k = loader.assign_scalar(C::Scalar::from(self.domain.k as u64)); + // n = 2^k + let two = loader.load_const(&C::Scalar::from(2)); + let n = two.pow_var(&k, bit_length(C::Scalar::S as u64) + 1); + // gen = omega = ROOT_OF_UNITY ^ {2^{S - k}}, where ROOT_OF_UNITY is primitive 2^S root of unity + // this makes omega a 2^k root of unity + let root_of_unity = loader.load_const(&C::Scalar::ROOT_OF_UNITY); + let s = loader.load_const(&C::Scalar::from(C::Scalar::S as u64)); + let exp = two.pow_var(&(s - &k), bit_length(C::Scalar::S as u64)); // if S - k < 0, constraint on max bits will fail + let gen = root_of_unity.pow_var(&exp, C::Scalar::S as usize); // 2^{S - k} < 2^S for k > 0 let gen_inv = gen.invert().expect("subgroup generation is invertible"); - DomainAsWitness { n, gen, gen_inv } + DomainAsWitness { k, n, gen, gen_inv } }); let preprocessed = self From 260962d4b597b4d470d074092c7c9e3b6fb0c378 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 8 Sep 2023 07:47:45 -0700 Subject: [PATCH 51/73] Move `OptimizedPoseidonSpec` to `halo2-base` (#31) * chore: move `OptimizedPoseidonSpec` to `halo2-base` * Bump version to 0.1.5 and remove poseidon-rs dep --- snark-verifier-sdk/Cargo.toml | 24 +- snark-verifier-sdk/src/halo2.rs | 2 +- snark-verifier/Cargo.toml | 6 +- snark-verifier/src/util/hash.rs | 4 +- snark-verifier/src/util/hash/poseidon.rs | 343 +----------------- .../src/util/hash/poseidon/tests.rs | 2 +- 6 files changed, 38 insertions(+), 343 deletions(-) diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index a62b3b0c..681f9121 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier-sdk" -version = "0.1.4" +version = "0.1.5" edition = "2021" [dependencies] @@ -22,14 +22,14 @@ snark-verifier = { path = "../snark-verifier", default-features = false } getset = "0.1.2" # loader_evm -ethereum-types = { version = "0.14.1", default-features = false, features = ["std"], optional = true } -# sha3 = { version = "0.10", optional = true } -# revm = { version = "2.3.1", optional = true } -# bytes = { version = "1.2", optional = true } -# rlp = { version = "0.5", default-features = false, features = ["std"], optional = true } +ethereum-types = { version = "0.14.1", default-features = false, features = [ + "std", +], optional = true } # zkevm benchmarks -zkevm-circuits = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", features = ["test"], optional = true } +zkevm-circuits = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", features = [ + "test", +], optional = true } bus-mapping = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } eth-types = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } mock = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } @@ -45,7 +45,13 @@ crossterm = { version = "0.25" } tui = { version = "0.19", default-features = false, features = ["crossterm"] } [features] -default = ["loader_halo2", "loader_evm", "halo2-axiom", "halo2-base/jemallocator", "display"] +default = [ + "loader_halo2", + "loader_evm", + "halo2-axiom", + "halo2-base/jemallocator", + "display", +] display = ["snark-verifier/display", "dep:ark-std"] loader_evm = ["snark-verifier/loader_evm", "dep:ethereum-types"] loader_halo2 = ["snark-verifier/loader_halo2"] @@ -74,4 +80,4 @@ harness = false [[bench]] name = "read_pk" required-features = ["loader_halo2"] -harness = false \ No newline at end of file +harness = false diff --git a/snark-verifier-sdk/src/halo2.rs b/snark-verifier-sdk/src/halo2.rs index 06d5e622..aa5f8810 100644 --- a/snark-verifier-sdk/src/halo2.rs +++ b/snark-verifier-sdk/src/halo2.rs @@ -2,6 +2,7 @@ use super::{read_instances, write_instances, CircuitExt, PlonkSuccinctVerifier, #[cfg(feature = "display")] use ark_std::{end_timer, start_timer}; use halo2_base::halo2_proofs; +pub use halo2_base::poseidon::hasher::spec::OptimizedPoseidonSpec; use halo2_proofs::{ circuit::Layouter, halo2curves::{ @@ -26,7 +27,6 @@ use halo2_proofs::{ use itertools::Itertools; use lazy_static::lazy_static; use rand::{rngs::StdRng, SeedableRng}; -pub use snark_verifier::util::hash::OptimizedPoseidonSpec; use snark_verifier::{ cost::CostEstimation, loader::native::NativeLoader, diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index fbc40c85..2fbe6682 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier" -version = "0.1.4" +version = "0.1.5" edition = "2021" [dependencies] @@ -16,10 +16,6 @@ pairing = { version = "0.23" } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } -# This is Scroll's audited poseidon circuit. We only use it for the Native Poseidon spec. We do not use the halo2 circuit at all (and it wouldn't even work because the halo2_proofs tag is not compatbile). -# We forked it to upgrade to ff v0.13 and removed the circuit module -poseidon-rs = { git = "https://github.com/axiom-crypto/poseidon-circuit.git", rev = "1aee4a1" } -# poseidon-circuit = { git = "https://github.com/scroll-tech/poseidon-circuit.git", rev = "50015b7" } # parallel rayon = { version = "1.7", optional = true } diff --git a/snark-verifier/src/util/hash.rs b/snark-verifier/src/util/hash.rs index a8fe168c..dfc02cf0 100644 --- a/snark-verifier/src/util/hash.rs +++ b/snark-verifier/src/util/hash.rs @@ -4,7 +4,9 @@ mod poseidon; #[cfg(feature = "loader_halo2")] -pub use crate::util::hash::poseidon::{OptimizedPoseidonSpec, Poseidon}; +pub use crate::util::hash::poseidon::Poseidon; +#[cfg(feature = "loader_halo2")] +pub(crate) use halo2_base::poseidon::hasher::spec::OptimizedPoseidonSpec; #[cfg(feature = "loader_evm")] pub use sha3::{Digest, Keccak256}; diff --git a/snark-verifier/src/util/hash/poseidon.rs b/snark-verifier/src/util/hash/poseidon.rs index e826ac52..740f4c72 100644 --- a/snark-verifier/src/util/hash/poseidon.rs +++ b/snark-verifier/src/util/hash/poseidon.rs @@ -1,4 +1,7 @@ -#![allow(clippy::needless_range_loop)] // for clarity of matrix operations +//! Trait based implementation of Poseidon permutation + +use halo2_base::poseidon::hasher::{mds::SparseMDSMatrix, spec::OptimizedPoseidonSpec}; + use crate::{ loader::{LoadedScalar, ScalarLoader}, util::{ @@ -6,323 +9,11 @@ use crate::{ Itertools, }, }; -use poseidon_rs::poseidon::primitives::Spec as PoseidonSpec; // trait use std::{iter, marker::PhantomData, mem}; #[cfg(test)] mod tests; -// struct so we can use PoseidonSpec trait to generate round constants and MDS matrix -#[derive(Debug)] -pub struct Poseidon128Pow5Gen< - F: PrimeField, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - const SECURE_MDS: usize, -> { - _marker: PhantomData, -} - -impl< - F: PrimeField, - const T: usize, - const RATE: usize, - const R_F: usize, - const R_P: usize, - const SECURE_MDS: usize, - > PoseidonSpec for Poseidon128Pow5Gen -{ - fn full_rounds() -> usize { - R_F - } - - fn partial_rounds() -> usize { - R_P - } - - fn sbox(val: F) -> F { - val.pow_vartime([5]) - } - - // see "Avoiding insecure matrices" in Section 2.3 of https://eprint.iacr.org/2019/458.pdf - // most Specs used in practice have SECURE_MDS = 0 - fn secure_mds() -> usize { - SECURE_MDS - } -} - -// We use the optimized Poseidon implementation described in Supplementary Material Section B of https://eprint.iacr.org/2019/458.pdf -// This involves some further computation of optimized constants and sparse MDS matrices beyond what the Scroll PoseidonSpec generates -// The implementation below is adapted from https://github.com/privacy-scaling-explorations/poseidon - -/// `OptimizedPoseidonSpec` holds construction parameters as well as constants that are used in -/// permutation step. -#[derive(Debug, Clone)] -pub struct OptimizedPoseidonSpec { - pub(crate) r_f: usize, - pub(crate) mds_matrices: MDSMatrices, - pub(crate) constants: OptimizedConstants, -} - -/// `OptimizedConstants` has round constants that are added each round. While -/// full rounds has T sized constants there is a single constant for each -/// partial round -#[derive(Debug, Clone)] -pub struct OptimizedConstants { - pub(crate) start: Vec<[F; T]>, - pub(crate) partial: Vec, - pub(crate) end: Vec<[F; T]>, -} - -/// The type used to hold the MDS matrix -pub(crate) type Mds = [[F; T]; T]; - -/// `MDSMatrices` holds the MDS matrix as well as transition matrix which is -/// also called `pre_sparse_mds` and sparse matrices that enables us to reduce -/// number of multiplications in apply MDS step -#[derive(Debug, Clone)] -pub struct MDSMatrices { - pub(crate) mds: MDSMatrix, - pub(crate) pre_sparse_mds: MDSMatrix, - pub(crate) sparse_matrices: Vec>, -} - -/// `SparseMDSMatrix` are in `[row], [hat | identity]` form and used in linear -/// layer of partial rounds instead of the original MDS -#[derive(Debug, Clone)] -pub struct SparseMDSMatrix { - pub(crate) row: [F; T], - pub(crate) col_hat: [F; RATE], -} - -/// `MDSMatrix` is applied to `State` to achive linear layer of Poseidon -#[derive(Clone, Debug)] -pub struct MDSMatrix(pub(crate) Mds); - -impl MDSMatrix { - pub(crate) fn mul_vector(&self, v: &[F; T]) -> [F; T] { - let mut res = [F::ZERO; T]; - for i in 0..T { - for j in 0..T { - res[i] += self.0[i][j] * v[j]; - } - } - res - } - - fn identity() -> Mds { - let mut mds = [[F::ZERO; T]; T]; - for i in 0..T { - mds[i][i] = F::ONE; - } - mds - } - - /// Multiplies two MDS matrices. Used in sparse matrix calculations - fn mul(&self, other: &Self) -> Self { - let mut res = [[F::ZERO; T]; T]; - for i in 0..T { - for j in 0..T { - for k in 0..T { - res[i][j] += self.0[i][k] * other.0[k][j]; - } - } - } - Self(res) - } - - fn transpose(&self) -> Self { - let mut res = [[F::ZERO; T]; T]; - for i in 0..T { - for j in 0..T { - res[i][j] = self.0[j][i]; - } - } - Self(res) - } - - fn determinant(m: [[F; N]; N]) -> F { - let mut res = F::ONE; - let mut m = m; - for i in 0..N { - let mut pivot = i; - while m[pivot][i] == F::ZERO { - pivot += 1; - assert!(pivot < N, "matrix is not invertible"); - } - if pivot != i { - res = -res; - m.swap(pivot, i); - } - res *= m[i][i]; - let inv = m[i][i].invert().unwrap(); - for j in i + 1..N { - let factor = m[j][i] * inv; - for k in i + 1..N { - m[j][k] -= m[i][k] * factor; - } - } - } - res - } - - /// See Section B in Supplementary Material https://eprint.iacr.org/2019/458.pdf - /// Factorises an MDS matrix `M` into `M'` and `M''` where `M = M' * M''`. - /// Resulted `M''` matrices are the sparse ones while `M'` will contribute - /// to the accumulator of the process - fn factorise(&self) -> (Self, SparseMDSMatrix) { - assert_eq!(RATE + 1, T); - // Given `(t-1 * t-1)` MDS matrix called `hat` constructs the `t * t` matrix in - // form `[[1 | 0], [0 | m]]`, ie `hat` is the right bottom sub-matrix - let prime = |hat: Mds| -> Self { - let mut prime = Self::identity(); - for (prime_row, hat_row) in prime.iter_mut().skip(1).zip(hat.iter()) { - for (el_prime, el_hat) in prime_row.iter_mut().skip(1).zip(hat_row.iter()) { - *el_prime = *el_hat; - } - } - Self(prime) - }; - - // Given `(t-1)` sized `w_hat` vector constructs the matrix in form - // `[[m_0_0 | m_0_i], [w_hat | identity]]` - let prime_prime = |w_hat: [F; RATE]| -> Mds { - let mut prime_prime = Self::identity(); - prime_prime[0] = self.0[0]; - for (row, w) in prime_prime.iter_mut().skip(1).zip(w_hat.iter()) { - row[0] = *w - } - prime_prime - }; - - let w = self.0.iter().skip(1).map(|row| row[0]).collect::>(); - // m_hat is the `(t-1 * t-1)` right bottom sub-matrix of m := self.0 - let mut m_hat = [[F::ZERO; RATE]; RATE]; - for i in 0..RATE { - for j in 0..RATE { - m_hat[i][j] = self.0[i + 1][j + 1]; - } - } - // w_hat = m_hat^{-1} * w, where m_hat^{-1} is matrix inverse and * is matrix mult - // we avoid computing m_hat^{-1} explicitly by using Cramer's rule: https://en.wikipedia.org/wiki/Cramer%27s_rule - let mut w_hat = [F::ZERO; RATE]; - let det = Self::determinant(m_hat); - let det_inv = Option::::from(det.invert()).expect("matrix is not invertible"); - for j in 0..RATE { - let mut m_hat_j = m_hat; - for i in 0..RATE { - m_hat_j[i][j] = w[i]; - } - w_hat[j] = Self::determinant(m_hat_j) * det_inv; - } - let m_prime = prime(m_hat); - let m_prime_prime = prime_prime(w_hat); - // row = first row of m_prime_prime.transpose() = first column of m_prime_prime - let row: [F; T] = - m_prime_prime.iter().map(|row| row[0]).collect::>().try_into().unwrap(); - // col_hat = first column of m_prime_prime.transpose() without first element = first row of m_prime_prime without first element - let col_hat: [F; RATE] = m_prime_prime[0][1..].try_into().unwrap(); - (m_prime, SparseMDSMatrix { row, col_hat }) - } -} - -impl OptimizedPoseidonSpec { - /// Generate new spec with specific number of full and partial rounds. `SECURE_MDS` is usually 0, but may need to be specified because insecure matrices may sometimes be generated - pub fn new() -> Self - where - F: FieldExt, - { - let (round_constants, mds, mds_inv) = - Poseidon128Pow5Gen::::constants(); - let mds = MDSMatrix(mds); - let inverse_mds = MDSMatrix(mds_inv); - - let constants = - Self::calculate_optimized_constants(R_F, R_P, round_constants, &inverse_mds); - let (sparse_matrices, pre_sparse_mds) = Self::calculate_sparse_matrices(R_P, &mds); - - Self { - r_f: R_F, - constants, - mds_matrices: MDSMatrices { mds, sparse_matrices, pre_sparse_mds }, - } - } - - fn calculate_optimized_constants( - r_f: usize, - r_p: usize, - constants: Vec<[F; T]>, - inverse_mds: &MDSMatrix, - ) -> OptimizedConstants { - let (number_of_rounds, r_f_half) = (r_f + r_p, r_f / 2); - assert_eq!(constants.len(), number_of_rounds); - - // Calculate optimized constants for first half of the full rounds - let mut constants_start: Vec<[F; T]> = vec![[F::ZERO; T]; r_f_half]; - constants_start[0] = constants[0]; - for (optimized, constants) in - constants_start.iter_mut().skip(1).zip(constants.iter().skip(1)) - { - *optimized = inverse_mds.mul_vector(constants); - } - - // Calculate constants for partial rounds - let mut acc = constants[r_f_half + r_p]; - let mut constants_partial = vec![F::ZERO; r_p]; - for (optimized, constants) in constants_partial - .iter_mut() - .rev() - .zip(constants.iter().skip(r_f_half).rev().skip(r_f_half)) - { - let mut tmp = inverse_mds.mul_vector(&acc); - *optimized = tmp[0]; - - tmp[0] = F::ZERO; - for ((acc, tmp), constant) in acc.iter_mut().zip(tmp).zip(constants.iter()) { - *acc = tmp + constant - } - } - constants_start.push(inverse_mds.mul_vector(&acc)); - - // Calculate optimized constants for ending half of the full rounds - let mut constants_end: Vec<[F; T]> = vec![[F::ZERO; T]; r_f_half - 1]; - for (optimized, constants) in - constants_end.iter_mut().zip(constants.iter().skip(r_f_half + r_p + 1)) - { - *optimized = inverse_mds.mul_vector(constants); - } - - OptimizedConstants { - start: constants_start, - partial: constants_partial, - end: constants_end, - } - } - - fn calculate_sparse_matrices( - r_p: usize, - mds: &MDSMatrix, - ) -> (Vec>, MDSMatrix) { - let mds = mds.transpose(); - let mut acc = mds.clone(); - let mut sparse_matrices = (0..r_p) - .map(|_| { - let (m_prime, m_prime_prime) = acc.factorise(); - acc = mds.mul(&m_prime); - m_prime_prime - }) - .collect::>>(); - - sparse_matrices.reverse(); - (sparse_matrices, acc.transpose()) - } -} - -// ================ END OF CONSTRUCTION OF POSEIDON SPEC ==================== - -// now we get to actual trait based implementation of Poseidon permutation // this works for any loader, where the two loaders used are NativeLoader (native rust) and Halo2Loader (ZK circuit) #[derive(Clone, Debug)] struct State { @@ -403,9 +94,9 @@ impl, const T: usize, const RATE: usize> State fn apply_sparse_mds(&mut self, mds: &SparseMDSMatrix) { self.inner = iter::once( self.loader() - .sum_with_coeff(&mds.row.iter().cloned().zip(self.inner.iter()).collect_vec()), + .sum_with_coeff(&mds.row().iter().cloned().zip(self.inner.iter()).collect_vec()), ) - .chain(mds.col_hat.iter().zip(self.inner.iter().skip(1)).map(|(coeff, state)| { + .chain(mds.col_hat().iter().zip(self.inner.iter().skip(1)).map(|(coeff, state)| { self.loader().sum_with_coeff(&[(*coeff, &self.inner[0]), (F::ONE, state)]) })) .collect_vec() @@ -475,35 +166,35 @@ impl, const T: usize, const RATE: usize> Posei } fn permutation(&mut self, inputs: &[L]) { - let r_f = self.spec.r_f / 2; - let mds = self.spec.mds_matrices.mds.0; - let pre_sparse_mds = self.spec.mds_matrices.pre_sparse_mds.0; - let sparse_matrices = &self.spec.mds_matrices.sparse_matrices; + let r_f = self.spec.r_f() / 2; + let mds = self.spec.mds_matrices().mds().as_ref(); + let pre_sparse_mds = self.spec.mds_matrices().pre_sparse_mds().as_ref(); + let sparse_matrices = &self.spec.mds_matrices().sparse_matrices(); // First half of the full rounds - let constants = &self.spec.constants.start; + let constants = self.spec.constants().start(); self.state.absorb_with_pre_constants(inputs, &constants[0]); for constants in constants.iter().skip(1).take(r_f - 1) { self.state.sbox_full(constants); - self.state.apply_mds(&mds); + self.state.apply_mds(mds); } self.state.sbox_full(constants.last().unwrap()); - self.state.apply_mds(&pre_sparse_mds); + self.state.apply_mds(pre_sparse_mds); // Partial rounds - let constants = &self.spec.constants.partial; + let constants = self.spec.constants().partial(); for (constant, sparse_mds) in constants.iter().zip(sparse_matrices.iter()) { self.state.sbox_part(constant); self.state.apply_sparse_mds(sparse_mds); } // Second half of the full rounds - let constants = &self.spec.constants.end; + let constants = self.spec.constants().end(); for constants in constants.iter() { self.state.sbox_full(constants); - self.state.apply_mds(&mds); + self.state.apply_mds(mds); } self.state.sbox_full(&[F::ZERO; T]); - self.state.apply_mds(&mds); + self.state.apply_mds(mds); } } diff --git a/snark-verifier/src/util/hash/poseidon/tests.rs b/snark-verifier/src/util/hash/poseidon/tests.rs index 76793c91..507b1d7c 100644 --- a/snark-verifier/src/util/hash/poseidon/tests.rs +++ b/snark-verifier/src/util/hash/poseidon/tests.rs @@ -24,7 +24,7 @@ fn test_mds() { "11597556804922396090267472882856054602429588299176362916247939723151043581408", ], ]; - for (row1, row2) in mds.iter().zip_eq(spec.mds_matrices.mds.0.iter()) { + for (row1, row2) in mds.iter().zip_eq(spec.mds_matrices().mds().as_ref().iter()) { for (e1, e2) in row1.iter().zip_eq(row2.iter()) { assert_eq!(Fr::from_str_vartime(e1).unwrap(), *e2); } From 1f5ebd39307d8e1824856f9e683a35a59b145a8d Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Sun, 10 Sep 2023 14:39:33 -0700 Subject: [PATCH 52/73] chore: util::hash available without loader_halo2 feature --- snark-verifier-sdk/Cargo.toml | 4 ++-- snark-verifier/src/util/hash.rs | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 681f9121..1d8019af 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -46,8 +46,8 @@ tui = { version = "0.19", default-features = false, features = ["crossterm"] } [features] default = [ - "loader_halo2", - "loader_evm", + #"loader_halo2", + #"loader_evm", "halo2-axiom", "halo2-base/jemallocator", "display", diff --git a/snark-verifier/src/util/hash.rs b/snark-verifier/src/util/hash.rs index dfc02cf0..245e9d24 100644 --- a/snark-verifier/src/util/hash.rs +++ b/snark-verifier/src/util/hash.rs @@ -1,11 +1,8 @@ //! Hash algorithms. -#[cfg(feature = "loader_halo2")] mod poseidon; -#[cfg(feature = "loader_halo2")] pub use crate::util::hash::poseidon::Poseidon; -#[cfg(feature = "loader_halo2")] pub(crate) use halo2_base::poseidon::hasher::spec::OptimizedPoseidonSpec; #[cfg(feature = "loader_evm")] From a0fa8ec6c27eb0884b9de88b61708f240e138064 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Sun, 10 Sep 2023 14:43:34 -0700 Subject: [PATCH 53/73] chore: nit --- snark-verifier-sdk/Cargo.toml | 4 ++-- snark-verifier/src/util/hash.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 1d8019af..681f9121 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -46,8 +46,8 @@ tui = { version = "0.19", default-features = false, features = ["crossterm"] } [features] default = [ - #"loader_halo2", - #"loader_evm", + "loader_halo2", + "loader_evm", "halo2-axiom", "halo2-base/jemallocator", "display", diff --git a/snark-verifier/src/util/hash.rs b/snark-verifier/src/util/hash.rs index 245e9d24..a14eec23 100644 --- a/snark-verifier/src/util/hash.rs +++ b/snark-verifier/src/util/hash.rs @@ -3,6 +3,7 @@ mod poseidon; pub use crate::util::hash::poseidon::Poseidon; +#[cfg(feature = "loader_halo2")] pub(crate) use halo2_base::poseidon::hasher::spec::OptimizedPoseidonSpec; #[cfg(feature = "loader_evm")] From df944c27989bebe9b981f9a6f3ae7f64cb51e6d5 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 11 Sep 2023 00:33:26 -0700 Subject: [PATCH 54/73] [feat] change yul code into Solidity assembly (#32) feat: change yul code into Solidity assembly Just changes to wrapping yul in solidity assembly block --- .github/workflows/ci.yaml | 4 + snark-verifier-sdk/Cargo.toml | 6 +- .../examples/StandardPlonkVerifier.sol | 1437 +++++++++++++++++ snark-verifier-sdk/examples/standard_plonk.rs | 216 +++ snark-verifier-sdk/src/evm.rs | 8 +- snark-verifier/Cargo.toml | 2 +- .../examples/evm-verifier-with-accumulator.rs | 2 +- snark-verifier/examples/evm-verifier.rs | 2 +- snark-verifier/src/loader/evm.rs | 4 +- snark-verifier/src/loader/evm/code.rs | 66 +- snark-verifier/src/loader/evm/loader.rs | 18 +- snark-verifier/src/loader/evm/util.rs | 5 +- 12 files changed, 1714 insertions(+), 56 deletions(-) create mode 100644 snark-verifier-sdk/examples/StandardPlonkVerifier.sol create mode 100644 snark-verifier-sdk/examples/standard_plonk.rs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 7261444e..733bfc9c 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -29,6 +29,10 @@ jobs: - name: Run test run: cargo test --all -- --nocapture + - name: Run example + working-directory: "snark-verifier-sdk" + run: cargo run --example standard_plonk + lint: name: Lint runs-on: ubuntu-latest diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 681f9121..db1f7071 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier-sdk" -version = "0.1.5" +version = "0.1.6" edition = "2021" [dependencies] @@ -81,3 +81,7 @@ harness = false name = "read_pk" required-features = ["loader_halo2"] harness = false + +[[example]] +name = "standard_plonk" +required-features = ["loader_halo2", "loader_evm"] diff --git a/snark-verifier-sdk/examples/StandardPlonkVerifier.sol b/snark-verifier-sdk/examples/StandardPlonkVerifier.sol new file mode 100644 index 00000000..d6e9427c --- /dev/null +++ b/snark-verifier-sdk/examples/StandardPlonkVerifier.sol @@ -0,0 +1,1437 @@ + +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.19; + +contract Halo2Verifier { + fallback(bytes calldata) external returns (bytes memory) { + assembly { + let success := true + let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 + let f_q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 + function validate_ec_point(x, y) -> valid { + { + let x_lt_p := lt(x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let y_lt_p := lt(y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + valid := and(x_lt_p, y_lt_p) + } + { + let y_square := mulmod(y, y, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_square := mulmod(x, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_cube := mulmod(x_square, x, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let x_cube_plus_3 := addmod(x_cube, 3, 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47) + let is_affine := eq(x_cube_plus_3, y_square) + valid := and(valid, is_affine) + } + } + mstore(0x20, mod(calldataload(0x0), f_q)) +mstore(0x40, mod(calldataload(0x20), f_q)) +mstore(0x60, mod(calldataload(0x40), f_q)) +mstore(0x80, mod(calldataload(0x60), f_q)) +mstore(0xa0, mod(calldataload(0x80), f_q)) +mstore(0xc0, mod(calldataload(0xa0), f_q)) +mstore(0xe0, mod(calldataload(0xc0), f_q)) +mstore(0x100, mod(calldataload(0xe0), f_q)) +mstore(0x120, mod(calldataload(0x100), f_q)) +mstore(0x140, mod(calldataload(0x120), f_q)) +mstore(0x160, mod(calldataload(0x140), f_q)) +mstore(0x180, mod(calldataload(0x160), f_q)) +mstore(0x0, 17740244582459666476042487670110999380715355991411842331101569887719361442506) + + { + let x := calldataload(0x180) + mstore(0x1a0, x) + let y := calldataload(0x1a0) + mstore(0x1c0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x1c0) + mstore(0x1e0, x) + let y := calldataload(0x1e0) + mstore(0x200, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x200) + mstore(0x220, x) + let y := calldataload(0x220) + mstore(0x240, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x260, keccak256(0x0, 608)) +{ + let hash := mload(0x260) + mstore(0x280, mod(hash, f_q)) + mstore(0x2a0, hash) + } + + { + let x := calldataload(0x240) + mstore(0x2c0, x) + let y := calldataload(0x260) + mstore(0x2e0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x280) + mstore(0x300, x) + let y := calldataload(0x2a0) + mstore(0x320, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x340, keccak256(0x2a0, 160)) +{ + let hash := mload(0x340) + mstore(0x360, mod(hash, f_q)) + mstore(0x380, hash) + } +mstore8(928, 1) +mstore(0x3a0, keccak256(0x380, 33)) +{ + let hash := mload(0x3a0) + mstore(0x3c0, mod(hash, f_q)) + mstore(0x3e0, hash) + } + + { + let x := calldataload(0x2c0) + mstore(0x400, x) + let y := calldataload(0x2e0) + mstore(0x420, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x300) + mstore(0x440, x) + let y := calldataload(0x320) + mstore(0x460, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x340) + mstore(0x480, x) + let y := calldataload(0x360) + mstore(0x4a0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x380) + mstore(0x4c0, x) + let y := calldataload(0x3a0) + mstore(0x4e0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x3c0) + mstore(0x500, x) + let y := calldataload(0x3e0) + mstore(0x520, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x540, keccak256(0x3e0, 352)) +{ + let hash := mload(0x540) + mstore(0x560, mod(hash, f_q)) + mstore(0x580, hash) + } + + { + let x := calldataload(0x400) + mstore(0x5a0, x) + let y := calldataload(0x420) + mstore(0x5c0, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x440) + mstore(0x5e0, x) + let y := calldataload(0x460) + mstore(0x600, y) + success := and(validate_ec_point(x, y), success) + } + + { + let x := calldataload(0x480) + mstore(0x620, x) + let y := calldataload(0x4a0) + mstore(0x640, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0x660, keccak256(0x580, 224)) +{ + let hash := mload(0x660) + mstore(0x680, mod(hash, f_q)) + mstore(0x6a0, hash) + } +mstore(0x6c0, mod(calldataload(0x4c0), f_q)) +mstore(0x6e0, mod(calldataload(0x4e0), f_q)) +mstore(0x700, mod(calldataload(0x500), f_q)) +mstore(0x720, mod(calldataload(0x520), f_q)) +mstore(0x740, mod(calldataload(0x540), f_q)) +mstore(0x760, mod(calldataload(0x560), f_q)) +mstore(0x780, mod(calldataload(0x580), f_q)) +mstore(0x7a0, mod(calldataload(0x5a0), f_q)) +mstore(0x7c0, mod(calldataload(0x5c0), f_q)) +mstore(0x7e0, mod(calldataload(0x5e0), f_q)) +mstore(0x800, mod(calldataload(0x600), f_q)) +mstore(0x820, mod(calldataload(0x620), f_q)) +mstore(0x840, mod(calldataload(0x640), f_q)) +mstore(0x860, mod(calldataload(0x660), f_q)) +mstore(0x880, mod(calldataload(0x680), f_q)) +mstore(0x8a0, mod(calldataload(0x6a0), f_q)) +mstore(0x8c0, mod(calldataload(0x6c0), f_q)) +mstore(0x8e0, mod(calldataload(0x6e0), f_q)) +mstore(0x900, mod(calldataload(0x700), f_q)) +mstore(0x920, mod(calldataload(0x720), f_q)) +mstore(0x940, mod(calldataload(0x740), f_q)) +mstore(0x960, mod(calldataload(0x760), f_q)) +mstore(0x980, mod(calldataload(0x780), f_q)) +mstore(0x9a0, mod(calldataload(0x7a0), f_q)) +mstore(0x9c0, mod(calldataload(0x7c0), f_q)) +mstore(0x9e0, mod(calldataload(0x7e0), f_q)) +mstore(0xa00, mod(calldataload(0x800), f_q)) +mstore(0xa20, mod(calldataload(0x820), f_q)) +mstore(0xa40, mod(calldataload(0x840), f_q)) +mstore(0xa60, mod(calldataload(0x860), f_q)) +mstore(0xa80, mod(calldataload(0x880), f_q)) +mstore(0xaa0, mod(calldataload(0x8a0), f_q)) +mstore(0xac0, keccak256(0x6a0, 1056)) +{ + let hash := mload(0xac0) + mstore(0xae0, mod(hash, f_q)) + mstore(0xb00, hash) + } +mstore8(2848, 1) +mstore(0xb20, keccak256(0xb00, 33)) +{ + let hash := mload(0xb20) + mstore(0xb40, mod(hash, f_q)) + mstore(0xb60, hash) + } + + { + let x := calldataload(0x8c0) + mstore(0xb80, x) + let y := calldataload(0x8e0) + mstore(0xba0, y) + success := and(validate_ec_point(x, y), success) + } +mstore(0xbc0, keccak256(0xb60, 96)) +{ + let hash := mload(0xbc0) + mstore(0xbe0, mod(hash, f_q)) + mstore(0xc00, hash) + } + + { + let x := calldataload(0x900) + mstore(0xc20, x) + let y := calldataload(0x920) + mstore(0xc40, y) + success := and(validate_ec_point(x, y), success) + } +{ + let x := mload(0x20) +x := add(x, shl(88, mload(0x40))) +x := add(x, shl(176, mload(0x60))) +mstore(3168, x) +let y := mload(0x80) +y := add(y, shl(88, mload(0xa0))) +y := add(y, shl(176, mload(0xc0))) +mstore(3200, y) + + success := and(validate_ec_point(x, y), success) + } +{ + let x := mload(0xe0) +x := add(x, shl(88, mload(0x100))) +x := add(x, shl(176, mload(0x120))) +mstore(3232, x) +let y := mload(0x140) +y := add(y, shl(88, mload(0x160))) +y := add(y, shl(176, mload(0x180))) +mstore(3264, y) + + success := and(validate_ec_point(x, y), success) + } +mstore(0xce0, mulmod(mload(0x680), mload(0x680), f_q)) +mstore(0xd00, mulmod(mload(0xce0), mload(0xce0), f_q)) +mstore(0xd20, mulmod(mload(0xd00), mload(0xd00), f_q)) +mstore(0xd40, mulmod(mload(0xd20), mload(0xd20), f_q)) +mstore(0xd60, mulmod(mload(0xd40), mload(0xd40), f_q)) +mstore(0xd80, mulmod(mload(0xd60), mload(0xd60), f_q)) +mstore(0xda0, mulmod(mload(0xd80), mload(0xd80), f_q)) +mstore(0xdc0, mulmod(mload(0xda0), mload(0xda0), f_q)) +mstore(0xde0, mulmod(mload(0xdc0), mload(0xdc0), f_q)) +mstore(0xe00, mulmod(mload(0xde0), mload(0xde0), f_q)) +mstore(0xe20, mulmod(mload(0xe00), mload(0xe00), f_q)) +mstore(0xe40, mulmod(mload(0xe20), mload(0xe20), f_q)) +mstore(0xe60, mulmod(mload(0xe40), mload(0xe40), f_q)) +mstore(0xe80, mulmod(mload(0xe60), mload(0xe60), f_q)) +mstore(0xea0, mulmod(mload(0xe80), mload(0xe80), f_q)) +mstore(0xec0, mulmod(mload(0xea0), mload(0xea0), f_q)) +mstore(0xee0, mulmod(mload(0xec0), mload(0xec0), f_q)) +mstore(0xf00, mulmod(mload(0xee0), mload(0xee0), f_q)) +mstore(0xf20, mulmod(mload(0xf00), mload(0xf00), f_q)) +mstore(0xf40, mulmod(mload(0xf20), mload(0xf20), f_q)) +mstore(0xf60, mulmod(mload(0xf40), mload(0xf40), f_q)) +mstore(0xf80, addmod(mload(0xf60), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0xfa0, mulmod(mload(0xf80), 21888232434711746154598842647110004286396165347431605739555851272621938401409, f_q)) +mstore(0xfc0, mulmod(mload(0xfa0), 20975929243409798062839949658616274858986091382510192949221301676705706354487, f_q)) +mstore(0xfe0, addmod(mload(0x680), 912313628429477159406456086641000229562273017905841394476902509870102141130, f_q)) +mstore(0x1000, mulmod(mload(0xfa0), 495188420091111145957709789221178673495499187437761988132837836548330853701, f_q)) +mstore(0x1020, addmod(mload(0x680), 21393054451748164076288695956036096415052865212978272355565366350027477641916, f_q)) +mstore(0x1040, mulmod(mload(0xfa0), 16064522944768515290584536219762686197737451920702130080538975732575755569557, f_q)) +mstore(0x1060, addmod(mload(0x680), 5823719927070759931661869525494588890810912479713904263159228454000052926060, f_q)) +mstore(0x1080, mulmod(mload(0xfa0), 14686510910986211321976396297238126901237973400949744736326777596334651355305, f_q)) +mstore(0x10a0, addmod(mload(0x680), 7201731960853063900270009448019148187310390999466289607371426590241157140312, f_q)) +mstore(0x10c0, mulmod(mload(0xfa0), 10939663269433627367777756708678102241564365262857670666700619874077960926249, f_q)) +mstore(0x10e0, addmod(mload(0x680), 10948579602405647854468649036579172846983999137558363676997584312497847569368, f_q)) +mstore(0x1100, mulmod(mload(0xfa0), 15402826414547299628414612080036060696555554914079673875872749760617770134879, f_q)) +mstore(0x1120, addmod(mload(0x680), 6485416457291975593831793665221214391992809486336360467825454425958038360738, f_q)) +mstore(0x1140, mulmod(mload(0xfa0), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) +mstore(0x1160, addmod(mload(0x680), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q)) +mstore(0x1180, mulmod(mload(0xfa0), 1, f_q)) +mstore(0x11a0, addmod(mload(0x680), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x11c0, mulmod(mload(0xfa0), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x11e0, addmod(mload(0x680), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q)) +mstore(0x1200, mulmod(mload(0xfa0), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) +mstore(0x1220, addmod(mload(0x680), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q)) +mstore(0x1240, mulmod(mload(0xfa0), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) +mstore(0x1260, addmod(mload(0x680), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q)) +mstore(0x1280, mulmod(mload(0xfa0), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q)) +mstore(0x12a0, addmod(mload(0x680), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q)) +mstore(0x12c0, mulmod(mload(0xfa0), 14557038802599140430182096396825290815503940951075961210638273254419942783582, f_q)) +mstore(0x12e0, addmod(mload(0x680), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q)) +mstore(0x1300, mulmod(mload(0xfa0), 9697063347556872083384215826199993067635178715531258559890418744774301211662, f_q)) +mstore(0x1320, addmod(mload(0x680), 12191179524282403138862189919057282020913185684884775783807785441801507283955, f_q)) +mstore(0x1340, mulmod(mload(0xfa0), 12459868075641381822485233712013080087763946065665469821362892189399541605692, f_q)) +mstore(0x1360, addmod(mload(0x680), 9428374796197893399761172033244195000784418334750564522335311997176266889925, f_q)) +mstore(0x1380, mulmod(mload(0xfa0), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q)) +mstore(0x13a0, addmod(mload(0x680), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q)) +mstore(0x13c0, mulmod(mload(0xfa0), 20345677989844117909528750049476969581182118546166966482506114734614108237981, f_q)) +mstore(0x13e0, addmod(mload(0x680), 1542564881995157312717655695780305507366245854249067861192089451961700257636, f_q)) +mstore(0x1400, mulmod(mload(0xfa0), 5289443209903185443361862148540090689648485914368835830972895623576469023722, f_q)) +mstore(0x1420, addmod(mload(0x680), 16598799661936089778884543596717184398899878486047198512725308562999339471895, f_q)) +mstore(0x1440, mulmod(mload(0xfa0), 557567375339945239933617516585967620814823575807691402619711360028043331811, f_q)) +mstore(0x1460, addmod(mload(0x680), 21330675496499329982312788228671307467733540824608342941078492826547765163806, f_q)) +{ + let prod := mload(0xfe0) + + prod := mulmod(mload(0x1020), prod, f_q) + mstore(0x1480, prod) + + prod := mulmod(mload(0x1060), prod, f_q) + mstore(0x14a0, prod) + + prod := mulmod(mload(0x10a0), prod, f_q) + mstore(0x14c0, prod) + + prod := mulmod(mload(0x10e0), prod, f_q) + mstore(0x14e0, prod) + + prod := mulmod(mload(0x1120), prod, f_q) + mstore(0x1500, prod) + + prod := mulmod(mload(0x1160), prod, f_q) + mstore(0x1520, prod) + + prod := mulmod(mload(0x11a0), prod, f_q) + mstore(0x1540, prod) + + prod := mulmod(mload(0x11e0), prod, f_q) + mstore(0x1560, prod) + + prod := mulmod(mload(0x1220), prod, f_q) + mstore(0x1580, prod) + + prod := mulmod(mload(0x1260), prod, f_q) + mstore(0x15a0, prod) + + prod := mulmod(mload(0x12a0), prod, f_q) + mstore(0x15c0, prod) + + prod := mulmod(mload(0x12e0), prod, f_q) + mstore(0x15e0, prod) + + prod := mulmod(mload(0x1320), prod, f_q) + mstore(0x1600, prod) + + prod := mulmod(mload(0x1360), prod, f_q) + mstore(0x1620, prod) + + prod := mulmod(mload(0x13a0), prod, f_q) + mstore(0x1640, prod) + + prod := mulmod(mload(0x13e0), prod, f_q) + mstore(0x1660, prod) + + prod := mulmod(mload(0x1420), prod, f_q) + mstore(0x1680, prod) + + prod := mulmod(mload(0x1460), prod, f_q) + mstore(0x16a0, prod) + + prod := mulmod(mload(0xf80), prod, f_q) + mstore(0x16c0, prod) + + } +mstore(0x1700, 32) +mstore(0x1720, 32) +mstore(0x1740, 32) +mstore(0x1760, mload(0x16c0)) +mstore(0x1780, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x17a0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x1700, 0xc0, 0x16e0, 0x20), 1), success) +{ + + let inv := mload(0x16e0) + let v + + v := mload(0xf80) + mstore(3968, mulmod(mload(0x16a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1460) + mstore(5216, mulmod(mload(0x1680), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1420) + mstore(5152, mulmod(mload(0x1660), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x13e0) + mstore(5088, mulmod(mload(0x1640), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x13a0) + mstore(5024, mulmod(mload(0x1620), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1360) + mstore(4960, mulmod(mload(0x1600), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1320) + mstore(4896, mulmod(mload(0x15e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x12e0) + mstore(4832, mulmod(mload(0x15c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x12a0) + mstore(4768, mulmod(mload(0x15a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1260) + mstore(4704, mulmod(mload(0x1580), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1220) + mstore(4640, mulmod(mload(0x1560), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x11e0) + mstore(4576, mulmod(mload(0x1540), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x11a0) + mstore(4512, mulmod(mload(0x1520), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1160) + mstore(4448, mulmod(mload(0x1500), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1120) + mstore(4384, mulmod(mload(0x14e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x10e0) + mstore(4320, mulmod(mload(0x14c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x10a0) + mstore(4256, mulmod(mload(0x14a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1060) + mstore(4192, mulmod(mload(0x1480), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x1020) + mstore(4128, mulmod(mload(0xfe0), inv, f_q)) + inv := mulmod(v, inv, f_q) + mstore(0xfe0, inv) + + } +mstore(0x17c0, mulmod(mload(0xfc0), mload(0xfe0), f_q)) +mstore(0x17e0, mulmod(mload(0x1000), mload(0x1020), f_q)) +mstore(0x1800, mulmod(mload(0x1040), mload(0x1060), f_q)) +mstore(0x1820, mulmod(mload(0x1080), mload(0x10a0), f_q)) +mstore(0x1840, mulmod(mload(0x10c0), mload(0x10e0), f_q)) +mstore(0x1860, mulmod(mload(0x1100), mload(0x1120), f_q)) +mstore(0x1880, mulmod(mload(0x1140), mload(0x1160), f_q)) +mstore(0x18a0, mulmod(mload(0x1180), mload(0x11a0), f_q)) +mstore(0x18c0, mulmod(mload(0x11c0), mload(0x11e0), f_q)) +mstore(0x18e0, mulmod(mload(0x1200), mload(0x1220), f_q)) +mstore(0x1900, mulmod(mload(0x1240), mload(0x1260), f_q)) +mstore(0x1920, mulmod(mload(0x1280), mload(0x12a0), f_q)) +mstore(0x1940, mulmod(mload(0x12c0), mload(0x12e0), f_q)) +mstore(0x1960, mulmod(mload(0x1300), mload(0x1320), f_q)) +mstore(0x1980, mulmod(mload(0x1340), mload(0x1360), f_q)) +mstore(0x19a0, mulmod(mload(0x1380), mload(0x13a0), f_q)) +mstore(0x19c0, mulmod(mload(0x13c0), mload(0x13e0), f_q)) +mstore(0x19e0, mulmod(mload(0x1400), mload(0x1420), f_q)) +mstore(0x1a00, mulmod(mload(0x1440), mload(0x1460), f_q)) +{ + let result := mulmod(mload(0x18a0), mload(0x20), f_q) +result := addmod(mulmod(mload(0x18c0), mload(0x40), f_q), result, f_q) +result := addmod(mulmod(mload(0x18e0), mload(0x60), f_q), result, f_q) +result := addmod(mulmod(mload(0x1900), mload(0x80), f_q), result, f_q) +result := addmod(mulmod(mload(0x1920), mload(0xa0), f_q), result, f_q) +result := addmod(mulmod(mload(0x1940), mload(0xc0), f_q), result, f_q) +result := addmod(mulmod(mload(0x1960), mload(0xe0), f_q), result, f_q) +result := addmod(mulmod(mload(0x1980), mload(0x100), f_q), result, f_q) +result := addmod(mulmod(mload(0x19a0), mload(0x120), f_q), result, f_q) +result := addmod(mulmod(mload(0x19c0), mload(0x140), f_q), result, f_q) +result := addmod(mulmod(mload(0x19e0), mload(0x160), f_q), result, f_q) +result := addmod(mulmod(mload(0x1a00), mload(0x180), f_q), result, f_q) +mstore(6688, result) + } +mstore(0x1a40, mulmod(mload(0x700), mload(0x6e0), f_q)) +mstore(0x1a60, addmod(mload(0x6c0), mload(0x1a40), f_q)) +mstore(0x1a80, addmod(mload(0x1a60), sub(f_q, mload(0x720)), f_q)) +mstore(0x1aa0, mulmod(mload(0x1a80), mload(0x820), f_q)) +mstore(0x1ac0, mulmod(mload(0x560), mload(0x1aa0), f_q)) +mstore(0x1ae0, mulmod(mload(0x780), mload(0x760), f_q)) +mstore(0x1b00, addmod(mload(0x740), mload(0x1ae0), f_q)) +mstore(0x1b20, addmod(mload(0x1b00), sub(f_q, mload(0x7a0)), f_q)) +mstore(0x1b40, mulmod(mload(0x1b20), mload(0x840), f_q)) +mstore(0x1b60, addmod(mload(0x1ac0), mload(0x1b40), f_q)) +mstore(0x1b80, mulmod(mload(0x560), mload(0x1b60), f_q)) +mstore(0x1ba0, addmod(1, sub(f_q, mload(0x920)), f_q)) +mstore(0x1bc0, mulmod(mload(0x1ba0), mload(0x18a0), f_q)) +mstore(0x1be0, addmod(mload(0x1b80), mload(0x1bc0), f_q)) +mstore(0x1c00, mulmod(mload(0x560), mload(0x1be0), f_q)) +mstore(0x1c20, mulmod(mload(0x9e0), mload(0x9e0), f_q)) +mstore(0x1c40, addmod(mload(0x1c20), sub(f_q, mload(0x9e0)), f_q)) +mstore(0x1c60, mulmod(mload(0x1c40), mload(0x17c0), f_q)) +mstore(0x1c80, addmod(mload(0x1c00), mload(0x1c60), f_q)) +mstore(0x1ca0, mulmod(mload(0x560), mload(0x1c80), f_q)) +mstore(0x1cc0, addmod(mload(0x980), sub(f_q, mload(0x960)), f_q)) +mstore(0x1ce0, mulmod(mload(0x1cc0), mload(0x18a0), f_q)) +mstore(0x1d00, addmod(mload(0x1ca0), mload(0x1ce0), f_q)) +mstore(0x1d20, mulmod(mload(0x560), mload(0x1d00), f_q)) +mstore(0x1d40, addmod(mload(0x9e0), sub(f_q, mload(0x9c0)), f_q)) +mstore(0x1d60, mulmod(mload(0x1d40), mload(0x18a0), f_q)) +mstore(0x1d80, addmod(mload(0x1d20), mload(0x1d60), f_q)) +mstore(0x1da0, mulmod(mload(0x560), mload(0x1d80), f_q)) +mstore(0x1dc0, addmod(1, sub(f_q, mload(0x17c0)), f_q)) +mstore(0x1de0, addmod(mload(0x17e0), mload(0x1800), f_q)) +mstore(0x1e00, addmod(mload(0x1de0), mload(0x1820), f_q)) +mstore(0x1e20, addmod(mload(0x1e00), mload(0x1840), f_q)) +mstore(0x1e40, addmod(mload(0x1e20), mload(0x1860), f_q)) +mstore(0x1e60, addmod(mload(0x1e40), mload(0x1880), f_q)) +mstore(0x1e80, addmod(mload(0x1dc0), sub(f_q, mload(0x1e60)), f_q)) +mstore(0x1ea0, mulmod(mload(0x880), mload(0x360), f_q)) +mstore(0x1ec0, addmod(mload(0x7e0), mload(0x1ea0), f_q)) +mstore(0x1ee0, addmod(mload(0x1ec0), mload(0x3c0), f_q)) +mstore(0x1f00, mulmod(mload(0x8a0), mload(0x360), f_q)) +mstore(0x1f20, addmod(mload(0x6c0), mload(0x1f00), f_q)) +mstore(0x1f40, addmod(mload(0x1f20), mload(0x3c0), f_q)) +mstore(0x1f60, mulmod(mload(0x1f40), mload(0x1ee0), f_q)) +mstore(0x1f80, mulmod(mload(0x1f60), mload(0x940), f_q)) +mstore(0x1fa0, mulmod(1, mload(0x360), f_q)) +mstore(0x1fc0, mulmod(mload(0x680), mload(0x1fa0), f_q)) +mstore(0x1fe0, addmod(mload(0x7e0), mload(0x1fc0), f_q)) +mstore(0x2000, addmod(mload(0x1fe0), mload(0x3c0), f_q)) +mstore(0x2020, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x360), f_q)) +mstore(0x2040, mulmod(mload(0x680), mload(0x2020), f_q)) +mstore(0x2060, addmod(mload(0x6c0), mload(0x2040), f_q)) +mstore(0x2080, addmod(mload(0x2060), mload(0x3c0), f_q)) +mstore(0x20a0, mulmod(mload(0x2080), mload(0x2000), f_q)) +mstore(0x20c0, mulmod(mload(0x20a0), mload(0x920), f_q)) +mstore(0x20e0, addmod(mload(0x1f80), sub(f_q, mload(0x20c0)), f_q)) +mstore(0x2100, mulmod(mload(0x20e0), mload(0x1e80), f_q)) +mstore(0x2120, addmod(mload(0x1da0), mload(0x2100), f_q)) +mstore(0x2140, mulmod(mload(0x560), mload(0x2120), f_q)) +mstore(0x2160, mulmod(mload(0x8c0), mload(0x360), f_q)) +mstore(0x2180, addmod(mload(0x740), mload(0x2160), f_q)) +mstore(0x21a0, addmod(mload(0x2180), mload(0x3c0), f_q)) +mstore(0x21c0, mulmod(mload(0x8e0), mload(0x360), f_q)) +mstore(0x21e0, addmod(mload(0x7c0), mload(0x21c0), f_q)) +mstore(0x2200, addmod(mload(0x21e0), mload(0x3c0), f_q)) +mstore(0x2220, mulmod(mload(0x2200), mload(0x21a0), f_q)) +mstore(0x2240, mulmod(mload(0x2220), mload(0x9a0), f_q)) +mstore(0x2260, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x360), f_q)) +mstore(0x2280, mulmod(mload(0x680), mload(0x2260), f_q)) +mstore(0x22a0, addmod(mload(0x740), mload(0x2280), f_q)) +mstore(0x22c0, addmod(mload(0x22a0), mload(0x3c0), f_q)) +mstore(0x22e0, mulmod(11166246659983828508719468090013646171463329086121580628794302409516816350802, mload(0x360), f_q)) +mstore(0x2300, mulmod(mload(0x680), mload(0x22e0), f_q)) +mstore(0x2320, addmod(mload(0x7c0), mload(0x2300), f_q)) +mstore(0x2340, addmod(mload(0x2320), mload(0x3c0), f_q)) +mstore(0x2360, mulmod(mload(0x2340), mload(0x22c0), f_q)) +mstore(0x2380, mulmod(mload(0x2360), mload(0x980), f_q)) +mstore(0x23a0, addmod(mload(0x2240), sub(f_q, mload(0x2380)), f_q)) +mstore(0x23c0, mulmod(mload(0x23a0), mload(0x1e80), f_q)) +mstore(0x23e0, addmod(mload(0x2140), mload(0x23c0), f_q)) +mstore(0x2400, mulmod(mload(0x560), mload(0x23e0), f_q)) +mstore(0x2420, mulmod(mload(0x900), mload(0x360), f_q)) +mstore(0x2440, addmod(mload(0x1a20), mload(0x2420), f_q)) +mstore(0x2460, addmod(mload(0x2440), mload(0x3c0), f_q)) +mstore(0x2480, mulmod(mload(0x2460), mload(0xa00), f_q)) +mstore(0x24a0, mulmod(284840088355319032285349970403338060113257071685626700086398481893096618818, mload(0x360), f_q)) +mstore(0x24c0, mulmod(mload(0x680), mload(0x24a0), f_q)) +mstore(0x24e0, addmod(mload(0x1a20), mload(0x24c0), f_q)) +mstore(0x2500, addmod(mload(0x24e0), mload(0x3c0), f_q)) +mstore(0x2520, mulmod(mload(0x2500), mload(0x9e0), f_q)) +mstore(0x2540, addmod(mload(0x2480), sub(f_q, mload(0x2520)), f_q)) +mstore(0x2560, mulmod(mload(0x2540), mload(0x1e80), f_q)) +mstore(0x2580, addmod(mload(0x2400), mload(0x2560), f_q)) +mstore(0x25a0, mulmod(mload(0x560), mload(0x2580), f_q)) +mstore(0x25c0, addmod(1, sub(f_q, mload(0xa20)), f_q)) +mstore(0x25e0, mulmod(mload(0x25c0), mload(0x18a0), f_q)) +mstore(0x2600, addmod(mload(0x25a0), mload(0x25e0), f_q)) +mstore(0x2620, mulmod(mload(0x560), mload(0x2600), f_q)) +mstore(0x2640, mulmod(mload(0xa20), mload(0xa20), f_q)) +mstore(0x2660, addmod(mload(0x2640), sub(f_q, mload(0xa20)), f_q)) +mstore(0x2680, mulmod(mload(0x2660), mload(0x17c0), f_q)) +mstore(0x26a0, addmod(mload(0x2620), mload(0x2680), f_q)) +mstore(0x26c0, mulmod(mload(0x560), mload(0x26a0), f_q)) +mstore(0x26e0, addmod(mload(0xa60), mload(0x360), f_q)) +mstore(0x2700, mulmod(mload(0x26e0), mload(0xa40), f_q)) +mstore(0x2720, addmod(mload(0xaa0), mload(0x3c0), f_q)) +mstore(0x2740, mulmod(mload(0x2720), mload(0x2700), f_q)) +mstore(0x2760, addmod(mload(0x7c0), mload(0x360), f_q)) +mstore(0x2780, mulmod(mload(0x2760), mload(0xa20), f_q)) +mstore(0x27a0, addmod(mload(0x800), mload(0x3c0), f_q)) +mstore(0x27c0, mulmod(mload(0x27a0), mload(0x2780), f_q)) +mstore(0x27e0, addmod(mload(0x2740), sub(f_q, mload(0x27c0)), f_q)) +mstore(0x2800, mulmod(mload(0x27e0), mload(0x1e80), f_q)) +mstore(0x2820, addmod(mload(0x26c0), mload(0x2800), f_q)) +mstore(0x2840, mulmod(mload(0x560), mload(0x2820), f_q)) +mstore(0x2860, addmod(mload(0xa60), sub(f_q, mload(0xaa0)), f_q)) +mstore(0x2880, mulmod(mload(0x2860), mload(0x18a0), f_q)) +mstore(0x28a0, addmod(mload(0x2840), mload(0x2880), f_q)) +mstore(0x28c0, mulmod(mload(0x560), mload(0x28a0), f_q)) +mstore(0x28e0, mulmod(mload(0x2860), mload(0x1e80), f_q)) +mstore(0x2900, addmod(mload(0xa60), sub(f_q, mload(0xa80)), f_q)) +mstore(0x2920, mulmod(mload(0x2900), mload(0x28e0), f_q)) +mstore(0x2940, addmod(mload(0x28c0), mload(0x2920), f_q)) +mstore(0x2960, mulmod(mload(0xf60), mload(0xf60), f_q)) +mstore(0x2980, mulmod(mload(0x2960), mload(0xf60), f_q)) +mstore(0x29a0, mulmod(1, mload(0xf60), f_q)) +mstore(0x29c0, mulmod(1, mload(0x2960), f_q)) +mstore(0x29e0, mulmod(mload(0x2940), mload(0xf80), f_q)) +mstore(0x2a00, mulmod(mload(0xce0), mload(0x680), f_q)) +mstore(0x2a20, mulmod(mload(0x2a00), mload(0x680), f_q)) +mstore(0x2a40, mulmod(mload(0x680), 20975929243409798062839949658616274858986091382510192949221301676705706354487, f_q)) +mstore(0x2a60, addmod(mload(0xbe0), sub(f_q, mload(0x2a40)), f_q)) +mstore(0x2a80, mulmod(mload(0x680), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) +mstore(0x2aa0, addmod(mload(0xbe0), sub(f_q, mload(0x2a80)), f_q)) +mstore(0x2ac0, mulmod(mload(0x680), 1, f_q)) +mstore(0x2ae0, addmod(mload(0xbe0), sub(f_q, mload(0x2ac0)), f_q)) +mstore(0x2b00, mulmod(mload(0x680), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x2b20, addmod(mload(0xbe0), sub(f_q, mload(0x2b00)), f_q)) +mstore(0x2b40, mulmod(mload(0x680), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) +mstore(0x2b60, addmod(mload(0xbe0), sub(f_q, mload(0x2b40)), f_q)) +mstore(0x2b80, mulmod(mload(0x680), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) +mstore(0x2ba0, addmod(mload(0xbe0), sub(f_q, mload(0x2b80)), f_q)) +mstore(0x2bc0, mulmod(12142985201493934370659158242092015678465417407805993602870272259656026591649, mload(0x2a00), f_q)) +mstore(0x2be0, mulmod(mload(0x2bc0), 1, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x2bc0), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2be0)), f_q), result, f_q) +mstore(11264, result) + } +mstore(0x2c20, mulmod(12858672892267984631233883117647866851148059157064290846881981435700301865966, mload(0x2a00), f_q)) +mstore(0x2c40, mulmod(mload(0x2c20), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x2c20), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2c40)), f_q), result, f_q) +mstore(11360, result) + } +mstore(0x2c80, mulmod(20880316823902385764034220950270964645276820671488089374347912013802613180902, mload(0x2a00), f_q)) +mstore(0x2ca0, mulmod(mload(0x2c80), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x2c80), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2ca0)), f_q), result, f_q) +mstore(11456, result) + } +mstore(0x2ce0, mulmod(17575202995145968412995467587554373308969396527144859871466654432792864477050, mload(0x2a00), f_q)) +mstore(0x2d00, mulmod(mload(0x2ce0), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x2ce0), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2d00)), f_q), result, f_q) +mstore(11552, result) + } +mstore(0x2d40, mulmod(1, mload(0x2ae0), f_q)) +mstore(0x2d60, mulmod(mload(0x2d40), mload(0x2b20), f_q)) +mstore(0x2d80, mulmod(mload(0x2d60), mload(0x2b60), f_q)) +mstore(0x2da0, mulmod(mload(0x2d80), mload(0x2ba0), f_q)) +{ + let result := mulmod(mload(0xbe0), 1, f_q) +result := addmod(mulmod(mload(0x680), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q) +mstore(11712, result) + } +mstore(0x2de0, mulmod(21869340487638379139105209872801492456082780734504032269410146788560475001942, mload(0xce0), f_q)) +mstore(0x2e00, mulmod(mload(0x2de0), 1, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x2de0), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2e00)), f_q), result, f_q) +mstore(11808, result) + } +mstore(0x2e40, mulmod(16199055355995875908874098831560099797649990976433931925532505422809603664814, mload(0xce0), f_q)) +mstore(0x2e60, mulmod(mload(0x2e40), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x2e40), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2e60)), f_q), result, f_q) +mstore(11904, result) + } +mstore(0x2ea0, mulmod(4865187280763976036134135047793386535665014353502380106898040096680231678680, mload(0xce0), f_q)) +mstore(0x2ec0, mulmod(mload(0x2ea0), 20975929243409798062839949658616274858986091382510192949221301676705706354487, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x2ea0), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2ec0)), f_q), result, f_q) +mstore(12000, result) + } +mstore(0x2f00, mulmod(mload(0x2d60), mload(0x2a60), f_q)) +mstore(0x2f20, mulmod(20461838439117790833741043996939313553025008529160428886800406442142042007111, mload(0x680), f_q)) +mstore(0x2f40, mulmod(mload(0x2f20), 1, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x2f20), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2f40)), f_q), result, f_q) +mstore(12128, result) + } +mstore(0x2f80, mulmod(1426404432721484388505361748317961535523355871255605456897797744433766488506, mload(0x680), f_q)) +mstore(0x2fa0, mulmod(mload(0x2f80), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x2f80), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2fa0)), f_q), result, f_q) +mstore(12224, result) + } +mstore(0x2fe0, mulmod(19102728315457599142069468034376470979900453007937332237837518576196438670602, mload(0x680), f_q)) +mstore(0x3000, mulmod(mload(0x2fe0), 1, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x2fe0), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x3000)), f_q), result, f_q) +mstore(12320, result) + } +mstore(0x3040, mulmod(2785514556381676080176937710880804108647911392478702105860685610379369825015, mload(0x680), f_q)) +mstore(0x3060, mulmod(mload(0x3040), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) +{ + let result := mulmod(mload(0xbe0), mload(0x3040), f_q) +result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x3060)), f_q), result, f_q) +mstore(12416, result) + } +mstore(0x30a0, mulmod(mload(0x2d40), mload(0x2aa0), f_q)) +{ + let prod := mload(0x2c00) + + prod := mulmod(mload(0x2c60), prod, f_q) + mstore(0x30c0, prod) + + prod := mulmod(mload(0x2cc0), prod, f_q) + mstore(0x30e0, prod) + + prod := mulmod(mload(0x2d20), prod, f_q) + mstore(0x3100, prod) + + prod := mulmod(mload(0x2dc0), prod, f_q) + mstore(0x3120, prod) + + prod := mulmod(mload(0x2d40), prod, f_q) + mstore(0x3140, prod) + + prod := mulmod(mload(0x2e20), prod, f_q) + mstore(0x3160, prod) + + prod := mulmod(mload(0x2e80), prod, f_q) + mstore(0x3180, prod) + + prod := mulmod(mload(0x2ee0), prod, f_q) + mstore(0x31a0, prod) + + prod := mulmod(mload(0x2f00), prod, f_q) + mstore(0x31c0, prod) + + prod := mulmod(mload(0x2f60), prod, f_q) + mstore(0x31e0, prod) + + prod := mulmod(mload(0x2fc0), prod, f_q) + mstore(0x3200, prod) + + prod := mulmod(mload(0x2d60), prod, f_q) + mstore(0x3220, prod) + + prod := mulmod(mload(0x3020), prod, f_q) + mstore(0x3240, prod) + + prod := mulmod(mload(0x3080), prod, f_q) + mstore(0x3260, prod) + + prod := mulmod(mload(0x30a0), prod, f_q) + mstore(0x3280, prod) + + } +mstore(0x32c0, 32) +mstore(0x32e0, 32) +mstore(0x3300, 32) +mstore(0x3320, mload(0x3280)) +mstore(0x3340, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x3360, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x32c0, 0xc0, 0x32a0, 0x20), 1), success) +{ + + let inv := mload(0x32a0) + let v + + v := mload(0x30a0) + mstore(12448, mulmod(mload(0x3260), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3080) + mstore(12416, mulmod(mload(0x3240), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3020) + mstore(12320, mulmod(mload(0x3220), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2d60) + mstore(11616, mulmod(mload(0x3200), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2fc0) + mstore(12224, mulmod(mload(0x31e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2f60) + mstore(12128, mulmod(mload(0x31c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2f00) + mstore(12032, mulmod(mload(0x31a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2ee0) + mstore(12000, mulmod(mload(0x3180), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2e80) + mstore(11904, mulmod(mload(0x3160), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2e20) + mstore(11808, mulmod(mload(0x3140), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2d40) + mstore(11584, mulmod(mload(0x3120), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2dc0) + mstore(11712, mulmod(mload(0x3100), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2d20) + mstore(11552, mulmod(mload(0x30e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2cc0) + mstore(11456, mulmod(mload(0x30c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x2c60) + mstore(11360, mulmod(mload(0x2c00), inv, f_q)) + inv := mulmod(v, inv, f_q) + mstore(0x2c00, inv) + + } +{ + let result := mload(0x2c00) +result := addmod(mload(0x2c60), result, f_q) +result := addmod(mload(0x2cc0), result, f_q) +result := addmod(mload(0x2d20), result, f_q) +mstore(13184, result) + } +mstore(0x33a0, mulmod(mload(0x2da0), mload(0x2d40), f_q)) +{ + let result := mload(0x2dc0) +mstore(13248, result) + } +mstore(0x33e0, mulmod(mload(0x2da0), mload(0x2f00), f_q)) +{ + let result := mload(0x2e20) +result := addmod(mload(0x2e80), result, f_q) +result := addmod(mload(0x2ee0), result, f_q) +mstore(13312, result) + } +mstore(0x3420, mulmod(mload(0x2da0), mload(0x2d60), f_q)) +{ + let result := mload(0x2f60) +result := addmod(mload(0x2fc0), result, f_q) +mstore(13376, result) + } +mstore(0x3460, mulmod(mload(0x2da0), mload(0x30a0), f_q)) +{ + let result := mload(0x3020) +result := addmod(mload(0x3080), result, f_q) +mstore(13440, result) + } +{ + let prod := mload(0x3380) + + prod := mulmod(mload(0x33c0), prod, f_q) + mstore(0x34a0, prod) + + prod := mulmod(mload(0x3400), prod, f_q) + mstore(0x34c0, prod) + + prod := mulmod(mload(0x3440), prod, f_q) + mstore(0x34e0, prod) + + prod := mulmod(mload(0x3480), prod, f_q) + mstore(0x3500, prod) + + } +mstore(0x3540, 32) +mstore(0x3560, 32) +mstore(0x3580, 32) +mstore(0x35a0, mload(0x3500)) +mstore(0x35c0, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x35e0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x3540, 0xc0, 0x3520, 0x20), 1), success) +{ + + let inv := mload(0x3520) + let v + + v := mload(0x3480) + mstore(13440, mulmod(mload(0x34e0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3440) + mstore(13376, mulmod(mload(0x34c0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x3400) + mstore(13312, mulmod(mload(0x34a0), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x33c0) + mstore(13248, mulmod(mload(0x3380), inv, f_q)) + inv := mulmod(v, inv, f_q) + mstore(0x3380, inv) + + } +mstore(0x3600, mulmod(mload(0x33a0), mload(0x33c0), f_q)) +mstore(0x3620, mulmod(mload(0x33e0), mload(0x3400), f_q)) +mstore(0x3640, mulmod(mload(0x3420), mload(0x3440), f_q)) +mstore(0x3660, mulmod(mload(0x3460), mload(0x3480), f_q)) +mstore(0x3680, mulmod(mload(0xae0), mload(0xae0), f_q)) +mstore(0x36a0, mulmod(mload(0x3680), mload(0xae0), f_q)) +mstore(0x36c0, mulmod(mload(0x36a0), mload(0xae0), f_q)) +mstore(0x36e0, mulmod(mload(0x36c0), mload(0xae0), f_q)) +mstore(0x3700, mulmod(mload(0x36e0), mload(0xae0), f_q)) +mstore(0x3720, mulmod(mload(0x3700), mload(0xae0), f_q)) +mstore(0x3740, mulmod(mload(0x3720), mload(0xae0), f_q)) +mstore(0x3760, mulmod(mload(0x3740), mload(0xae0), f_q)) +mstore(0x3780, mulmod(mload(0x3760), mload(0xae0), f_q)) +mstore(0x37a0, mulmod(mload(0x3780), mload(0xae0), f_q)) +mstore(0x37c0, mulmod(mload(0x37a0), mload(0xae0), f_q)) +mstore(0x37e0, mulmod(mload(0x37c0), mload(0xae0), f_q)) +mstore(0x3800, mulmod(mload(0xb40), mload(0xb40), f_q)) +mstore(0x3820, mulmod(mload(0x3800), mload(0xb40), f_q)) +mstore(0x3840, mulmod(mload(0x3820), mload(0xb40), f_q)) +mstore(0x3860, mulmod(mload(0x3840), mload(0xb40), f_q)) +{ + let result := mulmod(mload(0x6c0), mload(0x2c00), f_q) +result := addmod(mulmod(mload(0x6e0), mload(0x2c60), f_q), result, f_q) +result := addmod(mulmod(mload(0x700), mload(0x2cc0), f_q), result, f_q) +result := addmod(mulmod(mload(0x720), mload(0x2d20), f_q), result, f_q) +mstore(14464, result) + } +mstore(0x38a0, mulmod(mload(0x3880), mload(0x3380), f_q)) +mstore(0x38c0, mulmod(sub(f_q, mload(0x38a0)), 1, f_q)) +{ + let result := mulmod(mload(0x740), mload(0x2c00), f_q) +result := addmod(mulmod(mload(0x760), mload(0x2c60), f_q), result, f_q) +result := addmod(mulmod(mload(0x780), mload(0x2cc0), f_q), result, f_q) +result := addmod(mulmod(mload(0x7a0), mload(0x2d20), f_q), result, f_q) +mstore(14560, result) + } +mstore(0x3900, mulmod(mload(0x38e0), mload(0x3380), f_q)) +mstore(0x3920, mulmod(sub(f_q, mload(0x3900)), mload(0xae0), f_q)) +mstore(0x3940, mulmod(1, mload(0xae0), f_q)) +mstore(0x3960, addmod(mload(0x38c0), mload(0x3920), f_q)) +mstore(0x3980, mulmod(mload(0x3960), 1, f_q)) +mstore(0x39a0, mulmod(mload(0x3940), 1, f_q)) +mstore(0x39c0, mulmod(1, mload(0x33a0), f_q)) +{ + let result := mulmod(mload(0x7c0), mload(0x2dc0), f_q) +mstore(14816, result) + } +mstore(0x3a00, mulmod(mload(0x39e0), mload(0x3600), f_q)) +mstore(0x3a20, mulmod(sub(f_q, mload(0x3a00)), 1, f_q)) +mstore(0x3a40, mulmod(mload(0x39c0), 1, f_q)) +{ + let result := mulmod(mload(0xaa0), mload(0x2dc0), f_q) +mstore(14944, result) + } +mstore(0x3a80, mulmod(mload(0x3a60), mload(0x3600), f_q)) +mstore(0x3aa0, mulmod(sub(f_q, mload(0x3a80)), mload(0xae0), f_q)) +mstore(0x3ac0, mulmod(mload(0x39c0), mload(0xae0), f_q)) +mstore(0x3ae0, addmod(mload(0x3a20), mload(0x3aa0), f_q)) +{ + let result := mulmod(mload(0x7e0), mload(0x2dc0), f_q) +mstore(15104, result) + } +mstore(0x3b20, mulmod(mload(0x3b00), mload(0x3600), f_q)) +mstore(0x3b40, mulmod(sub(f_q, mload(0x3b20)), mload(0x3680), f_q)) +mstore(0x3b60, mulmod(mload(0x39c0), mload(0x3680), f_q)) +mstore(0x3b80, addmod(mload(0x3ae0), mload(0x3b40), f_q)) +{ + let result := mulmod(mload(0x800), mload(0x2dc0), f_q) +mstore(15264, result) + } +mstore(0x3bc0, mulmod(mload(0x3ba0), mload(0x3600), f_q)) +mstore(0x3be0, mulmod(sub(f_q, mload(0x3bc0)), mload(0x36a0), f_q)) +mstore(0x3c00, mulmod(mload(0x39c0), mload(0x36a0), f_q)) +mstore(0x3c20, addmod(mload(0x3b80), mload(0x3be0), f_q)) +{ + let result := mulmod(mload(0x820), mload(0x2dc0), f_q) +mstore(15424, result) + } +mstore(0x3c60, mulmod(mload(0x3c40), mload(0x3600), f_q)) +mstore(0x3c80, mulmod(sub(f_q, mload(0x3c60)), mload(0x36c0), f_q)) +mstore(0x3ca0, mulmod(mload(0x39c0), mload(0x36c0), f_q)) +mstore(0x3cc0, addmod(mload(0x3c20), mload(0x3c80), f_q)) +{ + let result := mulmod(mload(0x840), mload(0x2dc0), f_q) +mstore(15584, result) + } +mstore(0x3d00, mulmod(mload(0x3ce0), mload(0x3600), f_q)) +mstore(0x3d20, mulmod(sub(f_q, mload(0x3d00)), mload(0x36e0), f_q)) +mstore(0x3d40, mulmod(mload(0x39c0), mload(0x36e0), f_q)) +mstore(0x3d60, addmod(mload(0x3cc0), mload(0x3d20), f_q)) +{ + let result := mulmod(mload(0x880), mload(0x2dc0), f_q) +mstore(15744, result) + } +mstore(0x3da0, mulmod(mload(0x3d80), mload(0x3600), f_q)) +mstore(0x3dc0, mulmod(sub(f_q, mload(0x3da0)), mload(0x3700), f_q)) +mstore(0x3de0, mulmod(mload(0x39c0), mload(0x3700), f_q)) +mstore(0x3e00, addmod(mload(0x3d60), mload(0x3dc0), f_q)) +{ + let result := mulmod(mload(0x8a0), mload(0x2dc0), f_q) +mstore(15904, result) + } +mstore(0x3e40, mulmod(mload(0x3e20), mload(0x3600), f_q)) +mstore(0x3e60, mulmod(sub(f_q, mload(0x3e40)), mload(0x3720), f_q)) +mstore(0x3e80, mulmod(mload(0x39c0), mload(0x3720), f_q)) +mstore(0x3ea0, addmod(mload(0x3e00), mload(0x3e60), f_q)) +{ + let result := mulmod(mload(0x8c0), mload(0x2dc0), f_q) +mstore(16064, result) + } +mstore(0x3ee0, mulmod(mload(0x3ec0), mload(0x3600), f_q)) +mstore(0x3f00, mulmod(sub(f_q, mload(0x3ee0)), mload(0x3740), f_q)) +mstore(0x3f20, mulmod(mload(0x39c0), mload(0x3740), f_q)) +mstore(0x3f40, addmod(mload(0x3ea0), mload(0x3f00), f_q)) +{ + let result := mulmod(mload(0x8e0), mload(0x2dc0), f_q) +mstore(16224, result) + } +mstore(0x3f80, mulmod(mload(0x3f60), mload(0x3600), f_q)) +mstore(0x3fa0, mulmod(sub(f_q, mload(0x3f80)), mload(0x3760), f_q)) +mstore(0x3fc0, mulmod(mload(0x39c0), mload(0x3760), f_q)) +mstore(0x3fe0, addmod(mload(0x3f40), mload(0x3fa0), f_q)) +{ + let result := mulmod(mload(0x900), mload(0x2dc0), f_q) +mstore(16384, result) + } +mstore(0x4020, mulmod(mload(0x4000), mload(0x3600), f_q)) +mstore(0x4040, mulmod(sub(f_q, mload(0x4020)), mload(0x3780), f_q)) +mstore(0x4060, mulmod(mload(0x39c0), mload(0x3780), f_q)) +mstore(0x4080, addmod(mload(0x3fe0), mload(0x4040), f_q)) +mstore(0x40a0, mulmod(mload(0x29a0), mload(0x33a0), f_q)) +mstore(0x40c0, mulmod(mload(0x29c0), mload(0x33a0), f_q)) +{ + let result := mulmod(mload(0x29e0), mload(0x2dc0), f_q) +mstore(16608, result) + } +mstore(0x4100, mulmod(mload(0x40e0), mload(0x3600), f_q)) +mstore(0x4120, mulmod(sub(f_q, mload(0x4100)), mload(0x37a0), f_q)) +mstore(0x4140, mulmod(mload(0x39c0), mload(0x37a0), f_q)) +mstore(0x4160, mulmod(mload(0x40a0), mload(0x37a0), f_q)) +mstore(0x4180, mulmod(mload(0x40c0), mload(0x37a0), f_q)) +mstore(0x41a0, addmod(mload(0x4080), mload(0x4120), f_q)) +{ + let result := mulmod(mload(0x860), mload(0x2dc0), f_q) +mstore(16832, result) + } +mstore(0x41e0, mulmod(mload(0x41c0), mload(0x3600), f_q)) +mstore(0x4200, mulmod(sub(f_q, mload(0x41e0)), mload(0x37c0), f_q)) +mstore(0x4220, mulmod(mload(0x39c0), mload(0x37c0), f_q)) +mstore(0x4240, addmod(mload(0x41a0), mload(0x4200), f_q)) +mstore(0x4260, mulmod(mload(0x4240), mload(0xb40), f_q)) +mstore(0x4280, mulmod(mload(0x3a40), mload(0xb40), f_q)) +mstore(0x42a0, mulmod(mload(0x3ac0), mload(0xb40), f_q)) +mstore(0x42c0, mulmod(mload(0x3b60), mload(0xb40), f_q)) +mstore(0x42e0, mulmod(mload(0x3c00), mload(0xb40), f_q)) +mstore(0x4300, mulmod(mload(0x3ca0), mload(0xb40), f_q)) +mstore(0x4320, mulmod(mload(0x3d40), mload(0xb40), f_q)) +mstore(0x4340, mulmod(mload(0x3de0), mload(0xb40), f_q)) +mstore(0x4360, mulmod(mload(0x3e80), mload(0xb40), f_q)) +mstore(0x4380, mulmod(mload(0x3f20), mload(0xb40), f_q)) +mstore(0x43a0, mulmod(mload(0x3fc0), mload(0xb40), f_q)) +mstore(0x43c0, mulmod(mload(0x4060), mload(0xb40), f_q)) +mstore(0x43e0, mulmod(mload(0x4140), mload(0xb40), f_q)) +mstore(0x4400, mulmod(mload(0x4160), mload(0xb40), f_q)) +mstore(0x4420, mulmod(mload(0x4180), mload(0xb40), f_q)) +mstore(0x4440, mulmod(mload(0x4220), mload(0xb40), f_q)) +mstore(0x4460, addmod(mload(0x3980), mload(0x4260), f_q)) +mstore(0x4480, mulmod(1, mload(0x33e0), f_q)) +{ + let result := mulmod(mload(0x920), mload(0x2e20), f_q) +result := addmod(mulmod(mload(0x940), mload(0x2e80), f_q), result, f_q) +result := addmod(mulmod(mload(0x960), mload(0x2ee0), f_q), result, f_q) +mstore(17568, result) + } +mstore(0x44c0, mulmod(mload(0x44a0), mload(0x3620), f_q)) +mstore(0x44e0, mulmod(sub(f_q, mload(0x44c0)), 1, f_q)) +mstore(0x4500, mulmod(mload(0x4480), 1, f_q)) +{ + let result := mulmod(mload(0x980), mload(0x2e20), f_q) +result := addmod(mulmod(mload(0x9a0), mload(0x2e80), f_q), result, f_q) +result := addmod(mulmod(mload(0x9c0), mload(0x2ee0), f_q), result, f_q) +mstore(17696, result) + } +mstore(0x4540, mulmod(mload(0x4520), mload(0x3620), f_q)) +mstore(0x4560, mulmod(sub(f_q, mload(0x4540)), mload(0xae0), f_q)) +mstore(0x4580, mulmod(mload(0x4480), mload(0xae0), f_q)) +mstore(0x45a0, addmod(mload(0x44e0), mload(0x4560), f_q)) +mstore(0x45c0, mulmod(mload(0x45a0), mload(0x3800), f_q)) +mstore(0x45e0, mulmod(mload(0x4500), mload(0x3800), f_q)) +mstore(0x4600, mulmod(mload(0x4580), mload(0x3800), f_q)) +mstore(0x4620, addmod(mload(0x4460), mload(0x45c0), f_q)) +mstore(0x4640, mulmod(1, mload(0x3420), f_q)) +{ + let result := mulmod(mload(0x9e0), mload(0x2f60), f_q) +result := addmod(mulmod(mload(0xa00), mload(0x2fc0), f_q), result, f_q) +mstore(18016, result) + } +mstore(0x4680, mulmod(mload(0x4660), mload(0x3640), f_q)) +mstore(0x46a0, mulmod(sub(f_q, mload(0x4680)), 1, f_q)) +mstore(0x46c0, mulmod(mload(0x4640), 1, f_q)) +{ + let result := mulmod(mload(0xa20), mload(0x2f60), f_q) +result := addmod(mulmod(mload(0xa40), mload(0x2fc0), f_q), result, f_q) +mstore(18144, result) + } +mstore(0x4700, mulmod(mload(0x46e0), mload(0x3640), f_q)) +mstore(0x4720, mulmod(sub(f_q, mload(0x4700)), mload(0xae0), f_q)) +mstore(0x4740, mulmod(mload(0x4640), mload(0xae0), f_q)) +mstore(0x4760, addmod(mload(0x46a0), mload(0x4720), f_q)) +mstore(0x4780, mulmod(mload(0x4760), mload(0x3820), f_q)) +mstore(0x47a0, mulmod(mload(0x46c0), mload(0x3820), f_q)) +mstore(0x47c0, mulmod(mload(0x4740), mload(0x3820), f_q)) +mstore(0x47e0, addmod(mload(0x4620), mload(0x4780), f_q)) +mstore(0x4800, mulmod(1, mload(0x3460), f_q)) +{ + let result := mulmod(mload(0xa60), mload(0x3020), f_q) +result := addmod(mulmod(mload(0xa80), mload(0x3080), f_q), result, f_q) +mstore(18464, result) + } +mstore(0x4840, mulmod(mload(0x4820), mload(0x3660), f_q)) +mstore(0x4860, mulmod(sub(f_q, mload(0x4840)), 1, f_q)) +mstore(0x4880, mulmod(mload(0x4800), 1, f_q)) +mstore(0x48a0, mulmod(mload(0x4860), mload(0x3840), f_q)) +mstore(0x48c0, mulmod(mload(0x4880), mload(0x3840), f_q)) +mstore(0x48e0, addmod(mload(0x47e0), mload(0x48a0), f_q)) +mstore(0x4900, mulmod(1, mload(0x2da0), f_q)) +mstore(0x4920, mulmod(1, mload(0xbe0), f_q)) +mstore(0x4940, 0x0000000000000000000000000000000000000000000000000000000000000001) + mstore(0x4960, 0x0000000000000000000000000000000000000000000000000000000000000002) +mstore(0x4980, mload(0x48e0)) +success := and(eq(staticcall(gas(), 0x7, 0x4940, 0x60, 0x4940, 0x40), 1), success) +mstore(0x49a0, mload(0x4940)) + mstore(0x49c0, mload(0x4960)) +mstore(0x49e0, mload(0x1a0)) + mstore(0x4a00, mload(0x1c0)) +success := and(eq(staticcall(gas(), 0x6, 0x49a0, 0x80, 0x49a0, 0x40), 1), success) +mstore(0x4a20, mload(0x1e0)) + mstore(0x4a40, mload(0x200)) +mstore(0x4a60, mload(0x39a0)) +success := and(eq(staticcall(gas(), 0x7, 0x4a20, 0x60, 0x4a20, 0x40), 1), success) +mstore(0x4a80, mload(0x49a0)) + mstore(0x4aa0, mload(0x49c0)) +mstore(0x4ac0, mload(0x4a20)) + mstore(0x4ae0, mload(0x4a40)) +success := and(eq(staticcall(gas(), 0x6, 0x4a80, 0x80, 0x4a80, 0x40), 1), success) +mstore(0x4b00, mload(0x220)) + mstore(0x4b20, mload(0x240)) +mstore(0x4b40, mload(0x4280)) +success := and(eq(staticcall(gas(), 0x7, 0x4b00, 0x60, 0x4b00, 0x40), 1), success) +mstore(0x4b60, mload(0x4a80)) + mstore(0x4b80, mload(0x4aa0)) +mstore(0x4ba0, mload(0x4b00)) + mstore(0x4bc0, mload(0x4b20)) +success := and(eq(staticcall(gas(), 0x6, 0x4b60, 0x80, 0x4b60, 0x40), 1), success) +mstore(0x4be0, mload(0x300)) + mstore(0x4c00, mload(0x320)) +mstore(0x4c20, mload(0x42a0)) +success := and(eq(staticcall(gas(), 0x7, 0x4be0, 0x60, 0x4be0, 0x40), 1), success) +mstore(0x4c40, mload(0x4b60)) + mstore(0x4c60, mload(0x4b80)) +mstore(0x4c80, mload(0x4be0)) + mstore(0x4ca0, mload(0x4c00)) +success := and(eq(staticcall(gas(), 0x6, 0x4c40, 0x80, 0x4c40, 0x40), 1), success) +mstore(0x4cc0, 0x0a56bb24bdbd10b2ae380a0f6d2926afe21e55ef423d664a7093bdc47d7a970d) + mstore(0x4ce0, 0x3046067f3fbc66fb8322b30a454654489ad23370423a63caeab071e10143c65d) +mstore(0x4d00, mload(0x42c0)) +success := and(eq(staticcall(gas(), 0x7, 0x4cc0, 0x60, 0x4cc0, 0x40), 1), success) +mstore(0x4d20, mload(0x4c40)) + mstore(0x4d40, mload(0x4c60)) +mstore(0x4d60, mload(0x4cc0)) + mstore(0x4d80, mload(0x4ce0)) +success := and(eq(staticcall(gas(), 0x6, 0x4d20, 0x80, 0x4d20, 0x40), 1), success) +mstore(0x4da0, 0x165f42d12623508ec09f1a14ffe3841e636362840bcfe45fd4f0847a50968d91) + mstore(0x4dc0, 0x19664a50abfa10f51e0eb96bf39b959cd2ebd0ed52c60bc0d4e8535272a13ed9) +mstore(0x4de0, mload(0x42e0)) +success := and(eq(staticcall(gas(), 0x7, 0x4da0, 0x60, 0x4da0, 0x40), 1), success) +mstore(0x4e00, mload(0x4d20)) + mstore(0x4e20, mload(0x4d40)) +mstore(0x4e40, mload(0x4da0)) + mstore(0x4e60, mload(0x4dc0)) +success := and(eq(staticcall(gas(), 0x6, 0x4e00, 0x80, 0x4e00, 0x40), 1), success) +mstore(0x4e80, 0x0c7dc4e4516515f0050b10e6891a60f39ab7645bbf2134080574b9ae26a3fee2) + mstore(0x4ea0, 0x2ee3484a156715514bcc56f95e316bb23031b7460f679ebb427a7f8ad73aead2) +mstore(0x4ec0, mload(0x4300)) +success := and(eq(staticcall(gas(), 0x7, 0x4e80, 0x60, 0x4e80, 0x40), 1), success) +mstore(0x4ee0, mload(0x4e00)) + mstore(0x4f00, mload(0x4e20)) +mstore(0x4f20, mload(0x4e80)) + mstore(0x4f40, mload(0x4ea0)) +success := and(eq(staticcall(gas(), 0x6, 0x4ee0, 0x80, 0x4ee0, 0x40), 1), success) +mstore(0x4f60, 0x2fb1bc5dc1a8a163ac673f110c7ced2581955a8d47770fced15a66d8199a5c91) + mstore(0x4f80, 0x18f7802cf51055b658637bf93f53fcc4dbe4218c03cb54c9d3e74534e1b9cb8f) +mstore(0x4fa0, mload(0x4320)) +success := and(eq(staticcall(gas(), 0x7, 0x4f60, 0x60, 0x4f60, 0x40), 1), success) +mstore(0x4fc0, mload(0x4ee0)) + mstore(0x4fe0, mload(0x4f00)) +mstore(0x5000, mload(0x4f60)) + mstore(0x5020, mload(0x4f80)) +success := and(eq(staticcall(gas(), 0x6, 0x4fc0, 0x80, 0x4fc0, 0x40), 1), success) +mstore(0x5040, 0x2051ae2329a00ab4684564c9db909204379c6404686b9bb004253a0e87937c1a) + mstore(0x5060, 0x2228d27991956786c7b7ed829027a4268a8f57d342e507683aaaea7046a1721b) +mstore(0x5080, mload(0x4340)) +success := and(eq(staticcall(gas(), 0x7, 0x5040, 0x60, 0x5040, 0x40), 1), success) +mstore(0x50a0, mload(0x4fc0)) + mstore(0x50c0, mload(0x4fe0)) +mstore(0x50e0, mload(0x5040)) + mstore(0x5100, mload(0x5060)) +success := and(eq(staticcall(gas(), 0x6, 0x50a0, 0x80, 0x50a0, 0x40), 1), success) +mstore(0x5120, 0x144e8b5cd066532d7a019f3061d407aeb922b3a37125d39cee71a336088a8d57) + mstore(0x5140, 0x0465b8271620ef2988dbb05e0e32f58c14ee4aaec69263d36175afc35b129dc8) +mstore(0x5160, mload(0x4360)) +success := and(eq(staticcall(gas(), 0x7, 0x5120, 0x60, 0x5120, 0x40), 1), success) +mstore(0x5180, mload(0x50a0)) + mstore(0x51a0, mload(0x50c0)) +mstore(0x51c0, mload(0x5120)) + mstore(0x51e0, mload(0x5140)) +success := and(eq(staticcall(gas(), 0x6, 0x5180, 0x80, 0x5180, 0x40), 1), success) +mstore(0x5200, 0x2c5cb6e96533664432584b4373fc01286cb8aa2c8a7f05eac98fc5bc689e65bf) + mstore(0x5220, 0x2c6a00e02442db4548c0583842d7c460dfaba5a8ae3d86ca57b0d7c82d7090c8) +mstore(0x5240, mload(0x4380)) +success := and(eq(staticcall(gas(), 0x7, 0x5200, 0x60, 0x5200, 0x40), 1), success) +mstore(0x5260, mload(0x5180)) + mstore(0x5280, mload(0x51a0)) +mstore(0x52a0, mload(0x5200)) + mstore(0x52c0, mload(0x5220)) +success := and(eq(staticcall(gas(), 0x6, 0x5260, 0x80, 0x5260, 0x40), 1), success) +mstore(0x52e0, 0x2b737ba20cacc46db1394cb36a1cb92566946b943314b7037d038fbb83f233a8) + mstore(0x5300, 0x04dc42ddd6eb4c1c43a1175bc70c5b5c92577f968055708b4beeb22cea5cff99) +mstore(0x5320, mload(0x43a0)) +success := and(eq(staticcall(gas(), 0x7, 0x52e0, 0x60, 0x52e0, 0x40), 1), success) +mstore(0x5340, mload(0x5260)) + mstore(0x5360, mload(0x5280)) +mstore(0x5380, mload(0x52e0)) + mstore(0x53a0, mload(0x5300)) +success := and(eq(staticcall(gas(), 0x6, 0x5340, 0x80, 0x5340, 0x40), 1), success) +mstore(0x53c0, 0x0ff2ba345398269313967c25483b19e5e2de27f76a3a4357408c35dc42ddfec3) + mstore(0x53e0, 0x063d5c171abc02e7d09324a4f1bb6493d0584767678901f452ebc7f285037015) +mstore(0x5400, mload(0x43c0)) +success := and(eq(staticcall(gas(), 0x7, 0x53c0, 0x60, 0x53c0, 0x40), 1), success) +mstore(0x5420, mload(0x5340)) + mstore(0x5440, mload(0x5360)) +mstore(0x5460, mload(0x53c0)) + mstore(0x5480, mload(0x53e0)) +success := and(eq(staticcall(gas(), 0x6, 0x5420, 0x80, 0x5420, 0x40), 1), success) +mstore(0x54a0, mload(0x5a0)) + mstore(0x54c0, mload(0x5c0)) +mstore(0x54e0, mload(0x43e0)) +success := and(eq(staticcall(gas(), 0x7, 0x54a0, 0x60, 0x54a0, 0x40), 1), success) +mstore(0x5500, mload(0x5420)) + mstore(0x5520, mload(0x5440)) +mstore(0x5540, mload(0x54a0)) + mstore(0x5560, mload(0x54c0)) +success := and(eq(staticcall(gas(), 0x6, 0x5500, 0x80, 0x5500, 0x40), 1), success) +mstore(0x5580, mload(0x5e0)) + mstore(0x55a0, mload(0x600)) +mstore(0x55c0, mload(0x4400)) +success := and(eq(staticcall(gas(), 0x7, 0x5580, 0x60, 0x5580, 0x40), 1), success) +mstore(0x55e0, mload(0x5500)) + mstore(0x5600, mload(0x5520)) +mstore(0x5620, mload(0x5580)) + mstore(0x5640, mload(0x55a0)) +success := and(eq(staticcall(gas(), 0x6, 0x55e0, 0x80, 0x55e0, 0x40), 1), success) +mstore(0x5660, mload(0x620)) + mstore(0x5680, mload(0x640)) +mstore(0x56a0, mload(0x4420)) +success := and(eq(staticcall(gas(), 0x7, 0x5660, 0x60, 0x5660, 0x40), 1), success) +mstore(0x56c0, mload(0x55e0)) + mstore(0x56e0, mload(0x5600)) +mstore(0x5700, mload(0x5660)) + mstore(0x5720, mload(0x5680)) +success := and(eq(staticcall(gas(), 0x6, 0x56c0, 0x80, 0x56c0, 0x40), 1), success) +mstore(0x5740, mload(0x500)) + mstore(0x5760, mload(0x520)) +mstore(0x5780, mload(0x4440)) +success := and(eq(staticcall(gas(), 0x7, 0x5740, 0x60, 0x5740, 0x40), 1), success) +mstore(0x57a0, mload(0x56c0)) + mstore(0x57c0, mload(0x56e0)) +mstore(0x57e0, mload(0x5740)) + mstore(0x5800, mload(0x5760)) +success := and(eq(staticcall(gas(), 0x6, 0x57a0, 0x80, 0x57a0, 0x40), 1), success) +mstore(0x5820, mload(0x400)) + mstore(0x5840, mload(0x420)) +mstore(0x5860, mload(0x45e0)) +success := and(eq(staticcall(gas(), 0x7, 0x5820, 0x60, 0x5820, 0x40), 1), success) +mstore(0x5880, mload(0x57a0)) + mstore(0x58a0, mload(0x57c0)) +mstore(0x58c0, mload(0x5820)) + mstore(0x58e0, mload(0x5840)) +success := and(eq(staticcall(gas(), 0x6, 0x5880, 0x80, 0x5880, 0x40), 1), success) +mstore(0x5900, mload(0x440)) + mstore(0x5920, mload(0x460)) +mstore(0x5940, mload(0x4600)) +success := and(eq(staticcall(gas(), 0x7, 0x5900, 0x60, 0x5900, 0x40), 1), success) +mstore(0x5960, mload(0x5880)) + mstore(0x5980, mload(0x58a0)) +mstore(0x59a0, mload(0x5900)) + mstore(0x59c0, mload(0x5920)) +success := and(eq(staticcall(gas(), 0x6, 0x5960, 0x80, 0x5960, 0x40), 1), success) +mstore(0x59e0, mload(0x480)) + mstore(0x5a00, mload(0x4a0)) +mstore(0x5a20, mload(0x47a0)) +success := and(eq(staticcall(gas(), 0x7, 0x59e0, 0x60, 0x59e0, 0x40), 1), success) +mstore(0x5a40, mload(0x5960)) + mstore(0x5a60, mload(0x5980)) +mstore(0x5a80, mload(0x59e0)) + mstore(0x5aa0, mload(0x5a00)) +success := and(eq(staticcall(gas(), 0x6, 0x5a40, 0x80, 0x5a40, 0x40), 1), success) +mstore(0x5ac0, mload(0x4c0)) + mstore(0x5ae0, mload(0x4e0)) +mstore(0x5b00, mload(0x47c0)) +success := and(eq(staticcall(gas(), 0x7, 0x5ac0, 0x60, 0x5ac0, 0x40), 1), success) +mstore(0x5b20, mload(0x5a40)) + mstore(0x5b40, mload(0x5a60)) +mstore(0x5b60, mload(0x5ac0)) + mstore(0x5b80, mload(0x5ae0)) +success := and(eq(staticcall(gas(), 0x6, 0x5b20, 0x80, 0x5b20, 0x40), 1), success) +mstore(0x5ba0, mload(0x2c0)) + mstore(0x5bc0, mload(0x2e0)) +mstore(0x5be0, mload(0x48c0)) +success := and(eq(staticcall(gas(), 0x7, 0x5ba0, 0x60, 0x5ba0, 0x40), 1), success) +mstore(0x5c00, mload(0x5b20)) + mstore(0x5c20, mload(0x5b40)) +mstore(0x5c40, mload(0x5ba0)) + mstore(0x5c60, mload(0x5bc0)) +success := and(eq(staticcall(gas(), 0x6, 0x5c00, 0x80, 0x5c00, 0x40), 1), success) +mstore(0x5c80, mload(0xb80)) + mstore(0x5ca0, mload(0xba0)) +mstore(0x5cc0, sub(f_q, mload(0x4900))) +success := and(eq(staticcall(gas(), 0x7, 0x5c80, 0x60, 0x5c80, 0x40), 1), success) +mstore(0x5ce0, mload(0x5c00)) + mstore(0x5d00, mload(0x5c20)) +mstore(0x5d20, mload(0x5c80)) + mstore(0x5d40, mload(0x5ca0)) +success := and(eq(staticcall(gas(), 0x6, 0x5ce0, 0x80, 0x5ce0, 0x40), 1), success) +mstore(0x5d60, mload(0xc20)) + mstore(0x5d80, mload(0xc40)) +mstore(0x5da0, mload(0x4920)) +success := and(eq(staticcall(gas(), 0x7, 0x5d60, 0x60, 0x5d60, 0x40), 1), success) +mstore(0x5dc0, mload(0x5ce0)) + mstore(0x5de0, mload(0x5d00)) +mstore(0x5e00, mload(0x5d60)) + mstore(0x5e20, mload(0x5d80)) +success := and(eq(staticcall(gas(), 0x6, 0x5dc0, 0x80, 0x5dc0, 0x40), 1), success) +mstore(0x5e40, mload(0x5dc0)) + mstore(0x5e60, mload(0x5de0)) +mstore(0x5e80, mload(0xc20)) + mstore(0x5ea0, mload(0xc40)) +mstore(0x5ec0, mload(0xc60)) + mstore(0x5ee0, mload(0xc80)) +mstore(0x5f00, mload(0xca0)) + mstore(0x5f20, mload(0xcc0)) +mstore(0x5f40, keccak256(0x5e40, 256)) +mstore(24416, mod(mload(24384), f_q)) +mstore(0x5f80, mulmod(mload(0x5f60), mload(0x5f60), f_q)) +mstore(0x5fa0, mulmod(1, mload(0x5f60), f_q)) +mstore(0x5fc0, mload(0x5ec0)) + mstore(0x5fe0, mload(0x5ee0)) +mstore(0x6000, mload(0x5fa0)) +success := and(eq(staticcall(gas(), 0x7, 0x5fc0, 0x60, 0x5fc0, 0x40), 1), success) +mstore(0x6020, mload(0x5e40)) + mstore(0x6040, mload(0x5e60)) +mstore(0x6060, mload(0x5fc0)) + mstore(0x6080, mload(0x5fe0)) +success := and(eq(staticcall(gas(), 0x6, 0x6020, 0x80, 0x6020, 0x40), 1), success) +mstore(0x60a0, mload(0x5f00)) + mstore(0x60c0, mload(0x5f20)) +mstore(0x60e0, mload(0x5fa0)) +success := and(eq(staticcall(gas(), 0x7, 0x60a0, 0x60, 0x60a0, 0x40), 1), success) +mstore(0x6100, mload(0x5e80)) + mstore(0x6120, mload(0x5ea0)) +mstore(0x6140, mload(0x60a0)) + mstore(0x6160, mload(0x60c0)) +success := and(eq(staticcall(gas(), 0x6, 0x6100, 0x80, 0x6100, 0x40), 1), success) +mstore(0x6180, mload(0x6020)) + mstore(0x61a0, mload(0x6040)) +mstore(0x61c0, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) + mstore(0x61e0, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) + mstore(0x6200, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) + mstore(0x6220, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) +mstore(0x6240, mload(0x6100)) + mstore(0x6260, mload(0x6120)) +mstore(0x6280, 0x138d5863615c12d3bd7d3fd007776d281a337f9d7f6dce23532100bb4bb5839d) + mstore(0x62a0, 0x0a3bb881671ee4e9238366e87f6598f0de356372ed3dc870766ec8ac005211e4) + mstore(0x62c0, 0x19c9d7d9c6e7ad2d9a0d5847ebdd2687c668939a202553ded2760d3eb8dbf559) + mstore(0x62e0, 0x198adb441818c42721c88c532ed13a5da1ebb78b85574d0b7326d8e6f4c1e25a) +success := and(eq(staticcall(gas(), 0x8, 0x6180, 0x180, 0x6180, 0x20), 1), success) +success := and(eq(mload(0x6180), 1), success) + + // Revert if anything fails + if iszero(success) { revert(0, 0) } + + // Return empty bytes on success + return(0, 0) + + } + } +} + \ No newline at end of file diff --git a/snark-verifier-sdk/examples/standard_plonk.rs b/snark-verifier-sdk/examples/standard_plonk.rs new file mode 100644 index 00000000..7ad9c971 --- /dev/null +++ b/snark-verifier-sdk/examples/standard_plonk.rs @@ -0,0 +1,216 @@ +use std::path::Path; + +use halo2_base::gates::circuit::CircuitBuilderStage; +use halo2_base::halo2_proofs; +use halo2_base::utils::fs::gen_srs; +use halo2_proofs::halo2curves as halo2_curves; +use halo2_proofs::{halo2curves::bn256::Bn256, poly::kzg::commitment::ParamsKZG}; +use rand::rngs::OsRng; +use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; +use snark_verifier_sdk::halo2::aggregation::{AggregationConfigParams, VerifierUniversality}; +use snark_verifier_sdk::{ + gen_pk, + halo2::{aggregation::AggregationCircuit, gen_snark_shplonk}, + Snark, +}; +use snark_verifier_sdk::{CircuitExt, SHPLONK}; + +mod application { + use super::halo2_curves::bn256::Fr; + use super::halo2_proofs::{ + circuit::{Layouter, SimpleFloorPlanner, Value}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Instance}, + poly::Rotation, + }; + use rand::RngCore; + use snark_verifier_sdk::CircuitExt; + + #[derive(Clone, Copy)] + pub struct StandardPlonkConfig { + a: Column, + b: Column, + c: Column, + q_a: Column, + q_b: Column, + q_c: Column, + q_ab: Column, + constant: Column, + #[allow(dead_code)] + instance: Column, + } + + impl StandardPlonkConfig { + fn configure(meta: &mut ConstraintSystem) -> Self { + let [a, b, c] = [(); 3].map(|_| meta.advice_column()); + let [q_a, q_b, q_c, q_ab, constant] = [(); 5].map(|_| meta.fixed_column()); + let instance = meta.instance_column(); + + [a, b, c].map(|column| meta.enable_equality(column)); + + meta.create_gate( + "q_a·a + q_b·b + q_c·c + q_ab·a·b + constant + instance = 0", + |meta| { + let [a, b, c] = + [a, b, c].map(|column| meta.query_advice(column, Rotation::cur())); + let [q_a, q_b, q_c, q_ab, constant] = [q_a, q_b, q_c, q_ab, constant] + .map(|column| meta.query_fixed(column, Rotation::cur())); + let instance = meta.query_instance(instance, Rotation::cur()); + Some( + q_a * a.clone() + + q_b * b.clone() + + q_c * c + + q_ab * a * b + + constant + + instance, + ) + }, + ); + + StandardPlonkConfig { a, b, c, q_a, q_b, q_c, q_ab, constant, instance } + } + } + + #[derive(Clone, Default)] + pub struct StandardPlonk(Fr); + + impl StandardPlonk { + pub fn rand(mut rng: R) -> Self { + Self(Fr::from(rng.next_u32() as u64)) + } + } + + impl CircuitExt for StandardPlonk { + fn num_instance(&self) -> Vec { + vec![1] + } + + fn instances(&self) -> Vec> { + vec![vec![self.0]] + } + } + + impl Circuit for StandardPlonk { + type Config = StandardPlonkConfig; + type FloorPlanner = SimpleFloorPlanner; + + fn without_witnesses(&self) -> Self { + Self::default() + } + + fn configure(meta: &mut ConstraintSystem) -> Self::Config { + meta.set_minimum_degree(4); + StandardPlonkConfig::configure(meta) + } + + fn synthesize( + &self, + config: Self::Config, + mut layouter: impl Layouter, + ) -> Result<(), Error> { + layouter.assign_region( + || "", + |mut region| { + #[cfg(feature = "halo2-pse")] + { + region.assign_advice(|| "", config.a, 0, || Value::known(self.0))?; + region.assign_fixed(|| "", config.q_a, 0, || Value::known(-Fr::one()))?; + region.assign_advice( + || "", + config.a, + 1, + || Value::known(-Fr::from(5u64)), + )?; + for (idx, column) in (1..).zip([ + config.q_a, + config.q_b, + config.q_c, + config.q_ab, + config.constant, + ]) { + region.assign_fixed( + || "", + column, + 1, + || Value::known(Fr::from(idx as u64)), + )?; + } + let a = + region.assign_advice(|| "", config.a, 2, || Value::known(Fr::one()))?; + a.copy_advice(|| "", &mut region, config.b, 3)?; + a.copy_advice(|| "", &mut region, config.c, 4)?; + } + #[cfg(feature = "halo2-axiom")] + { + region.assign_advice(config.a, 0, Value::known(self.0)); + region.assign_fixed(config.q_a, 0, -Fr::one()); + region.assign_advice(config.a, 1, Value::known(-Fr::from(5u64))); + for (idx, column) in (1..).zip([ + config.q_a, + config.q_b, + config.q_c, + config.q_ab, + config.constant, + ]) { + region.assign_fixed(column, 1, Fr::from(idx as u64)); + } + + let a = region.assign_advice(config.a, 2, Value::known(Fr::one())); + a.copy_advice(&mut region, config.b, 3); + a.copy_advice(&mut region, config.c, 4); + } + + Ok(()) + }, + ) + } + } +} + +fn gen_application_snark(params: &ParamsKZG) -> Snark { + let circuit = application::StandardPlonk::rand(OsRng); + + let pk = gen_pk(params, &circuit, None); + gen_snark_shplonk(params, &pk, circuit, None::<&str>) +} + +fn main() { + let params_app = gen_srs(8); + + let k = 21u32; + let lookup_bits = k as usize - 1; + let params = gen_srs(k); + let snarks = [(); 1].map(|_| gen_application_snark(¶ms_app)); + + let mut agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Keygen, + AggregationConfigParams { degree: k, lookup_bits, ..Default::default() }, + ¶ms, + snarks.clone(), + VerifierUniversality::Full, + ); + let agg_config = agg_circuit.calculate_params(Some(10)); + + let pk = gen_pk(¶ms, &agg_circuit, None); + let break_points = agg_circuit.break_points(); + drop(agg_circuit); + + let agg_circuit = AggregationCircuit::new::( + CircuitBuilderStage::Prover, + agg_config, + ¶ms, + snarks.clone(), + VerifierUniversality::Full, + ) + .use_break_points(break_points); + let num_instances = agg_circuit.num_instance(); + let instances = agg_circuit.instances(); + let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); + + let deployment_code = gen_evm_verifier_shplonk::( + ¶ms, + pk.get_vk(), + num_instances, + Some(Path::new("examples/StandardPlonkVerifier.sol")), + ); + evm_verify(deployment_code, instances, proof); +} diff --git a/snark-verifier-sdk/src/evm.rs b/snark-verifier-sdk/src/evm.rs index 97b1b96e..d3b745fb 100644 --- a/snark-verifier-sdk/src/evm.rs +++ b/snark-verifier-sdk/src/evm.rs @@ -22,7 +22,7 @@ use itertools::Itertools; use rand::{rngs::StdRng, SeedableRng}; pub use snark_verifier::loader::evm::encode_calldata; use snark_verifier::{ - loader::evm::{compile_yul, deploy_and_call, EvmLoader}, + loader::evm::{compile_solidity, deploy_and_call, EvmLoader}, pcs::{ kzg::{KzgAccumulator, KzgAsVerifyingKey, KzgDecidingKey, KzgSuccinctVerifyingKey}, AccumulationDecider, AccumulationScheme, PolynomialCommitmentScheme, @@ -147,11 +147,11 @@ where PlonkVerifier::::read_proof(&dk, &protocol, &instances, &mut transcript).unwrap(); PlonkVerifier::::verify(&dk, &protocol, &instances, &proof).unwrap(); - let yul_code = loader.yul_code(); - let byte_code = compile_yul(&yul_code); + let sol_code = loader.solidity_code(); + let byte_code = compile_solidity(&sol_code); if let Some(path) = path { path.parent().and_then(|dir| fs::create_dir_all(dir).ok()).unwrap(); - fs::write(path, yul_code).unwrap(); + fs::write(path, sol_code).unwrap(); } byte_code } diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 2fbe6682..2321caa0 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier" -version = "0.1.5" +version = "0.1.6" edition = "2021" [dependencies] diff --git a/snark-verifier/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs index 645c71fd..304b7395 100644 --- a/snark-verifier/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -501,7 +501,7 @@ fn gen_aggregation_evm_verifier( let proof = PlonkVerifier::read_proof(&vk, &protocol, &instances, &mut transcript).unwrap(); PlonkVerifier::verify(&vk, &protocol, &instances, &proof).unwrap(); - evm::compile_yul(&loader.yul_code()) + evm::compile_solidity(&loader.solidity_code()) } fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { diff --git a/snark-verifier/examples/evm-verifier.rs b/snark-verifier/examples/evm-verifier.rs index c7f206b1..d541528a 100644 --- a/snark-verifier/examples/evm-verifier.rs +++ b/snark-verifier/examples/evm-verifier.rs @@ -237,7 +237,7 @@ fn gen_evm_verifier( let proof = PlonkVerifier::read_proof(&vk, &protocol, &instances, &mut transcript).unwrap(); PlonkVerifier::verify(&vk, &protocol, &instances, &proof).unwrap(); - evm::compile_yul(&loader.yul_code()) + evm::compile_solidity(&loader.solidity_code()) } fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { diff --git a/snark-verifier/src/loader/evm.rs b/snark-verifier/src/loader/evm.rs index 74ed0f4e..19b145bb 100644 --- a/snark-verifier/src/loader/evm.rs +++ b/snark-verifier/src/loader/evm.rs @@ -6,6 +6,6 @@ pub(crate) mod util; pub use loader::{EcPoint, EvmLoader, Scalar}; pub use util::{ - compile_yul, deploy_and_call, encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, - Address, B256, U256, U512, + compile_solidity, deploy_and_call, encode_calldata, estimate_gas, fe_to_u256, modulus, + u256_to_fe, Address, B256, U256, U512, }; diff --git a/snark-verifier/src/loader/evm/code.rs b/snark-verifier/src/loader/evm/code.rs index 236684d6..2634ba2d 100644 --- a/snark-verifier/src/loader/evm/code.rs +++ b/snark-verifier/src/loader/evm/code.rs @@ -6,55 +6,49 @@ pub enum Precompiled { } #[derive(Clone, Debug)] -pub struct YulCode { +pub struct SolidityAssemblyCode { // runtime code area runtime: String, } -impl YulCode { +impl SolidityAssemblyCode { pub fn new() -> Self { - YulCode { runtime: String::new() } + Self { runtime: String::new() } } pub fn code(&self, base_modulus: String, scalar_modulus: String) -> String { format!( " - object \"plonk_verifier\" {{ - code {{ - function allocate(size) -> ptr {{ - ptr := mload(0x40) - if eq(ptr, 0) {{ ptr := 0x60 }} - mstore(0x40, add(ptr, size)) +// SPDX-License-Identifier: MIT + +pragma solidity 0.8.19; + +contract Halo2Verifier {{ + fallback(bytes calldata) external returns (bytes memory) {{ + assembly {{ + let success := true + let f_p := {base_modulus} + let f_q := {scalar_modulus} + function validate_ec_point(x, y) -> valid {{ + {{ + let x_lt_p := lt(x, {base_modulus}) + let y_lt_p := lt(y, {base_modulus}) + valid := and(x_lt_p, y_lt_p) }} - let size := datasize(\"Runtime\") - let offset := allocate(size) - datacopy(offset, dataoffset(\"Runtime\"), size) - return(offset, size) - }} - object \"Runtime\" {{ - code {{ - let success:bool := true - let f_p := {base_modulus} - let f_q := {scalar_modulus} - function validate_ec_point(x, y) -> valid:bool {{ - {{ - let x_lt_p:bool := lt(x, {base_modulus}) - let y_lt_p:bool := lt(y, {base_modulus}) - valid := and(x_lt_p, y_lt_p) - }} - {{ - let y_square := mulmod(y, y, {base_modulus}) - let x_square := mulmod(x, x, {base_modulus}) - let x_cube := mulmod(x_square, x, {base_modulus}) - let x_cube_plus_3 := addmod(x_cube, 3, {base_modulus}) - let is_affine:bool := eq(x_cube_plus_3, y_square) - valid := and(valid, is_affine) - }} - }} - {} + {{ + let y_square := mulmod(y, y, {base_modulus}) + let x_square := mulmod(x, x, {base_modulus}) + let x_cube := mulmod(x_square, x, {base_modulus}) + let x_cube_plus_3 := addmod(x_cube, 3, {base_modulus}) + let is_affine := eq(x_cube_plus_3, y_square) + valid := and(valid, is_affine) }} }} - }}", + {} + }} + }} +}} + ", self.runtime ) } diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index 127cc7e4..3bf49baf 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -1,7 +1,7 @@ use crate::{ loader::{ evm::{ - code::{Precompiled, YulCode}, + code::{Precompiled, SolidityAssemblyCode}, fe_to_u256, modulus, u256_to_fe, U256, U512, }, EcPointLoader, LoadedEcPoint, LoadedScalar, Loader, ScalarLoader, @@ -52,7 +52,7 @@ impl Value { pub struct EvmLoader { base_modulus: U256, scalar_modulus: U256, - code: RefCell, + code: RefCell, ptr: RefCell, cache: RefCell>, } @@ -70,7 +70,7 @@ impl EvmLoader { { let base_modulus = modulus::(); let scalar_modulus = modulus::(); - let code = YulCode::new(); + let code = SolidityAssemblyCode::new(); Rc::new(Self { base_modulus, @@ -81,10 +81,14 @@ impl EvmLoader { }) } - /// Returns generated yul code. - pub fn yul_code(self: &Rc) -> String { + /// Returns generated Solidity code. This is "Solidity" code that is wrapped in an assembly block. + /// In other words, it's basically just assembly (equivalently, Yul). + pub fn solidity_code(self: &Rc) -> String { let code = " - if not(success) { revert(0, 0) } + // Revert if anything fails + if iszero(success) { revert(0, 0) } + + // Return empty bytes on success return(0, 0)" .to_string(); self.code.borrow_mut().runtime_append(code); @@ -104,7 +108,7 @@ impl EvmLoader { *self.ptr.borrow() } - pub(crate) fn code_mut(&self) -> impl DerefMut + '_ { + pub(crate) fn code_mut(&self) -> impl DerefMut + '_ { self.code.borrow_mut() } diff --git a/snark-verifier/src/loader/evm/util.rs b/snark-verifier/src/loader/evm/util.rs index 747849d4..031e85b9 100644 --- a/snark-verifier/src/loader/evm/util.rs +++ b/snark-verifier/src/loader/evm/util.rs @@ -101,13 +101,12 @@ pub fn estimate_gas(cost: Cost) -> usize { intrinsic_cost + calldata_cost + ec_operation_cost } -/// Compile given yul `code` into deployment bytecode. -pub fn compile_yul(code: &str) -> Vec { +/// Compile given Solidity `code` into deployment bytecode. +pub fn compile_solidity(code: &str) -> Vec { let mut cmd = Command::new("solc") .stdin(Stdio::piped()) .stdout(Stdio::piped()) .arg("--bin") - .arg("--yul") .arg("-") .spawn() .unwrap(); From d8400e60ae5762b9d3234f2fda68a556c463fa1a Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 11 Sep 2023 00:57:04 -0700 Subject: [PATCH 55/73] chore: change halo2-lib branch --- snark-verifier-sdk/Cargo.toml | 2 +- snark-verifier/Cargo.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index db1f7071..899c2cbb 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -17,7 +17,7 @@ serde_json = "1.0" serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc0", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } getset = "0.1.2" diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 2321caa0..a9072edd 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -15,7 +15,7 @@ serde = { version = "1.0", features = ["derive"] } pairing = { version = "0.23" } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc0", default-features = false } # parallel rayon = { version = "1.7", optional = true } @@ -25,7 +25,7 @@ sha3 = { version = "0.10", optional = true } revm = { version = "3.3.0", optional = true } # loader_halo2 -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "develop", default-features = false, optional = true } +halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc0", default-features = false, optional = true } [dev-dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } From bba2bb75e50bccb8f0158133ab79a9f512d044e7 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Sun, 22 Oct 2023 10:18:52 -0700 Subject: [PATCH 56/73] chore: `snark-verifier` re-exports `halo2-base`, `halo2-ecc` (#38) and `snark-verifier-sdk` re-exports `snark-verifier`. This is to minimize cargo dependency / version issues until we publish to crates.io. --- snark-verifier-sdk/src/lib.rs | 2 ++ snark-verifier/src/lib.rs | 4 ++++ 2 files changed, 6 insertions(+) diff --git a/snark-verifier-sdk/src/lib.rs b/snark-verifier-sdk/src/lib.rs index 40401a4c..932b20ab 100644 --- a/snark-verifier-sdk/src/lib.rs +++ b/snark-verifier-sdk/src/lib.rs @@ -25,6 +25,8 @@ use std::{ path::Path, }; +pub use snark_verifier; + #[cfg(feature = "loader_evm")] pub mod evm; #[cfg(feature = "loader_halo2")] diff --git a/snark-verifier/src/lib.rs b/snark-verifier/src/lib.rs index e9866167..8dab89c9 100644 --- a/snark-verifier/src/lib.rs +++ b/snark-verifier/src/lib.rs @@ -13,6 +13,10 @@ pub mod verifier; pub(crate) use halo2_base::halo2_proofs; pub(crate) use halo2_proofs::halo2curves as halo2_curves; +pub use halo2_base; +#[cfg(feature = "loader_halo2")] +pub use halo2_ecc; + /// Error that could happen while verification. #[derive(Clone, Debug)] pub enum Error { From 39ab9d362dd01cdcd6ff1e96187e46b877bd5a22 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 23 Oct 2023 13:12:00 -0700 Subject: [PATCH 57/73] [feat] make assembly block Solidity memory safe (#39) * feat: make assembly block Solidity memory safe * chore: add back example solidity code --- .../examples/StandardPlonkVerifier.sol | 2050 +++++++++-------- snark-verifier/src/loader/evm/code.rs | 8 +- snark-verifier/src/loader/evm/loader.rs | 5 +- .../src/system/halo2/transcript/evm.rs | 5 +- 4 files changed, 1042 insertions(+), 1026 deletions(-) diff --git a/snark-verifier-sdk/examples/StandardPlonkVerifier.sol b/snark-verifier-sdk/examples/StandardPlonkVerifier.sol index d6e9427c..2ac09483 100644 --- a/snark-verifier-sdk/examples/StandardPlonkVerifier.sol +++ b/snark-verifier-sdk/examples/StandardPlonkVerifier.sol @@ -5,7 +5,13 @@ pragma solidity 0.8.19; contract Halo2Verifier { fallback(bytes calldata) external returns (bytes memory) { - assembly { + assembly ("memory-safe") { + // Enforce that Solidity memory layout is respected + let data := mload(0x40) + if iszero(eq(data, 0x80)) { + revert(0, 0) + } + let success := true let f_p := 0x30644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd47 let f_q := 0x30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000001 @@ -24,250 +30,246 @@ contract Halo2Verifier { valid := and(valid, is_affine) } } - mstore(0x20, mod(calldataload(0x0), f_q)) -mstore(0x40, mod(calldataload(0x20), f_q)) -mstore(0x60, mod(calldataload(0x40), f_q)) -mstore(0x80, mod(calldataload(0x60), f_q)) -mstore(0xa0, mod(calldataload(0x80), f_q)) -mstore(0xc0, mod(calldataload(0xa0), f_q)) -mstore(0xe0, mod(calldataload(0xc0), f_q)) -mstore(0x100, mod(calldataload(0xe0), f_q)) -mstore(0x120, mod(calldataload(0x100), f_q)) -mstore(0x140, mod(calldataload(0x120), f_q)) -mstore(0x160, mod(calldataload(0x140), f_q)) -mstore(0x180, mod(calldataload(0x160), f_q)) -mstore(0x0, 17740244582459666476042487670110999380715355991411842331101569887719361442506) + mstore(0xa0, mod(calldataload(0x0), f_q)) +mstore(0xc0, mod(calldataload(0x20), f_q)) +mstore(0xe0, mod(calldataload(0x40), f_q)) +mstore(0x100, mod(calldataload(0x60), f_q)) +mstore(0x120, mod(calldataload(0x80), f_q)) +mstore(0x140, mod(calldataload(0xa0), f_q)) +mstore(0x160, mod(calldataload(0xc0), f_q)) +mstore(0x180, mod(calldataload(0xe0), f_q)) +mstore(0x1a0, mod(calldataload(0x100), f_q)) +mstore(0x1c0, mod(calldataload(0x120), f_q)) +mstore(0x1e0, mod(calldataload(0x140), f_q)) +mstore(0x200, mod(calldataload(0x160), f_q)) +mstore(0x80, 4821513469282282135963313459762076388609226322911319502565905456075264100373) { let x := calldataload(0x180) - mstore(0x1a0, x) + mstore(0x220, x) let y := calldataload(0x1a0) - mstore(0x1c0, y) + mstore(0x240, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x1c0) - mstore(0x1e0, x) + mstore(0x260, x) let y := calldataload(0x1e0) - mstore(0x200, y) + mstore(0x280, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x200) - mstore(0x220, x) + mstore(0x2a0, x) let y := calldataload(0x220) - mstore(0x240, y) + mstore(0x2c0, y) success := and(validate_ec_point(x, y), success) } -mstore(0x260, keccak256(0x0, 608)) +mstore(0x2e0, keccak256(0x80, 608)) { - let hash := mload(0x260) - mstore(0x280, mod(hash, f_q)) - mstore(0x2a0, hash) + let hash := mload(0x2e0) + mstore(0x300, mod(hash, f_q)) + mstore(0x320, hash) } { let x := calldataload(0x240) - mstore(0x2c0, x) + mstore(0x340, x) let y := calldataload(0x260) - mstore(0x2e0, y) + mstore(0x360, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x280) - mstore(0x300, x) + mstore(0x380, x) let y := calldataload(0x2a0) - mstore(0x320, y) + mstore(0x3a0, y) success := and(validate_ec_point(x, y), success) } -mstore(0x340, keccak256(0x2a0, 160)) +mstore(0x3c0, keccak256(0x320, 160)) { - let hash := mload(0x340) - mstore(0x360, mod(hash, f_q)) - mstore(0x380, hash) + let hash := mload(0x3c0) + mstore(0x3e0, mod(hash, f_q)) + mstore(0x400, hash) } -mstore8(928, 1) -mstore(0x3a0, keccak256(0x380, 33)) +mstore8(1056, 1) +mstore(0x420, keccak256(0x400, 33)) { - let hash := mload(0x3a0) - mstore(0x3c0, mod(hash, f_q)) - mstore(0x3e0, hash) + let hash := mload(0x420) + mstore(0x440, mod(hash, f_q)) + mstore(0x460, hash) } { let x := calldataload(0x2c0) - mstore(0x400, x) + mstore(0x480, x) let y := calldataload(0x2e0) - mstore(0x420, y) + mstore(0x4a0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x300) - mstore(0x440, x) + mstore(0x4c0, x) let y := calldataload(0x320) - mstore(0x460, y) + mstore(0x4e0, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x340) - mstore(0x480, x) + mstore(0x500, x) let y := calldataload(0x360) - mstore(0x4a0, y) + mstore(0x520, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x380) - mstore(0x4c0, x) + mstore(0x540, x) let y := calldataload(0x3a0) - mstore(0x4e0, y) + mstore(0x560, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x3c0) - mstore(0x500, x) + mstore(0x580, x) let y := calldataload(0x3e0) - mstore(0x520, y) + mstore(0x5a0, y) success := and(validate_ec_point(x, y), success) } -mstore(0x540, keccak256(0x3e0, 352)) +mstore(0x5c0, keccak256(0x460, 352)) { - let hash := mload(0x540) - mstore(0x560, mod(hash, f_q)) - mstore(0x580, hash) + let hash := mload(0x5c0) + mstore(0x5e0, mod(hash, f_q)) + mstore(0x600, hash) } { let x := calldataload(0x400) - mstore(0x5a0, x) + mstore(0x620, x) let y := calldataload(0x420) - mstore(0x5c0, y) + mstore(0x640, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x440) - mstore(0x5e0, x) + mstore(0x660, x) let y := calldataload(0x460) - mstore(0x600, y) + mstore(0x680, y) success := and(validate_ec_point(x, y), success) } { let x := calldataload(0x480) - mstore(0x620, x) + mstore(0x6a0, x) let y := calldataload(0x4a0) - mstore(0x640, y) + mstore(0x6c0, y) success := and(validate_ec_point(x, y), success) } -mstore(0x660, keccak256(0x580, 224)) +mstore(0x6e0, keccak256(0x600, 224)) { - let hash := mload(0x660) - mstore(0x680, mod(hash, f_q)) - mstore(0x6a0, hash) - } -mstore(0x6c0, mod(calldataload(0x4c0), f_q)) -mstore(0x6e0, mod(calldataload(0x4e0), f_q)) -mstore(0x700, mod(calldataload(0x500), f_q)) -mstore(0x720, mod(calldataload(0x520), f_q)) -mstore(0x740, mod(calldataload(0x540), f_q)) -mstore(0x760, mod(calldataload(0x560), f_q)) -mstore(0x780, mod(calldataload(0x580), f_q)) -mstore(0x7a0, mod(calldataload(0x5a0), f_q)) -mstore(0x7c0, mod(calldataload(0x5c0), f_q)) -mstore(0x7e0, mod(calldataload(0x5e0), f_q)) -mstore(0x800, mod(calldataload(0x600), f_q)) -mstore(0x820, mod(calldataload(0x620), f_q)) -mstore(0x840, mod(calldataload(0x640), f_q)) -mstore(0x860, mod(calldataload(0x660), f_q)) -mstore(0x880, mod(calldataload(0x680), f_q)) -mstore(0x8a0, mod(calldataload(0x6a0), f_q)) -mstore(0x8c0, mod(calldataload(0x6c0), f_q)) -mstore(0x8e0, mod(calldataload(0x6e0), f_q)) -mstore(0x900, mod(calldataload(0x700), f_q)) -mstore(0x920, mod(calldataload(0x720), f_q)) -mstore(0x940, mod(calldataload(0x740), f_q)) -mstore(0x960, mod(calldataload(0x760), f_q)) -mstore(0x980, mod(calldataload(0x780), f_q)) -mstore(0x9a0, mod(calldataload(0x7a0), f_q)) -mstore(0x9c0, mod(calldataload(0x7c0), f_q)) -mstore(0x9e0, mod(calldataload(0x7e0), f_q)) -mstore(0xa00, mod(calldataload(0x800), f_q)) -mstore(0xa20, mod(calldataload(0x820), f_q)) -mstore(0xa40, mod(calldataload(0x840), f_q)) -mstore(0xa60, mod(calldataload(0x860), f_q)) -mstore(0xa80, mod(calldataload(0x880), f_q)) -mstore(0xaa0, mod(calldataload(0x8a0), f_q)) -mstore(0xac0, keccak256(0x6a0, 1056)) + let hash := mload(0x6e0) + mstore(0x700, mod(hash, f_q)) + mstore(0x720, hash) + } +mstore(0x740, mod(calldataload(0x4c0), f_q)) +mstore(0x760, mod(calldataload(0x4e0), f_q)) +mstore(0x780, mod(calldataload(0x500), f_q)) +mstore(0x7a0, mod(calldataload(0x520), f_q)) +mstore(0x7c0, mod(calldataload(0x540), f_q)) +mstore(0x7e0, mod(calldataload(0x560), f_q)) +mstore(0x800, mod(calldataload(0x580), f_q)) +mstore(0x820, mod(calldataload(0x5a0), f_q)) +mstore(0x840, mod(calldataload(0x5c0), f_q)) +mstore(0x860, mod(calldataload(0x5e0), f_q)) +mstore(0x880, mod(calldataload(0x600), f_q)) +mstore(0x8a0, mod(calldataload(0x620), f_q)) +mstore(0x8c0, mod(calldataload(0x640), f_q)) +mstore(0x8e0, mod(calldataload(0x660), f_q)) +mstore(0x900, mod(calldataload(0x680), f_q)) +mstore(0x920, mod(calldataload(0x6a0), f_q)) +mstore(0x940, mod(calldataload(0x6c0), f_q)) +mstore(0x960, mod(calldataload(0x6e0), f_q)) +mstore(0x980, mod(calldataload(0x700), f_q)) +mstore(0x9a0, mod(calldataload(0x720), f_q)) +mstore(0x9c0, mod(calldataload(0x740), f_q)) +mstore(0x9e0, mod(calldataload(0x760), f_q)) +mstore(0xa00, mod(calldataload(0x780), f_q)) +mstore(0xa20, mod(calldataload(0x7a0), f_q)) +mstore(0xa40, mod(calldataload(0x7c0), f_q)) +mstore(0xa60, mod(calldataload(0x7e0), f_q)) +mstore(0xa80, mod(calldataload(0x800), f_q)) +mstore(0xaa0, mod(calldataload(0x820), f_q)) +mstore(0xac0, mod(calldataload(0x840), f_q)) +mstore(0xae0, mod(calldataload(0x860), f_q)) +mstore(0xb00, mod(calldataload(0x880), f_q)) +mstore(0xb20, mod(calldataload(0x8a0), f_q)) +mstore(0xb40, keccak256(0x720, 1056)) { - let hash := mload(0xac0) - mstore(0xae0, mod(hash, f_q)) - mstore(0xb00, hash) + let hash := mload(0xb40) + mstore(0xb60, mod(hash, f_q)) + mstore(0xb80, hash) } -mstore8(2848, 1) -mstore(0xb20, keccak256(0xb00, 33)) +mstore8(2976, 1) +mstore(0xba0, keccak256(0xb80, 33)) { - let hash := mload(0xb20) - mstore(0xb40, mod(hash, f_q)) - mstore(0xb60, hash) + let hash := mload(0xba0) + mstore(0xbc0, mod(hash, f_q)) + mstore(0xbe0, hash) } { let x := calldataload(0x8c0) - mstore(0xb80, x) + mstore(0xc00, x) let y := calldataload(0x8e0) - mstore(0xba0, y) + mstore(0xc20, y) success := and(validate_ec_point(x, y), success) } -mstore(0xbc0, keccak256(0xb60, 96)) +mstore(0xc40, keccak256(0xbe0, 96)) { - let hash := mload(0xbc0) - mstore(0xbe0, mod(hash, f_q)) - mstore(0xc00, hash) + let hash := mload(0xc40) + mstore(0xc60, mod(hash, f_q)) + mstore(0xc80, hash) } { let x := calldataload(0x900) - mstore(0xc20, x) + mstore(0xca0, x) let y := calldataload(0x920) - mstore(0xc40, y) + mstore(0xcc0, y) success := and(validate_ec_point(x, y), success) } { - let x := mload(0x20) -x := add(x, shl(88, mload(0x40))) -x := add(x, shl(176, mload(0x60))) -mstore(3168, x) -let y := mload(0x80) -y := add(y, shl(88, mload(0xa0))) -y := add(y, shl(176, mload(0xc0))) -mstore(3200, y) + let x := mload(0xa0) +x := add(x, shl(88, mload(0xc0))) +x := add(x, shl(176, mload(0xe0))) +mstore(3296, x) +let y := mload(0x100) +y := add(y, shl(88, mload(0x120))) +y := add(y, shl(176, mload(0x140))) +mstore(3328, y) success := and(validate_ec_point(x, y), success) } { - let x := mload(0xe0) -x := add(x, shl(88, mload(0x100))) -x := add(x, shl(176, mload(0x120))) -mstore(3232, x) -let y := mload(0x140) -y := add(y, shl(88, mload(0x160))) -y := add(y, shl(176, mload(0x180))) -mstore(3264, y) + let x := mload(0x160) +x := add(x, shl(88, mload(0x180))) +x := add(x, shl(176, mload(0x1a0))) +mstore(3360, x) +let y := mload(0x1c0) +y := add(y, shl(88, mload(0x1e0))) +y := add(y, shl(176, mload(0x200))) +mstore(3392, y) success := and(validate_ec_point(x, y), success) } -mstore(0xce0, mulmod(mload(0x680), mload(0x680), f_q)) -mstore(0xd00, mulmod(mload(0xce0), mload(0xce0), f_q)) -mstore(0xd20, mulmod(mload(0xd00), mload(0xd00), f_q)) -mstore(0xd40, mulmod(mload(0xd20), mload(0xd20), f_q)) -mstore(0xd60, mulmod(mload(0xd40), mload(0xd40), f_q)) +mstore(0xd60, mulmod(mload(0x700), mload(0x700), f_q)) mstore(0xd80, mulmod(mload(0xd60), mload(0xd60), f_q)) mstore(0xda0, mulmod(mload(0xd80), mload(0xd80), f_q)) mstore(0xdc0, mulmod(mload(0xda0), mload(0xda0), f_q)) @@ -284,222 +286,222 @@ mstore(0xf00, mulmod(mload(0xee0), mload(0xee0), f_q)) mstore(0xf20, mulmod(mload(0xf00), mload(0xf00), f_q)) mstore(0xf40, mulmod(mload(0xf20), mload(0xf20), f_q)) mstore(0xf60, mulmod(mload(0xf40), mload(0xf40), f_q)) -mstore(0xf80, addmod(mload(0xf60), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) -mstore(0xfa0, mulmod(mload(0xf80), 21888232434711746154598842647110004286396165347431605739555851272621938401409, f_q)) -mstore(0xfc0, mulmod(mload(0xfa0), 20975929243409798062839949658616274858986091382510192949221301676705706354487, f_q)) -mstore(0xfe0, addmod(mload(0x680), 912313628429477159406456086641000229562273017905841394476902509870102141130, f_q)) -mstore(0x1000, mulmod(mload(0xfa0), 495188420091111145957709789221178673495499187437761988132837836548330853701, f_q)) -mstore(0x1020, addmod(mload(0x680), 21393054451748164076288695956036096415052865212978272355565366350027477641916, f_q)) -mstore(0x1040, mulmod(mload(0xfa0), 16064522944768515290584536219762686197737451920702130080538975732575755569557, f_q)) -mstore(0x1060, addmod(mload(0x680), 5823719927070759931661869525494588890810912479713904263159228454000052926060, f_q)) -mstore(0x1080, mulmod(mload(0xfa0), 14686510910986211321976396297238126901237973400949744736326777596334651355305, f_q)) -mstore(0x10a0, addmod(mload(0x680), 7201731960853063900270009448019148187310390999466289607371426590241157140312, f_q)) -mstore(0x10c0, mulmod(mload(0xfa0), 10939663269433627367777756708678102241564365262857670666700619874077960926249, f_q)) -mstore(0x10e0, addmod(mload(0x680), 10948579602405647854468649036579172846983999137558363676997584312497847569368, f_q)) -mstore(0x1100, mulmod(mload(0xfa0), 15402826414547299628414612080036060696555554914079673875872749760617770134879, f_q)) -mstore(0x1120, addmod(mload(0x680), 6485416457291975593831793665221214391992809486336360467825454425958038360738, f_q)) -mstore(0x1140, mulmod(mload(0xfa0), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) -mstore(0x1160, addmod(mload(0x680), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q)) -mstore(0x1180, mulmod(mload(0xfa0), 1, f_q)) -mstore(0x11a0, addmod(mload(0x680), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) -mstore(0x11c0, mulmod(mload(0xfa0), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) -mstore(0x11e0, addmod(mload(0x680), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q)) -mstore(0x1200, mulmod(mload(0xfa0), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) -mstore(0x1220, addmod(mload(0x680), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q)) -mstore(0x1240, mulmod(mload(0xfa0), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) -mstore(0x1260, addmod(mload(0x680), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q)) -mstore(0x1280, mulmod(mload(0xfa0), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q)) -mstore(0x12a0, addmod(mload(0x680), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q)) -mstore(0x12c0, mulmod(mload(0xfa0), 14557038802599140430182096396825290815503940951075961210638273254419942783582, f_q)) -mstore(0x12e0, addmod(mload(0x680), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q)) -mstore(0x1300, mulmod(mload(0xfa0), 9697063347556872083384215826199993067635178715531258559890418744774301211662, f_q)) -mstore(0x1320, addmod(mload(0x680), 12191179524282403138862189919057282020913185684884775783807785441801507283955, f_q)) -mstore(0x1340, mulmod(mload(0xfa0), 12459868075641381822485233712013080087763946065665469821362892189399541605692, f_q)) -mstore(0x1360, addmod(mload(0x680), 9428374796197893399761172033244195000784418334750564522335311997176266889925, f_q)) -mstore(0x1380, mulmod(mload(0xfa0), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q)) -mstore(0x13a0, addmod(mload(0x680), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q)) -mstore(0x13c0, mulmod(mload(0xfa0), 20345677989844117909528750049476969581182118546166966482506114734614108237981, f_q)) -mstore(0x13e0, addmod(mload(0x680), 1542564881995157312717655695780305507366245854249067861192089451961700257636, f_q)) -mstore(0x1400, mulmod(mload(0xfa0), 5289443209903185443361862148540090689648485914368835830972895623576469023722, f_q)) -mstore(0x1420, addmod(mload(0x680), 16598799661936089778884543596717184398899878486047198512725308562999339471895, f_q)) -mstore(0x1440, mulmod(mload(0xfa0), 557567375339945239933617516585967620814823575807691402619711360028043331811, f_q)) -mstore(0x1460, addmod(mload(0x680), 21330675496499329982312788228671307467733540824608342941078492826547765163806, f_q)) +mstore(0xf80, mulmod(mload(0xf60), mload(0xf60), f_q)) +mstore(0xfa0, mulmod(mload(0xf80), mload(0xf80), f_q)) +mstore(0xfc0, mulmod(mload(0xfa0), mload(0xfa0), f_q)) +mstore(0xfe0, mulmod(mload(0xfc0), mload(0xfc0), f_q)) +mstore(0x1000, addmod(mload(0xfe0), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x1020, mulmod(mload(0x1000), 21888232434711746154598842647110004286396165347431605739555851272621938401409, f_q)) +mstore(0x1040, mulmod(mload(0x1020), 20975929243409798062839949658616274858986091382510192949221301676705706354487, f_q)) +mstore(0x1060, addmod(mload(0x700), 912313628429477159406456086641000229562273017905841394476902509870102141130, f_q)) +mstore(0x1080, mulmod(mload(0x1020), 495188420091111145957709789221178673495499187437761988132837836548330853701, f_q)) +mstore(0x10a0, addmod(mload(0x700), 21393054451748164076288695956036096415052865212978272355565366350027477641916, f_q)) +mstore(0x10c0, mulmod(mload(0x1020), 16064522944768515290584536219762686197737451920702130080538975732575755569557, f_q)) +mstore(0x10e0, addmod(mload(0x700), 5823719927070759931661869525494588890810912479713904263159228454000052926060, f_q)) +mstore(0x1100, mulmod(mload(0x1020), 14686510910986211321976396297238126901237973400949744736326777596334651355305, f_q)) +mstore(0x1120, addmod(mload(0x700), 7201731960853063900270009448019148187310390999466289607371426590241157140312, f_q)) +mstore(0x1140, mulmod(mload(0x1020), 10939663269433627367777756708678102241564365262857670666700619874077960926249, f_q)) +mstore(0x1160, addmod(mload(0x700), 10948579602405647854468649036579172846983999137558363676997584312497847569368, f_q)) +mstore(0x1180, mulmod(mload(0x1020), 15402826414547299628414612080036060696555554914079673875872749760617770134879, f_q)) +mstore(0x11a0, addmod(mload(0x700), 6485416457291975593831793665221214391992809486336360467825454425958038360738, f_q)) +mstore(0x11c0, mulmod(mload(0x1020), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) +mstore(0x11e0, addmod(mload(0x700), 19102728315457599142069468034376470979900453007937332237837518576196438670601, f_q)) +mstore(0x1200, mulmod(mload(0x1020), 1, f_q)) +mstore(0x1220, addmod(mload(0x700), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q)) +mstore(0x1240, mulmod(mload(0x1020), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x1260, addmod(mload(0x700), 20461838439117790833741043996939313553025008529160428886800406442142042007110, f_q)) +mstore(0x1280, mulmod(mload(0x1020), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) +mstore(0x12a0, addmod(mload(0x700), 2855281034601326619502779289517034852317245347382893578658160672914005347465, f_q)) +mstore(0x12c0, mulmod(mload(0x1020), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) +mstore(0x12e0, addmod(mload(0x700), 18122161250104879439014068220095202351720788102473020950742332016437772306424, f_q)) +mstore(0x1300, mulmod(mload(0x1020), 5854133144571823792863860130267644613802765696134002830362054821530146160770, f_q)) +mstore(0x1320, addmod(mload(0x700), 16034109727267451429382545614989630474745598704282031513336149365045662334847, f_q)) +mstore(0x1340, mulmod(mload(0x1020), 14557038802599140430182096396825290815503940951075961210638273254419942783582, f_q)) +mstore(0x1360, addmod(mload(0x700), 7331204069240134792064309348431984273044423449340073133059930932155865712035, f_q)) +mstore(0x1380, mulmod(mload(0x1020), 9697063347556872083384215826199993067635178715531258559890418744774301211662, f_q)) +mstore(0x13a0, addmod(mload(0x700), 12191179524282403138862189919057282020913185684884775783807785441801507283955, f_q)) +mstore(0x13c0, mulmod(mload(0x1020), 12459868075641381822485233712013080087763946065665469821362892189399541605692, f_q)) +mstore(0x13e0, addmod(mload(0x700), 9428374796197893399761172033244195000784418334750564522335311997176266889925, f_q)) +mstore(0x1400, mulmod(mload(0x1020), 6955697244493336113861667751840378876927906302623587437721024018233754910398, f_q)) +mstore(0x1420, addmod(mload(0x700), 14932545627345939108384737993416896211620458097792446905977180168342053585219, f_q)) +mstore(0x1440, mulmod(mload(0x1020), 20345677989844117909528750049476969581182118546166966482506114734614108237981, f_q)) +mstore(0x1460, addmod(mload(0x700), 1542564881995157312717655695780305507366245854249067861192089451961700257636, f_q)) +mstore(0x1480, mulmod(mload(0x1020), 5289443209903185443361862148540090689648485914368835830972895623576469023722, f_q)) +mstore(0x14a0, addmod(mload(0x700), 16598799661936089778884543596717184398899878486047198512725308562999339471895, f_q)) +mstore(0x14c0, mulmod(mload(0x1020), 557567375339945239933617516585967620814823575807691402619711360028043331811, f_q)) +mstore(0x14e0, addmod(mload(0x700), 21330675496499329982312788228671307467733540824608342941078492826547765163806, f_q)) { - let prod := mload(0xfe0) + let prod := mload(0x1060) - prod := mulmod(mload(0x1020), prod, f_q) - mstore(0x1480, prod) - - prod := mulmod(mload(0x1060), prod, f_q) - mstore(0x14a0, prod) - prod := mulmod(mload(0x10a0), prod, f_q) - mstore(0x14c0, prod) + mstore(0x1500, prod) prod := mulmod(mload(0x10e0), prod, f_q) - mstore(0x14e0, prod) + mstore(0x1520, prod) prod := mulmod(mload(0x1120), prod, f_q) - mstore(0x1500, prod) + mstore(0x1540, prod) prod := mulmod(mload(0x1160), prod, f_q) - mstore(0x1520, prod) + mstore(0x1560, prod) prod := mulmod(mload(0x11a0), prod, f_q) - mstore(0x1540, prod) + mstore(0x1580, prod) prod := mulmod(mload(0x11e0), prod, f_q) - mstore(0x1560, prod) + mstore(0x15a0, prod) prod := mulmod(mload(0x1220), prod, f_q) - mstore(0x1580, prod) + mstore(0x15c0, prod) prod := mulmod(mload(0x1260), prod, f_q) - mstore(0x15a0, prod) + mstore(0x15e0, prod) prod := mulmod(mload(0x12a0), prod, f_q) - mstore(0x15c0, prod) + mstore(0x1600, prod) prod := mulmod(mload(0x12e0), prod, f_q) - mstore(0x15e0, prod) + mstore(0x1620, prod) prod := mulmod(mload(0x1320), prod, f_q) - mstore(0x1600, prod) + mstore(0x1640, prod) prod := mulmod(mload(0x1360), prod, f_q) - mstore(0x1620, prod) + mstore(0x1660, prod) prod := mulmod(mload(0x13a0), prod, f_q) - mstore(0x1640, prod) + mstore(0x1680, prod) prod := mulmod(mload(0x13e0), prod, f_q) - mstore(0x1660, prod) + mstore(0x16a0, prod) prod := mulmod(mload(0x1420), prod, f_q) - mstore(0x1680, prod) + mstore(0x16c0, prod) prod := mulmod(mload(0x1460), prod, f_q) - mstore(0x16a0, prod) + mstore(0x16e0, prod) - prod := mulmod(mload(0xf80), prod, f_q) - mstore(0x16c0, prod) + prod := mulmod(mload(0x14a0), prod, f_q) + mstore(0x1700, prod) + + prod := mulmod(mload(0x14e0), prod, f_q) + mstore(0x1720, prod) + + prod := mulmod(mload(0x1000), prod, f_q) + mstore(0x1740, prod) } -mstore(0x1700, 32) -mstore(0x1720, 32) -mstore(0x1740, 32) -mstore(0x1760, mload(0x16c0)) -mstore(0x1780, 21888242871839275222246405745257275088548364400416034343698204186575808495615) -mstore(0x17a0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) -success := and(eq(staticcall(gas(), 0x5, 0x1700, 0xc0, 0x16e0, 0x20), 1), success) +mstore(0x1780, 32) +mstore(0x17a0, 32) +mstore(0x17c0, 32) +mstore(0x17e0, mload(0x1740)) +mstore(0x1800, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x1820, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x1780, 0xc0, 0x1760, 0x20), 1), success) { - let inv := mload(0x16e0) + let inv := mload(0x1760) let v - v := mload(0xf80) - mstore(3968, mulmod(mload(0x16a0), inv, f_q)) + v := mload(0x1000) + mstore(4096, mulmod(mload(0x1720), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x14e0) + mstore(5344, mulmod(mload(0x1700), inv, f_q)) + inv := mulmod(v, inv, f_q) + + v := mload(0x14a0) + mstore(5280, mulmod(mload(0x16e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1460) - mstore(5216, mulmod(mload(0x1680), inv, f_q)) + mstore(5216, mulmod(mload(0x16c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1420) - mstore(5152, mulmod(mload(0x1660), inv, f_q)) + mstore(5152, mulmod(mload(0x16a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x13e0) - mstore(5088, mulmod(mload(0x1640), inv, f_q)) + mstore(5088, mulmod(mload(0x1680), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x13a0) - mstore(5024, mulmod(mload(0x1620), inv, f_q)) + mstore(5024, mulmod(mload(0x1660), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1360) - mstore(4960, mulmod(mload(0x1600), inv, f_q)) + mstore(4960, mulmod(mload(0x1640), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1320) - mstore(4896, mulmod(mload(0x15e0), inv, f_q)) + mstore(4896, mulmod(mload(0x1620), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x12e0) - mstore(4832, mulmod(mload(0x15c0), inv, f_q)) + mstore(4832, mulmod(mload(0x1600), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x12a0) - mstore(4768, mulmod(mload(0x15a0), inv, f_q)) + mstore(4768, mulmod(mload(0x15e0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1260) - mstore(4704, mulmod(mload(0x1580), inv, f_q)) + mstore(4704, mulmod(mload(0x15c0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1220) - mstore(4640, mulmod(mload(0x1560), inv, f_q)) + mstore(4640, mulmod(mload(0x15a0), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x11e0) - mstore(4576, mulmod(mload(0x1540), inv, f_q)) + mstore(4576, mulmod(mload(0x1580), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x11a0) - mstore(4512, mulmod(mload(0x1520), inv, f_q)) + mstore(4512, mulmod(mload(0x1560), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1160) - mstore(4448, mulmod(mload(0x1500), inv, f_q)) + mstore(4448, mulmod(mload(0x1540), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x1120) - mstore(4384, mulmod(mload(0x14e0), inv, f_q)) + mstore(4384, mulmod(mload(0x1520), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x10e0) - mstore(4320, mulmod(mload(0x14c0), inv, f_q)) + mstore(4320, mulmod(mload(0x1500), inv, f_q)) inv := mulmod(v, inv, f_q) v := mload(0x10a0) - mstore(4256, mulmod(mload(0x14a0), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1060) - mstore(4192, mulmod(mload(0x1480), inv, f_q)) - inv := mulmod(v, inv, f_q) - - v := mload(0x1020) - mstore(4128, mulmod(mload(0xfe0), inv, f_q)) + mstore(4256, mulmod(mload(0x1060), inv, f_q)) inv := mulmod(v, inv, f_q) - mstore(0xfe0, inv) + mstore(0x1060, inv) } -mstore(0x17c0, mulmod(mload(0xfc0), mload(0xfe0), f_q)) -mstore(0x17e0, mulmod(mload(0x1000), mload(0x1020), f_q)) -mstore(0x1800, mulmod(mload(0x1040), mload(0x1060), f_q)) -mstore(0x1820, mulmod(mload(0x1080), mload(0x10a0), f_q)) -mstore(0x1840, mulmod(mload(0x10c0), mload(0x10e0), f_q)) -mstore(0x1860, mulmod(mload(0x1100), mload(0x1120), f_q)) -mstore(0x1880, mulmod(mload(0x1140), mload(0x1160), f_q)) -mstore(0x18a0, mulmod(mload(0x1180), mload(0x11a0), f_q)) -mstore(0x18c0, mulmod(mload(0x11c0), mload(0x11e0), f_q)) -mstore(0x18e0, mulmod(mload(0x1200), mload(0x1220), f_q)) -mstore(0x1900, mulmod(mload(0x1240), mload(0x1260), f_q)) -mstore(0x1920, mulmod(mload(0x1280), mload(0x12a0), f_q)) -mstore(0x1940, mulmod(mload(0x12c0), mload(0x12e0), f_q)) -mstore(0x1960, mulmod(mload(0x1300), mload(0x1320), f_q)) -mstore(0x1980, mulmod(mload(0x1340), mload(0x1360), f_q)) -mstore(0x19a0, mulmod(mload(0x1380), mload(0x13a0), f_q)) -mstore(0x19c0, mulmod(mload(0x13c0), mload(0x13e0), f_q)) -mstore(0x19e0, mulmod(mload(0x1400), mload(0x1420), f_q)) -mstore(0x1a00, mulmod(mload(0x1440), mload(0x1460), f_q)) +mstore(0x1840, mulmod(mload(0x1040), mload(0x1060), f_q)) +mstore(0x1860, mulmod(mload(0x1080), mload(0x10a0), f_q)) +mstore(0x1880, mulmod(mload(0x10c0), mload(0x10e0), f_q)) +mstore(0x18a0, mulmod(mload(0x1100), mload(0x1120), f_q)) +mstore(0x18c0, mulmod(mload(0x1140), mload(0x1160), f_q)) +mstore(0x18e0, mulmod(mload(0x1180), mload(0x11a0), f_q)) +mstore(0x1900, mulmod(mload(0x11c0), mload(0x11e0), f_q)) +mstore(0x1920, mulmod(mload(0x1200), mload(0x1220), f_q)) +mstore(0x1940, mulmod(mload(0x1240), mload(0x1260), f_q)) +mstore(0x1960, mulmod(mload(0x1280), mload(0x12a0), f_q)) +mstore(0x1980, mulmod(mload(0x12c0), mload(0x12e0), f_q)) +mstore(0x19a0, mulmod(mload(0x1300), mload(0x1320), f_q)) +mstore(0x19c0, mulmod(mload(0x1340), mload(0x1360), f_q)) +mstore(0x19e0, mulmod(mload(0x1380), mload(0x13a0), f_q)) +mstore(0x1a00, mulmod(mload(0x13c0), mload(0x13e0), f_q)) +mstore(0x1a20, mulmod(mload(0x1400), mload(0x1420), f_q)) +mstore(0x1a40, mulmod(mload(0x1440), mload(0x1460), f_q)) +mstore(0x1a60, mulmod(mload(0x1480), mload(0x14a0), f_q)) +mstore(0x1a80, mulmod(mload(0x14c0), mload(0x14e0), f_q)) { - let result := mulmod(mload(0x18a0), mload(0x20), f_q) -result := addmod(mulmod(mload(0x18c0), mload(0x40), f_q), result, f_q) -result := addmod(mulmod(mload(0x18e0), mload(0x60), f_q), result, f_q) -result := addmod(mulmod(mload(0x1900), mload(0x80), f_q), result, f_q) -result := addmod(mulmod(mload(0x1920), mload(0xa0), f_q), result, f_q) + let result := mulmod(mload(0x1920), mload(0xa0), f_q) result := addmod(mulmod(mload(0x1940), mload(0xc0), f_q), result, f_q) result := addmod(mulmod(mload(0x1960), mload(0xe0), f_q), result, f_q) result := addmod(mulmod(mload(0x1980), mload(0x100), f_q), result, f_q) @@ -507,923 +509,927 @@ result := addmod(mulmod(mload(0x19a0), mload(0x120), f_q), result, f_q) result := addmod(mulmod(mload(0x19c0), mload(0x140), f_q), result, f_q) result := addmod(mulmod(mload(0x19e0), mload(0x160), f_q), result, f_q) result := addmod(mulmod(mload(0x1a00), mload(0x180), f_q), result, f_q) -mstore(6688, result) - } -mstore(0x1a40, mulmod(mload(0x700), mload(0x6e0), f_q)) -mstore(0x1a60, addmod(mload(0x6c0), mload(0x1a40), f_q)) -mstore(0x1a80, addmod(mload(0x1a60), sub(f_q, mload(0x720)), f_q)) -mstore(0x1aa0, mulmod(mload(0x1a80), mload(0x820), f_q)) -mstore(0x1ac0, mulmod(mload(0x560), mload(0x1aa0), f_q)) -mstore(0x1ae0, mulmod(mload(0x780), mload(0x760), f_q)) -mstore(0x1b00, addmod(mload(0x740), mload(0x1ae0), f_q)) -mstore(0x1b20, addmod(mload(0x1b00), sub(f_q, mload(0x7a0)), f_q)) -mstore(0x1b40, mulmod(mload(0x1b20), mload(0x840), f_q)) -mstore(0x1b60, addmod(mload(0x1ac0), mload(0x1b40), f_q)) -mstore(0x1b80, mulmod(mload(0x560), mload(0x1b60), f_q)) -mstore(0x1ba0, addmod(1, sub(f_q, mload(0x920)), f_q)) -mstore(0x1bc0, mulmod(mload(0x1ba0), mload(0x18a0), f_q)) -mstore(0x1be0, addmod(mload(0x1b80), mload(0x1bc0), f_q)) -mstore(0x1c00, mulmod(mload(0x560), mload(0x1be0), f_q)) -mstore(0x1c20, mulmod(mload(0x9e0), mload(0x9e0), f_q)) -mstore(0x1c40, addmod(mload(0x1c20), sub(f_q, mload(0x9e0)), f_q)) -mstore(0x1c60, mulmod(mload(0x1c40), mload(0x17c0), f_q)) -mstore(0x1c80, addmod(mload(0x1c00), mload(0x1c60), f_q)) -mstore(0x1ca0, mulmod(mload(0x560), mload(0x1c80), f_q)) -mstore(0x1cc0, addmod(mload(0x980), sub(f_q, mload(0x960)), f_q)) -mstore(0x1ce0, mulmod(mload(0x1cc0), mload(0x18a0), f_q)) -mstore(0x1d00, addmod(mload(0x1ca0), mload(0x1ce0), f_q)) -mstore(0x1d20, mulmod(mload(0x560), mload(0x1d00), f_q)) -mstore(0x1d40, addmod(mload(0x9e0), sub(f_q, mload(0x9c0)), f_q)) -mstore(0x1d60, mulmod(mload(0x1d40), mload(0x18a0), f_q)) +result := addmod(mulmod(mload(0x1a20), mload(0x1a0), f_q), result, f_q) +result := addmod(mulmod(mload(0x1a40), mload(0x1c0), f_q), result, f_q) +result := addmod(mulmod(mload(0x1a60), mload(0x1e0), f_q), result, f_q) +result := addmod(mulmod(mload(0x1a80), mload(0x200), f_q), result, f_q) +mstore(6816, result) + } +mstore(0x1ac0, mulmod(mload(0x780), mload(0x760), f_q)) +mstore(0x1ae0, addmod(mload(0x740), mload(0x1ac0), f_q)) +mstore(0x1b00, addmod(mload(0x1ae0), sub(f_q, mload(0x7a0)), f_q)) +mstore(0x1b20, mulmod(mload(0x1b00), mload(0x8a0), f_q)) +mstore(0x1b40, mulmod(mload(0x5e0), mload(0x1b20), f_q)) +mstore(0x1b60, mulmod(mload(0x800), mload(0x7e0), f_q)) +mstore(0x1b80, addmod(mload(0x7c0), mload(0x1b60), f_q)) +mstore(0x1ba0, addmod(mload(0x1b80), sub(f_q, mload(0x820)), f_q)) +mstore(0x1bc0, mulmod(mload(0x1ba0), mload(0x8c0), f_q)) +mstore(0x1be0, addmod(mload(0x1b40), mload(0x1bc0), f_q)) +mstore(0x1c00, mulmod(mload(0x5e0), mload(0x1be0), f_q)) +mstore(0x1c20, addmod(1, sub(f_q, mload(0x9a0)), f_q)) +mstore(0x1c40, mulmod(mload(0x1c20), mload(0x1920), f_q)) +mstore(0x1c60, addmod(mload(0x1c00), mload(0x1c40), f_q)) +mstore(0x1c80, mulmod(mload(0x5e0), mload(0x1c60), f_q)) +mstore(0x1ca0, mulmod(mload(0xa60), mload(0xa60), f_q)) +mstore(0x1cc0, addmod(mload(0x1ca0), sub(f_q, mload(0xa60)), f_q)) +mstore(0x1ce0, mulmod(mload(0x1cc0), mload(0x1840), f_q)) +mstore(0x1d00, addmod(mload(0x1c80), mload(0x1ce0), f_q)) +mstore(0x1d20, mulmod(mload(0x5e0), mload(0x1d00), f_q)) +mstore(0x1d40, addmod(mload(0xa00), sub(f_q, mload(0x9e0)), f_q)) +mstore(0x1d60, mulmod(mload(0x1d40), mload(0x1920), f_q)) mstore(0x1d80, addmod(mload(0x1d20), mload(0x1d60), f_q)) -mstore(0x1da0, mulmod(mload(0x560), mload(0x1d80), f_q)) -mstore(0x1dc0, addmod(1, sub(f_q, mload(0x17c0)), f_q)) -mstore(0x1de0, addmod(mload(0x17e0), mload(0x1800), f_q)) -mstore(0x1e00, addmod(mload(0x1de0), mload(0x1820), f_q)) -mstore(0x1e20, addmod(mload(0x1e00), mload(0x1840), f_q)) -mstore(0x1e40, addmod(mload(0x1e20), mload(0x1860), f_q)) -mstore(0x1e60, addmod(mload(0x1e40), mload(0x1880), f_q)) -mstore(0x1e80, addmod(mload(0x1dc0), sub(f_q, mload(0x1e60)), f_q)) -mstore(0x1ea0, mulmod(mload(0x880), mload(0x360), f_q)) -mstore(0x1ec0, addmod(mload(0x7e0), mload(0x1ea0), f_q)) -mstore(0x1ee0, addmod(mload(0x1ec0), mload(0x3c0), f_q)) -mstore(0x1f00, mulmod(mload(0x8a0), mload(0x360), f_q)) -mstore(0x1f20, addmod(mload(0x6c0), mload(0x1f00), f_q)) -mstore(0x1f40, addmod(mload(0x1f20), mload(0x3c0), f_q)) -mstore(0x1f60, mulmod(mload(0x1f40), mload(0x1ee0), f_q)) -mstore(0x1f80, mulmod(mload(0x1f60), mload(0x940), f_q)) -mstore(0x1fa0, mulmod(1, mload(0x360), f_q)) -mstore(0x1fc0, mulmod(mload(0x680), mload(0x1fa0), f_q)) -mstore(0x1fe0, addmod(mload(0x7e0), mload(0x1fc0), f_q)) -mstore(0x2000, addmod(mload(0x1fe0), mload(0x3c0), f_q)) -mstore(0x2020, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x360), f_q)) -mstore(0x2040, mulmod(mload(0x680), mload(0x2020), f_q)) -mstore(0x2060, addmod(mload(0x6c0), mload(0x2040), f_q)) -mstore(0x2080, addmod(mload(0x2060), mload(0x3c0), f_q)) -mstore(0x20a0, mulmod(mload(0x2080), mload(0x2000), f_q)) -mstore(0x20c0, mulmod(mload(0x20a0), mload(0x920), f_q)) -mstore(0x20e0, addmod(mload(0x1f80), sub(f_q, mload(0x20c0)), f_q)) -mstore(0x2100, mulmod(mload(0x20e0), mload(0x1e80), f_q)) -mstore(0x2120, addmod(mload(0x1da0), mload(0x2100), f_q)) -mstore(0x2140, mulmod(mload(0x560), mload(0x2120), f_q)) -mstore(0x2160, mulmod(mload(0x8c0), mload(0x360), f_q)) -mstore(0x2180, addmod(mload(0x740), mload(0x2160), f_q)) -mstore(0x21a0, addmod(mload(0x2180), mload(0x3c0), f_q)) -mstore(0x21c0, mulmod(mload(0x8e0), mload(0x360), f_q)) -mstore(0x21e0, addmod(mload(0x7c0), mload(0x21c0), f_q)) -mstore(0x2200, addmod(mload(0x21e0), mload(0x3c0), f_q)) -mstore(0x2220, mulmod(mload(0x2200), mload(0x21a0), f_q)) -mstore(0x2240, mulmod(mload(0x2220), mload(0x9a0), f_q)) -mstore(0x2260, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x360), f_q)) -mstore(0x2280, mulmod(mload(0x680), mload(0x2260), f_q)) -mstore(0x22a0, addmod(mload(0x740), mload(0x2280), f_q)) -mstore(0x22c0, addmod(mload(0x22a0), mload(0x3c0), f_q)) -mstore(0x22e0, mulmod(11166246659983828508719468090013646171463329086121580628794302409516816350802, mload(0x360), f_q)) -mstore(0x2300, mulmod(mload(0x680), mload(0x22e0), f_q)) +mstore(0x1da0, mulmod(mload(0x5e0), mload(0x1d80), f_q)) +mstore(0x1dc0, addmod(mload(0xa60), sub(f_q, mload(0xa40)), f_q)) +mstore(0x1de0, mulmod(mload(0x1dc0), mload(0x1920), f_q)) +mstore(0x1e00, addmod(mload(0x1da0), mload(0x1de0), f_q)) +mstore(0x1e20, mulmod(mload(0x5e0), mload(0x1e00), f_q)) +mstore(0x1e40, addmod(1, sub(f_q, mload(0x1840)), f_q)) +mstore(0x1e60, addmod(mload(0x1860), mload(0x1880), f_q)) +mstore(0x1e80, addmod(mload(0x1e60), mload(0x18a0), f_q)) +mstore(0x1ea0, addmod(mload(0x1e80), mload(0x18c0), f_q)) +mstore(0x1ec0, addmod(mload(0x1ea0), mload(0x18e0), f_q)) +mstore(0x1ee0, addmod(mload(0x1ec0), mload(0x1900), f_q)) +mstore(0x1f00, addmod(mload(0x1e40), sub(f_q, mload(0x1ee0)), f_q)) +mstore(0x1f20, mulmod(mload(0x900), mload(0x3e0), f_q)) +mstore(0x1f40, addmod(mload(0x860), mload(0x1f20), f_q)) +mstore(0x1f60, addmod(mload(0x1f40), mload(0x440), f_q)) +mstore(0x1f80, mulmod(mload(0x920), mload(0x3e0), f_q)) +mstore(0x1fa0, addmod(mload(0x740), mload(0x1f80), f_q)) +mstore(0x1fc0, addmod(mload(0x1fa0), mload(0x440), f_q)) +mstore(0x1fe0, mulmod(mload(0x1fc0), mload(0x1f60), f_q)) +mstore(0x2000, mulmod(mload(0x1fe0), mload(0x9c0), f_q)) +mstore(0x2020, mulmod(1, mload(0x3e0), f_q)) +mstore(0x2040, mulmod(mload(0x700), mload(0x2020), f_q)) +mstore(0x2060, addmod(mload(0x860), mload(0x2040), f_q)) +mstore(0x2080, addmod(mload(0x2060), mload(0x440), f_q)) +mstore(0x20a0, mulmod(4131629893567559867359510883348571134090853742863529169391034518566172092834, mload(0x3e0), f_q)) +mstore(0x20c0, mulmod(mload(0x700), mload(0x20a0), f_q)) +mstore(0x20e0, addmod(mload(0x740), mload(0x20c0), f_q)) +mstore(0x2100, addmod(mload(0x20e0), mload(0x440), f_q)) +mstore(0x2120, mulmod(mload(0x2100), mload(0x2080), f_q)) +mstore(0x2140, mulmod(mload(0x2120), mload(0x9a0), f_q)) +mstore(0x2160, addmod(mload(0x2000), sub(f_q, mload(0x2140)), f_q)) +mstore(0x2180, mulmod(mload(0x2160), mload(0x1f00), f_q)) +mstore(0x21a0, addmod(mload(0x1e20), mload(0x2180), f_q)) +mstore(0x21c0, mulmod(mload(0x5e0), mload(0x21a0), f_q)) +mstore(0x21e0, mulmod(mload(0x940), mload(0x3e0), f_q)) +mstore(0x2200, addmod(mload(0x7c0), mload(0x21e0), f_q)) +mstore(0x2220, addmod(mload(0x2200), mload(0x440), f_q)) +mstore(0x2240, mulmod(mload(0x960), mload(0x3e0), f_q)) +mstore(0x2260, addmod(mload(0x840), mload(0x2240), f_q)) +mstore(0x2280, addmod(mload(0x2260), mload(0x440), f_q)) +mstore(0x22a0, mulmod(mload(0x2280), mload(0x2220), f_q)) +mstore(0x22c0, mulmod(mload(0x22a0), mload(0xa20), f_q)) +mstore(0x22e0, mulmod(8910878055287538404433155982483128285667088683464058436815641868457422632747, mload(0x3e0), f_q)) +mstore(0x2300, mulmod(mload(0x700), mload(0x22e0), f_q)) mstore(0x2320, addmod(mload(0x7c0), mload(0x2300), f_q)) -mstore(0x2340, addmod(mload(0x2320), mload(0x3c0), f_q)) -mstore(0x2360, mulmod(mload(0x2340), mload(0x22c0), f_q)) -mstore(0x2380, mulmod(mload(0x2360), mload(0x980), f_q)) -mstore(0x23a0, addmod(mload(0x2240), sub(f_q, mload(0x2380)), f_q)) -mstore(0x23c0, mulmod(mload(0x23a0), mload(0x1e80), f_q)) -mstore(0x23e0, addmod(mload(0x2140), mload(0x23c0), f_q)) -mstore(0x2400, mulmod(mload(0x560), mload(0x23e0), f_q)) -mstore(0x2420, mulmod(mload(0x900), mload(0x360), f_q)) -mstore(0x2440, addmod(mload(0x1a20), mload(0x2420), f_q)) -mstore(0x2460, addmod(mload(0x2440), mload(0x3c0), f_q)) -mstore(0x2480, mulmod(mload(0x2460), mload(0xa00), f_q)) -mstore(0x24a0, mulmod(284840088355319032285349970403338060113257071685626700086398481893096618818, mload(0x360), f_q)) -mstore(0x24c0, mulmod(mload(0x680), mload(0x24a0), f_q)) -mstore(0x24e0, addmod(mload(0x1a20), mload(0x24c0), f_q)) -mstore(0x2500, addmod(mload(0x24e0), mload(0x3c0), f_q)) -mstore(0x2520, mulmod(mload(0x2500), mload(0x9e0), f_q)) -mstore(0x2540, addmod(mload(0x2480), sub(f_q, mload(0x2520)), f_q)) -mstore(0x2560, mulmod(mload(0x2540), mload(0x1e80), f_q)) -mstore(0x2580, addmod(mload(0x2400), mload(0x2560), f_q)) -mstore(0x25a0, mulmod(mload(0x560), mload(0x2580), f_q)) -mstore(0x25c0, addmod(1, sub(f_q, mload(0xa20)), f_q)) -mstore(0x25e0, mulmod(mload(0x25c0), mload(0x18a0), f_q)) -mstore(0x2600, addmod(mload(0x25a0), mload(0x25e0), f_q)) -mstore(0x2620, mulmod(mload(0x560), mload(0x2600), f_q)) -mstore(0x2640, mulmod(mload(0xa20), mload(0xa20), f_q)) -mstore(0x2660, addmod(mload(0x2640), sub(f_q, mload(0xa20)), f_q)) -mstore(0x2680, mulmod(mload(0x2660), mload(0x17c0), f_q)) -mstore(0x26a0, addmod(mload(0x2620), mload(0x2680), f_q)) -mstore(0x26c0, mulmod(mload(0x560), mload(0x26a0), f_q)) -mstore(0x26e0, addmod(mload(0xa60), mload(0x360), f_q)) -mstore(0x2700, mulmod(mload(0x26e0), mload(0xa40), f_q)) -mstore(0x2720, addmod(mload(0xaa0), mload(0x3c0), f_q)) -mstore(0x2740, mulmod(mload(0x2720), mload(0x2700), f_q)) -mstore(0x2760, addmod(mload(0x7c0), mload(0x360), f_q)) -mstore(0x2780, mulmod(mload(0x2760), mload(0xa20), f_q)) -mstore(0x27a0, addmod(mload(0x800), mload(0x3c0), f_q)) +mstore(0x2340, addmod(mload(0x2320), mload(0x440), f_q)) +mstore(0x2360, mulmod(11166246659983828508719468090013646171463329086121580628794302409516816350802, mload(0x3e0), f_q)) +mstore(0x2380, mulmod(mload(0x700), mload(0x2360), f_q)) +mstore(0x23a0, addmod(mload(0x840), mload(0x2380), f_q)) +mstore(0x23c0, addmod(mload(0x23a0), mload(0x440), f_q)) +mstore(0x23e0, mulmod(mload(0x23c0), mload(0x2340), f_q)) +mstore(0x2400, mulmod(mload(0x23e0), mload(0xa00), f_q)) +mstore(0x2420, addmod(mload(0x22c0), sub(f_q, mload(0x2400)), f_q)) +mstore(0x2440, mulmod(mload(0x2420), mload(0x1f00), f_q)) +mstore(0x2460, addmod(mload(0x21c0), mload(0x2440), f_q)) +mstore(0x2480, mulmod(mload(0x5e0), mload(0x2460), f_q)) +mstore(0x24a0, mulmod(mload(0x980), mload(0x3e0), f_q)) +mstore(0x24c0, addmod(mload(0x1aa0), mload(0x24a0), f_q)) +mstore(0x24e0, addmod(mload(0x24c0), mload(0x440), f_q)) +mstore(0x2500, mulmod(mload(0x24e0), mload(0xa80), f_q)) +mstore(0x2520, mulmod(284840088355319032285349970403338060113257071685626700086398481893096618818, mload(0x3e0), f_q)) +mstore(0x2540, mulmod(mload(0x700), mload(0x2520), f_q)) +mstore(0x2560, addmod(mload(0x1aa0), mload(0x2540), f_q)) +mstore(0x2580, addmod(mload(0x2560), mload(0x440), f_q)) +mstore(0x25a0, mulmod(mload(0x2580), mload(0xa60), f_q)) +mstore(0x25c0, addmod(mload(0x2500), sub(f_q, mload(0x25a0)), f_q)) +mstore(0x25e0, mulmod(mload(0x25c0), mload(0x1f00), f_q)) +mstore(0x2600, addmod(mload(0x2480), mload(0x25e0), f_q)) +mstore(0x2620, mulmod(mload(0x5e0), mload(0x2600), f_q)) +mstore(0x2640, addmod(1, sub(f_q, mload(0xaa0)), f_q)) +mstore(0x2660, mulmod(mload(0x2640), mload(0x1920), f_q)) +mstore(0x2680, addmod(mload(0x2620), mload(0x2660), f_q)) +mstore(0x26a0, mulmod(mload(0x5e0), mload(0x2680), f_q)) +mstore(0x26c0, mulmod(mload(0xaa0), mload(0xaa0), f_q)) +mstore(0x26e0, addmod(mload(0x26c0), sub(f_q, mload(0xaa0)), f_q)) +mstore(0x2700, mulmod(mload(0x26e0), mload(0x1840), f_q)) +mstore(0x2720, addmod(mload(0x26a0), mload(0x2700), f_q)) +mstore(0x2740, mulmod(mload(0x5e0), mload(0x2720), f_q)) +mstore(0x2760, addmod(mload(0xae0), mload(0x3e0), f_q)) +mstore(0x2780, mulmod(mload(0x2760), mload(0xac0), f_q)) +mstore(0x27a0, addmod(mload(0xb20), mload(0x440), f_q)) mstore(0x27c0, mulmod(mload(0x27a0), mload(0x2780), f_q)) -mstore(0x27e0, addmod(mload(0x2740), sub(f_q, mload(0x27c0)), f_q)) -mstore(0x2800, mulmod(mload(0x27e0), mload(0x1e80), f_q)) -mstore(0x2820, addmod(mload(0x26c0), mload(0x2800), f_q)) -mstore(0x2840, mulmod(mload(0x560), mload(0x2820), f_q)) -mstore(0x2860, addmod(mload(0xa60), sub(f_q, mload(0xaa0)), f_q)) -mstore(0x2880, mulmod(mload(0x2860), mload(0x18a0), f_q)) -mstore(0x28a0, addmod(mload(0x2840), mload(0x2880), f_q)) -mstore(0x28c0, mulmod(mload(0x560), mload(0x28a0), f_q)) -mstore(0x28e0, mulmod(mload(0x2860), mload(0x1e80), f_q)) -mstore(0x2900, addmod(mload(0xa60), sub(f_q, mload(0xa80)), f_q)) -mstore(0x2920, mulmod(mload(0x2900), mload(0x28e0), f_q)) -mstore(0x2940, addmod(mload(0x28c0), mload(0x2920), f_q)) -mstore(0x2960, mulmod(mload(0xf60), mload(0xf60), f_q)) -mstore(0x2980, mulmod(mload(0x2960), mload(0xf60), f_q)) -mstore(0x29a0, mulmod(1, mload(0xf60), f_q)) -mstore(0x29c0, mulmod(1, mload(0x2960), f_q)) -mstore(0x29e0, mulmod(mload(0x2940), mload(0xf80), f_q)) -mstore(0x2a00, mulmod(mload(0xce0), mload(0x680), f_q)) -mstore(0x2a20, mulmod(mload(0x2a00), mload(0x680), f_q)) -mstore(0x2a40, mulmod(mload(0x680), 20975929243409798062839949658616274858986091382510192949221301676705706354487, f_q)) -mstore(0x2a60, addmod(mload(0xbe0), sub(f_q, mload(0x2a40)), f_q)) -mstore(0x2a80, mulmod(mload(0x680), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) -mstore(0x2aa0, addmod(mload(0xbe0), sub(f_q, mload(0x2a80)), f_q)) -mstore(0x2ac0, mulmod(mload(0x680), 1, f_q)) -mstore(0x2ae0, addmod(mload(0xbe0), sub(f_q, mload(0x2ac0)), f_q)) -mstore(0x2b00, mulmod(mload(0x680), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) -mstore(0x2b20, addmod(mload(0xbe0), sub(f_q, mload(0x2b00)), f_q)) -mstore(0x2b40, mulmod(mload(0x680), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) -mstore(0x2b60, addmod(mload(0xbe0), sub(f_q, mload(0x2b40)), f_q)) -mstore(0x2b80, mulmod(mload(0x680), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) -mstore(0x2ba0, addmod(mload(0xbe0), sub(f_q, mload(0x2b80)), f_q)) -mstore(0x2bc0, mulmod(12142985201493934370659158242092015678465417407805993602870272259656026591649, mload(0x2a00), f_q)) -mstore(0x2be0, mulmod(mload(0x2bc0), 1, f_q)) +mstore(0x27e0, addmod(mload(0x840), mload(0x3e0), f_q)) +mstore(0x2800, mulmod(mload(0x27e0), mload(0xaa0), f_q)) +mstore(0x2820, addmod(mload(0x880), mload(0x440), f_q)) +mstore(0x2840, mulmod(mload(0x2820), mload(0x2800), f_q)) +mstore(0x2860, addmod(mload(0x27c0), sub(f_q, mload(0x2840)), f_q)) +mstore(0x2880, mulmod(mload(0x2860), mload(0x1f00), f_q)) +mstore(0x28a0, addmod(mload(0x2740), mload(0x2880), f_q)) +mstore(0x28c0, mulmod(mload(0x5e0), mload(0x28a0), f_q)) +mstore(0x28e0, addmod(mload(0xae0), sub(f_q, mload(0xb20)), f_q)) +mstore(0x2900, mulmod(mload(0x28e0), mload(0x1920), f_q)) +mstore(0x2920, addmod(mload(0x28c0), mload(0x2900), f_q)) +mstore(0x2940, mulmod(mload(0x5e0), mload(0x2920), f_q)) +mstore(0x2960, mulmod(mload(0x28e0), mload(0x1f00), f_q)) +mstore(0x2980, addmod(mload(0xae0), sub(f_q, mload(0xb00)), f_q)) +mstore(0x29a0, mulmod(mload(0x2980), mload(0x2960), f_q)) +mstore(0x29c0, addmod(mload(0x2940), mload(0x29a0), f_q)) +mstore(0x29e0, mulmod(mload(0xfe0), mload(0xfe0), f_q)) +mstore(0x2a00, mulmod(mload(0x29e0), mload(0xfe0), f_q)) +mstore(0x2a20, mulmod(1, mload(0xfe0), f_q)) +mstore(0x2a40, mulmod(1, mload(0x29e0), f_q)) +mstore(0x2a60, mulmod(mload(0x29c0), mload(0x1000), f_q)) +mstore(0x2a80, mulmod(mload(0xd60), mload(0x700), f_q)) +mstore(0x2aa0, mulmod(mload(0x2a80), mload(0x700), f_q)) +mstore(0x2ac0, mulmod(mload(0x700), 20975929243409798062839949658616274858986091382510192949221301676705706354487, f_q)) +mstore(0x2ae0, addmod(mload(0xc60), sub(f_q, mload(0x2ac0)), f_q)) +mstore(0x2b00, mulmod(mload(0x700), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) +mstore(0x2b20, addmod(mload(0xc60), sub(f_q, mload(0x2b00)), f_q)) +mstore(0x2b40, mulmod(mload(0x700), 1, f_q)) +mstore(0x2b60, addmod(mload(0xc60), sub(f_q, mload(0x2b40)), f_q)) +mstore(0x2b80, mulmod(mload(0x700), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x2ba0, addmod(mload(0xc60), sub(f_q, mload(0x2b80)), f_q)) +mstore(0x2bc0, mulmod(mload(0x700), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) +mstore(0x2be0, addmod(mload(0xc60), sub(f_q, mload(0x2bc0)), f_q)) +mstore(0x2c00, mulmod(mload(0x700), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) +mstore(0x2c20, addmod(mload(0xc60), sub(f_q, mload(0x2c00)), f_q)) +mstore(0x2c40, mulmod(12142985201493934370659158242092015678465417407805993602870272259656026591649, mload(0x2a80), f_q)) +mstore(0x2c60, mulmod(mload(0x2c40), 1, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x2bc0), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2be0)), f_q), result, f_q) -mstore(11264, result) + let result := mulmod(mload(0xc60), mload(0x2c40), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x2c60)), f_q), result, f_q) +mstore(11392, result) } -mstore(0x2c20, mulmod(12858672892267984631233883117647866851148059157064290846881981435700301865966, mload(0x2a00), f_q)) -mstore(0x2c40, mulmod(mload(0x2c20), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x2ca0, mulmod(12858672892267984631233883117647866851148059157064290846881981435700301865966, mload(0x2a80), f_q)) +mstore(0x2cc0, mulmod(mload(0x2ca0), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x2c20), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2c40)), f_q), result, f_q) -mstore(11360, result) + let result := mulmod(mload(0xc60), mload(0x2ca0), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x2cc0)), f_q), result, f_q) +mstore(11488, result) } -mstore(0x2c80, mulmod(20880316823902385764034220950270964645276820671488089374347912013802613180902, mload(0x2a00), f_q)) -mstore(0x2ca0, mulmod(mload(0x2c80), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) +mstore(0x2d00, mulmod(20880316823902385764034220950270964645276820671488089374347912013802613180902, mload(0x2a80), f_q)) +mstore(0x2d20, mulmod(mload(0x2d00), 19032961837237948602743626455740240236231119053033140765040043513661803148152, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x2c80), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2ca0)), f_q), result, f_q) -mstore(11456, result) + let result := mulmod(mload(0xc60), mload(0x2d00), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x2d20)), f_q), result, f_q) +mstore(11584, result) } -mstore(0x2ce0, mulmod(17575202995145968412995467587554373308969396527144859871466654432792864477050, mload(0x2a00), f_q)) -mstore(0x2d00, mulmod(mload(0x2ce0), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) +mstore(0x2d60, mulmod(17575202995145968412995467587554373308969396527144859871466654432792864477050, mload(0x2a80), f_q)) +mstore(0x2d80, mulmod(mload(0x2d60), 3766081621734395783232337525162072736827576297943013392955872170138036189193, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x2ce0), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2d00)), f_q), result, f_q) -mstore(11552, result) - } -mstore(0x2d40, mulmod(1, mload(0x2ae0), f_q)) -mstore(0x2d60, mulmod(mload(0x2d40), mload(0x2b20), f_q)) -mstore(0x2d80, mulmod(mload(0x2d60), mload(0x2b60), f_q)) -mstore(0x2da0, mulmod(mload(0x2d80), mload(0x2ba0), f_q)) + let result := mulmod(mload(0xc60), mload(0x2d60), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x2d80)), f_q), result, f_q) +mstore(11680, result) + } +mstore(0x2dc0, mulmod(1, mload(0x2b60), f_q)) +mstore(0x2de0, mulmod(mload(0x2dc0), mload(0x2ba0), f_q)) +mstore(0x2e00, mulmod(mload(0x2de0), mload(0x2be0), f_q)) +mstore(0x2e20, mulmod(mload(0x2e00), mload(0x2c20), f_q)) { - let result := mulmod(mload(0xbe0), 1, f_q) -result := addmod(mulmod(mload(0x680), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q) -mstore(11712, result) + let result := mulmod(mload(0xc60), 1, f_q) +result := addmod(mulmod(mload(0x700), 21888242871839275222246405745257275088548364400416034343698204186575808495616, f_q), result, f_q) +mstore(11840, result) } -mstore(0x2de0, mulmod(21869340487638379139105209872801492456082780734504032269410146788560475001942, mload(0xce0), f_q)) -mstore(0x2e00, mulmod(mload(0x2de0), 1, f_q)) +mstore(0x2e60, mulmod(21869340487638379139105209872801492456082780734504032269410146788560475001942, mload(0xd60), f_q)) +mstore(0x2e80, mulmod(mload(0x2e60), 1, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x2de0), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2e00)), f_q), result, f_q) -mstore(11808, result) + let result := mulmod(mload(0xc60), mload(0x2e60), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x2e80)), f_q), result, f_q) +mstore(11936, result) } -mstore(0x2e40, mulmod(16199055355995875908874098831560099797649990976433931925532505422809603664814, mload(0xce0), f_q)) -mstore(0x2e60, mulmod(mload(0x2e40), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x2ec0, mulmod(16199055355995875908874098831560099797649990976433931925532505422809603664814, mload(0xd60), f_q)) +mstore(0x2ee0, mulmod(mload(0x2ec0), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x2e40), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2e60)), f_q), result, f_q) -mstore(11904, result) + let result := mulmod(mload(0xc60), mload(0x2ec0), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x2ee0)), f_q), result, f_q) +mstore(12032, result) } -mstore(0x2ea0, mulmod(4865187280763976036134135047793386535665014353502380106898040096680231678680, mload(0xce0), f_q)) -mstore(0x2ec0, mulmod(mload(0x2ea0), 20975929243409798062839949658616274858986091382510192949221301676705706354487, f_q)) +mstore(0x2f20, mulmod(4865187280763976036134135047793386535665014353502380106898040096680231678680, mload(0xd60), f_q)) +mstore(0x2f40, mulmod(mload(0x2f20), 20975929243409798062839949658616274858986091382510192949221301676705706354487, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x2ea0), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2ec0)), f_q), result, f_q) -mstore(12000, result) + let result := mulmod(mload(0xc60), mload(0x2f20), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x2f40)), f_q), result, f_q) +mstore(12128, result) } -mstore(0x2f00, mulmod(mload(0x2d60), mload(0x2a60), f_q)) -mstore(0x2f20, mulmod(20461838439117790833741043996939313553025008529160428886800406442142042007111, mload(0x680), f_q)) -mstore(0x2f40, mulmod(mload(0x2f20), 1, f_q)) +mstore(0x2f80, mulmod(mload(0x2de0), mload(0x2ae0), f_q)) +mstore(0x2fa0, mulmod(20461838439117790833741043996939313553025008529160428886800406442142042007111, mload(0x700), f_q)) +mstore(0x2fc0, mulmod(mload(0x2fa0), 1, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x2f20), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2f40)), f_q), result, f_q) -mstore(12128, result) + let result := mulmod(mload(0xc60), mload(0x2fa0), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x2fc0)), f_q), result, f_q) +mstore(12256, result) } -mstore(0x2f80, mulmod(1426404432721484388505361748317961535523355871255605456897797744433766488506, mload(0x680), f_q)) -mstore(0x2fa0, mulmod(mload(0x2f80), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) +mstore(0x3000, mulmod(1426404432721484388505361748317961535523355871255605456897797744433766488506, mload(0x700), f_q)) +mstore(0x3020, mulmod(mload(0x3000), 1426404432721484388505361748317961535523355871255605456897797744433766488507, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x2f80), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x2fa0)), f_q), result, f_q) -mstore(12224, result) + let result := mulmod(mload(0xc60), mload(0x3000), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x3020)), f_q), result, f_q) +mstore(12352, result) } -mstore(0x2fe0, mulmod(19102728315457599142069468034376470979900453007937332237837518576196438670602, mload(0x680), f_q)) -mstore(0x3000, mulmod(mload(0x2fe0), 1, f_q)) +mstore(0x3060, mulmod(19102728315457599142069468034376470979900453007937332237837518576196438670602, mload(0x700), f_q)) +mstore(0x3080, mulmod(mload(0x3060), 1, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x2fe0), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x3000)), f_q), result, f_q) -mstore(12320, result) + let result := mulmod(mload(0xc60), mload(0x3060), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x3080)), f_q), result, f_q) +mstore(12448, result) } -mstore(0x3040, mulmod(2785514556381676080176937710880804108647911392478702105860685610379369825015, mload(0x680), f_q)) -mstore(0x3060, mulmod(mload(0x3040), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) +mstore(0x30c0, mulmod(2785514556381676080176937710880804108647911392478702105860685610379369825015, mload(0x700), f_q)) +mstore(0x30e0, mulmod(mload(0x30c0), 2785514556381676080176937710880804108647911392478702105860685610379369825016, f_q)) { - let result := mulmod(mload(0xbe0), mload(0x3040), f_q) -result := addmod(mulmod(mload(0x680), sub(f_q, mload(0x3060)), f_q), result, f_q) -mstore(12416, result) + let result := mulmod(mload(0xc60), mload(0x30c0), f_q) +result := addmod(mulmod(mload(0x700), sub(f_q, mload(0x30e0)), f_q), result, f_q) +mstore(12544, result) } -mstore(0x30a0, mulmod(mload(0x2d40), mload(0x2aa0), f_q)) +mstore(0x3120, mulmod(mload(0x2dc0), mload(0x2b20), f_q)) { - let prod := mload(0x2c00) + let prod := mload(0x2c80) - prod := mulmod(mload(0x2c60), prod, f_q) - mstore(0x30c0, prod) - - prod := mulmod(mload(0x2cc0), prod, f_q) - mstore(0x30e0, prod) - - prod := mulmod(mload(0x2d20), prod, f_q) - mstore(0x3100, prod) - - prod := mulmod(mload(0x2dc0), prod, f_q) - mstore(0x3120, prod) - - prod := mulmod(mload(0x2d40), prod, f_q) + prod := mulmod(mload(0x2ce0), prod, f_q) mstore(0x3140, prod) - prod := mulmod(mload(0x2e20), prod, f_q) + prod := mulmod(mload(0x2d40), prod, f_q) mstore(0x3160, prod) - prod := mulmod(mload(0x2e80), prod, f_q) + prod := mulmod(mload(0x2da0), prod, f_q) mstore(0x3180, prod) - prod := mulmod(mload(0x2ee0), prod, f_q) + prod := mulmod(mload(0x2e40), prod, f_q) mstore(0x31a0, prod) - prod := mulmod(mload(0x2f00), prod, f_q) + prod := mulmod(mload(0x2dc0), prod, f_q) mstore(0x31c0, prod) - prod := mulmod(mload(0x2f60), prod, f_q) + prod := mulmod(mload(0x2ea0), prod, f_q) mstore(0x31e0, prod) - prod := mulmod(mload(0x2fc0), prod, f_q) + prod := mulmod(mload(0x2f00), prod, f_q) mstore(0x3200, prod) - prod := mulmod(mload(0x2d60), prod, f_q) + prod := mulmod(mload(0x2f60), prod, f_q) mstore(0x3220, prod) - prod := mulmod(mload(0x3020), prod, f_q) + prod := mulmod(mload(0x2f80), prod, f_q) mstore(0x3240, prod) - prod := mulmod(mload(0x3080), prod, f_q) + prod := mulmod(mload(0x2fe0), prod, f_q) mstore(0x3260, prod) - prod := mulmod(mload(0x30a0), prod, f_q) + prod := mulmod(mload(0x3040), prod, f_q) mstore(0x3280, prod) + prod := mulmod(mload(0x2de0), prod, f_q) + mstore(0x32a0, prod) + + prod := mulmod(mload(0x30a0), prod, f_q) + mstore(0x32c0, prod) + + prod := mulmod(mload(0x3100), prod, f_q) + mstore(0x32e0, prod) + + prod := mulmod(mload(0x3120), prod, f_q) + mstore(0x3300, prod) + } -mstore(0x32c0, 32) -mstore(0x32e0, 32) -mstore(0x3300, 32) -mstore(0x3320, mload(0x3280)) -mstore(0x3340, 21888242871839275222246405745257275088548364400416034343698204186575808495615) -mstore(0x3360, 21888242871839275222246405745257275088548364400416034343698204186575808495617) -success := and(eq(staticcall(gas(), 0x5, 0x32c0, 0xc0, 0x32a0, 0x20), 1), success) +mstore(0x3340, 32) +mstore(0x3360, 32) +mstore(0x3380, 32) +mstore(0x33a0, mload(0x3300)) +mstore(0x33c0, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x33e0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x3340, 0xc0, 0x3320, 0x20), 1), success) { - let inv := mload(0x32a0) + let inv := mload(0x3320) let v - v := mload(0x30a0) - mstore(12448, mulmod(mload(0x3260), inv, f_q)) + v := mload(0x3120) + mstore(12576, mulmod(mload(0x32e0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3080) - mstore(12416, mulmod(mload(0x3240), inv, f_q)) + v := mload(0x3100) + mstore(12544, mulmod(mload(0x32c0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3020) - mstore(12320, mulmod(mload(0x3220), inv, f_q)) + v := mload(0x30a0) + mstore(12448, mulmod(mload(0x32a0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2d60) - mstore(11616, mulmod(mload(0x3200), inv, f_q)) + v := mload(0x2de0) + mstore(11744, mulmod(mload(0x3280), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2fc0) - mstore(12224, mulmod(mload(0x31e0), inv, f_q)) + v := mload(0x3040) + mstore(12352, mulmod(mload(0x3260), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2f60) - mstore(12128, mulmod(mload(0x31c0), inv, f_q)) + v := mload(0x2fe0) + mstore(12256, mulmod(mload(0x3240), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2f00) - mstore(12032, mulmod(mload(0x31a0), inv, f_q)) + v := mload(0x2f80) + mstore(12160, mulmod(mload(0x3220), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2ee0) - mstore(12000, mulmod(mload(0x3180), inv, f_q)) + v := mload(0x2f60) + mstore(12128, mulmod(mload(0x3200), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2e80) - mstore(11904, mulmod(mload(0x3160), inv, f_q)) + v := mload(0x2f00) + mstore(12032, mulmod(mload(0x31e0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2e20) - mstore(11808, mulmod(mload(0x3140), inv, f_q)) + v := mload(0x2ea0) + mstore(11936, mulmod(mload(0x31c0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2d40) - mstore(11584, mulmod(mload(0x3120), inv, f_q)) + v := mload(0x2dc0) + mstore(11712, mulmod(mload(0x31a0), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2dc0) - mstore(11712, mulmod(mload(0x3100), inv, f_q)) + v := mload(0x2e40) + mstore(11840, mulmod(mload(0x3180), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2d20) - mstore(11552, mulmod(mload(0x30e0), inv, f_q)) + v := mload(0x2da0) + mstore(11680, mulmod(mload(0x3160), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2cc0) - mstore(11456, mulmod(mload(0x30c0), inv, f_q)) + v := mload(0x2d40) + mstore(11584, mulmod(mload(0x3140), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x2c60) - mstore(11360, mulmod(mload(0x2c00), inv, f_q)) + v := mload(0x2ce0) + mstore(11488, mulmod(mload(0x2c80), inv, f_q)) inv := mulmod(v, inv, f_q) - mstore(0x2c00, inv) + mstore(0x2c80, inv) } { - let result := mload(0x2c00) -result := addmod(mload(0x2c60), result, f_q) -result := addmod(mload(0x2cc0), result, f_q) -result := addmod(mload(0x2d20), result, f_q) -mstore(13184, result) + let result := mload(0x2c80) +result := addmod(mload(0x2ce0), result, f_q) +result := addmod(mload(0x2d40), result, f_q) +result := addmod(mload(0x2da0), result, f_q) +mstore(13312, result) } -mstore(0x33a0, mulmod(mload(0x2da0), mload(0x2d40), f_q)) +mstore(0x3420, mulmod(mload(0x2e20), mload(0x2dc0), f_q)) { - let result := mload(0x2dc0) -mstore(13248, result) + let result := mload(0x2e40) +mstore(13376, result) } -mstore(0x33e0, mulmod(mload(0x2da0), mload(0x2f00), f_q)) +mstore(0x3460, mulmod(mload(0x2e20), mload(0x2f80), f_q)) { - let result := mload(0x2e20) -result := addmod(mload(0x2e80), result, f_q) -result := addmod(mload(0x2ee0), result, f_q) -mstore(13312, result) + let result := mload(0x2ea0) +result := addmod(mload(0x2f00), result, f_q) +result := addmod(mload(0x2f60), result, f_q) +mstore(13440, result) } -mstore(0x3420, mulmod(mload(0x2da0), mload(0x2d60), f_q)) +mstore(0x34a0, mulmod(mload(0x2e20), mload(0x2de0), f_q)) { - let result := mload(0x2f60) -result := addmod(mload(0x2fc0), result, f_q) -mstore(13376, result) + let result := mload(0x2fe0) +result := addmod(mload(0x3040), result, f_q) +mstore(13504, result) } -mstore(0x3460, mulmod(mload(0x2da0), mload(0x30a0), f_q)) +mstore(0x34e0, mulmod(mload(0x2e20), mload(0x3120), f_q)) { - let result := mload(0x3020) -result := addmod(mload(0x3080), result, f_q) -mstore(13440, result) + let result := mload(0x30a0) +result := addmod(mload(0x3100), result, f_q) +mstore(13568, result) } { - let prod := mload(0x3380) + let prod := mload(0x3400) - prod := mulmod(mload(0x33c0), prod, f_q) - mstore(0x34a0, prod) - - prod := mulmod(mload(0x3400), prod, f_q) - mstore(0x34c0, prod) - prod := mulmod(mload(0x3440), prod, f_q) - mstore(0x34e0, prod) + mstore(0x3520, prod) prod := mulmod(mload(0x3480), prod, f_q) - mstore(0x3500, prod) + mstore(0x3540, prod) + + prod := mulmod(mload(0x34c0), prod, f_q) + mstore(0x3560, prod) + + prod := mulmod(mload(0x3500), prod, f_q) + mstore(0x3580, prod) } -mstore(0x3540, 32) -mstore(0x3560, 32) -mstore(0x3580, 32) -mstore(0x35a0, mload(0x3500)) -mstore(0x35c0, 21888242871839275222246405745257275088548364400416034343698204186575808495615) -mstore(0x35e0, 21888242871839275222246405745257275088548364400416034343698204186575808495617) -success := and(eq(staticcall(gas(), 0x5, 0x3540, 0xc0, 0x3520, 0x20), 1), success) +mstore(0x35c0, 32) +mstore(0x35e0, 32) +mstore(0x3600, 32) +mstore(0x3620, mload(0x3580)) +mstore(0x3640, 21888242871839275222246405745257275088548364400416034343698204186575808495615) +mstore(0x3660, 21888242871839275222246405745257275088548364400416034343698204186575808495617) +success := and(eq(staticcall(gas(), 0x5, 0x35c0, 0xc0, 0x35a0, 0x20), 1), success) { - let inv := mload(0x3520) + let inv := mload(0x35a0) let v - v := mload(0x3480) - mstore(13440, mulmod(mload(0x34e0), inv, f_q)) + v := mload(0x3500) + mstore(13568, mulmod(mload(0x3560), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3440) - mstore(13376, mulmod(mload(0x34c0), inv, f_q)) + v := mload(0x34c0) + mstore(13504, mulmod(mload(0x3540), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x3400) - mstore(13312, mulmod(mload(0x34a0), inv, f_q)) + v := mload(0x3480) + mstore(13440, mulmod(mload(0x3520), inv, f_q)) inv := mulmod(v, inv, f_q) - v := mload(0x33c0) - mstore(13248, mulmod(mload(0x3380), inv, f_q)) + v := mload(0x3440) + mstore(13376, mulmod(mload(0x3400), inv, f_q)) inv := mulmod(v, inv, f_q) - mstore(0x3380, inv) + mstore(0x3400, inv) } -mstore(0x3600, mulmod(mload(0x33a0), mload(0x33c0), f_q)) -mstore(0x3620, mulmod(mload(0x33e0), mload(0x3400), f_q)) -mstore(0x3640, mulmod(mload(0x3420), mload(0x3440), f_q)) -mstore(0x3660, mulmod(mload(0x3460), mload(0x3480), f_q)) -mstore(0x3680, mulmod(mload(0xae0), mload(0xae0), f_q)) -mstore(0x36a0, mulmod(mload(0x3680), mload(0xae0), f_q)) -mstore(0x36c0, mulmod(mload(0x36a0), mload(0xae0), f_q)) -mstore(0x36e0, mulmod(mload(0x36c0), mload(0xae0), f_q)) -mstore(0x3700, mulmod(mload(0x36e0), mload(0xae0), f_q)) -mstore(0x3720, mulmod(mload(0x3700), mload(0xae0), f_q)) -mstore(0x3740, mulmod(mload(0x3720), mload(0xae0), f_q)) -mstore(0x3760, mulmod(mload(0x3740), mload(0xae0), f_q)) -mstore(0x3780, mulmod(mload(0x3760), mload(0xae0), f_q)) -mstore(0x37a0, mulmod(mload(0x3780), mload(0xae0), f_q)) -mstore(0x37c0, mulmod(mload(0x37a0), mload(0xae0), f_q)) -mstore(0x37e0, mulmod(mload(0x37c0), mload(0xae0), f_q)) -mstore(0x3800, mulmod(mload(0xb40), mload(0xb40), f_q)) -mstore(0x3820, mulmod(mload(0x3800), mload(0xb40), f_q)) -mstore(0x3840, mulmod(mload(0x3820), mload(0xb40), f_q)) -mstore(0x3860, mulmod(mload(0x3840), mload(0xb40), f_q)) +mstore(0x3680, mulmod(mload(0x3420), mload(0x3440), f_q)) +mstore(0x36a0, mulmod(mload(0x3460), mload(0x3480), f_q)) +mstore(0x36c0, mulmod(mload(0x34a0), mload(0x34c0), f_q)) +mstore(0x36e0, mulmod(mload(0x34e0), mload(0x3500), f_q)) +mstore(0x3700, mulmod(mload(0xb60), mload(0xb60), f_q)) +mstore(0x3720, mulmod(mload(0x3700), mload(0xb60), f_q)) +mstore(0x3740, mulmod(mload(0x3720), mload(0xb60), f_q)) +mstore(0x3760, mulmod(mload(0x3740), mload(0xb60), f_q)) +mstore(0x3780, mulmod(mload(0x3760), mload(0xb60), f_q)) +mstore(0x37a0, mulmod(mload(0x3780), mload(0xb60), f_q)) +mstore(0x37c0, mulmod(mload(0x37a0), mload(0xb60), f_q)) +mstore(0x37e0, mulmod(mload(0x37c0), mload(0xb60), f_q)) +mstore(0x3800, mulmod(mload(0x37e0), mload(0xb60), f_q)) +mstore(0x3820, mulmod(mload(0x3800), mload(0xb60), f_q)) +mstore(0x3840, mulmod(mload(0x3820), mload(0xb60), f_q)) +mstore(0x3860, mulmod(mload(0x3840), mload(0xb60), f_q)) +mstore(0x3880, mulmod(mload(0xbc0), mload(0xbc0), f_q)) +mstore(0x38a0, mulmod(mload(0x3880), mload(0xbc0), f_q)) +mstore(0x38c0, mulmod(mload(0x38a0), mload(0xbc0), f_q)) +mstore(0x38e0, mulmod(mload(0x38c0), mload(0xbc0), f_q)) { - let result := mulmod(mload(0x6c0), mload(0x2c00), f_q) -result := addmod(mulmod(mload(0x6e0), mload(0x2c60), f_q), result, f_q) -result := addmod(mulmod(mload(0x700), mload(0x2cc0), f_q), result, f_q) -result := addmod(mulmod(mload(0x720), mload(0x2d20), f_q), result, f_q) -mstore(14464, result) - } -mstore(0x38a0, mulmod(mload(0x3880), mload(0x3380), f_q)) -mstore(0x38c0, mulmod(sub(f_q, mload(0x38a0)), 1, f_q)) + let result := mulmod(mload(0x740), mload(0x2c80), f_q) +result := addmod(mulmod(mload(0x760), mload(0x2ce0), f_q), result, f_q) +result := addmod(mulmod(mload(0x780), mload(0x2d40), f_q), result, f_q) +result := addmod(mulmod(mload(0x7a0), mload(0x2da0), f_q), result, f_q) +mstore(14592, result) + } +mstore(0x3920, mulmod(mload(0x3900), mload(0x3400), f_q)) +mstore(0x3940, mulmod(sub(f_q, mload(0x3920)), 1, f_q)) { - let result := mulmod(mload(0x740), mload(0x2c00), f_q) -result := addmod(mulmod(mload(0x760), mload(0x2c60), f_q), result, f_q) -result := addmod(mulmod(mload(0x780), mload(0x2cc0), f_q), result, f_q) -result := addmod(mulmod(mload(0x7a0), mload(0x2d20), f_q), result, f_q) -mstore(14560, result) - } -mstore(0x3900, mulmod(mload(0x38e0), mload(0x3380), f_q)) -mstore(0x3920, mulmod(sub(f_q, mload(0x3900)), mload(0xae0), f_q)) -mstore(0x3940, mulmod(1, mload(0xae0), f_q)) -mstore(0x3960, addmod(mload(0x38c0), mload(0x3920), f_q)) -mstore(0x3980, mulmod(mload(0x3960), 1, f_q)) -mstore(0x39a0, mulmod(mload(0x3940), 1, f_q)) -mstore(0x39c0, mulmod(1, mload(0x33a0), f_q)) -{ - let result := mulmod(mload(0x7c0), mload(0x2dc0), f_q) -mstore(14816, result) - } -mstore(0x3a00, mulmod(mload(0x39e0), mload(0x3600), f_q)) -mstore(0x3a20, mulmod(sub(f_q, mload(0x3a00)), 1, f_q)) -mstore(0x3a40, mulmod(mload(0x39c0), 1, f_q)) + let result := mulmod(mload(0x7c0), mload(0x2c80), f_q) +result := addmod(mulmod(mload(0x7e0), mload(0x2ce0), f_q), result, f_q) +result := addmod(mulmod(mload(0x800), mload(0x2d40), f_q), result, f_q) +result := addmod(mulmod(mload(0x820), mload(0x2da0), f_q), result, f_q) +mstore(14688, result) + } +mstore(0x3980, mulmod(mload(0x3960), mload(0x3400), f_q)) +mstore(0x39a0, mulmod(sub(f_q, mload(0x3980)), mload(0xb60), f_q)) +mstore(0x39c0, mulmod(1, mload(0xb60), f_q)) +mstore(0x39e0, addmod(mload(0x3940), mload(0x39a0), f_q)) +mstore(0x3a00, mulmod(mload(0x39e0), 1, f_q)) +mstore(0x3a20, mulmod(mload(0x39c0), 1, f_q)) +mstore(0x3a40, mulmod(1, mload(0x3420), f_q)) { - let result := mulmod(mload(0xaa0), mload(0x2dc0), f_q) + let result := mulmod(mload(0x840), mload(0x2e40), f_q) mstore(14944, result) } -mstore(0x3a80, mulmod(mload(0x3a60), mload(0x3600), f_q)) -mstore(0x3aa0, mulmod(sub(f_q, mload(0x3a80)), mload(0xae0), f_q)) -mstore(0x3ac0, mulmod(mload(0x39c0), mload(0xae0), f_q)) -mstore(0x3ae0, addmod(mload(0x3a20), mload(0x3aa0), f_q)) +mstore(0x3a80, mulmod(mload(0x3a60), mload(0x3680), f_q)) +mstore(0x3aa0, mulmod(sub(f_q, mload(0x3a80)), 1, f_q)) +mstore(0x3ac0, mulmod(mload(0x3a40), 1, f_q)) { - let result := mulmod(mload(0x7e0), mload(0x2dc0), f_q) -mstore(15104, result) + let result := mulmod(mload(0xb20), mload(0x2e40), f_q) +mstore(15072, result) } -mstore(0x3b20, mulmod(mload(0x3b00), mload(0x3600), f_q)) -mstore(0x3b40, mulmod(sub(f_q, mload(0x3b20)), mload(0x3680), f_q)) -mstore(0x3b60, mulmod(mload(0x39c0), mload(0x3680), f_q)) -mstore(0x3b80, addmod(mload(0x3ae0), mload(0x3b40), f_q)) +mstore(0x3b00, mulmod(mload(0x3ae0), mload(0x3680), f_q)) +mstore(0x3b20, mulmod(sub(f_q, mload(0x3b00)), mload(0xb60), f_q)) +mstore(0x3b40, mulmod(mload(0x3a40), mload(0xb60), f_q)) +mstore(0x3b60, addmod(mload(0x3aa0), mload(0x3b20), f_q)) { - let result := mulmod(mload(0x800), mload(0x2dc0), f_q) -mstore(15264, result) + let result := mulmod(mload(0x860), mload(0x2e40), f_q) +mstore(15232, result) } -mstore(0x3bc0, mulmod(mload(0x3ba0), mload(0x3600), f_q)) -mstore(0x3be0, mulmod(sub(f_q, mload(0x3bc0)), mload(0x36a0), f_q)) -mstore(0x3c00, mulmod(mload(0x39c0), mload(0x36a0), f_q)) -mstore(0x3c20, addmod(mload(0x3b80), mload(0x3be0), f_q)) +mstore(0x3ba0, mulmod(mload(0x3b80), mload(0x3680), f_q)) +mstore(0x3bc0, mulmod(sub(f_q, mload(0x3ba0)), mload(0x3700), f_q)) +mstore(0x3be0, mulmod(mload(0x3a40), mload(0x3700), f_q)) +mstore(0x3c00, addmod(mload(0x3b60), mload(0x3bc0), f_q)) { - let result := mulmod(mload(0x820), mload(0x2dc0), f_q) -mstore(15424, result) + let result := mulmod(mload(0x880), mload(0x2e40), f_q) +mstore(15392, result) } -mstore(0x3c60, mulmod(mload(0x3c40), mload(0x3600), f_q)) -mstore(0x3c80, mulmod(sub(f_q, mload(0x3c60)), mload(0x36c0), f_q)) -mstore(0x3ca0, mulmod(mload(0x39c0), mload(0x36c0), f_q)) -mstore(0x3cc0, addmod(mload(0x3c20), mload(0x3c80), f_q)) +mstore(0x3c40, mulmod(mload(0x3c20), mload(0x3680), f_q)) +mstore(0x3c60, mulmod(sub(f_q, mload(0x3c40)), mload(0x3720), f_q)) +mstore(0x3c80, mulmod(mload(0x3a40), mload(0x3720), f_q)) +mstore(0x3ca0, addmod(mload(0x3c00), mload(0x3c60), f_q)) { - let result := mulmod(mload(0x840), mload(0x2dc0), f_q) -mstore(15584, result) + let result := mulmod(mload(0x8a0), mload(0x2e40), f_q) +mstore(15552, result) } -mstore(0x3d00, mulmod(mload(0x3ce0), mload(0x3600), f_q)) -mstore(0x3d20, mulmod(sub(f_q, mload(0x3d00)), mload(0x36e0), f_q)) -mstore(0x3d40, mulmod(mload(0x39c0), mload(0x36e0), f_q)) -mstore(0x3d60, addmod(mload(0x3cc0), mload(0x3d20), f_q)) +mstore(0x3ce0, mulmod(mload(0x3cc0), mload(0x3680), f_q)) +mstore(0x3d00, mulmod(sub(f_q, mload(0x3ce0)), mload(0x3740), f_q)) +mstore(0x3d20, mulmod(mload(0x3a40), mload(0x3740), f_q)) +mstore(0x3d40, addmod(mload(0x3ca0), mload(0x3d00), f_q)) { - let result := mulmod(mload(0x880), mload(0x2dc0), f_q) -mstore(15744, result) + let result := mulmod(mload(0x8c0), mload(0x2e40), f_q) +mstore(15712, result) } -mstore(0x3da0, mulmod(mload(0x3d80), mload(0x3600), f_q)) -mstore(0x3dc0, mulmod(sub(f_q, mload(0x3da0)), mload(0x3700), f_q)) -mstore(0x3de0, mulmod(mload(0x39c0), mload(0x3700), f_q)) -mstore(0x3e00, addmod(mload(0x3d60), mload(0x3dc0), f_q)) +mstore(0x3d80, mulmod(mload(0x3d60), mload(0x3680), f_q)) +mstore(0x3da0, mulmod(sub(f_q, mload(0x3d80)), mload(0x3760), f_q)) +mstore(0x3dc0, mulmod(mload(0x3a40), mload(0x3760), f_q)) +mstore(0x3de0, addmod(mload(0x3d40), mload(0x3da0), f_q)) { - let result := mulmod(mload(0x8a0), mload(0x2dc0), f_q) -mstore(15904, result) + let result := mulmod(mload(0x900), mload(0x2e40), f_q) +mstore(15872, result) } -mstore(0x3e40, mulmod(mload(0x3e20), mload(0x3600), f_q)) -mstore(0x3e60, mulmod(sub(f_q, mload(0x3e40)), mload(0x3720), f_q)) -mstore(0x3e80, mulmod(mload(0x39c0), mload(0x3720), f_q)) -mstore(0x3ea0, addmod(mload(0x3e00), mload(0x3e60), f_q)) +mstore(0x3e20, mulmod(mload(0x3e00), mload(0x3680), f_q)) +mstore(0x3e40, mulmod(sub(f_q, mload(0x3e20)), mload(0x3780), f_q)) +mstore(0x3e60, mulmod(mload(0x3a40), mload(0x3780), f_q)) +mstore(0x3e80, addmod(mload(0x3de0), mload(0x3e40), f_q)) { - let result := mulmod(mload(0x8c0), mload(0x2dc0), f_q) -mstore(16064, result) + let result := mulmod(mload(0x920), mload(0x2e40), f_q) +mstore(16032, result) } -mstore(0x3ee0, mulmod(mload(0x3ec0), mload(0x3600), f_q)) -mstore(0x3f00, mulmod(sub(f_q, mload(0x3ee0)), mload(0x3740), f_q)) -mstore(0x3f20, mulmod(mload(0x39c0), mload(0x3740), f_q)) -mstore(0x3f40, addmod(mload(0x3ea0), mload(0x3f00), f_q)) +mstore(0x3ec0, mulmod(mload(0x3ea0), mload(0x3680), f_q)) +mstore(0x3ee0, mulmod(sub(f_q, mload(0x3ec0)), mload(0x37a0), f_q)) +mstore(0x3f00, mulmod(mload(0x3a40), mload(0x37a0), f_q)) +mstore(0x3f20, addmod(mload(0x3e80), mload(0x3ee0), f_q)) { - let result := mulmod(mload(0x8e0), mload(0x2dc0), f_q) -mstore(16224, result) + let result := mulmod(mload(0x940), mload(0x2e40), f_q) +mstore(16192, result) } -mstore(0x3f80, mulmod(mload(0x3f60), mload(0x3600), f_q)) -mstore(0x3fa0, mulmod(sub(f_q, mload(0x3f80)), mload(0x3760), f_q)) -mstore(0x3fc0, mulmod(mload(0x39c0), mload(0x3760), f_q)) -mstore(0x3fe0, addmod(mload(0x3f40), mload(0x3fa0), f_q)) +mstore(0x3f60, mulmod(mload(0x3f40), mload(0x3680), f_q)) +mstore(0x3f80, mulmod(sub(f_q, mload(0x3f60)), mload(0x37c0), f_q)) +mstore(0x3fa0, mulmod(mload(0x3a40), mload(0x37c0), f_q)) +mstore(0x3fc0, addmod(mload(0x3f20), mload(0x3f80), f_q)) { - let result := mulmod(mload(0x900), mload(0x2dc0), f_q) -mstore(16384, result) - } -mstore(0x4020, mulmod(mload(0x4000), mload(0x3600), f_q)) -mstore(0x4040, mulmod(sub(f_q, mload(0x4020)), mload(0x3780), f_q)) -mstore(0x4060, mulmod(mload(0x39c0), mload(0x3780), f_q)) -mstore(0x4080, addmod(mload(0x3fe0), mload(0x4040), f_q)) -mstore(0x40a0, mulmod(mload(0x29a0), mload(0x33a0), f_q)) -mstore(0x40c0, mulmod(mload(0x29c0), mload(0x33a0), f_q)) + let result := mulmod(mload(0x960), mload(0x2e40), f_q) +mstore(16352, result) + } +mstore(0x4000, mulmod(mload(0x3fe0), mload(0x3680), f_q)) +mstore(0x4020, mulmod(sub(f_q, mload(0x4000)), mload(0x37e0), f_q)) +mstore(0x4040, mulmod(mload(0x3a40), mload(0x37e0), f_q)) +mstore(0x4060, addmod(mload(0x3fc0), mload(0x4020), f_q)) { - let result := mulmod(mload(0x29e0), mload(0x2dc0), f_q) -mstore(16608, result) - } -mstore(0x4100, mulmod(mload(0x40e0), mload(0x3600), f_q)) -mstore(0x4120, mulmod(sub(f_q, mload(0x4100)), mload(0x37a0), f_q)) -mstore(0x4140, mulmod(mload(0x39c0), mload(0x37a0), f_q)) -mstore(0x4160, mulmod(mload(0x40a0), mload(0x37a0), f_q)) -mstore(0x4180, mulmod(mload(0x40c0), mload(0x37a0), f_q)) -mstore(0x41a0, addmod(mload(0x4080), mload(0x4120), f_q)) + let result := mulmod(mload(0x980), mload(0x2e40), f_q) +mstore(16512, result) + } +mstore(0x40a0, mulmod(mload(0x4080), mload(0x3680), f_q)) +mstore(0x40c0, mulmod(sub(f_q, mload(0x40a0)), mload(0x3800), f_q)) +mstore(0x40e0, mulmod(mload(0x3a40), mload(0x3800), f_q)) +mstore(0x4100, addmod(mload(0x4060), mload(0x40c0), f_q)) +mstore(0x4120, mulmod(mload(0x2a20), mload(0x3420), f_q)) +mstore(0x4140, mulmod(mload(0x2a40), mload(0x3420), f_q)) { - let result := mulmod(mload(0x860), mload(0x2dc0), f_q) -mstore(16832, result) - } -mstore(0x41e0, mulmod(mload(0x41c0), mload(0x3600), f_q)) -mstore(0x4200, mulmod(sub(f_q, mload(0x41e0)), mload(0x37c0), f_q)) -mstore(0x4220, mulmod(mload(0x39c0), mload(0x37c0), f_q)) -mstore(0x4240, addmod(mload(0x41a0), mload(0x4200), f_q)) -mstore(0x4260, mulmod(mload(0x4240), mload(0xb40), f_q)) -mstore(0x4280, mulmod(mload(0x3a40), mload(0xb40), f_q)) -mstore(0x42a0, mulmod(mload(0x3ac0), mload(0xb40), f_q)) -mstore(0x42c0, mulmod(mload(0x3b60), mload(0xb40), f_q)) -mstore(0x42e0, mulmod(mload(0x3c00), mload(0xb40), f_q)) -mstore(0x4300, mulmod(mload(0x3ca0), mload(0xb40), f_q)) -mstore(0x4320, mulmod(mload(0x3d40), mload(0xb40), f_q)) -mstore(0x4340, mulmod(mload(0x3de0), mload(0xb40), f_q)) -mstore(0x4360, mulmod(mload(0x3e80), mload(0xb40), f_q)) -mstore(0x4380, mulmod(mload(0x3f20), mload(0xb40), f_q)) -mstore(0x43a0, mulmod(mload(0x3fc0), mload(0xb40), f_q)) -mstore(0x43c0, mulmod(mload(0x4060), mload(0xb40), f_q)) -mstore(0x43e0, mulmod(mload(0x4140), mload(0xb40), f_q)) -mstore(0x4400, mulmod(mload(0x4160), mload(0xb40), f_q)) -mstore(0x4420, mulmod(mload(0x4180), mload(0xb40), f_q)) -mstore(0x4440, mulmod(mload(0x4220), mload(0xb40), f_q)) -mstore(0x4460, addmod(mload(0x3980), mload(0x4260), f_q)) -mstore(0x4480, mulmod(1, mload(0x33e0), f_q)) + let result := mulmod(mload(0x2a60), mload(0x2e40), f_q) +mstore(16736, result) + } +mstore(0x4180, mulmod(mload(0x4160), mload(0x3680), f_q)) +mstore(0x41a0, mulmod(sub(f_q, mload(0x4180)), mload(0x3820), f_q)) +mstore(0x41c0, mulmod(mload(0x3a40), mload(0x3820), f_q)) +mstore(0x41e0, mulmod(mload(0x4120), mload(0x3820), f_q)) +mstore(0x4200, mulmod(mload(0x4140), mload(0x3820), f_q)) +mstore(0x4220, addmod(mload(0x4100), mload(0x41a0), f_q)) { - let result := mulmod(mload(0x920), mload(0x2e20), f_q) -result := addmod(mulmod(mload(0x940), mload(0x2e80), f_q), result, f_q) -result := addmod(mulmod(mload(0x960), mload(0x2ee0), f_q), result, f_q) -mstore(17568, result) - } -mstore(0x44c0, mulmod(mload(0x44a0), mload(0x3620), f_q)) -mstore(0x44e0, mulmod(sub(f_q, mload(0x44c0)), 1, f_q)) -mstore(0x4500, mulmod(mload(0x4480), 1, f_q)) + let result := mulmod(mload(0x8e0), mload(0x2e40), f_q) +mstore(16960, result) + } +mstore(0x4260, mulmod(mload(0x4240), mload(0x3680), f_q)) +mstore(0x4280, mulmod(sub(f_q, mload(0x4260)), mload(0x3840), f_q)) +mstore(0x42a0, mulmod(mload(0x3a40), mload(0x3840), f_q)) +mstore(0x42c0, addmod(mload(0x4220), mload(0x4280), f_q)) +mstore(0x42e0, mulmod(mload(0x42c0), mload(0xbc0), f_q)) +mstore(0x4300, mulmod(mload(0x3ac0), mload(0xbc0), f_q)) +mstore(0x4320, mulmod(mload(0x3b40), mload(0xbc0), f_q)) +mstore(0x4340, mulmod(mload(0x3be0), mload(0xbc0), f_q)) +mstore(0x4360, mulmod(mload(0x3c80), mload(0xbc0), f_q)) +mstore(0x4380, mulmod(mload(0x3d20), mload(0xbc0), f_q)) +mstore(0x43a0, mulmod(mload(0x3dc0), mload(0xbc0), f_q)) +mstore(0x43c0, mulmod(mload(0x3e60), mload(0xbc0), f_q)) +mstore(0x43e0, mulmod(mload(0x3f00), mload(0xbc0), f_q)) +mstore(0x4400, mulmod(mload(0x3fa0), mload(0xbc0), f_q)) +mstore(0x4420, mulmod(mload(0x4040), mload(0xbc0), f_q)) +mstore(0x4440, mulmod(mload(0x40e0), mload(0xbc0), f_q)) +mstore(0x4460, mulmod(mload(0x41c0), mload(0xbc0), f_q)) +mstore(0x4480, mulmod(mload(0x41e0), mload(0xbc0), f_q)) +mstore(0x44a0, mulmod(mload(0x4200), mload(0xbc0), f_q)) +mstore(0x44c0, mulmod(mload(0x42a0), mload(0xbc0), f_q)) +mstore(0x44e0, addmod(mload(0x3a00), mload(0x42e0), f_q)) +mstore(0x4500, mulmod(1, mload(0x3460), f_q)) { - let result := mulmod(mload(0x980), mload(0x2e20), f_q) -result := addmod(mulmod(mload(0x9a0), mload(0x2e80), f_q), result, f_q) -result := addmod(mulmod(mload(0x9c0), mload(0x2ee0), f_q), result, f_q) + let result := mulmod(mload(0x9a0), mload(0x2ea0), f_q) +result := addmod(mulmod(mload(0x9c0), mload(0x2f00), f_q), result, f_q) +result := addmod(mulmod(mload(0x9e0), mload(0x2f60), f_q), result, f_q) mstore(17696, result) } -mstore(0x4540, mulmod(mload(0x4520), mload(0x3620), f_q)) -mstore(0x4560, mulmod(sub(f_q, mload(0x4540)), mload(0xae0), f_q)) -mstore(0x4580, mulmod(mload(0x4480), mload(0xae0), f_q)) -mstore(0x45a0, addmod(mload(0x44e0), mload(0x4560), f_q)) -mstore(0x45c0, mulmod(mload(0x45a0), mload(0x3800), f_q)) -mstore(0x45e0, mulmod(mload(0x4500), mload(0x3800), f_q)) -mstore(0x4600, mulmod(mload(0x4580), mload(0x3800), f_q)) -mstore(0x4620, addmod(mload(0x4460), mload(0x45c0), f_q)) -mstore(0x4640, mulmod(1, mload(0x3420), f_q)) +mstore(0x4540, mulmod(mload(0x4520), mload(0x36a0), f_q)) +mstore(0x4560, mulmod(sub(f_q, mload(0x4540)), 1, f_q)) +mstore(0x4580, mulmod(mload(0x4500), 1, f_q)) { - let result := mulmod(mload(0x9e0), mload(0x2f60), f_q) -result := addmod(mulmod(mload(0xa00), mload(0x2fc0), f_q), result, f_q) -mstore(18016, result) - } -mstore(0x4680, mulmod(mload(0x4660), mload(0x3640), f_q)) -mstore(0x46a0, mulmod(sub(f_q, mload(0x4680)), 1, f_q)) -mstore(0x46c0, mulmod(mload(0x4640), 1, f_q)) + let result := mulmod(mload(0xa00), mload(0x2ea0), f_q) +result := addmod(mulmod(mload(0xa20), mload(0x2f00), f_q), result, f_q) +result := addmod(mulmod(mload(0xa40), mload(0x2f60), f_q), result, f_q) +mstore(17824, result) + } +mstore(0x45c0, mulmod(mload(0x45a0), mload(0x36a0), f_q)) +mstore(0x45e0, mulmod(sub(f_q, mload(0x45c0)), mload(0xb60), f_q)) +mstore(0x4600, mulmod(mload(0x4500), mload(0xb60), f_q)) +mstore(0x4620, addmod(mload(0x4560), mload(0x45e0), f_q)) +mstore(0x4640, mulmod(mload(0x4620), mload(0x3880), f_q)) +mstore(0x4660, mulmod(mload(0x4580), mload(0x3880), f_q)) +mstore(0x4680, mulmod(mload(0x4600), mload(0x3880), f_q)) +mstore(0x46a0, addmod(mload(0x44e0), mload(0x4640), f_q)) +mstore(0x46c0, mulmod(1, mload(0x34a0), f_q)) { - let result := mulmod(mload(0xa20), mload(0x2f60), f_q) -result := addmod(mulmod(mload(0xa40), mload(0x2fc0), f_q), result, f_q) + let result := mulmod(mload(0xa60), mload(0x2fe0), f_q) +result := addmod(mulmod(mload(0xa80), mload(0x3040), f_q), result, f_q) mstore(18144, result) } -mstore(0x4700, mulmod(mload(0x46e0), mload(0x3640), f_q)) -mstore(0x4720, mulmod(sub(f_q, mload(0x4700)), mload(0xae0), f_q)) -mstore(0x4740, mulmod(mload(0x4640), mload(0xae0), f_q)) -mstore(0x4760, addmod(mload(0x46a0), mload(0x4720), f_q)) -mstore(0x4780, mulmod(mload(0x4760), mload(0x3820), f_q)) -mstore(0x47a0, mulmod(mload(0x46c0), mload(0x3820), f_q)) -mstore(0x47c0, mulmod(mload(0x4740), mload(0x3820), f_q)) -mstore(0x47e0, addmod(mload(0x4620), mload(0x4780), f_q)) -mstore(0x4800, mulmod(1, mload(0x3460), f_q)) +mstore(0x4700, mulmod(mload(0x46e0), mload(0x36c0), f_q)) +mstore(0x4720, mulmod(sub(f_q, mload(0x4700)), 1, f_q)) +mstore(0x4740, mulmod(mload(0x46c0), 1, f_q)) +{ + let result := mulmod(mload(0xaa0), mload(0x2fe0), f_q) +result := addmod(mulmod(mload(0xac0), mload(0x3040), f_q), result, f_q) +mstore(18272, result) + } +mstore(0x4780, mulmod(mload(0x4760), mload(0x36c0), f_q)) +mstore(0x47a0, mulmod(sub(f_q, mload(0x4780)), mload(0xb60), f_q)) +mstore(0x47c0, mulmod(mload(0x46c0), mload(0xb60), f_q)) +mstore(0x47e0, addmod(mload(0x4720), mload(0x47a0), f_q)) +mstore(0x4800, mulmod(mload(0x47e0), mload(0x38a0), f_q)) +mstore(0x4820, mulmod(mload(0x4740), mload(0x38a0), f_q)) +mstore(0x4840, mulmod(mload(0x47c0), mload(0x38a0), f_q)) +mstore(0x4860, addmod(mload(0x46a0), mload(0x4800), f_q)) +mstore(0x4880, mulmod(1, mload(0x34e0), f_q)) { - let result := mulmod(mload(0xa60), mload(0x3020), f_q) -result := addmod(mulmod(mload(0xa80), mload(0x3080), f_q), result, f_q) -mstore(18464, result) - } -mstore(0x4840, mulmod(mload(0x4820), mload(0x3660), f_q)) -mstore(0x4860, mulmod(sub(f_q, mload(0x4840)), 1, f_q)) -mstore(0x4880, mulmod(mload(0x4800), 1, f_q)) -mstore(0x48a0, mulmod(mload(0x4860), mload(0x3840), f_q)) -mstore(0x48c0, mulmod(mload(0x4880), mload(0x3840), f_q)) -mstore(0x48e0, addmod(mload(0x47e0), mload(0x48a0), f_q)) -mstore(0x4900, mulmod(1, mload(0x2da0), f_q)) -mstore(0x4920, mulmod(1, mload(0xbe0), f_q)) -mstore(0x4940, 0x0000000000000000000000000000000000000000000000000000000000000001) - mstore(0x4960, 0x0000000000000000000000000000000000000000000000000000000000000002) -mstore(0x4980, mload(0x48e0)) -success := and(eq(staticcall(gas(), 0x7, 0x4940, 0x60, 0x4940, 0x40), 1), success) -mstore(0x49a0, mload(0x4940)) - mstore(0x49c0, mload(0x4960)) -mstore(0x49e0, mload(0x1a0)) - mstore(0x4a00, mload(0x1c0)) -success := and(eq(staticcall(gas(), 0x6, 0x49a0, 0x80, 0x49a0, 0x40), 1), success) -mstore(0x4a20, mload(0x1e0)) - mstore(0x4a40, mload(0x200)) -mstore(0x4a60, mload(0x39a0)) -success := and(eq(staticcall(gas(), 0x7, 0x4a20, 0x60, 0x4a20, 0x40), 1), success) -mstore(0x4a80, mload(0x49a0)) - mstore(0x4aa0, mload(0x49c0)) -mstore(0x4ac0, mload(0x4a20)) - mstore(0x4ae0, mload(0x4a40)) -success := and(eq(staticcall(gas(), 0x6, 0x4a80, 0x80, 0x4a80, 0x40), 1), success) -mstore(0x4b00, mload(0x220)) - mstore(0x4b20, mload(0x240)) -mstore(0x4b40, mload(0x4280)) -success := and(eq(staticcall(gas(), 0x7, 0x4b00, 0x60, 0x4b00, 0x40), 1), success) -mstore(0x4b60, mload(0x4a80)) - mstore(0x4b80, mload(0x4aa0)) -mstore(0x4ba0, mload(0x4b00)) - mstore(0x4bc0, mload(0x4b20)) -success := and(eq(staticcall(gas(), 0x6, 0x4b60, 0x80, 0x4b60, 0x40), 1), success) -mstore(0x4be0, mload(0x300)) - mstore(0x4c00, mload(0x320)) -mstore(0x4c20, mload(0x42a0)) -success := and(eq(staticcall(gas(), 0x7, 0x4be0, 0x60, 0x4be0, 0x40), 1), success) -mstore(0x4c40, mload(0x4b60)) - mstore(0x4c60, mload(0x4b80)) -mstore(0x4c80, mload(0x4be0)) - mstore(0x4ca0, mload(0x4c00)) -success := and(eq(staticcall(gas(), 0x6, 0x4c40, 0x80, 0x4c40, 0x40), 1), success) -mstore(0x4cc0, 0x0a56bb24bdbd10b2ae380a0f6d2926afe21e55ef423d664a7093bdc47d7a970d) - mstore(0x4ce0, 0x3046067f3fbc66fb8322b30a454654489ad23370423a63caeab071e10143c65d) -mstore(0x4d00, mload(0x42c0)) -success := and(eq(staticcall(gas(), 0x7, 0x4cc0, 0x60, 0x4cc0, 0x40), 1), success) -mstore(0x4d20, mload(0x4c40)) - mstore(0x4d40, mload(0x4c60)) -mstore(0x4d60, mload(0x4cc0)) - mstore(0x4d80, mload(0x4ce0)) -success := and(eq(staticcall(gas(), 0x6, 0x4d20, 0x80, 0x4d20, 0x40), 1), success) -mstore(0x4da0, 0x165f42d12623508ec09f1a14ffe3841e636362840bcfe45fd4f0847a50968d91) - mstore(0x4dc0, 0x19664a50abfa10f51e0eb96bf39b959cd2ebd0ed52c60bc0d4e8535272a13ed9) -mstore(0x4de0, mload(0x42e0)) -success := and(eq(staticcall(gas(), 0x7, 0x4da0, 0x60, 0x4da0, 0x40), 1), success) -mstore(0x4e00, mload(0x4d20)) - mstore(0x4e20, mload(0x4d40)) -mstore(0x4e40, mload(0x4da0)) - mstore(0x4e60, mload(0x4dc0)) -success := and(eq(staticcall(gas(), 0x6, 0x4e00, 0x80, 0x4e00, 0x40), 1), success) -mstore(0x4e80, 0x0c7dc4e4516515f0050b10e6891a60f39ab7645bbf2134080574b9ae26a3fee2) - mstore(0x4ea0, 0x2ee3484a156715514bcc56f95e316bb23031b7460f679ebb427a7f8ad73aead2) -mstore(0x4ec0, mload(0x4300)) -success := and(eq(staticcall(gas(), 0x7, 0x4e80, 0x60, 0x4e80, 0x40), 1), success) -mstore(0x4ee0, mload(0x4e00)) - mstore(0x4f00, mload(0x4e20)) -mstore(0x4f20, mload(0x4e80)) - mstore(0x4f40, mload(0x4ea0)) -success := and(eq(staticcall(gas(), 0x6, 0x4ee0, 0x80, 0x4ee0, 0x40), 1), success) -mstore(0x4f60, 0x2fb1bc5dc1a8a163ac673f110c7ced2581955a8d47770fced15a66d8199a5c91) - mstore(0x4f80, 0x18f7802cf51055b658637bf93f53fcc4dbe4218c03cb54c9d3e74534e1b9cb8f) -mstore(0x4fa0, mload(0x4320)) -success := and(eq(staticcall(gas(), 0x7, 0x4f60, 0x60, 0x4f60, 0x40), 1), success) -mstore(0x4fc0, mload(0x4ee0)) - mstore(0x4fe0, mload(0x4f00)) -mstore(0x5000, mload(0x4f60)) - mstore(0x5020, mload(0x4f80)) -success := and(eq(staticcall(gas(), 0x6, 0x4fc0, 0x80, 0x4fc0, 0x40), 1), success) -mstore(0x5040, 0x2051ae2329a00ab4684564c9db909204379c6404686b9bb004253a0e87937c1a) - mstore(0x5060, 0x2228d27991956786c7b7ed829027a4268a8f57d342e507683aaaea7046a1721b) -mstore(0x5080, mload(0x4340)) -success := and(eq(staticcall(gas(), 0x7, 0x5040, 0x60, 0x5040, 0x40), 1), success) -mstore(0x50a0, mload(0x4fc0)) - mstore(0x50c0, mload(0x4fe0)) -mstore(0x50e0, mload(0x5040)) - mstore(0x5100, mload(0x5060)) -success := and(eq(staticcall(gas(), 0x6, 0x50a0, 0x80, 0x50a0, 0x40), 1), success) -mstore(0x5120, 0x144e8b5cd066532d7a019f3061d407aeb922b3a37125d39cee71a336088a8d57) - mstore(0x5140, 0x0465b8271620ef2988dbb05e0e32f58c14ee4aaec69263d36175afc35b129dc8) -mstore(0x5160, mload(0x4360)) -success := and(eq(staticcall(gas(), 0x7, 0x5120, 0x60, 0x5120, 0x40), 1), success) -mstore(0x5180, mload(0x50a0)) - mstore(0x51a0, mload(0x50c0)) -mstore(0x51c0, mload(0x5120)) - mstore(0x51e0, mload(0x5140)) -success := and(eq(staticcall(gas(), 0x6, 0x5180, 0x80, 0x5180, 0x40), 1), success) -mstore(0x5200, 0x2c5cb6e96533664432584b4373fc01286cb8aa2c8a7f05eac98fc5bc689e65bf) - mstore(0x5220, 0x2c6a00e02442db4548c0583842d7c460dfaba5a8ae3d86ca57b0d7c82d7090c8) -mstore(0x5240, mload(0x4380)) -success := and(eq(staticcall(gas(), 0x7, 0x5200, 0x60, 0x5200, 0x40), 1), success) -mstore(0x5260, mload(0x5180)) - mstore(0x5280, mload(0x51a0)) -mstore(0x52a0, mload(0x5200)) - mstore(0x52c0, mload(0x5220)) -success := and(eq(staticcall(gas(), 0x6, 0x5260, 0x80, 0x5260, 0x40), 1), success) -mstore(0x52e0, 0x2b737ba20cacc46db1394cb36a1cb92566946b943314b7037d038fbb83f233a8) - mstore(0x5300, 0x04dc42ddd6eb4c1c43a1175bc70c5b5c92577f968055708b4beeb22cea5cff99) -mstore(0x5320, mload(0x43a0)) -success := and(eq(staticcall(gas(), 0x7, 0x52e0, 0x60, 0x52e0, 0x40), 1), success) -mstore(0x5340, mload(0x5260)) - mstore(0x5360, mload(0x5280)) -mstore(0x5380, mload(0x52e0)) - mstore(0x53a0, mload(0x5300)) -success := and(eq(staticcall(gas(), 0x6, 0x5340, 0x80, 0x5340, 0x40), 1), success) -mstore(0x53c0, 0x0ff2ba345398269313967c25483b19e5e2de27f76a3a4357408c35dc42ddfec3) - mstore(0x53e0, 0x063d5c171abc02e7d09324a4f1bb6493d0584767678901f452ebc7f285037015) -mstore(0x5400, mload(0x43c0)) -success := and(eq(staticcall(gas(), 0x7, 0x53c0, 0x60, 0x53c0, 0x40), 1), success) -mstore(0x5420, mload(0x5340)) - mstore(0x5440, mload(0x5360)) -mstore(0x5460, mload(0x53c0)) - mstore(0x5480, mload(0x53e0)) -success := and(eq(staticcall(gas(), 0x6, 0x5420, 0x80, 0x5420, 0x40), 1), success) -mstore(0x54a0, mload(0x5a0)) - mstore(0x54c0, mload(0x5c0)) -mstore(0x54e0, mload(0x43e0)) -success := and(eq(staticcall(gas(), 0x7, 0x54a0, 0x60, 0x54a0, 0x40), 1), success) -mstore(0x5500, mload(0x5420)) - mstore(0x5520, mload(0x5440)) -mstore(0x5540, mload(0x54a0)) - mstore(0x5560, mload(0x54c0)) -success := and(eq(staticcall(gas(), 0x6, 0x5500, 0x80, 0x5500, 0x40), 1), success) -mstore(0x5580, mload(0x5e0)) - mstore(0x55a0, mload(0x600)) -mstore(0x55c0, mload(0x4400)) -success := and(eq(staticcall(gas(), 0x7, 0x5580, 0x60, 0x5580, 0x40), 1), success) -mstore(0x55e0, mload(0x5500)) - mstore(0x5600, mload(0x5520)) -mstore(0x5620, mload(0x5580)) - mstore(0x5640, mload(0x55a0)) -success := and(eq(staticcall(gas(), 0x6, 0x55e0, 0x80, 0x55e0, 0x40), 1), success) -mstore(0x5660, mload(0x620)) - mstore(0x5680, mload(0x640)) -mstore(0x56a0, mload(0x4420)) -success := and(eq(staticcall(gas(), 0x7, 0x5660, 0x60, 0x5660, 0x40), 1), success) -mstore(0x56c0, mload(0x55e0)) - mstore(0x56e0, mload(0x5600)) -mstore(0x5700, mload(0x5660)) - mstore(0x5720, mload(0x5680)) -success := and(eq(staticcall(gas(), 0x6, 0x56c0, 0x80, 0x56c0, 0x40), 1), success) -mstore(0x5740, mload(0x500)) - mstore(0x5760, mload(0x520)) -mstore(0x5780, mload(0x4440)) -success := and(eq(staticcall(gas(), 0x7, 0x5740, 0x60, 0x5740, 0x40), 1), success) -mstore(0x57a0, mload(0x56c0)) - mstore(0x57c0, mload(0x56e0)) -mstore(0x57e0, mload(0x5740)) - mstore(0x5800, mload(0x5760)) -success := and(eq(staticcall(gas(), 0x6, 0x57a0, 0x80, 0x57a0, 0x40), 1), success) -mstore(0x5820, mload(0x400)) - mstore(0x5840, mload(0x420)) -mstore(0x5860, mload(0x45e0)) -success := and(eq(staticcall(gas(), 0x7, 0x5820, 0x60, 0x5820, 0x40), 1), success) -mstore(0x5880, mload(0x57a0)) - mstore(0x58a0, mload(0x57c0)) -mstore(0x58c0, mload(0x5820)) - mstore(0x58e0, mload(0x5840)) -success := and(eq(staticcall(gas(), 0x6, 0x5880, 0x80, 0x5880, 0x40), 1), success) -mstore(0x5900, mload(0x440)) - mstore(0x5920, mload(0x460)) -mstore(0x5940, mload(0x4600)) -success := and(eq(staticcall(gas(), 0x7, 0x5900, 0x60, 0x5900, 0x40), 1), success) -mstore(0x5960, mload(0x5880)) - mstore(0x5980, mload(0x58a0)) -mstore(0x59a0, mload(0x5900)) - mstore(0x59c0, mload(0x5920)) -success := and(eq(staticcall(gas(), 0x6, 0x5960, 0x80, 0x5960, 0x40), 1), success) -mstore(0x59e0, mload(0x480)) - mstore(0x5a00, mload(0x4a0)) -mstore(0x5a20, mload(0x47a0)) -success := and(eq(staticcall(gas(), 0x7, 0x59e0, 0x60, 0x59e0, 0x40), 1), success) -mstore(0x5a40, mload(0x5960)) - mstore(0x5a60, mload(0x5980)) -mstore(0x5a80, mload(0x59e0)) - mstore(0x5aa0, mload(0x5a00)) -success := and(eq(staticcall(gas(), 0x6, 0x5a40, 0x80, 0x5a40, 0x40), 1), success) -mstore(0x5ac0, mload(0x4c0)) - mstore(0x5ae0, mload(0x4e0)) -mstore(0x5b00, mload(0x47c0)) -success := and(eq(staticcall(gas(), 0x7, 0x5ac0, 0x60, 0x5ac0, 0x40), 1), success) -mstore(0x5b20, mload(0x5a40)) - mstore(0x5b40, mload(0x5a60)) -mstore(0x5b60, mload(0x5ac0)) - mstore(0x5b80, mload(0x5ae0)) -success := and(eq(staticcall(gas(), 0x6, 0x5b20, 0x80, 0x5b20, 0x40), 1), success) -mstore(0x5ba0, mload(0x2c0)) - mstore(0x5bc0, mload(0x2e0)) -mstore(0x5be0, mload(0x48c0)) -success := and(eq(staticcall(gas(), 0x7, 0x5ba0, 0x60, 0x5ba0, 0x40), 1), success) -mstore(0x5c00, mload(0x5b20)) - mstore(0x5c20, mload(0x5b40)) -mstore(0x5c40, mload(0x5ba0)) - mstore(0x5c60, mload(0x5bc0)) -success := and(eq(staticcall(gas(), 0x6, 0x5c00, 0x80, 0x5c00, 0x40), 1), success) -mstore(0x5c80, mload(0xb80)) - mstore(0x5ca0, mload(0xba0)) -mstore(0x5cc0, sub(f_q, mload(0x4900))) -success := and(eq(staticcall(gas(), 0x7, 0x5c80, 0x60, 0x5c80, 0x40), 1), success) -mstore(0x5ce0, mload(0x5c00)) - mstore(0x5d00, mload(0x5c20)) -mstore(0x5d20, mload(0x5c80)) - mstore(0x5d40, mload(0x5ca0)) -success := and(eq(staticcall(gas(), 0x6, 0x5ce0, 0x80, 0x5ce0, 0x40), 1), success) -mstore(0x5d60, mload(0xc20)) - mstore(0x5d80, mload(0xc40)) -mstore(0x5da0, mload(0x4920)) -success := and(eq(staticcall(gas(), 0x7, 0x5d60, 0x60, 0x5d60, 0x40), 1), success) -mstore(0x5dc0, mload(0x5ce0)) - mstore(0x5de0, mload(0x5d00)) -mstore(0x5e00, mload(0x5d60)) - mstore(0x5e20, mload(0x5d80)) -success := and(eq(staticcall(gas(), 0x6, 0x5dc0, 0x80, 0x5dc0, 0x40), 1), success) -mstore(0x5e40, mload(0x5dc0)) - mstore(0x5e60, mload(0x5de0)) -mstore(0x5e80, mload(0xc20)) - mstore(0x5ea0, mload(0xc40)) -mstore(0x5ec0, mload(0xc60)) - mstore(0x5ee0, mload(0xc80)) + let result := mulmod(mload(0xae0), mload(0x30a0), f_q) +result := addmod(mulmod(mload(0xb00), mload(0x3100), f_q), result, f_q) +mstore(18592, result) + } +mstore(0x48c0, mulmod(mload(0x48a0), mload(0x36e0), f_q)) +mstore(0x48e0, mulmod(sub(f_q, mload(0x48c0)), 1, f_q)) +mstore(0x4900, mulmod(mload(0x4880), 1, f_q)) +mstore(0x4920, mulmod(mload(0x48e0), mload(0x38c0), f_q)) +mstore(0x4940, mulmod(mload(0x4900), mload(0x38c0), f_q)) +mstore(0x4960, addmod(mload(0x4860), mload(0x4920), f_q)) +mstore(0x4980, mulmod(1, mload(0x2e20), f_q)) +mstore(0x49a0, mulmod(1, mload(0xc60), f_q)) +mstore(0x49c0, 0x0000000000000000000000000000000000000000000000000000000000000001) + mstore(0x49e0, 0x0000000000000000000000000000000000000000000000000000000000000002) +mstore(0x4a00, mload(0x4960)) +success := and(eq(staticcall(gas(), 0x7, 0x49c0, 0x60, 0x49c0, 0x40), 1), success) +mstore(0x4a20, mload(0x49c0)) + mstore(0x4a40, mload(0x49e0)) +mstore(0x4a60, mload(0x220)) + mstore(0x4a80, mload(0x240)) +success := and(eq(staticcall(gas(), 0x6, 0x4a20, 0x80, 0x4a20, 0x40), 1), success) +mstore(0x4aa0, mload(0x260)) + mstore(0x4ac0, mload(0x280)) +mstore(0x4ae0, mload(0x3a20)) +success := and(eq(staticcall(gas(), 0x7, 0x4aa0, 0x60, 0x4aa0, 0x40), 1), success) +mstore(0x4b00, mload(0x4a20)) + mstore(0x4b20, mload(0x4a40)) +mstore(0x4b40, mload(0x4aa0)) + mstore(0x4b60, mload(0x4ac0)) +success := and(eq(staticcall(gas(), 0x6, 0x4b00, 0x80, 0x4b00, 0x40), 1), success) +mstore(0x4b80, mload(0x2a0)) + mstore(0x4ba0, mload(0x2c0)) +mstore(0x4bc0, mload(0x4300)) +success := and(eq(staticcall(gas(), 0x7, 0x4b80, 0x60, 0x4b80, 0x40), 1), success) +mstore(0x4be0, mload(0x4b00)) + mstore(0x4c00, mload(0x4b20)) +mstore(0x4c20, mload(0x4b80)) + mstore(0x4c40, mload(0x4ba0)) +success := and(eq(staticcall(gas(), 0x6, 0x4be0, 0x80, 0x4be0, 0x40), 1), success) +mstore(0x4c60, mload(0x380)) + mstore(0x4c80, mload(0x3a0)) +mstore(0x4ca0, mload(0x4320)) +success := and(eq(staticcall(gas(), 0x7, 0x4c60, 0x60, 0x4c60, 0x40), 1), success) +mstore(0x4cc0, mload(0x4be0)) + mstore(0x4ce0, mload(0x4c00)) +mstore(0x4d00, mload(0x4c60)) + mstore(0x4d20, mload(0x4c80)) +success := and(eq(staticcall(gas(), 0x6, 0x4cc0, 0x80, 0x4cc0, 0x40), 1), success) +mstore(0x4d40, 0x0a56bb24bdbd10b2ae380a0f6d2926afe21e55ef423d664a7093bdc47d7a970d) + mstore(0x4d60, 0x3046067f3fbc66fb8322b30a454654489ad23370423a63caeab071e10143c65d) +mstore(0x4d80, mload(0x4340)) +success := and(eq(staticcall(gas(), 0x7, 0x4d40, 0x60, 0x4d40, 0x40), 1), success) +mstore(0x4da0, mload(0x4cc0)) + mstore(0x4dc0, mload(0x4ce0)) +mstore(0x4de0, mload(0x4d40)) + mstore(0x4e00, mload(0x4d60)) +success := and(eq(staticcall(gas(), 0x6, 0x4da0, 0x80, 0x4da0, 0x40), 1), success) +mstore(0x4e20, 0x165f42d12623508ec09f1a14ffe3841e636362840bcfe45fd4f0847a50968d91) + mstore(0x4e40, 0x19664a50abfa10f51e0eb96bf39b959cd2ebd0ed52c60bc0d4e8535272a13ed9) +mstore(0x4e60, mload(0x4360)) +success := and(eq(staticcall(gas(), 0x7, 0x4e20, 0x60, 0x4e20, 0x40), 1), success) +mstore(0x4e80, mload(0x4da0)) + mstore(0x4ea0, mload(0x4dc0)) +mstore(0x4ec0, mload(0x4e20)) + mstore(0x4ee0, mload(0x4e40)) +success := and(eq(staticcall(gas(), 0x6, 0x4e80, 0x80, 0x4e80, 0x40), 1), success) +mstore(0x4f00, 0x0c7dc4e4516515f0050b10e6891a60f39ab7645bbf2134080574b9ae26a3fee2) + mstore(0x4f20, 0x2ee3484a156715514bcc56f95e316bb23031b7460f679ebb427a7f8ad73aead2) +mstore(0x4f40, mload(0x4380)) +success := and(eq(staticcall(gas(), 0x7, 0x4f00, 0x60, 0x4f00, 0x40), 1), success) +mstore(0x4f60, mload(0x4e80)) + mstore(0x4f80, mload(0x4ea0)) +mstore(0x4fa0, mload(0x4f00)) + mstore(0x4fc0, mload(0x4f20)) +success := and(eq(staticcall(gas(), 0x6, 0x4f60, 0x80, 0x4f60, 0x40), 1), success) +mstore(0x4fe0, 0x2fb1bc5dc1a8a163ac673f110c7ced2581955a8d47770fced15a66d8199a5c91) + mstore(0x5000, 0x18f7802cf51055b658637bf93f53fcc4dbe4218c03cb54c9d3e74534e1b9cb8f) +mstore(0x5020, mload(0x43a0)) +success := and(eq(staticcall(gas(), 0x7, 0x4fe0, 0x60, 0x4fe0, 0x40), 1), success) +mstore(0x5040, mload(0x4f60)) + mstore(0x5060, mload(0x4f80)) +mstore(0x5080, mload(0x4fe0)) + mstore(0x50a0, mload(0x5000)) +success := and(eq(staticcall(gas(), 0x6, 0x5040, 0x80, 0x5040, 0x40), 1), success) +mstore(0x50c0, 0x2051ae2329a00ab4684564c9db909204379c6404686b9bb004253a0e87937c1a) + mstore(0x50e0, 0x2228d27991956786c7b7ed829027a4268a8f57d342e507683aaaea7046a1721b) +mstore(0x5100, mload(0x43c0)) +success := and(eq(staticcall(gas(), 0x7, 0x50c0, 0x60, 0x50c0, 0x40), 1), success) +mstore(0x5120, mload(0x5040)) + mstore(0x5140, mload(0x5060)) +mstore(0x5160, mload(0x50c0)) + mstore(0x5180, mload(0x50e0)) +success := and(eq(staticcall(gas(), 0x6, 0x5120, 0x80, 0x5120, 0x40), 1), success) +mstore(0x51a0, 0x144e8b5cd066532d7a019f3061d407aeb922b3a37125d39cee71a336088a8d57) + mstore(0x51c0, 0x0465b8271620ef2988dbb05e0e32f58c14ee4aaec69263d36175afc35b129dc8) +mstore(0x51e0, mload(0x43e0)) +success := and(eq(staticcall(gas(), 0x7, 0x51a0, 0x60, 0x51a0, 0x40), 1), success) +mstore(0x5200, mload(0x5120)) + mstore(0x5220, mload(0x5140)) +mstore(0x5240, mload(0x51a0)) + mstore(0x5260, mload(0x51c0)) +success := and(eq(staticcall(gas(), 0x6, 0x5200, 0x80, 0x5200, 0x40), 1), success) +mstore(0x5280, 0x2c5cb6e96533664432584b4373fc01286cb8aa2c8a7f05eac98fc5bc689e65bf) + mstore(0x52a0, 0x2c6a00e02442db4548c0583842d7c460dfaba5a8ae3d86ca57b0d7c82d7090c8) +mstore(0x52c0, mload(0x4400)) +success := and(eq(staticcall(gas(), 0x7, 0x5280, 0x60, 0x5280, 0x40), 1), success) +mstore(0x52e0, mload(0x5200)) + mstore(0x5300, mload(0x5220)) +mstore(0x5320, mload(0x5280)) + mstore(0x5340, mload(0x52a0)) +success := and(eq(staticcall(gas(), 0x6, 0x52e0, 0x80, 0x52e0, 0x40), 1), success) +mstore(0x5360, 0x2b737ba20cacc46db1394cb36a1cb92566946b943314b7037d038fbb83f233a8) + mstore(0x5380, 0x04dc42ddd6eb4c1c43a1175bc70c5b5c92577f968055708b4beeb22cea5cff99) +mstore(0x53a0, mload(0x4420)) +success := and(eq(staticcall(gas(), 0x7, 0x5360, 0x60, 0x5360, 0x40), 1), success) +mstore(0x53c0, mload(0x52e0)) + mstore(0x53e0, mload(0x5300)) +mstore(0x5400, mload(0x5360)) + mstore(0x5420, mload(0x5380)) +success := and(eq(staticcall(gas(), 0x6, 0x53c0, 0x80, 0x53c0, 0x40), 1), success) +mstore(0x5440, 0x0ff2ba345398269313967c25483b19e5e2de27f76a3a4357408c35dc42ddfec3) + mstore(0x5460, 0x063d5c171abc02e7d09324a4f1bb6493d0584767678901f452ebc7f285037015) +mstore(0x5480, mload(0x4440)) +success := and(eq(staticcall(gas(), 0x7, 0x5440, 0x60, 0x5440, 0x40), 1), success) +mstore(0x54a0, mload(0x53c0)) + mstore(0x54c0, mload(0x53e0)) +mstore(0x54e0, mload(0x5440)) + mstore(0x5500, mload(0x5460)) +success := and(eq(staticcall(gas(), 0x6, 0x54a0, 0x80, 0x54a0, 0x40), 1), success) +mstore(0x5520, mload(0x620)) + mstore(0x5540, mload(0x640)) +mstore(0x5560, mload(0x4460)) +success := and(eq(staticcall(gas(), 0x7, 0x5520, 0x60, 0x5520, 0x40), 1), success) +mstore(0x5580, mload(0x54a0)) + mstore(0x55a0, mload(0x54c0)) +mstore(0x55c0, mload(0x5520)) + mstore(0x55e0, mload(0x5540)) +success := and(eq(staticcall(gas(), 0x6, 0x5580, 0x80, 0x5580, 0x40), 1), success) +mstore(0x5600, mload(0x660)) + mstore(0x5620, mload(0x680)) +mstore(0x5640, mload(0x4480)) +success := and(eq(staticcall(gas(), 0x7, 0x5600, 0x60, 0x5600, 0x40), 1), success) +mstore(0x5660, mload(0x5580)) + mstore(0x5680, mload(0x55a0)) +mstore(0x56a0, mload(0x5600)) + mstore(0x56c0, mload(0x5620)) +success := and(eq(staticcall(gas(), 0x6, 0x5660, 0x80, 0x5660, 0x40), 1), success) +mstore(0x56e0, mload(0x6a0)) + mstore(0x5700, mload(0x6c0)) +mstore(0x5720, mload(0x44a0)) +success := and(eq(staticcall(gas(), 0x7, 0x56e0, 0x60, 0x56e0, 0x40), 1), success) +mstore(0x5740, mload(0x5660)) + mstore(0x5760, mload(0x5680)) +mstore(0x5780, mload(0x56e0)) + mstore(0x57a0, mload(0x5700)) +success := and(eq(staticcall(gas(), 0x6, 0x5740, 0x80, 0x5740, 0x40), 1), success) +mstore(0x57c0, mload(0x580)) + mstore(0x57e0, mload(0x5a0)) +mstore(0x5800, mload(0x44c0)) +success := and(eq(staticcall(gas(), 0x7, 0x57c0, 0x60, 0x57c0, 0x40), 1), success) +mstore(0x5820, mload(0x5740)) + mstore(0x5840, mload(0x5760)) +mstore(0x5860, mload(0x57c0)) + mstore(0x5880, mload(0x57e0)) +success := and(eq(staticcall(gas(), 0x6, 0x5820, 0x80, 0x5820, 0x40), 1), success) +mstore(0x58a0, mload(0x480)) + mstore(0x58c0, mload(0x4a0)) +mstore(0x58e0, mload(0x4660)) +success := and(eq(staticcall(gas(), 0x7, 0x58a0, 0x60, 0x58a0, 0x40), 1), success) +mstore(0x5900, mload(0x5820)) + mstore(0x5920, mload(0x5840)) +mstore(0x5940, mload(0x58a0)) + mstore(0x5960, mload(0x58c0)) +success := and(eq(staticcall(gas(), 0x6, 0x5900, 0x80, 0x5900, 0x40), 1), success) +mstore(0x5980, mload(0x4c0)) + mstore(0x59a0, mload(0x4e0)) +mstore(0x59c0, mload(0x4680)) +success := and(eq(staticcall(gas(), 0x7, 0x5980, 0x60, 0x5980, 0x40), 1), success) +mstore(0x59e0, mload(0x5900)) + mstore(0x5a00, mload(0x5920)) +mstore(0x5a20, mload(0x5980)) + mstore(0x5a40, mload(0x59a0)) +success := and(eq(staticcall(gas(), 0x6, 0x59e0, 0x80, 0x59e0, 0x40), 1), success) +mstore(0x5a60, mload(0x500)) + mstore(0x5a80, mload(0x520)) +mstore(0x5aa0, mload(0x4820)) +success := and(eq(staticcall(gas(), 0x7, 0x5a60, 0x60, 0x5a60, 0x40), 1), success) +mstore(0x5ac0, mload(0x59e0)) + mstore(0x5ae0, mload(0x5a00)) +mstore(0x5b00, mload(0x5a60)) + mstore(0x5b20, mload(0x5a80)) +success := and(eq(staticcall(gas(), 0x6, 0x5ac0, 0x80, 0x5ac0, 0x40), 1), success) +mstore(0x5b40, mload(0x540)) + mstore(0x5b60, mload(0x560)) +mstore(0x5b80, mload(0x4840)) +success := and(eq(staticcall(gas(), 0x7, 0x5b40, 0x60, 0x5b40, 0x40), 1), success) +mstore(0x5ba0, mload(0x5ac0)) + mstore(0x5bc0, mload(0x5ae0)) +mstore(0x5be0, mload(0x5b40)) + mstore(0x5c00, mload(0x5b60)) +success := and(eq(staticcall(gas(), 0x6, 0x5ba0, 0x80, 0x5ba0, 0x40), 1), success) +mstore(0x5c20, mload(0x340)) + mstore(0x5c40, mload(0x360)) +mstore(0x5c60, mload(0x4940)) +success := and(eq(staticcall(gas(), 0x7, 0x5c20, 0x60, 0x5c20, 0x40), 1), success) +mstore(0x5c80, mload(0x5ba0)) + mstore(0x5ca0, mload(0x5bc0)) +mstore(0x5cc0, mload(0x5c20)) + mstore(0x5ce0, mload(0x5c40)) +success := and(eq(staticcall(gas(), 0x6, 0x5c80, 0x80, 0x5c80, 0x40), 1), success) +mstore(0x5d00, mload(0xc00)) + mstore(0x5d20, mload(0xc20)) +mstore(0x5d40, sub(f_q, mload(0x4980))) +success := and(eq(staticcall(gas(), 0x7, 0x5d00, 0x60, 0x5d00, 0x40), 1), success) +mstore(0x5d60, mload(0x5c80)) + mstore(0x5d80, mload(0x5ca0)) +mstore(0x5da0, mload(0x5d00)) + mstore(0x5dc0, mload(0x5d20)) +success := and(eq(staticcall(gas(), 0x6, 0x5d60, 0x80, 0x5d60, 0x40), 1), success) +mstore(0x5de0, mload(0xca0)) + mstore(0x5e00, mload(0xcc0)) +mstore(0x5e20, mload(0x49a0)) +success := and(eq(staticcall(gas(), 0x7, 0x5de0, 0x60, 0x5de0, 0x40), 1), success) +mstore(0x5e40, mload(0x5d60)) + mstore(0x5e60, mload(0x5d80)) +mstore(0x5e80, mload(0x5de0)) + mstore(0x5ea0, mload(0x5e00)) +success := and(eq(staticcall(gas(), 0x6, 0x5e40, 0x80, 0x5e40, 0x40), 1), success) +mstore(0x5ec0, mload(0x5e40)) + mstore(0x5ee0, mload(0x5e60)) mstore(0x5f00, mload(0xca0)) mstore(0x5f20, mload(0xcc0)) -mstore(0x5f40, keccak256(0x5e40, 256)) -mstore(24416, mod(mload(24384), f_q)) -mstore(0x5f80, mulmod(mload(0x5f60), mload(0x5f60), f_q)) -mstore(0x5fa0, mulmod(1, mload(0x5f60), f_q)) -mstore(0x5fc0, mload(0x5ec0)) - mstore(0x5fe0, mload(0x5ee0)) -mstore(0x6000, mload(0x5fa0)) -success := and(eq(staticcall(gas(), 0x7, 0x5fc0, 0x60, 0x5fc0, 0x40), 1), success) -mstore(0x6020, mload(0x5e40)) - mstore(0x6040, mload(0x5e60)) -mstore(0x6060, mload(0x5fc0)) - mstore(0x6080, mload(0x5fe0)) -success := and(eq(staticcall(gas(), 0x6, 0x6020, 0x80, 0x6020, 0x40), 1), success) -mstore(0x60a0, mload(0x5f00)) - mstore(0x60c0, mload(0x5f20)) -mstore(0x60e0, mload(0x5fa0)) -success := and(eq(staticcall(gas(), 0x7, 0x60a0, 0x60, 0x60a0, 0x40), 1), success) -mstore(0x6100, mload(0x5e80)) - mstore(0x6120, mload(0x5ea0)) -mstore(0x6140, mload(0x60a0)) - mstore(0x6160, mload(0x60c0)) -success := and(eq(staticcall(gas(), 0x6, 0x6100, 0x80, 0x6100, 0x40), 1), success) -mstore(0x6180, mload(0x6020)) - mstore(0x61a0, mload(0x6040)) -mstore(0x61c0, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) - mstore(0x61e0, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) - mstore(0x6200, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) - mstore(0x6220, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) -mstore(0x6240, mload(0x6100)) - mstore(0x6260, mload(0x6120)) -mstore(0x6280, 0x138d5863615c12d3bd7d3fd007776d281a337f9d7f6dce23532100bb4bb5839d) - mstore(0x62a0, 0x0a3bb881671ee4e9238366e87f6598f0de356372ed3dc870766ec8ac005211e4) - mstore(0x62c0, 0x19c9d7d9c6e7ad2d9a0d5847ebdd2687c668939a202553ded2760d3eb8dbf559) - mstore(0x62e0, 0x198adb441818c42721c88c532ed13a5da1ebb78b85574d0b7326d8e6f4c1e25a) -success := and(eq(staticcall(gas(), 0x8, 0x6180, 0x180, 0x6180, 0x20), 1), success) -success := and(eq(mload(0x6180), 1), success) +mstore(0x5f40, mload(0xce0)) + mstore(0x5f60, mload(0xd00)) +mstore(0x5f80, mload(0xd20)) + mstore(0x5fa0, mload(0xd40)) +mstore(0x5fc0, keccak256(0x5ec0, 256)) +mstore(24544, mod(mload(24512), f_q)) +mstore(0x6000, mulmod(mload(0x5fe0), mload(0x5fe0), f_q)) +mstore(0x6020, mulmod(1, mload(0x5fe0), f_q)) +mstore(0x6040, mload(0x5f40)) + mstore(0x6060, mload(0x5f60)) +mstore(0x6080, mload(0x6020)) +success := and(eq(staticcall(gas(), 0x7, 0x6040, 0x60, 0x6040, 0x40), 1), success) +mstore(0x60a0, mload(0x5ec0)) + mstore(0x60c0, mload(0x5ee0)) +mstore(0x60e0, mload(0x6040)) + mstore(0x6100, mload(0x6060)) +success := and(eq(staticcall(gas(), 0x6, 0x60a0, 0x80, 0x60a0, 0x40), 1), success) +mstore(0x6120, mload(0x5f80)) + mstore(0x6140, mload(0x5fa0)) +mstore(0x6160, mload(0x6020)) +success := and(eq(staticcall(gas(), 0x7, 0x6120, 0x60, 0x6120, 0x40), 1), success) +mstore(0x6180, mload(0x5f00)) + mstore(0x61a0, mload(0x5f20)) +mstore(0x61c0, mload(0x6120)) + mstore(0x61e0, mload(0x6140)) +success := and(eq(staticcall(gas(), 0x6, 0x6180, 0x80, 0x6180, 0x40), 1), success) +mstore(0x6200, mload(0x60a0)) + mstore(0x6220, mload(0x60c0)) +mstore(0x6240, 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2) + mstore(0x6260, 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed) + mstore(0x6280, 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b) + mstore(0x62a0, 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa) +mstore(0x62c0, mload(0x6180)) + mstore(0x62e0, mload(0x61a0)) +mstore(0x6300, 0x138d5863615c12d3bd7d3fd007776d281a337f9d7f6dce23532100bb4bb5839d) + mstore(0x6320, 0x0a3bb881671ee4e9238366e87f6598f0de356372ed3dc870766ec8ac005211e4) + mstore(0x6340, 0x19c9d7d9c6e7ad2d9a0d5847ebdd2687c668939a202553ded2760d3eb8dbf559) + mstore(0x6360, 0x198adb441818c42721c88c532ed13a5da1ebb78b85574d0b7326d8e6f4c1e25a) +success := and(eq(staticcall(gas(), 0x8, 0x6200, 0x180, 0x6200, 0x20), 1), success) +success := and(eq(mload(0x6200), 1), success) // Revert if anything fails if iszero(success) { revert(0, 0) } diff --git a/snark-verifier/src/loader/evm/code.rs b/snark-verifier/src/loader/evm/code.rs index 2634ba2d..eee4fb3e 100644 --- a/snark-verifier/src/loader/evm/code.rs +++ b/snark-verifier/src/loader/evm/code.rs @@ -25,7 +25,13 @@ pragma solidity 0.8.19; contract Halo2Verifier {{ fallback(bytes calldata) external returns (bytes memory) {{ - assembly {{ + assembly (\"memory-safe\") {{ + // Enforce that Solidity memory layout is respected + let data := mload(0x40) + if iszero(eq(data, 0x80)) {{ + revert(0, 0) + }} + let success := true let f_p := {base_modulus} let f_q := {scalar_modulus} diff --git a/snark-verifier/src/loader/evm/loader.rs b/snark-verifier/src/loader/evm/loader.rs index 3bf49baf..af2795c1 100644 --- a/snark-verifier/src/loader/evm/loader.rs +++ b/snark-verifier/src/loader/evm/loader.rs @@ -21,6 +21,9 @@ use std::{ rc::Rc, }; +/// Memory pointer starts at 0x80, which is the end of the Solidity memory layout scratch space. +pub const MEM_PTR_START: usize = 0x80; + #[derive(Clone, Debug)] pub enum Value { Constant(T), @@ -76,7 +79,7 @@ impl EvmLoader { base_modulus, scalar_modulus, code: RefCell::new(code), - ptr: Default::default(), + ptr: RefCell::new(MEM_PTR_START), cache: Default::default(), }) } diff --git a/snark-verifier/src/system/halo2/transcript/evm.rs b/snark-verifier/src/system/halo2/transcript/evm.rs index da2c09c2..372b1388 100644 --- a/snark-verifier/src/system/halo2/transcript/evm.rs +++ b/snark-verifier/src/system/halo2/transcript/evm.rs @@ -1,6 +1,7 @@ //! Transcript for verifier on EVM. use crate::halo2_proofs; +use crate::loader::evm::loader::MEM_PTR_START; use crate::{ loader::{ evm::{loader::Value, u256_to_fe, util::MemoryChunk, EcPoint, EvmLoader, Scalar, U256}, @@ -41,7 +42,7 @@ where /// u256 for `transcript_initial_state`. pub fn new(loader: &Rc) -> Self { let ptr = loader.allocate(0x20); - assert_eq!(ptr, 0); + assert_eq!(ptr, MEM_PTR_START); let mut buf = MemoryChunk::new(ptr); buf.extend(0x20); Self { loader: loader.clone(), stream: 0, buf, _marker: PhantomData } @@ -116,7 +117,7 @@ where fn common_scalar(&mut self, scalar: &Scalar) -> Result<(), Error> { match scalar.value() { - Value::Constant(_) if self.buf.ptr() == 0 => { + Value::Constant(_) if self.buf.ptr() == MEM_PTR_START => { self.loader.copy_scalar(scalar, self.buf.ptr()); } Value::Memory(ptr) => { From 1f97d2949d9d46d86fb8f05cb7d13f5a1737e284 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Thu, 2 Nov 2023 13:34:27 -0700 Subject: [PATCH 58/73] chore: switch CI to solidity v0.8.19 --- .github/workflows/ci.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 733bfc9c..cd98b964 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -24,7 +24,7 @@ jobs: cache-on-failure: true - name: Install solc - run: (hash svm 2>/dev/null || cargo install --version 0.2.23 svm-rs) && svm install 0.8.20 && solc --version + run: (hash svm 2>/dev/null || cargo install --version 0.2.23 svm-rs) && svm install 0.8.19 && solc --version - name: Run test run: cargo test --all -- --nocapture From ffdd599671999bd63a6de591f67a1c731c189c64 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Thu, 2 Nov 2023 14:47:00 -0700 Subject: [PATCH 59/73] [chore] add `cargo audit` and update dependencies (#40) * chore: add `cargo audit` and update dependencies disabling zkevm benches due to versioning issues * chore: autobenches false * fix: audit-check CI --- .github/workflows/ci.yaml | 8 ++++++++ snark-verifier-sdk/Cargo.toml | 37 ++++++++++++++++++----------------- snark-verifier/Cargo.toml | 6 +++--- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index cd98b964..97e72b2e 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -52,3 +52,11 @@ jobs: - name: Run clippy run: cargo clippy --all --all-targets -- -D warnings + + - name: Generate Cargo.lock + run: cargo generate-lockfile + + - name: Run cargo audit + uses: actions-rs/audit-check@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 899c2cbb..5bfb6a21 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -2,6 +2,7 @@ name = "snark-verifier-sdk" version = "0.1.6" edition = "2021" +autobenches = false [dependencies] itertools = "0.10.5" @@ -17,7 +18,7 @@ serde_json = "1.0" serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc0", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } getset = "0.1.2" @@ -27,22 +28,22 @@ ethereum-types = { version = "0.14.1", default-features = false, features = [ ], optional = true } # zkevm benchmarks -zkevm-circuits = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", features = [ - "test", -], optional = true } -bus-mapping = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } -eth-types = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } -mock = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } +# zkevm-circuits = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", features = [ +# "test", +# ], optional = true } +# bus-mapping = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } +# eth-types = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } +# mock = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", optional = true } [dev-dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } paste = "1.0.7" -pprof = { version = "0.11", features = ["criterion", "flamegraph"] } -criterion = "0.4" +pprof = { version = "0.13", features = ["criterion", "flamegraph"] } +criterion = "0.5.1" criterion-macro = "0.4" # loader_evm crossterm = { version = "0.25" } -tui = { version = "0.19", default-features = false, features = ["crossterm"] } +ratatui = { version = "0.24", default-features = false, features = ["crossterm"] } [features] default = [ @@ -67,15 +68,15 @@ name = "standard_plonk" required-features = ["loader_halo2"] harness = false -[[bench]] -name = "zkevm" -required-features = ["loader_halo2", "loader_evm", "zkevm", "halo2-pse"] -harness = false +# [[bench]] +# name = "zkevm" +# required-features = ["loader_halo2", "loader_evm", "zkevm", "halo2-pse"] +# harness = false -[[bench]] -name = "zkevm_plus_state" -required-features = ["loader_halo2", "loader_evm", "zkevm", "halo2-pse"] -harness = false +# [[bench]] +# name = "zkevm_plus_state" +# required-features = ["loader_halo2", "loader_evm", "zkevm", "halo2-pse"] +# harness = false [[bench]] name = "read_pk" diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index a9072edd..8c437a2e 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -15,7 +15,7 @@ serde = { version = "1.0", features = ["derive"] } pairing = { version = "0.23" } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc0", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc", default-features = false } # parallel rayon = { version = "1.7", optional = true } @@ -25,7 +25,7 @@ sha3 = { version = "0.10", optional = true } revm = { version = "3.3.0", optional = true } # loader_halo2 -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc0", default-features = false, optional = true } +halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc", default-features = false, optional = true } [dev-dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } @@ -35,7 +35,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" # loader_evm crossterm = { version = "0.25" } -tui = { version = "0.19", default-features = false, features = ["crossterm"] } +ratatui = { version = "0.24", default-features = false, features = ["crossterm"] } [features] default = ["loader_evm", "loader_halo2", "halo2-axiom", "display"] From 055527aa837f70ba14d275dc7016b1aa229a39cc Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Thu, 2 Nov 2023 21:43:48 -0700 Subject: [PATCH 60/73] [chore] fix hyperlinks in docs (#41) chore: fix hyperlinks in docs --- snark-verifier/src/loader/halo2.rs | 2 +- snark-verifier/src/loader/halo2/loader.rs | 2 +- snark-verifier/src/pcs/ipa/multiopen/bgh19.rs | 2 +- snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs | 2 +- snark-verifier/src/pcs/kzg/multiopen/gwc19.rs | 2 +- snark-verifier/src/system/halo2.rs | 6 +++--- snark-verifier/src/system/halo2/transcript/evm.rs | 2 +- snark-verifier/src/util/arithmetic.rs | 2 +- 8 files changed, 10 insertions(+), 10 deletions(-) diff --git a/snark-verifier/src/loader/halo2.rs b/snark-verifier/src/loader/halo2.rs index 4d37c5ce..814fbda3 100644 --- a/snark-verifier/src/loader/halo2.rs +++ b/snark-verifier/src/loader/halo2.rs @@ -1,4 +1,4 @@ -//! `Loader` implementation for generating verifier in [`halo2_proofs`] circuit. +//! `Loader` implementation for generating verifier in [`halo2_proofs`](crate::halo2_proofs) circuit. pub(crate) mod loader; mod shim; diff --git a/snark-verifier/src/loader/halo2/loader.rs b/snark-verifier/src/loader/halo2/loader.rs index f8e1da7d..ecb8af19 100644 --- a/snark-verifier/src/loader/halo2/loader.rs +++ b/snark-verifier/src/loader/halo2/loader.rs @@ -16,7 +16,7 @@ use std::{ rc::Rc, }; -/// `Loader` implementation for generating verifier in [`halo2_proofs`] circuit. +/// `Loader` implementation for generating verifier in [`halo2_proofs`](crate::halo2_proofs) circuit. #[derive(Debug)] pub struct Halo2Loader> { ecc_chip: RefCell, diff --git a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs index e2cb87ab..5ea93c99 100644 --- a/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs +++ b/snark-verifier/src/pcs/ipa/multiopen/bgh19.rs @@ -19,7 +19,7 @@ use std::{ }; /// Verifier of multi-open inner product argument. It is for the implementation -/// in [`halo2_proofs`], which is previously +/// in [`halo2_proofs`](crate::halo2_proofs), which is previously /// . #[derive(Clone, Debug)] pub struct Bgh19; diff --git a/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs index e13e09cc..f3f60b8d 100644 --- a/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/bdfg21.rs @@ -19,7 +19,7 @@ use std::{ }; /// Verifier of multi-open KZG. It is for the SHPLONK implementation -/// in [`halo2_proofs`]. +/// in [`halo2_proofs`](crate::halo2_proofs). /// Notations are following . #[derive(Clone, Debug)] pub struct Bdfg21; diff --git a/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs index e8114d09..b8bd4bf9 100644 --- a/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs +++ b/snark-verifier/src/pcs/kzg/multiopen/gwc19.rs @@ -15,7 +15,7 @@ use crate::{ }; /// Verifier of multi-open KZG. It is for the GWC implementation -/// in [`halo2_proofs`]. +/// in [`halo2_proofs`](crate::halo2_proofs). /// Notations are following . #[derive(Clone, Debug)] pub struct Gwc19; diff --git a/snark-verifier/src/system/halo2.rs b/snark-verifier/src/system/halo2.rs index 74824361..82bffc20 100644 --- a/snark-verifier/src/system/halo2.rs +++ b/snark-verifier/src/system/halo2.rs @@ -1,4 +1,4 @@ -//! [`halo2_proofs`] proof system +//! [`halo2_proofs`](crate::halo2_proofs) proof system use crate::halo2_proofs::{ plonk::{self, Any, ConstraintSystem, FirstPhase, SecondPhase, ThirdPhase, VerifyingKey}, @@ -21,7 +21,7 @@ use std::{io, iter, mem::size_of}; pub mod strategy; pub mod transcript; -/// Configuration for converting a [`VerifyingKey`] of [`halo2_proofs`] into +/// Configuration for converting a [`VerifyingKey`] of [`halo2_proofs`](crate::halo2_proofs) into /// [`PlonkProtocol`]. #[derive(Clone, Debug, Default)] pub struct Config { @@ -78,7 +78,7 @@ impl Config { } } -/// Convert a [`VerifyingKey`] of [`halo2_proofs`] into [`PlonkProtocol`]. +/// Convert a [`VerifyingKey`] of [`halo2_proofs`](crate::halo2_proofs) into [`PlonkProtocol`]. pub fn compile<'a, C: CurveAffine, P: Params<'a, C>>( params: &P, vk: &VerifyingKey, diff --git a/snark-verifier/src/system/halo2/transcript/evm.rs b/snark-verifier/src/system/halo2/transcript/evm.rs index 372b1388..5707fdfa 100644 --- a/snark-verifier/src/system/halo2/transcript/evm.rs +++ b/snark-verifier/src/system/halo2/transcript/evm.rs @@ -75,7 +75,7 @@ where } /// Does not allow the input to be a one-byte sequence, because the Transcript trait only supports writing scalars and elliptic curve points. - /// If the one-byte sequence [0x01] is a valid input to the transcript, the empty input [] will have the same transcript result as [0x01]. + /// If the one-byte sequence `[0x01]` is a valid input to the transcript, the empty input `[]` will have the same transcript result as `[0x01]`. fn squeeze_challenge(&mut self) -> Scalar { let len = if self.buf.len() == 0x20 { assert_eq!(self.loader.ptr(), self.buf.end()); diff --git a/snark-verifier/src/util/arithmetic.rs b/snark-verifier/src/util/arithmetic.rs index c34daef8..3594be45 100644 --- a/snark-verifier/src/util/arithmetic.rs +++ b/snark-verifier/src/util/arithmetic.rs @@ -21,7 +21,7 @@ use std::{ ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; -/// [`halo2_curves::pairing::MultiMillerLoop`] with [`std::fmt::Debug`]. +/// [pairing::MultiMillerLoop] with [`std::fmt::Debug`]. pub trait MultiMillerLoop: pairing::MultiMillerLoop + Debug {} impl MultiMillerLoop for M {} From 1cf2986121603d614210e4657941f53c0fd153cf Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 3 Nov 2023 17:56:25 -0700 Subject: [PATCH 61/73] [chore] separate `revm` import into separate feature (#44) * chore: import `ruint` separately to not rely on `revm` * feat: add feature `revm` to toggle `revm` import Separates `revm` import, which is only used for testing EVM execution, from `loader_evm` feature, which is used more broadly for generating proofs to be sent to on-chain verifier. * chore: add CI to check `--release` compilation with assembly * fix: import under revm --- .github/workflows/ci.yaml | 4 +- .github/workflows/release.yaml | 36 + .gitignore | 4 +- Cargo.lock | 3282 +++++++++++++++++ snark-verifier-sdk/Cargo.toml | 7 +- snark-verifier-sdk/benches/standard_plonk.rs | 11 +- snark-verifier-sdk/examples/standard_plonk.rs | 11 +- snark-verifier-sdk/src/evm.rs | 5 +- snark-verifier/Cargo.toml | 16 +- .../examples/evm-verifier-with-accumulator.rs | 22 +- snark-verifier/examples/evm-verifier.rs | 12 +- snark-verifier/src/loader/evm.rs | 4 +- snark-verifier/src/loader/evm/util.rs | 4 +- 13 files changed, 3380 insertions(+), 38 deletions(-) create mode 100644 .github/workflows/release.yaml create mode 100644 Cargo.lock diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 97e72b2e..d8c87a8d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -27,11 +27,11 @@ jobs: run: (hash svm 2>/dev/null || cargo install --version 0.2.23 svm-rs) && svm install 0.8.19 && solc --version - name: Run test - run: cargo test --all -- --nocapture + run: cargo test --all --features "revm" -- --nocapture - name: Run example working-directory: "snark-verifier-sdk" - run: cargo run --example standard_plonk + run: cargo run --example standard_plonk --features "revm" lint: name: Lint diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 00000000..1c89b2e3 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,36 @@ +name: CI + +on: + pull_request: + branches: + - ["main", "release-*"] + push: + branches: + - main + +jobs: + test: + name: Test assembly release + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + override: false + + - uses: Swatinem/rust-cache@v1 + with: + cache-on-failure: true + + - name: Install solc + run: (hash svm 2>/dev/null || cargo install --version 0.2.23 svm-rs) && svm install 0.8.19 && solc --version + + - name: Run test + run: cargo test --all --features "revm, halo2-base/asm" -- --nocapture + + - name: Run example + working-directory: "snark-verifier-sdk" + run: cargo run --example standard_plonk --features "revm, halo2-base/asm" diff --git a/.gitignore b/.gitignore index ec2971fb..8d7c1190 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ /target testdata -Cargo.lock +# Cargo.lock params agg.pk -break_points.json \ No newline at end of file +break_points.json diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..edc988a7 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,3282 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" + +[[package]] +name = "alloy-primitives" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0628ec0ba5b98b3370bb6be17b12f23bfce8ee4ad83823325a20546d9b03b78" +dependencies = [ + "alloy-rlp", + "bytes", + "cfg-if", + "const-hex", + "derive_more", + "hex-literal", + "itoa", + "ruint", + "tiny-keccak", +] + +[[package]] +name = "alloy-rlp" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef" +dependencies = [ + "alloy-rlp-derive", + "arrayvec", + "bytes", + "smol_str", +] + +[[package]] +name = "alloy-rlp-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0391754c09fab4eae3404d19d0d297aa1c670c1775ab51d8a5312afeca23157" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anes" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299" + +[[package]] +name = "anstyle" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87" + +[[package]] +name = "ark-ff" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6" +dependencies = [ + "ark-ff-asm 0.3.0", + "ark-ff-macros 0.3.0", + "ark-serialize 0.3.0", + "ark-std 0.3.0", + "derivative", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.3.3", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint", + "num-traits", + "paste", + "rustc_version 0.4.0", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20" +dependencies = [ + "num-bigint", + "num-traits", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671" +dependencies = [ + "ark-std 0.3.0", + "digest 0.9.0", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-std" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" +dependencies = [ + "colored", + "num-traits", + "rand", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand", +] + +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + +[[package]] +name = "arrayvec" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" + +[[package]] +name = "auto_impl" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "backtrace" +version = "0.3.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bindgen" +version = "0.66.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7" +dependencies = [ + "bitflags 2.4.1", + "cexpr", + "clang-sys", + "lazy_static", + "lazycell", + "log", + "peeking_take_while", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex", + "syn 2.0.38", + "which", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[package]] +name = "blst" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c94087b935a822949d3291a9989ad2b2051ea141eda0fd4e478a75f6aa3e604b" +dependencies = [ + "cc", + "glob", + "threadpool", + "zeroize", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "byte-slice-cast" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "bytes" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" + +[[package]] +name = "c-kzg" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac926d808fb72fe09ebf471a091d6d72918876ccf0b4989766093d2d0d24a0ef" +dependencies = [ + "bindgen", + "blst", + "cc", + "glob", + "hex", + "libc", + "serde", +] + +[[package]] +name = "cassowary" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df8670b8c7b9dae1793364eafadf7239c40d669904660c5960d74cfd80b46a53" + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets", +] + +[[package]] +name = "ciborium" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "effd91f6c78e5a4ace8a5d3c0b6bfaec9e2baaef55f3efc00e45fb2e477ee926" +dependencies = [ + "ciborium-io", + "ciborium-ll", + "serde", +] + +[[package]] +name = "ciborium-io" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdf919175532b369853f5d5e20b26b43112613fd6fe7aee757e35f7a44642656" + +[[package]] +name = "ciborium-ll" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defaa24ecc093c77630e6c15e17c51f5e187bf35ee514f4e2d67baaa96dae22b" +dependencies = [ + "ciborium-io", + "half", +] + +[[package]] +name = "clang-sys" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" +dependencies = [ + "anstyle", + "clap_lex", +] + +[[package]] +name = "clap_lex" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" + +[[package]] +name = "colored" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2674ec482fbc38012cf31e6c42ba0177b431a0cb6f15fe40efa5aab1bda516f6" +dependencies = [ + "is-terminal", + "lazy_static", + "windows-sys", +] + +[[package]] +name = "const-hex" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557" +dependencies = [ + "cfg-if", + "cpufeatures", + "hex", + "proptest", + "serde", +] + +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "convert_case" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpp_demangle" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e8227005286ec39567949b33df9896bcadfa6051bccca2488129f108ca23119" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "cpufeatures" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0" +dependencies = [ + "libc", +] + +[[package]] +name = "criterion" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2b12d017a929603d80db1831cd3a24082f8137ce19c69e6447f54f5fc8d692f" +dependencies = [ + "anes", + "cast", + "ciborium", + "clap", + "criterion-plot", + "is-terminal", + "itertools 0.10.5", + "num-traits", + "once_cell", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-macro" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "288a8f36b28a19d7dbd572c76006c0a0eba1f3bf912a254dda211c6f665e7ffc" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "criterion-plot" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1" +dependencies = [ + "cast", + "itertools 0.10.5", +] + +[[package]] +name = "crossbeam" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2801af0d36612ae591caa9568261fddce32ce6e08a7275ea334a06a4ad021a2c" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1cfb3ea8a53f37c40dea2c7bedcbd88bdfae54f5e2175d6ecaff1c988353add" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossterm" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" +dependencies = [ + "bitflags 1.3.2", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f476fe445d41c9e991fd07515a6f463074b782242ccf4a5b7b1d1012e70824df" +dependencies = [ + "bitflags 2.4.1", + "crossterm_winapi", + "libc", + "mio", + "parking_lot", + "signal-hook", + "signal-hook-mio", + "winapi", +] + +[[package]] +name = "crossterm_winapi" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b" +dependencies = [ + "winapi", +] + +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" + +[[package]] +name = "crypto-bigint" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.38", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "debugid" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" +dependencies = [ + "uuid", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "deranged" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", + "serde", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "ecdsa" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "elliptic-curve" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "enumn" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "equivalent" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" + +[[package]] +name = "errno" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "primitive-types", + "uint", +] + +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + +[[package]] +name = "fastrlp" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "bitvec", + "rand_core", + "subtle", +] + +[[package]] +name = "findshlibs" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40b9e59cd0f7e0806cca4be089683ecb6434e602038df21fe6bf6711b2f07f64" +dependencies = [ + "cc", + "lazy_static", + "libc", + "winapi", +] + +[[package]] +name = "fixed-hash" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" +dependencies = [ + "byteorder", + "rand", + "rustc-hex", + "static_assertions", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getset" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "gimli" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0" + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "halo2-base" +version = "0.4.0" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.4.0-rc#67e3a0eee37c3b25b393cdea7514fef4e8af0bf9" +dependencies = [ + "getset", + "halo2_proofs 0.2.0", + "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?rev=7a21656)", + "itertools 0.11.0", + "jemallocator", + "log", + "num-bigint", + "num-integer", + "num-traits", + "poseidon-rs", + "rand_chacha", + "rayon", + "rustc-hash", + "serde", + "serde_json", +] + +[[package]] +name = "halo2-ecc" +version = "0.4.0" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.4.0-rc#67e3a0eee37c3b25b393cdea7514fef4e8af0bf9" +dependencies = [ + "halo2-base", + "itertools 0.10.5", + "num-bigint", + "num-integer", + "num-traits", + "rand", + "rand_chacha", + "rand_core", + "rayon", + "serde", + "serde_json", + "test-case", +] + +[[package]] +name = "halo2_proofs" +version = "0.2.0" +dependencies = [ + "blake2b_simd", + "crossbeam", + "ff", + "group", + "halo2curves 0.4.0", + "maybe-rayon", + "pairing", + "rand", + "rand_core", + "rustc-hash", + "sha3 0.10.8", + "tracing", +] + +[[package]] +name = "halo2_proofs" +version = "0.2.0" +source = "git+https://github.com/privacy-scaling-explorations/halo2.git?rev=7a21656#7a2165617195d8baa422ca7b2b364cef02380390" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "halo2curves 0.1.0", + "maybe-rayon", + "rand_chacha", + "rand_core", + "sha3 0.9.1", + "tracing", +] + +[[package]] +name = "halo2curves" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6b1142bd1059aacde1b477e0c80c142910f1ceae67fc619311d6a17428007ab" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "num-bigint", + "num-traits", + "pasta_curves", + "paste", + "rand", + "rand_core", + "static_assertions", + "subtle", +] + +[[package]] +name = "halo2curves" +version = "0.4.0" +source = "git+https://github.com/axiom-crypto/halo2curves.git?branch=main#e185711b6ba8f3e22f2af8bf24a5fc84b781ca46" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "hex", + "lazy_static", + "maybe-rayon", + "num-bigint", + "num-traits", + "pairing", + "pasta_curves", + "paste", + "rand", + "rand_core", + "serde", + "serde_arrays", + "static_assertions", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156" +dependencies = [ + "ahash", + "allocator-api2", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +dependencies = [ + "serde", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "iana-time-zone" +version = "0.1.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "impl-codec" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba6a270039626615617f3f36d15fc827041df3b78c439da2cadfa47455a77f2f" +dependencies = [ + "parity-scale-codec", +] + +[[package]] +name = "impl-trait-for-tuples" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" +dependencies = [ + "equivalent", + "hashbrown 0.14.2", +] + +[[package]] +name = "indoc" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e186cfbae8084e513daff4240b4797e342f988cecda4fb6c939150f96315fd8" + +[[package]] +name = "inferno" +version = "0.11.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50453ec3a6555fad17b1cd1a80d16af5bc7cb35094f64e429fd46549018c6a3" +dependencies = [ + "ahash", + "indexmap 2.1.0", + "is-terminal", + "itoa", + "log", + "num-format", + "once_cell", + "quick-xml", + "rgb", + "str_stack", +] + +[[package]] +name = "is-terminal" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0889898416213fab133e1d33a0e5858a48177452750691bde3666d0fdbaf8b" +dependencies = [ + "hermit-abi", + "rustix", + "windows-sys", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + +[[package]] +name = "jemalloc-sys" +version = "0.5.4+5.3.0-patched" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac6c1946e1cea1788cbfde01c993b52a10e2da07f4bac608228d1bed20bfebf2" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "jemallocator" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0de374a9f8e63150e6f5e8a60cc14c668226d7a347d8aee1a45766e3c4dd3bc" +dependencies = [ + "jemalloc-sys", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c0c35952f67de54bb584e9fd912b3023117cbafc0a77d8f3dee1fb5f572fe8" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "k256" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2", +] + +[[package]] +name = "keccak" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "libc" +version = "0.2.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" + +[[package]] +name = "libloading" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" +dependencies = [ + "cfg-if", + "winapi", +] + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + +[[package]] +name = "lock_api" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "lru" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efa59af2ddfad1854ae27d75009d538d0998b4b2fd47083e743ac1a10e46c60" +dependencies = [ + "hashbrown 0.14.2", +] + +[[package]] +name = "maybe-rayon" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" +dependencies = [ + "cfg-if", + "rayon", +] + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "memmap2" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a5a03cefb0d953ec0be133036f14e109412fa594edc2f77227249db66cc3ed" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", +] + +[[package]] +name = "mio" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0" +dependencies = [ + "libc", + "log", + "wasi", + "windows-sys", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05180d69e3da0e530ba2a1dae5110317e49e3b7f3d41be227dc5f92e49ee7af" +dependencies = [ + "num-bigint", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", + "rand", +] + +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-format" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a652d9771a63711fd3c3deb670acfbe5c30a4072e664d7a3bf5a9e1056ac72c3" +dependencies = [ + "arrayvec", + "itoa", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-bigint", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "object" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "pairing" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" +dependencies = [ + "group", +] + +[[package]] +name = "parity-scale-codec" +version = "3.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff", + "group", + "lazy_static", + "rand", + "static_assertions", + "subtle", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" + +[[package]] +name = "pest" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae9cee2a55a544be8b89dc6848072af97a20f2422603c10865be2a42b580fff5" +dependencies = [ + "memchr", + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "plotters" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" + +[[package]] +name = "plotters-svg" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38f6d39893cca0701371e3c27294f09797214b86f1fb951b89ade8ec04e2abab" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "poseidon-rs" +version = "0.1.1" +source = "git+https://github.com/axiom-crypto/poseidon-circuit.git?rev=1aee4a1#1aee4a1bf6220578924079aac4f2eee3874116a1" +dependencies = [ + "bitvec", + "ff", + "lazy_static", + "log", + "rand", + "rand_xorshift", + "thiserror", +] + +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + +[[package]] +name = "pprof" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef5c97c51bd34c7e742402e216abdeb44d415fbe6ae41d56b114723e953711cb" +dependencies = [ + "backtrace", + "cfg-if", + "criterion", + "findshlibs", + "inferno", + "libc", + "log", + "nix", + "once_cell", + "parking_lot", + "smallvec", + "symbolic-demangle", + "tempfile", + "thiserror", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prettyplease" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +dependencies = [ + "proc-macro2", + "syn 2.0.38", +] + +[[package]] +name = "primitive-types" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" +dependencies = [ + "fixed-hash", + "impl-codec", + "uint", +] + +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "proptest" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e" +dependencies = [ + "bitflags 2.4.1", + "lazy_static", + "num-traits", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax 0.7.5", + "unarray", +] + +[[package]] +name = "quick-xml" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f50b1c63b38611e7d4d7f68b82d3ad0cc71a2ad2e7f61fc10f1328d917c93cd" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "ratatui" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ebc917cfb527a566c37ecb94c7e3fd098353516fb4eb6bea17015ade0182425" +dependencies = [ + "bitflags 2.4.1", + "cassowary", + "crossterm 0.27.0", + "indoc", + "itertools 0.11.0", + "lru", + "paste", + "strum", + "unicode-segmentation", + "unicode-width", +] + +[[package]] +name = "rayon" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-automata" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax 0.8.2", +] + +[[package]] +name = "regex-syntax" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "revm" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68f4ca8ae0345104523b4af1a8a7ea97cfa1865cdb7a7c25d23c1a18d9b48598" +dependencies = [ + "auto_impl", + "revm-interpreter", + "revm-precompile", +] + +[[package]] +name = "revm-interpreter" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f959cafdf64a7f89b014fa73dc2325001cf654b3d9400260b212d19a2ebe3da0" +dependencies = [ + "revm-primitives", +] + +[[package]] +name = "revm-precompile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d360a88223d85709d2e95d4609eb1e19c649c47e28954bfabae5e92bb37e83e" +dependencies = [ + "c-kzg", + "k256", + "num", + "once_cell", + "revm-primitives", + "ripemd", + "secp256k1", + "sha2", + "substrate-bn", +] + +[[package]] +name = "revm-primitives" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51187b852d9e458816a2e19c81f1dd6c924077e1a8fccd16e4f044f865f299d7" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "auto_impl", + "bitflags 2.4.1", + "bitvec", + "c-kzg", + "enumn", + "hashbrown 0.14.2", + "hex", + "once_cell", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rgb" +version = "0.8.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05aaa8004b64fd573fc9d002f4e632d51ad4f026c2b5ba95fcb6c2f32c2c47d8" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "rlp" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" +dependencies = [ + "bytes", + "rustc-hex", +] + +[[package]] +name = "ruint" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95294d6e3a6192f3aabf91c38f56505a625aa495533442744185a36d75a790c4" +dependencies = [ + "alloy-rlp", + "ark-ff 0.3.0", + "ark-ff 0.4.2", + "bytes", + "fastrlp", + "num-bigint", + "parity-scale-codec", + "primitive-types", + "proptest", + "rand", + "rlp", + "ruint-macro", + "serde", + "valuable", + "zeroize", +] + +[[package]] +name = "ruint-macro" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e666a5496a0b2186dbcd0ff6106e29e093c15591bde62c20d3842007c6978a09" + +[[package]] +name = "rustc-demangle" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hex" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6" + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", +] + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver 1.0.20", +] + +[[package]] +name = "rustix" +version = "0.38.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "secp256k1" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e" +dependencies = [ + "cc", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" + +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + +[[package]] +name = "serde" +version = "1.0.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_arrays" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38636132857f68ec3d5f3eb121166d2af33cb55174c4d5ff645db6165cbef0fd" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.190" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "serde_json" +version = "1.0.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "base64", + "chrono", + "hex", + "indexmap 1.9.3", + "serde", + "serde_json", + "serde_with_macros", + "time", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380" + +[[package]] +name = "signal-hook" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-mio" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ad2e15f37ec9a6cc544097b78a1ec90001e9f71b81338ca39f430adaca99af" +dependencies = [ + "libc", + "mio", + "signal-hook", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest 0.10.7", + "rand_core", +] + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "smol_str" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c" +dependencies = [ + "serde", +] + +[[package]] +name = "snark-verifier" +version = "0.1.6" +dependencies = [ + "ark-std 0.3.0", + "crossterm 0.25.0", + "halo2-base", + "halo2-ecc", + "hex", + "itertools 0.11.0", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "pairing", + "paste", + "rand", + "rand_chacha", + "ratatui", + "rayon", + "revm", + "ruint", + "serde", + "serde_json", + "sha3 0.10.8", +] + +[[package]] +name = "snark-verifier-sdk" +version = "0.1.6" +dependencies = [ + "ark-std 0.3.0", + "bincode", + "criterion", + "criterion-macro", + "crossterm 0.25.0", + "ethereum-types", + "getset", + "halo2-base", + "hex", + "itertools 0.11.0", + "lazy_static", + "num-bigint", + "num-integer", + "num-traits", + "paste", + "pprof", + "rand", + "rand_chacha", + "ratatui", + "serde", + "serde_json", + "serde_with", + "snark-verifier", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "str_stack" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9091b6114800a5f2141aee1d1b9d6ca3592ac062dc5decb3764ec5895a47b4eb" + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "strum" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290d54ea6f91c969195bdbcd7442c8c2a2ba87da8bf60a7ee86a235d4bc1e125" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.38", +] + +[[package]] +name = "substrate-bn" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b5bbfa79abbae15dd642ea8176a21a635ff3c00059961d1ea27ad04e5b441c" +dependencies = [ + "byteorder", + "crunchy", + "lazy_static", + "rand", + "rustc-hex", +] + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "symbolic-common" +version = "12.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d3aa424281de488c1ddbaffb55a421ad87d04b0fdd5106e7e71d748c0c71ea6" +dependencies = [ + "debugid", + "memmap2", + "stable_deref_trait", + "uuid", +] + +[[package]] +name = "symbolic-demangle" +version = "12.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bdcf77effe2908a21c1011b4d49a7122e0f44487a6ad89db67c55a1687e2572" +dependencies = [ + "cpp_demangle", + "rustc-demangle", + "symbolic-common", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "tempfile" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix", + "windows-sys", +] + +[[package]] +name = "test-case" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8f1e820b7f1d95a0cdbf97a5df9de10e1be731983ab943e56703ac1b8e9d425" +dependencies = [ + "test-case-macros", +] + +[[package]] +name = "test-case-core" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54c25e2cb8f5fcd7318157634e8838aa6f7e4715c96637f969fabaccd1ef5462" +dependencies = [ + "cfg-if", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "test-case-macros" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37cfd7bbc88a0104e304229fba519bdc45501a30b760fb72240342f1289ad257" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.38", + "test-case-core", +] + +[[package]] +name = "thiserror" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "threadpool" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" +dependencies = [ + "num_cpus", +] + +[[package]] +name = "time" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" +dependencies = [ + "deranged", + "itoa", + "powerfmt", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" + +[[package]] +name = "time-macros" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +dependencies = [ + "time-core", +] + +[[package]] +name = "tiny-keccak" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" +dependencies = [ + "crunchy", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "toml_datetime" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.1.0", + "toml_datetime", + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +dependencies = [ + "once_cell", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "ucd-trie" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9" + +[[package]] +name = "uint" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76f64bba2c53b04fcab63c01a7d7427eadc821e3bc48c34dc9ba29c501164b52" +dependencies = [ + "byteorder", + "crunchy", + "hex", + "static_assertions", +] + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "uuid" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7daec296f25a1bae309c0cd5c29c4b260e510e6d813c286b19eaadf409d40fce" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e397f4664c0e4e428e8313a469aaa58310d302159845980fd23b0f22a847f217" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.38", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5961017b3b08ad5f3fe39f1e79877f8ee7c23c5e5fd5eb80de95abc41f1f16b2" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5353b8dab669f5e10f5bd76df26a9360c748f054f862ff5f3f8aae0c7fb3907" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.88" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d046c5d029ba91a1ed14da14dca44b68bf2f124cfbaf741c54151fdb3e0750b" + +[[package]] +name = "web-sys" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5db499c5f66323272151db0e666cd34f78617522fb0c1604d31a27c50c206a85" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "which" +version = "4.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" +dependencies = [ + "either", + "home", + "once_cell", + "rustix", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-core" +version = "0.51.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "winnow" +version = "0.5.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "829846f3e3db426d4cee4510841b71a8e58aa2a76b1132579487ae430ccd9c7b" +dependencies = [ + "memchr", +] + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "zerocopy" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "092cd76b01a033a9965b9097da258689d9e17c69ded5dcf41bca001dd20ebc6d" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a13a20a7c6a90e2034bcc65495799da92efcec6a8dd4f3fcb6f7a48988637ead" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 5bfb6a21..1bfb01bd 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -5,7 +5,7 @@ edition = "2021" autobenches = false [dependencies] -itertools = "0.10.5" +itertools = "0.11" lazy_static = "1.4.0" num-bigint = "0.4.3" num-integer = "0.1.45" @@ -23,7 +23,7 @@ snark-verifier = { path = "../snark-verifier", default-features = false } getset = "0.1.2" # loader_evm -ethereum-types = { version = "0.14.1", default-features = false, features = [ +ethereum-types = { version = "=0.14.1", default-features = false, features = [ "std", ], optional = true } @@ -54,8 +54,9 @@ default = [ "display", ] display = ["snark-verifier/display", "dep:ark-std"] -loader_evm = ["snark-verifier/loader_evm", "dep:ethereum-types"] loader_halo2 = ["snark-verifier/loader_halo2"] +loader_evm = ["snark-verifier/loader_evm", "dep:ethereum-types"] +revm = ["snark-verifier/revm"] parallel = ["snark-verifier/parallel"] # EXACTLY one of halo2-pse / halo2-axiom should always be turned on; not sure how to enforce this with Cargo halo2-pse = ["snark-verifier/halo2-pse", "dep:serde_with"] diff --git a/snark-verifier-sdk/benches/standard_plonk.rs b/snark-verifier-sdk/benches/standard_plonk.rs index 9f566999..6f933bb9 100644 --- a/snark-verifier-sdk/benches/standard_plonk.rs +++ b/snark-verifier-sdk/benches/standard_plonk.rs @@ -11,7 +11,9 @@ use halo2_proofs::{ }; use pprof::criterion::{Output, PProfProfiler}; use rand::rngs::OsRng; -use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; +#[cfg(feature = "revm")] +use snark_verifier_sdk::evm::evm_verify; +use snark_verifier_sdk::evm::{gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; use snark_verifier_sdk::halo2::aggregation::{AggregationConfigParams, VerifierUniversality}; use snark_verifier_sdk::{ gen_pk, @@ -235,15 +237,16 @@ fn bench(c: &mut Criterion) { .use_break_points(break_points); let num_instances = agg_circuit.num_instance(); let instances = agg_circuit.instances(); - let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); + let _proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); - let deployment_code = gen_evm_verifier_shplonk::( + let _deployment_code = gen_evm_verifier_shplonk::( ¶ms, pk.get_vk(), num_instances, None, ); - evm_verify(deployment_code, instances, proof); + #[cfg(feature = "revm")] + evm_verify(_deployment_code, instances, _proof); } } diff --git a/snark-verifier-sdk/examples/standard_plonk.rs b/snark-verifier-sdk/examples/standard_plonk.rs index 7ad9c971..fb0e17c1 100644 --- a/snark-verifier-sdk/examples/standard_plonk.rs +++ b/snark-verifier-sdk/examples/standard_plonk.rs @@ -6,7 +6,9 @@ use halo2_base::utils::fs::gen_srs; use halo2_proofs::halo2curves as halo2_curves; use halo2_proofs::{halo2curves::bn256::Bn256, poly::kzg::commitment::ParamsKZG}; use rand::rngs::OsRng; -use snark_verifier_sdk::evm::{evm_verify, gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; +#[cfg(feature = "revm")] +use snark_verifier_sdk::evm::evm_verify; +use snark_verifier_sdk::evm::{gen_evm_proof_shplonk, gen_evm_verifier_shplonk}; use snark_verifier_sdk::halo2::aggregation::{AggregationConfigParams, VerifierUniversality}; use snark_verifier_sdk::{ gen_pk, @@ -204,13 +206,14 @@ fn main() { .use_break_points(break_points); let num_instances = agg_circuit.num_instance(); let instances = agg_circuit.instances(); - let proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); + let _proof = gen_evm_proof_shplonk(¶ms, &pk, agg_circuit, instances.clone()); - let deployment_code = gen_evm_verifier_shplonk::( + let _deployment_code = gen_evm_verifier_shplonk::( ¶ms, pk.get_vk(), num_instances, Some(Path::new("examples/StandardPlonkVerifier.sol")), ); - evm_verify(deployment_code, instances, proof); + #[cfg(feature = "revm")] + evm_verify(_deployment_code, instances, _proof); } diff --git a/snark-verifier-sdk/src/evm.rs b/snark-verifier-sdk/src/evm.rs index d3b745fb..6519752a 100644 --- a/snark-verifier-sdk/src/evm.rs +++ b/snark-verifier-sdk/src/evm.rs @@ -22,7 +22,7 @@ use itertools::Itertools; use rand::{rngs::StdRng, SeedableRng}; pub use snark_verifier::loader::evm::encode_calldata; use snark_verifier::{ - loader::evm::{compile_solidity, deploy_and_call, EvmLoader}, + loader::evm::{compile_solidity, EvmLoader}, pcs::{ kzg::{KzgAccumulator, KzgAsVerifyingKey, KzgDecidingKey, KzgSuccinctVerifyingKey}, AccumulationDecider, AccumulationScheme, PolynomialCommitmentScheme, @@ -174,9 +174,10 @@ pub fn gen_evm_verifier_shplonk>( gen_evm_verifier::(params, vk, num_instance, path) } +#[cfg(feature = "revm")] pub fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { let calldata = encode_calldata(&instances, &proof); - let gas_cost = deploy_and_call(deployment_code, calldata).unwrap(); + let gas_cost = snark_verifier::loader::evm::deploy_and_call(deployment_code, calldata).unwrap(); dbg!(gas_cost); } diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 8c437a2e..167fd962 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -17,15 +17,18 @@ pairing = { version = "0.23" } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc", default-features = false } +# loader_halo2 +halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc", default-features = false, optional = true } + # parallel -rayon = { version = "1.7", optional = true } +rayon = { version = "1.8", optional = true } # loader_evm -sha3 = { version = "0.10", optional = true } -revm = { version = "3.3.0", optional = true } +sha3 = { version = "=0.10", optional = true } +ruint = { version = "=1.10", optional = true } -# loader_halo2 -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc", default-features = false, optional = true } +# revm only used for testing smart contract execution +revm = { version = "=3.5.0", optional = true } [dev-dependencies] ark-std = { version = "0.3.0", features = ["print-trace"] } @@ -40,8 +43,9 @@ ratatui = { version = "0.24", default-features = false, features = ["crossterm"] [features] default = ["loader_evm", "loader_halo2", "halo2-axiom", "display"] display = ["halo2-base/display", "halo2-ecc?/display"] -loader_evm = ["dep:sha3", "dep:revm"] loader_halo2 = ["halo2-ecc"] +loader_evm = ["dep:sha3", "dep:ruint"] +revm = ["loader_evm", "dep:revm"] parallel = ["dep:rayon"] # EXACTLY one of halo2-pse / halo2-axiom should always be turned on; not sure how to enforce this with Cargo halo2-pse = ["halo2-base/halo2-pse", "halo2-ecc?/halo2-pse"] diff --git a/snark-verifier/examples/evm-verifier-with-accumulator.rs b/snark-verifier/examples/evm-verifier-with-accumulator.rs index 304b7395..b18e992d 100644 --- a/snark-verifier/examples/evm-verifier-with-accumulator.rs +++ b/snark-verifier/examples/evm-verifier-with-accumulator.rs @@ -21,9 +21,11 @@ use halo2_proofs::{ }; use itertools::Itertools; use rand::rngs::OsRng; +#[cfg(feature = "revm")] +use snark_verifier::loader::evm::{deploy_and_call, encode_calldata}; use snark_verifier::{ loader::{ - evm::{self, deploy_and_call, encode_calldata, EvmLoader}, + evm::{self, EvmLoader}, native::NativeLoader, }, pcs::kzg::{Gwc19, KzgAs, LimbsEncoding}, @@ -504,6 +506,7 @@ fn gen_aggregation_evm_verifier( evm::compile_solidity(&loader.solidity_code()) } +#[cfg(feature = "revm")] fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { let calldata = encode_calldata(&instances, &proof); let gas_cost = deploy_and_call(deployment_code, calldata).unwrap(); @@ -546,7 +549,7 @@ fn main() { let params = gen_srs(agg_config.degree); let pk = gen_pk(¶ms, &agg_circuit.inner); - let deployment_code = gen_aggregation_evm_verifier( + let _deployment_code = gen_aggregation_evm_verifier( ¶ms, pk.get_vk(), aggregation::AggregationCircuit::num_instance(), @@ -564,11 +567,12 @@ fn main() { snarks, ); let instances = agg_circuit.instances(); - let proof = gen_proof::<_, _, EvmTranscript, EvmTranscript>( - ¶ms, - &pk, - agg_circuit.inner, - instances.clone(), - ); - evm_verify(deployment_code, instances, proof); + let _proof = gen_proof::< + _, + _, + EvmTranscript, + EvmTranscript, + >(¶ms, &pk, agg_circuit.inner, instances.clone()); + #[cfg(feature = "revm")] + evm_verify(_deployment_code, instances, _proof); } diff --git a/snark-verifier/examples/evm-verifier.rs b/snark-verifier/examples/evm-verifier.rs index d541528a..9bd8c61d 100644 --- a/snark-verifier/examples/evm-verifier.rs +++ b/snark-verifier/examples/evm-verifier.rs @@ -20,8 +20,10 @@ use halo2_proofs::{ }; use itertools::Itertools; use rand::{rngs::OsRng, RngCore}; +#[cfg(feature = "revm")] +use snark_verifier::loader::evm::{deploy_and_call, encode_calldata}; use snark_verifier::{ - loader::evm::{self, deploy_and_call, encode_calldata, EvmLoader}, + loader::evm::{self, EvmLoader}, pcs::kzg::{Gwc19, KzgAs}, system::halo2::{compile, transcript::evm::EvmTranscript, Config}, verifier::{self, SnarkVerifier}, @@ -240,6 +242,7 @@ fn gen_evm_verifier( evm::compile_solidity(&loader.solidity_code()) } +#[cfg(feature = "revm")] fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) { let calldata = encode_calldata(&instances, &proof); let gas_cost = deploy_and_call(deployment_code, calldata).unwrap(); @@ -251,8 +254,9 @@ fn main() { let circuit = StandardPlonk::rand(OsRng); let pk = gen_pk(¶ms, &circuit); - let deployment_code = gen_evm_verifier(¶ms, pk.get_vk(), StandardPlonk::num_instance()); + let _deployment_code = gen_evm_verifier(¶ms, pk.get_vk(), StandardPlonk::num_instance()); - let proof = gen_proof(¶ms, &pk, circuit.clone(), circuit.instances()); - evm_verify(deployment_code, circuit.instances(), proof); + let _proof = gen_proof(¶ms, &pk, circuit.clone(), circuit.instances()); + #[cfg(feature = "revm")] + evm_verify(_deployment_code, circuit.instances(), _proof); } diff --git a/snark-verifier/src/loader/evm.rs b/snark-verifier/src/loader/evm.rs index 19b145bb..9ab472db 100644 --- a/snark-verifier/src/loader/evm.rs +++ b/snark-verifier/src/loader/evm.rs @@ -6,6 +6,8 @@ pub(crate) mod util; pub use loader::{EcPoint, EvmLoader, Scalar}; pub use util::{ - compile_solidity, deploy_and_call, encode_calldata, estimate_gas, fe_to_u256, modulus, + compile_solidity, encode_calldata, estimate_gas, fe_to_u256, modulus, u256_to_fe, Address, B256, U256, U512, }; +#[cfg(feature = "revm")] +pub use util::deploy_and_call; diff --git a/snark-verifier/src/loader/evm/util.rs b/snark-verifier/src/loader/evm/util.rs index 031e85b9..8bf92dd1 100644 --- a/snark-verifier/src/loader/evm/util.rs +++ b/snark-verifier/src/loader/evm/util.rs @@ -8,9 +8,11 @@ use std::{ process::{Command, Stdio}, }; +#[cfg(feature = "revm")] pub use executor::deploy_and_call; -pub use revm::primitives::ruint::aliases::{B160 as Address, B256, U256, U512}; +pub use ruint::aliases::{B160 as Address, B256, U256, U512}; +#[cfg(feature = "revm")] pub(crate) mod executor; /// Memory chunk in EVM. From 18a1dd504b3e1e8b903e40b5e3af71ac98e40cbd Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 3 Nov 2023 18:11:10 -0700 Subject: [PATCH 62/73] 0.1.6-rc -> 0.1.7-rc (#37) * chore: try pragma solidity 0.8.20 with CI * chore: make `transcript_initial_state` public So we can read transcript initial state from `VerifyingKey` * test: edit range_check example to trigger selector compression * [feat] add `aggregate_snarks` function (#34) * feat: add `aggregate_snarks` function - Previously you could only create a new `builder` pre-populated with the witnesses for snark aggregation. - This is a bad design pattern if you want to make a circuit that aggregates and also does other stuff. - This function will use whatever `SinglePhaseCoreManager` and `RangeChip` you provide to prove the snark aggregation. * chore: add comment * chore: fix comment * [feat(sdk)] `aggregate_snarks` returns loaded proof witnesses (#36) * feat(sdk): `aggregate_snarks` returns loaded proof witnesses * feat: add `TranscriptObject` to track assigned proof transcript * chore: Bump version to 0.1.7 --- Cargo.lock | 8 +- snark-verifier-sdk/Cargo.toml | 12 +- snark-verifier-sdk/examples/range_check.rs | 27 +- snark-verifier-sdk/src/halo2/aggregation.rs | 240 ++++++++++++------ snark-verifier/Cargo.toml | 6 +- snark-verifier/src/loader/evm/code.rs | 2 +- snark-verifier/src/system/halo2.rs | 4 +- .../src/system/halo2/transcript/halo2.rs | 36 ++- 8 files changed, 232 insertions(+), 103 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index edc988a7..f2a6bd84 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1137,7 +1137,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "halo2-base" version = "0.4.0" -source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.4.0-rc#67e3a0eee37c3b25b393cdea7514fef4e8af0bf9" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.4.1-rc#a30e3b18d285c8b0d7145c1c34297edd9433df60" dependencies = [ "getset", "halo2_proofs 0.2.0", @@ -1159,7 +1159,7 @@ dependencies = [ [[package]] name = "halo2-ecc" version = "0.4.0" -source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.4.0-rc#67e3a0eee37c3b25b393cdea7514fef4e8af0bf9" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.4.1-rc#a30e3b18d285c8b0d7145c1c34297edd9433df60" dependencies = [ "halo2-base", "itertools 0.10.5", @@ -2600,7 +2600,7 @@ dependencies = [ [[package]] name = "snark-verifier" -version = "0.1.6" +version = "0.1.7" dependencies = [ "ark-std 0.3.0", "crossterm 0.25.0", @@ -2627,7 +2627,7 @@ dependencies = [ [[package]] name = "snark-verifier-sdk" -version = "0.1.6" +version = "0.1.7" dependencies = [ "ark-std 0.3.0", "bincode", diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index 1bfb01bd..ff1e909a 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier-sdk" -version = "0.1.6" +version = "0.1.7" edition = "2021" autobenches = false @@ -18,7 +18,7 @@ serde_json = "1.0" serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.1-rc", default-features = false } snark-verifier = { path = "../snark-verifier", default-features = false } getset = "0.1.2" @@ -46,13 +46,7 @@ crossterm = { version = "0.25" } ratatui = { version = "0.24", default-features = false, features = ["crossterm"] } [features] -default = [ - "loader_halo2", - "loader_evm", - "halo2-axiom", - "halo2-base/jemallocator", - "display", -] +default = ["loader_halo2", "loader_evm", "halo2-axiom", "halo2-base/jemallocator", "display"] display = ["snark-verifier/display", "dep:ark-std"] loader_halo2 = ["snark-verifier/loader_halo2"] loader_evm = ["snark-verifier/loader_evm", "dep:ethereum-types"] diff --git a/snark-verifier-sdk/examples/range_check.rs b/snark-verifier-sdk/examples/range_check.rs index 2beb5a78..3d75c2cd 100644 --- a/snark-verifier-sdk/examples/range_check.rs +++ b/snark-verifier-sdk/examples/range_check.rs @@ -14,7 +14,7 @@ use snark_verifier_sdk::{ Snark, }; -fn generate_circuit(k: u32) -> Snark { +fn generate_circuit(k: u32, fill: bool) -> Snark { let lookup_bits = k as usize - 1; let circuit_params = BaseCircuitParams { k: k as usize, @@ -30,20 +30,31 @@ fn generate_circuit(k: u32) -> Snark { let ctx = builder.main(0); let x = ctx.load_witness(Fr::from(14)); - range.range_check(ctx, x, 2 * lookup_bits + 1); - range.gate().add(ctx, x, x); + if fill { + for _ in 0..2 << k { + range.gate().add(ctx, x, x); + } + } let params = gen_srs(k); // do not call calculate_params, we want to use fixed params let pk = gen_pk(¶ms, &builder, None); + // std::fs::remove_file(Path::new("examples/app.pk")).ok(); + // let _pk = gen_pk(¶ms, &builder, Some(Path::new("examples/app.pk"))); + // let pk = read_pk::>( + // Path::new("examples/app.pk"), + // builder.config_params.clone(), + // ) + // .unwrap(); + // std::fs::remove_file(Path::new("examples/app.pk")).ok(); // builder now has break_point set gen_snark_shplonk(¶ms, &pk, builder, None::<&str>) } fn main() { - let dummy_snark = generate_circuit(9); + let dummy_snark = generate_circuit(9, false); - let k = 14u32; + let k = 16u32; let lookup_bits = k as usize - 1; let params = gen_srs(k); let mut agg_circuit = AggregationCircuit::new::( @@ -57,10 +68,14 @@ fn main() { let start0 = start_timer!(|| "gen vk & pk"); let pk = gen_pk(¶ms, &agg_circuit, None); + // std::fs::remove_file(Path::new("examples/agg.pk")).ok(); + // let _pk = gen_pk(¶ms, &agg_circuit, Some(Path::new("examples/agg.pk"))); end_timer!(start0); + // let pk = read_pk::(Path::new("examples/agg.pk"), agg_config).unwrap(); + // std::fs::remove_file(Path::new("examples/agg.pk")).ok(); let break_points = agg_circuit.break_points(); - let snarks = (10..16).map(generate_circuit).collect_vec(); + let snarks = (10..16).map(|k| generate_circuit(k, true)).collect_vec(); for (i, snark) in snarks.into_iter().enumerate() { let agg_circuit = AggregationCircuit::new::( CircuitBuilderStage::Prover, diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index 690a64fc..ed940729 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -6,7 +6,8 @@ use halo2_base::{ circuit::{ builder::BaseCircuitBuilder, BaseCircuitParams, BaseConfig, CircuitBuilderStage, }, - flex_gate::MultiPhaseThreadBreakPoints, + flex_gate::{threads::SinglePhaseCoreManager, MultiPhaseThreadBreakPoints}, + RangeChip, }, halo2_proofs::{ circuit::{Layouter, SimpleFloorPlanner}, @@ -25,13 +26,14 @@ use snark_verifier::util::arithmetic::fe_to_limbs; use snark_verifier::{ loader::{ self, - halo2::halo2_ecc::{self, bn254::FpChip}, + halo2::halo2_ecc::{self, bigint::ProperCrtUint, bn254::FpChip}, native::NativeLoader, }, pcs::{ kzg::{KzgAccumulator, KzgAsProvingKey, KzgAsVerifyingKey, KzgSuccinctVerifyingKey}, AccumulationScheme, AccumulationSchemeProver, PolynomialCommitmentScheme, }, + system::halo2::transcript::halo2::TranscriptObject, verifier::SnarkVerifier, }; use std::{fs::File, mem, path::Path, rc::Rc}; @@ -56,6 +58,8 @@ pub struct SnarkAggregationWitness<'a> { /// This returns the assigned `preprocessed` and `transcript_initial_state` values as a vector of assigned values, one for each aggregated snark. /// These can then be exposed as public instances. pub preprocessed: Vec, + /// The proof transcript, as loaded scalars and elliptic curve points, for each SNARK that was aggregated. + pub proof_transcripts: Vec>>>>, } /// Different possible stages of universality the aggregation circuit can support @@ -132,9 +136,9 @@ where ); let preprocessed_as_witness = universality.preprocessed_as_witness(); - let mut accumulators = snarks + let (proof_transcripts, accumulators): (Vec<_>, Vec<_>) = snarks .iter() - .flat_map(|snark: &Snark| { + .map(|snark: &Snark| { let protocol = if preprocessed_as_witness { // always load `domain.n` as witness if vkey is witness snark.protocol.loaded_preprocessed_as_witness(loader, universality.k_as_witness()) @@ -184,10 +188,21 @@ where previous_instances.push( instances.into_iter().flatten().map(|scalar| scalar.into_assigned()).collect(), ); - - accumulator + let proof_transcript = transcript.loaded_stream.clone(); + debug_assert_eq!( + snark.proof().len(), + proof_transcript + .iter() + .map(|t| match t { + TranscriptObject::Scalar(_) => 32, + TranscriptObject::EcPoint(_) => 32, + }) + .sum::() + ); + (proof_transcript, accumulator) }) - .collect_vec(); + .unzip(); + let mut accumulators = accumulators.into_iter().flatten().collect_vec(); let accumulator = if accumulators.len() > 1 { transcript.new_stream(as_proof); @@ -207,6 +222,7 @@ where previous_instances, accumulator, preprocessed: preprocessed_witnesses, + proof_transcripts, } } @@ -314,6 +330,145 @@ pub trait Halo2KzgAccumulationScheme<'a> = PolynomialCommitmentScheme< VerifyingKey = KzgAsVerifyingKey, > + AccumulationSchemeProver>; +/// **Private** witnesses that form the output of [aggregate_snarks]. +/// Same as [SnarkAggregationWitness] except that we flatten `accumulator` into a vector of field elements. +#[derive(Clone, Debug)] +pub struct SnarkAggregationOutput { + pub previous_instances: Vec>>, + pub accumulator: Vec>, + /// This returns the assigned `preprocessed` and `transcript_initial_state` values as a vector of assigned values, one for each aggregated snark. + /// These can then be exposed as public instances. + pub preprocessed: Vec, + /// The proof transcript, as loaded scalars and elliptic curve points, for each SNARK that was aggregated. + pub proof_transcripts: Vec>, +} + +#[allow(clippy::large_enum_variant)] +#[derive(Clone, Debug)] +pub enum AssignedTranscriptObject { + Scalar(AssignedValue), + EcPoint(halo2_ecc::ecc::EcPoint>), +} + +/// Given snarks, this populates the circuit builder with the virtual cells and constraints necessary to verify all the snarks. +/// +/// ## Notes +/// - This function does _not_ expose any public instances. +/// - `svk` is the generator of the KZG trusted setup, usually gotten via `params.get_g()[0]` +/// (avoids having to pass `params` into function just to get generator) +/// +/// ## Universality +/// - If `universality` is not `None`, then the verifying keys of each snark in `snarks` is loaded as a witness in the circuit. +/// - Moreover, if `universality` is `Full`, then the number of rows `n` of each snark in `snarks` is also loaded as a witness. In this case the generator `omega` of the order `n` multiplicative subgroup of `F` is also loaded as a witness. +/// - By default, these witnesses are _private_ and returned in `self.preprocessed_digests +/// - The user can optionally modify the circuit after calling this function to add more instances to `assigned_instances` to expose. +/// +/// ## Warning +/// Will fail silently if `snarks` were created using a different multi-open scheme than `AS` +/// where `AS` can be either [`crate::SHPLONK`] or [`crate::GWC`] (for original PLONK multi-open scheme) +/// +/// ## Assumptions +/// - `pool` and `range` reference the same `SharedCopyConstraintManager`. +pub fn aggregate_snarks( + pool: &mut SinglePhaseCoreManager, + range: &RangeChip, + svk: Svk, // gotten by params.get_g()[0].into() + snarks: impl IntoIterator, + universality: VerifierUniversality, +) -> SnarkAggregationOutput +where + AS: for<'a> Halo2KzgAccumulationScheme<'a>, +{ + let snarks = snarks.into_iter().collect_vec(); + + let mut transcript_read = + PoseidonTranscript::::from_spec(&[], POSEIDON_SPEC.clone()); + // TODO: the snarks can probably store these accumulators + let accumulators = snarks + .iter() + .flat_map(|snark| { + transcript_read.new_stream(snark.proof()); + let proof = PlonkSuccinctVerifier::::read_proof( + &svk, + &snark.protocol, + &snark.instances, + &mut transcript_read, + ) + .unwrap(); + PlonkSuccinctVerifier::::verify(&svk, &snark.protocol, &snark.instances, &proof) + .unwrap() + }) + .collect_vec(); + + let (_accumulator, as_proof) = { + let mut transcript_write = + PoseidonTranscript::>::from_spec(vec![], POSEIDON_SPEC.clone()); + let rng = StdRng::from_entropy(); + let accumulator = + AS::create_proof(&Default::default(), &accumulators, &mut transcript_write, rng) + .unwrap(); + (accumulator, transcript_write.finalize()) + }; + + // create halo2loader + let fp_chip = FpChip::::new(range, BITS, LIMBS); + let ecc_chip = BaseFieldEccChip::new(&fp_chip); + // `pool` needs to be owned by loader. + // We put it back later (below), so it should have same effect as just mutating `pool`. + let tmp_pool = mem::take(pool); + // range_chip has shared reference to LookupAnyManager, with shared CopyConstraintManager + // pool has shared reference to CopyConstraintManager + let loader = Halo2Loader::new(ecc_chip, tmp_pool); + + // run witness and copy constraint generation + let SnarkAggregationWitness { + previous_instances, + accumulator, + preprocessed, + proof_transcripts, + } = aggregate::(&svk, &loader, &snarks, as_proof.as_slice(), universality); + let lhs = accumulator.lhs.assigned(); + let rhs = accumulator.rhs.assigned(); + let accumulator = lhs + .x() + .limbs() + .iter() + .chain(lhs.y().limbs().iter()) + .chain(rhs.x().limbs().iter()) + .chain(rhs.y().limbs().iter()) + .copied() + .collect_vec(); + let proof_transcripts = proof_transcripts + .into_iter() + .map(|transcript| { + transcript + .into_iter() + .map(|obj| match obj { + TranscriptObject::Scalar(scalar) => { + AssignedTranscriptObject::Scalar(scalar.into_assigned()) + } + TranscriptObject::EcPoint(point) => { + AssignedTranscriptObject::EcPoint(point.into_assigned()) + } + }) + .collect() + }) + .collect(); + + #[cfg(debug_assertions)] + { + let KzgAccumulator { lhs, rhs } = _accumulator; + let instances = + [lhs.x, lhs.y, rhs.x, rhs.y].map(fe_to_limbs::<_, Fr, LIMBS, BITS>).concat(); + for (lhs, rhs) in instances.iter().zip(accumulator.iter()) { + assert_eq!(lhs, rhs.value()); + } + } + // put back `pool` into `builder` + *pool = loader.take_ctx(); + SnarkAggregationOutput { previous_instances, accumulator, preprocessed, proof_transcripts } +} + impl AggregationCircuit { /// Given snarks, this creates `BaseCircuitBuilder` and populates the circuit builder with the virtual cells and constraints necessary to verify all the snarks. /// @@ -339,77 +494,10 @@ impl AggregationCircuit { AS: for<'a> Halo2KzgAccumulationScheme<'a>, { let svk: Svk = params.get_g()[0].into(); - let snarks = snarks.into_iter().collect_vec(); - - let mut transcript_read = - PoseidonTranscript::::from_spec(&[], POSEIDON_SPEC.clone()); - // TODO: the snarks can probably store these accumulators - let accumulators = snarks - .iter() - .flat_map(|snark| { - transcript_read.new_stream(snark.proof()); - let proof = PlonkSuccinctVerifier::::read_proof( - &svk, - &snark.protocol, - &snark.instances, - &mut transcript_read, - ) - .unwrap(); - PlonkSuccinctVerifier::::verify(&svk, &snark.protocol, &snark.instances, &proof) - .unwrap() - }) - .collect_vec(); - - let (_accumulator, as_proof) = { - let mut transcript_write = PoseidonTranscript::>::from_spec( - vec![], - POSEIDON_SPEC.clone(), - ); - let rng = StdRng::from_entropy(); - let accumulator = - AS::create_proof(&Default::default(), &accumulators, &mut transcript_write, rng) - .unwrap(); - (accumulator, transcript_write.finalize()) - }; - let mut builder = BaseCircuitBuilder::from_stage(stage).use_params(config_params.into()); - // create halo2loader let range = builder.range_chip(); - let fp_chip = FpChip::::new(&range, BITS, LIMBS); - let ecc_chip = BaseFieldEccChip::new(&fp_chip); - // Take the phase 0 pool from `builder`; it needs to be owned by loader. - // We put it back later (below), so it should have same effect as just mutating `builder.pool(0)`. - let pool = mem::take(builder.pool(0)); - // range_chip has shared reference to LookupAnyManager, with shared CopyConstraintManager - // pool has shared reference to CopyConstraintManager - let loader = Halo2Loader::new(ecc_chip, pool); - - // run witness and copy constraint generation - let SnarkAggregationWitness { previous_instances, accumulator, preprocessed } = - aggregate::(&svk, &loader, &snarks, as_proof.as_slice(), universality); - let lhs = accumulator.lhs.assigned(); - let rhs = accumulator.rhs.assigned(); - let accumulator = lhs - .x() - .limbs() - .iter() - .chain(lhs.y().limbs().iter()) - .chain(rhs.x().limbs().iter()) - .chain(rhs.y().limbs().iter()) - .copied() - .collect_vec(); - - #[cfg(debug_assertions)] - { - let KzgAccumulator { lhs, rhs } = _accumulator; - let instances = - [lhs.x, lhs.y, rhs.x, rhs.y].map(fe_to_limbs::<_, Fr, LIMBS, BITS>).concat(); - for (lhs, rhs) in instances.iter().zip(accumulator.iter()) { - assert_eq!(lhs, rhs.value()); - } - } - // put back `pool` into `builder` - *builder.pool(0) = loader.take_ctx(); + let SnarkAggregationOutput { previous_instances, accumulator, preprocessed, .. } = + aggregate_snarks::(builder.pool(0), &range, svk, snarks, universality); assert_eq!( builder.assigned_instances.len(), 1, diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 167fd962..5b082dc9 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "snark-verifier" -version = "0.1.6" +version = "0.1.7" edition = "2021" [dependencies] @@ -15,10 +15,10 @@ serde = { version = "1.0", features = ["derive"] } pairing = { version = "0.23" } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc", default-features = false } +halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.1-rc", default-features = false } # loader_halo2 -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.0-rc", default-features = false, optional = true } +halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.1-rc", default-features = false, optional = true } # parallel rayon = { version = "1.8", optional = true } diff --git a/snark-verifier/src/loader/evm/code.rs b/snark-verifier/src/loader/evm/code.rs index eee4fb3e..7744ab35 100644 --- a/snark-verifier/src/loader/evm/code.rs +++ b/snark-verifier/src/loader/evm/code.rs @@ -21,7 +21,7 @@ impl SolidityAssemblyCode { " // SPDX-License-Identifier: MIT -pragma solidity 0.8.19; +pragma solidity >=0.8.19 <0.8.21; contract Halo2Verifier {{ fallback(bytes calldata) external returns (bytes memory) {{ diff --git a/snark-verifier/src/system/halo2.rs b/snark-verifier/src/system/halo2.rs index 82bffc20..fd5778e8 100644 --- a/snark-verifier/src/system/halo2.rs +++ b/snark-verifier/src/system/halo2.rs @@ -716,7 +716,9 @@ impl Transcript for MockTranscript } } -fn transcript_initial_state(vk: &VerifyingKey) -> C::Scalar { +/// Returns the transcript initial state of the [VerifyingKey]. +/// Roundabout way to do it because [VerifyingKey] doesn't expose the field. +pub fn transcript_initial_state(vk: &VerifyingKey) -> C::Scalar { let mut transcript = MockTranscript::default(); vk.hash_into(&mut transcript).unwrap(); transcript.0 diff --git a/snark-verifier/src/system/halo2/transcript/halo2.rs b/snark-verifier/src/system/halo2/transcript/halo2.rs index 8a0ce6d4..ab62b088 100644 --- a/snark-verifier/src/system/halo2/transcript/halo2.rs +++ b/snark-verifier/src/system/halo2/transcript/halo2.rs @@ -35,6 +35,19 @@ where ) -> Result, Error>; } +/// A way to keep track of what gets read in the transcript. +#[derive(Clone, Debug)] +pub enum TranscriptObject +where + C: CurveAffine, + L: Loader, +{ + /// Scalar + Scalar(L::LoadedScalar), + /// Elliptic curve point + EcPoint(L::LoadedEcPoint), +} + #[derive(Debug)] /// Transcript for verifier in [`halo2_proofs`] circuit using poseidon hasher. /// Currently It assumes the elliptic curve scalar field is same as native @@ -53,6 +66,10 @@ pub struct PoseidonTranscript< { loader: L, stream: S, + /// Only relevant for Halo2 loader: as elements from `stream` are read, they are assigned as witnesses. + /// The loaded witnesses are pushed to `loaded_stream`. This way at the end we have the entire proof transcript + /// as loaded witnesses. + pub loaded_stream: Vec>, buf: Poseidon>::LoadedScalar, T, RATE>, } @@ -70,7 +87,7 @@ where C::Scalar: FieldExt, { let buf = Poseidon::new::(loader); - Self { loader: loader.clone(), stream, buf } + Self { loader: loader.clone(), stream, buf, loaded_stream: vec![] } } /// Initialize [`PoseidonTranscript`] from a precomputed spec of round constants and MDS matrix because computing the constants is expensive. @@ -80,12 +97,13 @@ where spec: OptimizedPoseidonSpec, ) -> Self { let buf = Poseidon::from_spec(loader, spec); - Self { loader: loader.clone(), stream, buf } + Self { loader: loader.clone(), stream, buf, loaded_stream: vec![] } } /// Clear the buffer and set the stream to a new one. Effectively the same as starting from a new transcript. pub fn new_stream(&mut self, stream: R) { self.buf.clear(); + self.loaded_stream.clear(); self.stream = stream; } } @@ -148,6 +166,7 @@ where C::Scalar::from_repr(data).unwrap() }; let scalar = self.loader.assign_scalar(scalar); + self.loaded_stream.push(TranscriptObject::Scalar(scalar.clone())); self.common_scalar(&scalar)?; Ok(scalar) } @@ -159,6 +178,7 @@ where C::from_bytes(&compressed).unwrap() }; let ec_point = self.loader.assign_ec_point(ec_point); + self.loaded_stream.push(TranscriptObject::EcPoint(ec_point.clone())); self.common_ec_point(&ec_point)?; Ok(ec_point) } @@ -177,17 +197,24 @@ impl(&NativeLoader), + loaded_stream: vec![], } } /// Initialize [`PoseidonTranscript`] from a precomputed spec of round constants and MDS matrix because computing the constants is expensive. pub fn from_spec(stream: S, spec: OptimizedPoseidonSpec) -> Self { - Self { loader: NativeLoader, stream, buf: Poseidon::from_spec(&NativeLoader, spec) } + Self { + loader: NativeLoader, + stream, + buf: Poseidon::from_spec(&NativeLoader, spec), + loaded_stream: vec![], + } } /// Clear the buffer and set the stream to a new one. Effectively the same as starting from a new transcript. pub fn new_stream(&mut self, stream: S) { self.buf.clear(); + self.loaded_stream.clear(); self.stream = stream; } } @@ -198,6 +225,7 @@ impl Date: Fri, 3 Nov 2023 18:14:32 -0700 Subject: [PATCH 63/73] chore: fix solidity pragma at 0.8.19 --- snark-verifier/src/loader/evm/code.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/snark-verifier/src/loader/evm/code.rs b/snark-verifier/src/loader/evm/code.rs index 7744ab35..eee4fb3e 100644 --- a/snark-verifier/src/loader/evm/code.rs +++ b/snark-verifier/src/loader/evm/code.rs @@ -21,7 +21,7 @@ impl SolidityAssemblyCode { " // SPDX-License-Identifier: MIT -pragma solidity >=0.8.19 <0.8.21; +pragma solidity 0.8.19; contract Halo2Verifier {{ fallback(bytes calldata) external returns (bytes memory) {{ From a9310f62c36e891f2a741777ca56681103e6e702 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 3 Nov 2023 18:29:51 -0700 Subject: [PATCH 64/73] chore: fix release CI --- .github/workflows/release.yaml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 1c89b2e3..6a212b81 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,12 +1,10 @@ -name: CI +name: Release on: pull_request: - branches: - - ["main", "release-*"] + branches: ["main", "release-*"] push: - branches: - - main + branches: ["main"] jobs: test: From 5c5791fb27c48b004c93d5a4e168f971d4350ce5 Mon Sep 17 00:00:00 2001 From: Han Date: Wed, 8 Nov 2023 22:31:30 +0800 Subject: [PATCH 65/73] fix: compute `system_challenge_offset` correctly (#53) --- snark-verifier/src/system/halo2.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/snark-verifier/src/system/halo2.rs b/snark-verifier/src/system/halo2.rs index fd5778e8..1aee2f87 100644 --- a/snark-verifier/src/system/halo2.rs +++ b/snark-verifier/src/system/halo2.rs @@ -479,8 +479,7 @@ impl<'a, F: PrimeField> Polynomials<'a, F> { } fn system_challenge_offset(&self) -> usize { - let num_challenge = self.num_challenge(); - num_challenge[..num_challenge.len() - 3].iter().sum() + self.num_challenge.iter().sum() } fn theta(&self) -> Expression { From 707b1ad538b0d389cd07eb947963577d26370c95 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Wed, 13 Dec 2023 01:23:36 -0500 Subject: [PATCH 66/73] [feat] update `gen_dummy_snark` to help with keygen (#48) * chore: update `gen_dummy_snark` with circuit-params * chore: better doc comment * chore: remove dbg * feat: refactor into `gen_dummy_snark_from_vk` This function does not need to know the `ConcreteCircuit` type * feat: add `KeygenAggregationCircuitIntent` for keygen Trait to help keygen of aggregation circuits. * chore: fix clippy * chore: rename function * chore: add `AggregationDependencyIntentOwned` * chore: From impl * chore: add `gen_dummy_snark_from_protocol` Also added `NativeKzgAccumulationScheme` trait * chore: remove redundancy --- Cargo.lock | 63 +++++------ snark-verifier-sdk/src/halo2.rs | 111 ++++++++++++++++---- snark-verifier-sdk/src/halo2/aggregation.rs | 10 +- snark-verifier-sdk/src/halo2/utils.rs | 91 ++++++++++++++++ 4 files changed, 219 insertions(+), 56 deletions(-) create mode 100644 snark-verifier-sdk/src/halo2/utils.rs diff --git a/Cargo.lock b/Cargo.lock index f2a6bd84..e1dcfeaf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1134,21 +1134,39 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" +[[package]] +name = "halo2-axiom" +version = "0.4.1" +dependencies = [ + "blake2b_simd", + "crossbeam", + "ff", + "group", + "halo2curves-axiom", + "itertools 0.11.0", + "maybe-rayon", + "pairing", + "rand", + "rand_core", + "rustc-hash", + "sha3 0.10.8", + "tracing", +] + [[package]] name = "halo2-base" -version = "0.4.0" -source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.4.1-rc#a30e3b18d285c8b0d7145c1c34297edd9433df60" +version = "0.4.1" dependencies = [ "getset", - "halo2_proofs 0.2.0", - "halo2_proofs 0.2.0 (git+https://github.com/privacy-scaling-explorations/halo2.git?rev=7a21656)", + "halo2-axiom", + "halo2_proofs", "itertools 0.11.0", "jemallocator", "log", "num-bigint", "num-integer", "num-traits", - "poseidon-rs", + "poseidon-primitives", "rand_chacha", "rayon", "rustc-hash", @@ -1158,8 +1176,7 @@ dependencies = [ [[package]] name = "halo2-ecc" -version = "0.4.0" -source = "git+https://github.com/axiom-crypto/halo2-lib.git?branch=release-0.4.1-rc#a30e3b18d285c8b0d7145c1c34297edd9433df60" +version = "0.4.1" dependencies = [ "halo2-base", "itertools 0.10.5", @@ -1175,24 +1192,6 @@ dependencies = [ "test-case", ] -[[package]] -name = "halo2_proofs" -version = "0.2.0" -dependencies = [ - "blake2b_simd", - "crossbeam", - "ff", - "group", - "halo2curves 0.4.0", - "maybe-rayon", - "pairing", - "rand", - "rand_core", - "rustc-hash", - "sha3 0.10.8", - "tracing", -] - [[package]] name = "halo2_proofs" version = "0.2.0" @@ -1201,7 +1200,7 @@ dependencies = [ "blake2b_simd", "ff", "group", - "halo2curves 0.1.0", + "halo2curves", "maybe-rayon", "rand_chacha", "rand_core", @@ -1230,9 +1229,10 @@ dependencies = [ ] [[package]] -name = "halo2curves" -version = "0.4.0" -source = "git+https://github.com/axiom-crypto/halo2curves.git?branch=main#e185711b6ba8f3e22f2af8bf24a5fc84b781ca46" +name = "halo2curves-axiom" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d47eaec6a3040c2fbaa020716bf571b0c55025126242510f774183aff84b92e" dependencies = [ "blake2b_simd", "ff", @@ -1910,9 +1910,10 @@ dependencies = [ ] [[package]] -name = "poseidon-rs" +name = "poseidon-primitives" version = "0.1.1" -source = "git+https://github.com/axiom-crypto/poseidon-circuit.git?rev=1aee4a1#1aee4a1bf6220578924079aac4f2eee3874116a1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bd95570f7ea849b4187298b5bb229643e44e1d47ddf3979d0db8a1c28be26a8" dependencies = [ "bitvec", "ff", diff --git a/snark-verifier-sdk/src/halo2.rs b/snark-verifier-sdk/src/halo2.rs index aa5f8810..ee400913 100644 --- a/snark-verifier-sdk/src/halo2.rs +++ b/snark-verifier-sdk/src/halo2.rs @@ -37,7 +37,7 @@ use snark_verifier::{ system::halo2::{compile, Config}, util::arithmetic::Rotation, util::transcript::TranscriptWrite, - verifier::plonk::PlonkProof, + verifier::plonk::{PlonkProof, PlonkProtocol}, }; use std::{ fs::{self, File}, @@ -46,6 +46,7 @@ use std::{ }; pub mod aggregation; +pub mod utils; // Poseidon parameters // We use the same ones Scroll uses for security: https://github.com/scroll-tech/poseidon-circuit/blob/714f50c7572a4ff6f2b1fa51a9604a99cd7b6c71/src/poseidon/primitives/bn256/fp.rs @@ -274,38 +275,67 @@ pub fn read_snark(path: impl AsRef) -> Result { bincode::deserialize_from(f) } +pub trait NativeKzgAccumulationScheme = PolynomialCommitmentScheme< + G1Affine, + NativeLoader, + VerifyingKey = KzgSuccinctVerifyingKey, + Output = KzgAccumulator, + > + AccumulationScheme< + G1Affine, + NativeLoader, + Accumulator = KzgAccumulator, + VerifyingKey = KzgAsVerifyingKey, + > + CostEstimation>>; + // copied from snark_verifier --example recursion pub fn gen_dummy_snark( params: &ParamsKZG, vk: Option<&VerifyingKey>, num_instance: Vec, + circuit_params: ConcreteCircuit::Params, ) -> Snark where ConcreteCircuit: CircuitExt, - AS: PolynomialCommitmentScheme< - G1Affine, - NativeLoader, - VerifyingKey = KzgSuccinctVerifyingKey, - Output = KzgAccumulator, - > + AccumulationScheme< - G1Affine, - NativeLoader, - Accumulator = KzgAccumulator, - VerifyingKey = KzgAsVerifyingKey, - > + CostEstimation>>, + ConcreteCircuit::Params: Clone, + AS: NativeKzgAccumulationScheme, { - struct CsProxy(PhantomData<(F, C)>); + #[derive(Clone)] + struct CsProxy> { + params: C::Params, + _marker: PhantomData, + } - impl> Circuit for CsProxy { + impl> CsProxy { + pub fn new(params: C::Params) -> Self { + Self { params, _marker: PhantomData } + } + } + + impl> Circuit for CsProxy + where + C::Params: Clone, + { type Config = C::Config; type FloorPlanner = C::FloorPlanner; + type Params = C::Params; fn without_witnesses(&self) -> Self { - CsProxy(PhantomData) + Self::new(self.params.clone()) } - fn configure(meta: &mut ConstraintSystem) -> Self::Config { - C::configure(meta) + fn params(&self) -> Self::Params { + self.params.clone() + } + + fn configure_with_params( + meta: &mut ConstraintSystem, + params: Self::Params, + ) -> Self::Config { + C::configure_with_params(meta, params) + } + + fn configure(_: &mut ConstraintSystem) -> Self::Config { + unreachable!("must use configure_with_params") } fn synthesize( @@ -330,15 +360,50 @@ where let dummy_vk = vk .is_none() - .then(|| keygen_vk(params, &CsProxy::(PhantomData)).unwrap()); - let protocol = compile( + .then(|| keygen_vk(params, &CsProxy::::new(circuit_params)).unwrap()); + + gen_dummy_snark_from_vk::( params, vk.or(dummy_vk.as_ref()).unwrap(), - Config::kzg() - .with_num_instance(num_instance.clone()) - .with_accumulator_indices(ConcreteCircuit::accumulator_indices()), + num_instance, + ConcreteCircuit::accumulator_indices(), + ) +} + +/// Creates a dummy snark in the correct shape corresponding to the given verifying key. +/// This dummy snark will **not** verify. +/// This snark can be used as a placeholder input into an aggregation circuit expecting a snark +/// with this verifying key. +/// +/// Note that this function does not need to know the concrete `Circuit` type. +pub fn gen_dummy_snark_from_vk( + params: &ParamsKZG, + vk: &VerifyingKey, + num_instance: Vec, + accumulator_indices: Option>, +) -> Snark +where + AS: NativeKzgAccumulationScheme, +{ + let protocol = compile( + params, + vk, + Config::kzg().with_num_instance(num_instance).with_accumulator_indices(accumulator_indices), ); - let instances = num_instance.into_iter().map(|n| vec![Fr::default(); n]).collect(); + gen_dummy_snark_from_protocol::(protocol) +} + +/// Creates a dummy snark in the correct shape corresponding to the given Plonk protocol. +/// This dummy snark will **not** verify. +/// This snark can be used as a placeholder input into an aggregation circuit expecting a snark +/// with this protocol. +/// +/// Note that this function does not need to know the concrete `Circuit` type. +pub fn gen_dummy_snark_from_protocol(protocol: PlonkProtocol) -> Snark +where + AS: NativeKzgAccumulationScheme, +{ + let instances = protocol.num_instance.iter().map(|&n| vec![Fr::default(); n]).collect(); let proof = { let mut transcript = PoseidonTranscript::::new::(Vec::new()); for _ in 0..protocol diff --git a/snark-verifier-sdk/src/halo2/aggregation.rs b/snark-verifier-sdk/src/halo2/aggregation.rs index ed940729..60c4b3db 100644 --- a/snark-verifier-sdk/src/halo2/aggregation.rs +++ b/snark-verifier-sdk/src/halo2/aggregation.rs @@ -53,6 +53,10 @@ pub struct PreprocessedAndDomainAsWitness { #[derive(Clone, Debug)] pub struct SnarkAggregationWitness<'a> { + /// The (flattened) public instances from previous snarks that were aggregated, now collected as PRIVATE assigned values. + /// * If previous snark was from aggregation circuit, the previous instances will still contain the old KZG accumulator. + /// + /// The user can optionally append these private witnesses to `inner.assigned_instances` to expose them. pub previous_instances: Vec>>, pub accumulator: KzgAccumulator>>, /// This returns the assigned `preprocessed` and `transcript_initial_state` values as a vector of assigned values, one for each aggregated snark. @@ -295,8 +299,10 @@ impl TryFrom for AggregationConfigParams { pub struct AggregationCircuit { /// Circuit builder consisting of virtual region managers pub builder: BaseCircuitBuilder, - // the public instances from previous snarks that were aggregated, now collected as PRIVATE assigned values - // the user can optionally append these to `inner.assigned_instances` to expose them + /// The (flattened) public instances from previous snarks that were aggregated, now collected as PRIVATE assigned values. + /// * If previous snark was from aggregation circuit, the previous instances will still contain the old KZG accumulator. + /// + /// The user can optionally append these private witnesses to `inner.assigned_instances` to expose them. #[getset(get = "pub")] previous_instances: Vec>>, /// This returns the assigned `preprocessed_digest` (vkey), optional `transcript_initial_state`, `domain.n` (optional), and `omega` (optional) values as a vector of assigned values, one for each aggregated snark. diff --git a/snark-verifier-sdk/src/halo2/utils.rs b/snark-verifier-sdk/src/halo2/utils.rs new file mode 100644 index 00000000..a7faa64e --- /dev/null +++ b/snark-verifier-sdk/src/halo2/utils.rs @@ -0,0 +1,91 @@ +use halo2_base::{ + halo2_proofs::{ + halo2curves::bn256::{Fr, G1Affine}, + plonk::{Circuit, VerifyingKey}, + }, + utils::fs::read_params, +}; + +use crate::{CircuitExt, Snark, SHPLONK}; + +use super::{aggregation::AggregationCircuit, gen_dummy_snark_from_vk}; + +#[derive(Clone, Copy, Debug)] +pub struct AggregationDependencyIntent<'a> { + pub vk: &'a VerifyingKey, + pub num_instance: &'a [usize], + pub is_aggregation: bool, +} + +#[derive(Clone, Debug)] +pub struct AggregationDependencyIntentOwned { + pub vk: VerifyingKey, + pub num_instance: Vec, + pub is_aggregation: bool, +} + +/// This trait should be implemented on the minimal circuit configuration data necessary to +/// completely determine an aggregation circuit +/// (independent of circuit inputs or specific snarks to be aggregated). +/// This is used to generate a _dummy_ instantiation of a concrete `Circuit` type for the purposes of key generation. +/// This dummy instantiation just needs to have the correct arithmetization format, but the witnesses do not need to +/// satisfy constraints. +/// +/// This trait is specialized for aggregation circuits, which need to aggregate **dependency** snarks. +/// The aggregation circuit should only depend on the verifying key of each dependency snark. +pub trait KeygenAggregationCircuitIntent { + /// Concrete circuit type. Defaults to [`AggregationCircuit`]. + type AggregationCircuit: Circuit = AggregationCircuit; + + /// The **ordered** list of [`VerifyingKey`]s of the circuits to be aggregated. + fn intent_of_dependencies(&self) -> Vec; + + /// Builds a _dummy_ instantiation of `Self::AggregationCircuit` for the purposes of key generation. + /// Assumes that `snarks` is an ordered list of [`Snark`]s, where the `i`th snark corresponds to the `i`th [`VerifyingKey`] in `vk_of_dependencies`. + /// The `snarks` only need to have the correct witness sizes (e.g., proof length) but the + /// snarks do _not_ need to verify. + /// + /// May specify additional custom logic for building the aggregation circuit from the snarks. + fn build_keygen_circuit_from_snarks(self, snarks: Vec) -> Self::AggregationCircuit; + + /// Builds a _dummy_ instantiation of `Self::AggregationCircuit` for the purposes of key generation. + /// + /// Generates dummy snarks from the verifying keys in `vk_of_dependencies`, **assuming** that SHPLONK is + /// used for the multi-open scheme. + /// To do so, it will try to read KZG trusted setup files from the directory set by environmental variable + /// `PARAMS_DIR` or `./params/`. + // The `params` is not actually used, so this requirement should be removed in the future: + // requires refactoring `compile`. + fn build_keygen_circuit_shplonk(self) -> Self::AggregationCircuit + where + Self: Sized, + { + let snarks = self + .intent_of_dependencies() + .into_iter() + .map(|AggregationDependencyIntent { vk, num_instance, is_aggregation }| { + let k = vk.get_domain().k(); + let params = read_params(k); + let accumulator_indices = + is_aggregation.then_some(AggregationCircuit::accumulator_indices().unwrap()); + gen_dummy_snark_from_vk::( + ¶ms, + vk, + num_instance.to_vec(), + accumulator_indices, + ) + }) + .collect(); + self.build_keygen_circuit_from_snarks(snarks) + } +} + +impl<'a> From<&'a AggregationDependencyIntentOwned> for AggregationDependencyIntent<'a> { + fn from(intent: &'a AggregationDependencyIntentOwned) -> Self { + Self { + vk: &intent.vk, + num_instance: &intent.num_instance, + is_aggregation: intent.is_aggregation, + } + } +} From 5a89f1380266f7b0dbf11e03871db9eccd6f1dc8 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Sun, 17 Dec 2023 22:41:21 -0500 Subject: [PATCH 67/73] fix: `AggregationDependencyIntent` should include full `accumulator_indices` (#49) fix: `AggregationDependencyIntent` includes `accumulator_indices` --- Cargo.lock | 4 ++-- snark-verifier-sdk/src/halo2/utils.rs | 14 ++++++-------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e1dcfeaf..251a3944 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1230,9 +1230,9 @@ dependencies = [ [[package]] name = "halo2curves-axiom" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d47eaec6a3040c2fbaa020716bf571b0c55025126242510f774183aff84b92e" +checksum = "d1f0b8f4b7dc27d1e438dae6573e8d95c9f6ee568d1d21146a4c34c17db2ad38" dependencies = [ "blake2b_simd", "ff", diff --git a/snark-verifier-sdk/src/halo2/utils.rs b/snark-verifier-sdk/src/halo2/utils.rs index a7faa64e..99af320e 100644 --- a/snark-verifier-sdk/src/halo2/utils.rs +++ b/snark-verifier-sdk/src/halo2/utils.rs @@ -6,7 +6,7 @@ use halo2_base::{ utils::fs::read_params, }; -use crate::{CircuitExt, Snark, SHPLONK}; +use crate::{Snark, SHPLONK}; use super::{aggregation::AggregationCircuit, gen_dummy_snark_from_vk}; @@ -14,14 +14,14 @@ use super::{aggregation::AggregationCircuit, gen_dummy_snark_from_vk}; pub struct AggregationDependencyIntent<'a> { pub vk: &'a VerifyingKey, pub num_instance: &'a [usize], - pub is_aggregation: bool, + pub accumulator_indices: Option<&'a [(usize, usize)]>, } #[derive(Clone, Debug)] pub struct AggregationDependencyIntentOwned { pub vk: VerifyingKey, pub num_instance: Vec, - pub is_aggregation: bool, + pub accumulator_indices: Option>, } /// This trait should be implemented on the minimal circuit configuration data necessary to @@ -63,16 +63,14 @@ pub trait KeygenAggregationCircuitIntent { let snarks = self .intent_of_dependencies() .into_iter() - .map(|AggregationDependencyIntent { vk, num_instance, is_aggregation }| { + .map(|AggregationDependencyIntent { vk, num_instance, accumulator_indices }| { let k = vk.get_domain().k(); let params = read_params(k); - let accumulator_indices = - is_aggregation.then_some(AggregationCircuit::accumulator_indices().unwrap()); gen_dummy_snark_from_vk::( ¶ms, vk, num_instance.to_vec(), - accumulator_indices, + accumulator_indices.map(|v| v.to_vec()), ) }) .collect(); @@ -85,7 +83,7 @@ impl<'a> From<&'a AggregationDependencyIntentOwned> for AggregationDependencyInt Self { vk: &intent.vk, num_instance: &intent.num_instance, - is_aggregation: intent.is_aggregation, + accumulator_indices: intent.accumulator_indices.as_deref(), } } } From fcfe813b842039f4b1978939f586dcc2ae068073 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Mon, 18 Dec 2023 01:58:10 -0500 Subject: [PATCH 68/73] chore: remove `read_params` from `build_keygen_circuit_shplonk` (#50) --- snark-verifier-sdk/src/halo2/utils.rs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/snark-verifier-sdk/src/halo2/utils.rs b/snark-verifier-sdk/src/halo2/utils.rs index 99af320e..d5719cd1 100644 --- a/snark-verifier-sdk/src/halo2/utils.rs +++ b/snark-verifier-sdk/src/halo2/utils.rs @@ -1,10 +1,9 @@ -use halo2_base::{ - halo2_proofs::{ - halo2curves::bn256::{Fr, G1Affine}, - plonk::{Circuit, VerifyingKey}, - }, - utils::fs::read_params, +use halo2_base::halo2_proofs::{ + halo2curves::bn256::{Fr, G1Affine}, + plonk::{Circuit, VerifyingKey}, + poly::kzg::commitment::ParamsKZG, }; +use rand::{rngs::StdRng, SeedableRng}; use crate::{Snark, SHPLONK}; @@ -52,20 +51,19 @@ pub trait KeygenAggregationCircuitIntent { /// /// Generates dummy snarks from the verifying keys in `vk_of_dependencies`, **assuming** that SHPLONK is /// used for the multi-open scheme. - /// To do so, it will try to read KZG trusted setup files from the directory set by environmental variable - /// `PARAMS_DIR` or `./params/`. - // The `params` is not actually used, so this requirement should be removed in the future: - // requires refactoring `compile`. fn build_keygen_circuit_shplonk(self) -> Self::AggregationCircuit where Self: Sized, { + let mut rng = StdRng::seed_from_u64(0u64); let snarks = self .intent_of_dependencies() .into_iter() .map(|AggregationDependencyIntent { vk, num_instance, accumulator_indices }| { let k = vk.get_domain().k(); - let params = read_params(k); + // In KZG `gen_dummy_snark_from_vk` calls `compile`, which only uses `params` for `params.k()` so we can just use a random untrusted setup. + // Moreover since this is a dummy snark, the trusted setup shouldn't matter. + let params = ParamsKZG::setup(k, &mut rng); gen_dummy_snark_from_vk::( ¶ms, vk, From 47edd9053d44f2d6bff46086e73c7e07a3759869 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Thu, 28 Dec 2023 00:17:10 -0500 Subject: [PATCH 69/73] feat: dummy snark should have correct `agg_vkey_hash` (#51) if it is for a universal aggregation circuit --- Cargo.lock | 6 ++-- snark-verifier-sdk/src/halo2/utils.rs | 52 +++++++++++++++++++-------- 2 files changed, 40 insertions(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 251a3944..9f7a723d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1136,7 +1136,7 @@ checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" [[package]] name = "halo2-axiom" -version = "0.4.1" +version = "0.4.2" dependencies = [ "blake2b_simd", "crossbeam", @@ -1230,9 +1230,9 @@ dependencies = [ [[package]] name = "halo2curves-axiom" -version = "0.4.4" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1f0b8f4b7dc27d1e438dae6573e8d95c9f6ee568d1d21146a4c34c17db2ad38" +checksum = "4a11fd188635e09153d007ac33300d0af76972342b2f5ca3f116cba8c759f57d" dependencies = [ "blake2b_simd", "ff", diff --git a/snark-verifier-sdk/src/halo2/utils.rs b/snark-verifier-sdk/src/halo2/utils.rs index d5719cd1..d7588860 100644 --- a/snark-verifier-sdk/src/halo2/utils.rs +++ b/snark-verifier-sdk/src/halo2/utils.rs @@ -14,6 +14,8 @@ pub struct AggregationDependencyIntent<'a> { pub vk: &'a VerifyingKey, pub num_instance: &'a [usize], pub accumulator_indices: Option<&'a [(usize, usize)]>, + /// See [`AggregationDependencyIntentOwned::agg_vk_hash_data`]. + pub agg_vk_hash_data: Option<((usize, usize), Fr)>, } #[derive(Clone, Debug)] @@ -21,6 +23,8 @@ pub struct AggregationDependencyIntentOwned { pub vk: VerifyingKey, pub num_instance: Vec, pub accumulator_indices: Option>, + /// If this dependency is itself from a universal aggregation circuit, this should contain (index, agg_vkey_hash), where `index = (i,j)` is the pair recording that the agg_vkey_hash is located at `instances[i][j]`. + pub agg_vk_hash_data: Option<((usize, usize), Fr)>, } /// This trait should be implemented on the minimal circuit configuration data necessary to @@ -56,22 +60,39 @@ pub trait KeygenAggregationCircuitIntent { Self: Sized, { let mut rng = StdRng::seed_from_u64(0u64); - let snarks = self - .intent_of_dependencies() - .into_iter() - .map(|AggregationDependencyIntent { vk, num_instance, accumulator_indices }| { - let k = vk.get_domain().k(); - // In KZG `gen_dummy_snark_from_vk` calls `compile`, which only uses `params` for `params.k()` so we can just use a random untrusted setup. - // Moreover since this is a dummy snark, the trusted setup shouldn't matter. - let params = ParamsKZG::setup(k, &mut rng); - gen_dummy_snark_from_vk::( - ¶ms, - vk, - num_instance.to_vec(), - accumulator_indices.map(|v| v.to_vec()), + let snarks = + self.intent_of_dependencies() + .into_iter() + .map( + |AggregationDependencyIntent { + vk, + num_instance, + accumulator_indices, + agg_vk_hash_data, + }| { + let k = vk.get_domain().k(); + // In KZG `gen_dummy_snark_from_vk` calls `compile`, which only uses `params` for `params.k()` so we can just use a random untrusted setup. + // Moreover since this is a dummy snark, the trusted setup shouldn't matter. + let params = ParamsKZG::setup(k, &mut rng); + let mut snark = gen_dummy_snark_from_vk::( + ¶ms, + vk, + num_instance.to_vec(), + accumulator_indices.map(|v| v.to_vec()), + ); + // We set the current agg_vk_hash in the dummy snark so that the final agg_vk_hash is correct at the end of keygen. + if let Some(((i, j), agg_vk_hash)) = agg_vk_hash_data { + assert!( + i < snark.instances.len(), + "Invalid agg_vk_hash index: ({i},{j}), num_instance: {num_instance:?}"); + assert!(j < snark.instances[i].len(), + "Invalid agg_vk_hash index: ({i},{j}), num_instance: {num_instance:?}"); + snark.instances[i][j] = agg_vk_hash; + } + snark + }, ) - }) - .collect(); + .collect(); self.build_keygen_circuit_from_snarks(snarks) } } @@ -82,6 +103,7 @@ impl<'a> From<&'a AggregationDependencyIntentOwned> for AggregationDependencyInt vk: &intent.vk, num_instance: &intent.num_instance, accumulator_indices: intent.accumulator_indices.as_deref(), + agg_vk_hash_data: intent.agg_vk_hash_data, } } } From 0b33650f14fad71de6d383b022ad861a38f2a042 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Fri, 29 Dec 2023 18:28:05 -0500 Subject: [PATCH 70/73] chore: derive serde for `KzgDecidingKey` (#52) --- snark-verifier/src/pcs/kzg.rs | 3 ++- snark-verifier/src/pcs/kzg/decider.rs | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/snark-verifier/src/pcs/kzg.rs b/snark-verifier/src/pcs/kzg.rs index 387a108c..2e60ec11 100644 --- a/snark-verifier/src/pcs/kzg.rs +++ b/snark-verifier/src/pcs/kzg.rs @@ -15,9 +15,10 @@ pub use multiopen::{Bdfg21, Bdfg21Proof, Gwc19, Gwc19Proof}; #[cfg(feature = "loader_halo2")] pub use accumulator::LimbsEncodingInstructions; +use serde::{Deserialize, Serialize}; /// KZG succinct verifying key. -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, Serialize, Deserialize)] pub struct KzgSuccinctVerifyingKey { /// Generator. pub g: C, diff --git a/snark-verifier/src/pcs/kzg/decider.rs b/snark-verifier/src/pcs/kzg/decider.rs index d55e0a57..be845b60 100644 --- a/snark-verifier/src/pcs/kzg/decider.rs +++ b/snark-verifier/src/pcs/kzg/decider.rs @@ -1,3 +1,5 @@ +use serde::{Deserialize, Serialize}; + use crate::{ pcs::kzg::KzgSuccinctVerifyingKey, util::arithmetic::{CurveAffine, MultiMillerLoop}, @@ -5,7 +7,11 @@ use crate::{ use std::marker::PhantomData; /// KZG deciding key. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize, Deserialize)] +#[serde(bound( + serialize = "M::G1Affine: Serialize, M::G2Affine: Serialize", + deserialize = "M::G1Affine: Deserialize<'de>, M::G2Affine: Deserialize<'de>" +))] pub struct KzgDecidingKey { svk: KzgSuccinctVerifyingKey, /// Generator on G2. From c0740060e567976cebcb0bd3dd86594732604140 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Sat, 30 Dec 2023 01:44:40 -0500 Subject: [PATCH 71/73] chore: add getters to `KzgDecidingKey` (#53) --- snark-verifier/src/pcs/kzg/decider.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/snark-verifier/src/pcs/kzg/decider.rs b/snark-verifier/src/pcs/kzg/decider.rs index be845b60..e746fcb8 100644 --- a/snark-verifier/src/pcs/kzg/decider.rs +++ b/snark-verifier/src/pcs/kzg/decider.rs @@ -30,6 +30,18 @@ impl KzgDecidingKey { ) -> Self { Self { svk: svk.into(), g2, s_g2, _marker: PhantomData } } + /// Succinct verifying key. + pub fn svk(&self) -> KzgSuccinctVerifyingKey { + self.svk + } + /// Generator on G2. + pub fn g2(&self) -> M::G2Affine { + self.g2 + } + /// Generator to the trusted-setup secret on G2. + pub fn s_g2(&self) -> M::G2Affine { + self.s_g2 + } } impl From<(M::G1Affine, M::G2Affine, M::G2Affine)> for KzgDecidingKey From 56d11450dfe5db43e53c645dc6db05c8c8cebc89 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Sun, 31 Dec 2023 22:08:27 -0500 Subject: [PATCH 72/73] chore: add `compile` function to `AggregationDependencyIntent` --- snark-verifier-sdk/src/halo2/utils.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/snark-verifier-sdk/src/halo2/utils.rs b/snark-verifier-sdk/src/halo2/utils.rs index d7588860..b2d99de7 100644 --- a/snark-verifier-sdk/src/halo2/utils.rs +++ b/snark-verifier-sdk/src/halo2/utils.rs @@ -1,9 +1,13 @@ use halo2_base::halo2_proofs::{ - halo2curves::bn256::{Fr, G1Affine}, + halo2curves::bn256::{Bn256, Fr, G1Affine}, plonk::{Circuit, VerifyingKey}, poly::kzg::commitment::ParamsKZG, }; use rand::{rngs::StdRng, SeedableRng}; +use snark_verifier::{ + system::halo2::{compile, Config}, + verifier::plonk::PlonkProtocol, +}; use crate::{Snark, SHPLONK}; @@ -27,6 +31,19 @@ pub struct AggregationDependencyIntentOwned { pub agg_vk_hash_data: Option<((usize, usize), Fr)>, } +impl<'a> AggregationDependencyIntent<'a> { + /// Converts `self` into `PlonkProtocol` + pub fn compile(self, params: &ParamsKZG) -> PlonkProtocol { + compile( + params, + self.vk, + Config::kzg() + .with_num_instance(self.num_instance.to_vec()) + .with_accumulator_indices(self.accumulator_indices.map(|v| v.to_vec())), + ) + } +} + /// This trait should be implemented on the minimal circuit configuration data necessary to /// completely determine an aggregation circuit /// (independent of circuit inputs or specific snarks to be aggregated). From 6b47987805ca5801d00f7f904f9b635b97a048e3 Mon Sep 17 00:00:00 2001 From: Jonathan Wang <31040440+jonathanpwang@users.noreply.github.com> Date: Thu, 18 Jan 2024 14:34:31 -0500 Subject: [PATCH 73/73] chore: use released halo2-lib v0.4.1 Turns off halo2-pse for crates.io release --- Cargo.lock | 91 ++++++----------------------------- snark-verifier-sdk/Cargo.toml | 17 ++++--- snark-verifier/Cargo.toml | 8 +-- 3 files changed, 32 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9f7a723d..f54a549d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -367,16 +367,6 @@ dependencies = [ "constant_time_eq", ] -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "block-padding", - "generic-array", -] - [[package]] name = "block-buffer" version = "0.10.4" @@ -386,12 +376,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-padding" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" - [[package]] name = "blst" version = "0.3.11" @@ -912,7 +896,7 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.4", + "block-buffer", "const-oid", "crypto-common", "subtle", @@ -1149,17 +1133,18 @@ dependencies = [ "rand", "rand_core", "rustc-hash", - "sha3 0.10.8", + "sha3", "tracing", ] [[package]] name = "halo2-base" version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f2045beb3860227b7d354419f2b25a17ad05b2cd68d553dbb9cbbf35daef9d0" dependencies = [ "getset", "halo2-axiom", - "halo2_proofs", "itertools 0.11.0", "jemallocator", "log", @@ -1177,9 +1162,11 @@ dependencies = [ [[package]] name = "halo2-ecc" version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeba4bd49c6eb05815a9809e749f1db525b26b17f5cafb40c5d9a9a4d483f541" dependencies = [ "halo2-base", - "itertools 0.10.5", + "itertools 0.11.0", "num-bigint", "num-integer", "num-traits", @@ -1192,42 +1179,6 @@ dependencies = [ "test-case", ] -[[package]] -name = "halo2_proofs" -version = "0.2.0" -source = "git+https://github.com/privacy-scaling-explorations/halo2.git?rev=7a21656#7a2165617195d8baa422ca7b2b364cef02380390" -dependencies = [ - "blake2b_simd", - "ff", - "group", - "halo2curves", - "maybe-rayon", - "rand_chacha", - "rand_core", - "sha3 0.9.1", - "tracing", -] - -[[package]] -name = "halo2curves" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b1142bd1059aacde1b477e0c80c142910f1ceae67fc619311d6a17428007ab" -dependencies = [ - "blake2b_simd", - "ff", - "group", - "lazy_static", - "num-bigint", - "num-traits", - "pasta_curves", - "paste", - "rand", - "rand_core", - "static_assertions", - "subtle", -] - [[package]] name = "halo2curves-axiom" version = "0.5.0" @@ -1763,12 +1714,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "opaque-debug" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" - [[package]] name = "pairing" version = "0.23.0" @@ -2516,18 +2461,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "sha3" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug", -] - [[package]] name = "sha3" version = "0.10.8" @@ -2623,7 +2556,7 @@ dependencies = [ "ruint", "serde", "serde_json", - "sha3 0.10.8", + "sha3", ] [[package]] @@ -3281,3 +3214,11 @@ dependencies = [ "quote", "syn 2.0.38", ] + +[[patch.unused]] +name = "halo2-base" +version = "0.4.1" + +[[patch.unused]] +name = "halo2-ecc" +version = "0.4.1" diff --git a/snark-verifier-sdk/Cargo.toml b/snark-verifier-sdk/Cargo.toml index ff1e909a..ae48fee6 100644 --- a/snark-verifier-sdk/Cargo.toml +++ b/snark-verifier-sdk/Cargo.toml @@ -1,7 +1,13 @@ [package] name = "snark-verifier-sdk" version = "0.1.7" +authors = ["Privacy Scaling Explorations Team", "Intrinsic Technologies"] +license = "MIT" edition = "2021" +repository = "https://github.com/axiom-crypto/snark-verifier" +readme = "../README.md" +description = "SDK for using snark-verifier." +rust-version = "1.73.0" autobenches = false [dependencies] @@ -18,14 +24,13 @@ serde_json = "1.0" serde_with = { version = "2.2", optional = true } bincode = "1.3.3" ark-std = { version = "0.3.0", features = ["print-trace"], optional = true } -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.1-rc", default-features = false } -snark-verifier = { path = "../snark-verifier", default-features = false } +halo2-base = { version = "=0.4.1", default-features = false } +#halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "main", default-features = false } +snark-verifier = { version = "=0.1.7", path = "../snark-verifier", default-features = false } getset = "0.1.2" # loader_evm -ethereum-types = { version = "=0.14.1", default-features = false, features = [ - "std", -], optional = true } +ethereum-types = { version = "=0.14.1", default-features = false, features = ["std"], optional = true } # zkevm benchmarks # zkevm-circuits = { git = "https://github.com/privacy-scaling-explorations/zkevm-circuits.git", rev = "f834e61", features = [ @@ -53,7 +58,7 @@ loader_evm = ["snark-verifier/loader_evm", "dep:ethereum-types"] revm = ["snark-verifier/revm"] parallel = ["snark-verifier/parallel"] # EXACTLY one of halo2-pse / halo2-axiom should always be turned on; not sure how to enforce this with Cargo -halo2-pse = ["snark-verifier/halo2-pse", "dep:serde_with"] +# halo2-pse = ["snark-verifier/halo2-pse", "dep:serde_with"] halo2-axiom = ["snark-verifier/halo2-axiom"] # zkevm = ["dep:zkevm-circuits", "dep:bus-mapping", "dep:mock", "dep:eth-types"] diff --git a/snark-verifier/Cargo.toml b/snark-verifier/Cargo.toml index 5b082dc9..87c17546 100644 --- a/snark-verifier/Cargo.toml +++ b/snark-verifier/Cargo.toml @@ -15,10 +15,12 @@ serde = { version = "1.0", features = ["derive"] } pairing = { version = "0.23" } # Use halo2-base as non-optional dependency because it re-exports halo2_proofs, halo2curves, and poseidon, using different repos based on feature flag "halo2-axiom" or "halo2-pse" -halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.1-rc", default-features = false } +halo2-base = { version = "=0.4.1", default-features = false } +# halo2-base = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "main", default-features = false } # loader_halo2 -halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "release-0.4.1-rc", default-features = false, optional = true } +halo2-ecc = { version = "=0.4.1", default-features = false, optional = true } +# halo2-ecc = { git = "https://github.com/axiom-crypto/halo2-lib.git", branch = "main", default-features = false, optional = true } # parallel rayon = { version = "1.8", optional = true } @@ -48,7 +50,7 @@ loader_evm = ["dep:sha3", "dep:ruint"] revm = ["loader_evm", "dep:revm"] parallel = ["dep:rayon"] # EXACTLY one of halo2-pse / halo2-axiom should always be turned on; not sure how to enforce this with Cargo -halo2-pse = ["halo2-base/halo2-pse", "halo2-ecc?/halo2-pse"] +# halo2-pse = ["halo2-base/halo2-pse", "halo2-ecc?/halo2-pse"] halo2-axiom = ["halo2-base/halo2-axiom", "halo2-ecc?/halo2-axiom"] [[example]]