From f96b07d0c53b97fa15fc457867eea39f9fd0cb19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20P=C3=A9rez?= <37264926+CPerezz@users.noreply.github.com> Date: Wed, 13 Apr 2022 16:30:04 +0200 Subject: [PATCH] Migrate gadgets from zkevm-circuits mod to it'w own crate (#457) * Migrate gadgets from zkevm-circuits mod to it'w own crate * add: Include `gadgets` as workspace member * update: Include `gadgets` into workflows config Resolves: #444 --- .github/labeler.yml | 3 ++ .github/release-drafter.yml | 2 + Cargo.lock | 15 ++++++ Cargo.toml | 1 + gadgets/.gitignore | 1 + gadgets/Cargo.toml | 17 ++++++ .../src/gadget => gadgets/src}/evm_word.rs | 52 ++++++++----------- .../src/gadget => gadgets/src}/is_zero.rs | 48 ++++++++++++----- gadgets/src/lib.rs | 33 ++++++++++++ .../src/gadget => gadgets/src}/monotone.rs | 6 +++ zkevm-circuits/Cargo.toml | 4 +- .../src/bytecode_circuit/bytecode_unroller.rs | 8 +-- zkevm-circuits/src/gadget.rs | 20 ------- zkevm-circuits/src/lib.rs | 1 - zkevm-circuits/src/state_circuit/state.rs | 21 ++++---- 15 files changed, 150 insertions(+), 82 deletions(-) create mode 100644 gadgets/.gitignore create mode 100644 gadgets/Cargo.toml rename {zkevm-circuits/src/gadget => gadgets/src}/evm_word.rs (88%) rename {zkevm-circuits/src/gadget => gadgets/src}/is_zero.rs (87%) create mode 100644 gadgets/src/lib.rs rename {zkevm-circuits/src/gadget => gadgets/src}/monotone.rs (97%) delete mode 100644 zkevm-circuits/src/gadget.rs diff --git a/.github/labeler.yml b/.github/labeler.yml index ceaa77a450..55b78caf22 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -10,6 +10,8 @@ crate-eth-types: - eth-types/**/* crate-external-tracer: - external-tracer/**/* +crate-gadgets: + - gadgets/**/* crate-geth-utils: - geth-utils/**/* crate-integration-tests: @@ -30,6 +32,7 @@ T-opcode: "zkevm-circuits/src/evm_circuit/execution/**/*", "bus-mapping/src/evm/opcodes/**/*", ] + # Add 'T-bench' to any changes related to benchmarks in `circuit-benchmarks`. T-bench: - circuit-benchmarks/**/* diff --git a/.github/release-drafter.yml b/.github/release-drafter.yml index d9dadf9904..950aa422ea 100644 --- a/.github/release-drafter.yml +++ b/.github/release-drafter.yml @@ -7,6 +7,8 @@ categories: label: "crate-eth-types" - title: "Changes in external-tracer" label: "crate-external-tracer" + - title: "Changes in gadgets" + label: "crate-gadgets" - title: "Changes in geth-utils" label: "crate-geth-utils" - title: "Changes in integration-tests" diff --git a/Cargo.lock b/Cargo.lock index 672533b3a1..bc23eb213c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1629,6 +1629,20 @@ dependencies = [ "slab", ] +[[package]] +name = "gadgets" +version = "0.1.0" +dependencies = [ + "digest 0.7.6", + "eth-types", + "ff 0.11.0", + "halo2_proofs", + "pairing_bn256", + "rand", + "rand_xorshift", + "sha3 0.7.3", +] + [[package]] name = "generic-array" version = "0.9.1" @@ -4062,6 +4076,7 @@ dependencies = [ "eth-types", "ethers-core", "ff 0.11.0", + "gadgets", "halo2_proofs", "hex", "itertools", diff --git a/Cargo.toml b/Cargo.toml index 930d423cfe..dc6b5b5544 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "bus-mapping", "keccak256", "geth-utils", + "gadgets", "integration-tests", "circuit-benchmarks", "eth-types", diff --git a/gadgets/.gitignore b/gadgets/.gitignore new file mode 100644 index 0000000000..ea8c4bf7f3 --- /dev/null +++ b/gadgets/.gitignore @@ -0,0 +1 @@ +/target diff --git a/gadgets/Cargo.toml b/gadgets/Cargo.toml new file mode 100644 index 0000000000..4f8e5a2515 --- /dev/null +++ b/gadgets/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "gadgets" +version = "0.1.0" +edition = "2021" +authors = ["The appliedzkp team"] + +[dependencies] +ff = "0.11" +halo2_proofs = { git = "https://github.com/appliedzkp/halo2.git", tag = "v2022_03_06" } +pairing = { git = 'https://github.com/appliedzkp/pairing', package = "pairing_bn256" } +sha3 = "0.7.2" +eth-types = { path = "../eth-types" } +digest = "0.7.6" + +[dev-dependencies] +rand_xorshift = "0.3" +rand = "0.8" diff --git a/zkevm-circuits/src/gadget/evm_word.rs b/gadgets/src/evm_word.rs similarity index 88% rename from zkevm-circuits/src/gadget/evm_word.rs rename to gadgets/src/evm_word.rs index 3dbb100c0f..0d8af5ec38 100644 --- a/zkevm-circuits/src/gadget/evm_word.rs +++ b/gadgets/src/evm_word.rs @@ -6,7 +6,7 @@ //! In the zkevm circuit, this `encode(word)` expression will not be directly //! looked up. Instead, it will be folded into the bus mapping lookup. -use crate::gadget::Variable; +use crate::Variable; use digest::{FixedOutput, Input}; use eth_types::Field; use halo2_proofs::{ @@ -20,9 +20,9 @@ use std::convert::TryInto; #[cfg(test)] use halo2_proofs::circuit::Layouter; -// r = hash([0, 1, ..., 255]) // TODO: Move into crate-level `constants` file. -pub(crate) fn r() -> F { +/// r = hash([0, 1, ..., 255]) +pub fn r() -> F { let mut hasher = Keccak256::new(); for byte in 0..=u8::MAX { hasher.process(&[byte]); @@ -32,8 +32,8 @@ pub(crate) fn r() -> F { F::from_bytes_wide(&r) } -// Returns encoding of big-endian representation of a 256-bit word. -pub(crate) fn encode(vals: impl Iterator, r: F) -> F { +/// Returns encoding of big-endian representation of a 256-bit word. +pub fn encode(vals: impl Iterator, r: F) -> F { vals.fold(F::zero(), |acc, val| { let byte = F::from(val as u64); acc * r + byte @@ -41,37 +41,31 @@ pub(crate) fn encode(vals: impl Iterator, r: F) -> F { } /// A 256-bit word represented in the circuit as 32 bytes. -pub(crate) struct Word([Variable; 32]); - -impl Word { - fn encoded_val(&self, r: F) -> Option { - if self.0[0].value.is_some() { - let val = self.0.iter().rev().map(|var| var.value.unwrap()); - let val = encode(val, r); - Some(val) - } else { - None - } - } -} +pub struct Word([Variable; 32]); +#[allow(dead_code)] +/// Configuration structure used to constraint. generate and assign an EVM Word +/// inside a circuit. #[derive(Clone, Debug)] -pub(crate) struct WordConfig { - // Randomness used to compress the word encoding. +pub struct WordConfig { + /// Randomness used to compress the word encoding. r: F, - // Selector to toggle the word encoding gate. + /// Selector to toggle the word encoding gate. // TODO: This may be replaced by a synthetic selector. - pub q_encode: Selector, - // Advice columns used to witness the byte representation of the word. - pub bytes: [Column; 32], - // Fixed column containing all possible 8-bit values. This is used in - // a lookup argument to range-constrain each byte. - pub byte_lookup: Column, - // Expression representing `encode(word)`. - pub encode_word_expr: Expression, + q_encode: Selector, + /// Advice columns used to witness the byte representation of the word. + bytes: [Column; 32], + /// Fixed column containing all possible 8-bit values. This is used in + /// a lookup argument to range-constrain each byte. + byte_lookup: Column, + /// Expression representing `encode(word)`. + encode_word_expr: Expression, } impl WordConfig { + /// Sets up the configuration of the config by creating the required columns + /// & selectors and defining the constraints that take part when using a + /// Word. pub fn configure( meta: &mut ConstraintSystem, r: F, diff --git a/zkevm-circuits/src/gadget/is_zero.rs b/gadgets/src/is_zero.rs similarity index 87% rename from zkevm-circuits/src/gadget/is_zero.rs rename to gadgets/src/is_zero.rs index 1740d46739..51d97c1d89 100644 --- a/zkevm-circuits/src/gadget/is_zero.rs +++ b/gadgets/src/is_zero.rs @@ -1,3 +1,9 @@ +//! IsZero gadget works as follows: +//! +//! Given a `value` to be checked if it is zero: +//! - witnesses `inv0(value)`, where `inv0(x)` is 0 when `x` = 0, and +//! `1/x` otherwise + use halo2_proofs::{ circuit::{Chip, Region}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, VirtualCells}, @@ -6,7 +12,9 @@ use halo2_proofs::{ use pairing::arithmetic::FieldExt; use std::array; -pub(crate) trait IsZeroInstruction { +/// Trait that needs to be implemented for any gadget or circuit that wants to +/// implement `IsZero`. +pub trait IsZeroInstruction { /// Given a `value` to be checked if it is zero: /// - witnesses `inv0(value)`, where `inv0(x)` is 0 when `x` = 0, and /// `1/x` otherwise @@ -18,19 +26,41 @@ pub(crate) trait IsZeroInstruction { ) -> Result<(), Error>; } +/// Config struct representing the required fields for an `IsZero` config to +/// exist. #[derive(Clone, Debug)] -pub(crate) struct IsZeroConfig { +pub struct IsZeroConfig { + /// Modular inverse of the value. pub value_inv: Column, /// This can be used directly for custom gate at the offset if `is_zero` is /// called, it will be 1 if `value` is zero, and 0 otherwise. pub is_zero_expression: Expression, } -pub(crate) struct IsZeroChip { +/// Wrapper arround [`IsZeroConfig`] for which [`Chip`] is implemented. +pub struct IsZeroChip { config: IsZeroConfig, } impl IsZeroChip { + #[rustfmt::skip] + /// Sets up the configuration of the chip by creating the required columns + /// and defining the constraints that take part when using `is_zero` gate. + /// + /// Truth table of iz_zero gate: + /// +----+-------+-----------+-----------------------+---------------------------------+-------------------------------------+ + /// | ok | value | value_inv | 1 - value ⋅ value_inv | value ⋅ (1 - value ⋅ + /// value_inv) | value_inv ⋅ (1 - value ⋅ value_inv) | + /// +----+-------+-----------+-----------------------+---------------------------------+-------------------------------------+ + /// | V | 0 | 0 | 1 | 0 + /// | 0 | | | 0 | x | 1 + /// | 0 | x | + /// | | x | 0 | 1 | x + /// | 0 | | V | x | 1/x | 0 + /// | 0 | 0 | + /// | | x | y | 1 - xy | x(1 - xy) + /// | y(1 - xy) | + /// +----+-------+-----------+-----------------------+---------------------------------+-------------------------------------+ pub fn configure( meta: &mut ConstraintSystem, q_enable: impl FnOnce(&mut VirtualCells<'_, F>) -> Expression, @@ -40,17 +70,6 @@ impl IsZeroChip { // dummy initialization let mut is_zero_expression = Expression::Constant(F::zero()); - #[rustfmt::skip] - // Truth table of iz_zero gate: - // +----+-------+-----------+-----------------------+---------------------------------+-------------------------------------+ - // | ok | value | value_inv | 1 - value ⋅ value_inv | value ⋅ (1 - value ⋅ value_inv) | value_inv ⋅ (1 - value ⋅ value_inv) | - // +----+-------+-----------+-----------------------+---------------------------------+-------------------------------------+ - // | V | 0 | 0 | 1 | 0 | 0 | - // | | 0 | x | 1 | 0 | x | - // | | x | 0 | 1 | x | 0 | - // | V | x | 1/x | 0 | 0 | 0 | - // | | x | y | 1 - xy | x(1 - xy) | y(1 - xy) | - // +----+-------+-----------+-----------------------+---------------------------------+-------------------------------------+ meta.create_gate("is_zero gate", |meta| { let q_enable = q_enable(meta); @@ -77,6 +96,7 @@ impl IsZeroChip { } } + /// Given an `IsZeroConfig`, construct the chip. pub fn construct(config: IsZeroConfig) -> Self { IsZeroChip { config } } diff --git a/gadgets/src/lib.rs b/gadgets/src/lib.rs new file mode 100644 index 0000000000..14f7a977c7 --- /dev/null +++ b/gadgets/src/lib.rs @@ -0,0 +1,33 @@ +//! # ZKEVM-Gadgets +//! +//! A collection of reusable gadgets for the zk_evm circuits. + +#![cfg_attr(docsrs, feature(doc_cfg))] +// We want to have UPPERCASE idents sometimes. +#![allow(clippy::upper_case_acronyms)] +// Catch documentation errors caused by code changes. +#![deny(rustdoc::broken_intra_doc_links)] +#![deny(missing_docs)] +#![deny(unsafe_code)] +#![deny(clippy::debug_assert_with_mut_call)] + +pub mod evm_word; +pub mod is_zero; +pub mod monotone; + +use halo2_proofs::circuit::AssignedCell; +use pairing::arithmetic::FieldExt; + +#[allow(dead_code)] +/// An assigned cell in the circuit. +#[derive(Clone, Debug)] +pub struct Variable { + assig_cell: AssignedCell, + value: Option, +} + +impl Variable { + pub(crate) fn new(assig_cell: AssignedCell, value: Option) -> Self { + Self { assig_cell, value } + } +} diff --git a/zkevm-circuits/src/gadget/monotone.rs b/gadgets/src/monotone.rs similarity index 97% rename from zkevm-circuits/src/gadget/monotone.rs rename to gadgets/src/monotone.rs index 0d10e450ad..1e8458c0aa 100644 --- a/zkevm-circuits/src/gadget/monotone.rs +++ b/gadgets/src/monotone.rs @@ -1,3 +1,7 @@ +//! # Monotone mod +//! Monotone gadget helps to check if an advice column is monotonically +//! increasing within a range. With strict enabled, it disallows equality of two +//! cell. use halo2_proofs::{ circuit::{Chip, Layouter}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells}, @@ -6,6 +10,7 @@ use halo2_proofs::{ use pairing::arithmetic::FieldExt; use std::{marker::PhantomData, u64}; +#[allow(dead_code)] #[derive(Clone, Debug)] pub(crate) struct MonotoneConfig { range_table: Column, @@ -19,6 +24,7 @@ pub(crate) struct MonotoneChip, } +#[allow(dead_code)] impl MonotoneChip { diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index b3c7748d8a..bfee3fd65d 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -16,8 +16,9 @@ sha3 = "0.7.2" digest = "0.7.6" array-init = "2.0.0" paste = "1.0" -bus-mapping = { path = "../bus-mapping"} +bus-mapping = { path = "../bus-mapping" } eth-types = { path = "../eth-types" } +gadgets = { path = "../gadgets" } ethers-core = "0.6" serde_json = "1.0.66" rand_xorshift = "0.3" @@ -25,7 +26,6 @@ rand = "0.8" itertools = "0.10.3" lazy_static = "1.4" keccak256 = { path = "../keccak256"} - log = "0.4.14" env_logger = "0.9" diff --git a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs index 191ba5279f..654b436a40 100644 --- a/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs +++ b/zkevm-circuits/src/bytecode_circuit/bytecode_unroller.rs @@ -6,14 +6,14 @@ use crate::{ RandomLinearCombination, }, }, - gadget::{ - evm_word::encode, - is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, - }, util::Expr, }; use bus_mapping::evm::OpcodeId; use eth_types::Field; +use gadgets::{ + evm_word::encode, + is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, +}; use halo2_proofs::{ circuit::{Layouter, Region}, plonk::{Advice, Column, ConstraintSystem, Error, Expression, Fixed, Selector, VirtualCells}, diff --git a/zkevm-circuits/src/gadget.rs b/zkevm-circuits/src/gadget.rs deleted file mode 100644 index fa3c5beab0..0000000000 --- a/zkevm-circuits/src/gadget.rs +++ /dev/null @@ -1,20 +0,0 @@ -//! Reusable gadgets for the zk_evm circuits. -use halo2_proofs::circuit::AssignedCell; -use pairing::arithmetic::FieldExt; - -/// An assigned cell in the circuit. -#[derive(Clone, Debug)] -pub(crate) struct Variable { - pub(crate) assig_cell: AssignedCell, - pub(crate) value: Option, -} - -impl Variable { - pub(crate) fn new(assig_cell: AssignedCell, value: Option) -> Self { - Self { assig_cell, value } - } -} - -pub(crate) mod evm_word; -pub(crate) mod is_zero; -pub(crate) mod monotone; diff --git a/zkevm-circuits/src/lib.rs b/zkevm-circuits/src/lib.rs index f11e685c27..a40a1482f2 100644 --- a/zkevm-circuits/src/lib.rs +++ b/zkevm-circuits/src/lib.rs @@ -13,7 +13,6 @@ pub mod bytecode_circuit; pub mod evm_circuit; -pub mod gadget; pub mod rw_table; pub mod state_circuit; #[cfg(test)] diff --git a/zkevm-circuits/src/state_circuit/state.rs b/zkevm-circuits/src/state_circuit/state.rs index 86e2a33533..06521b54f4 100644 --- a/zkevm-circuits/src/state_circuit/state.rs +++ b/zkevm-circuits/src/state_circuit/state.rs @@ -1,18 +1,15 @@ -use crate::{ - evm_circuit::{ - table::RwTableTag, - util::{ - constraint_builder::BaseConstraintBuilder, - math_gadget::generate_lagrange_base_polynomial, - }, - witness::{RwMap, RwRow}, - }, - gadget::{ - is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, - Variable, +use crate::evm_circuit::{ + table::RwTableTag, + util::{ + constraint_builder::BaseConstraintBuilder, math_gadget::generate_lagrange_base_polynomial, }, + witness::{RwMap, RwRow}, }; use eth_types::Field; +use gadgets::{ + is_zero::{IsZeroChip, IsZeroConfig, IsZeroInstruction}, + Variable, +}; use halo2_proofs::{ circuit::{Layouter, Region, SimpleFloorPlanner}, plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Expression, Fixed, VirtualCells},