Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* init copy table & circuit

* fix: compilation and fmt/clippy

* fix: rebase, fmt, clippy

* feat(copy-table): constraints for verifying row and step

* feat: add copy pairs to fixed table

* chore: refactor and docs

* feat: busmapping updates with new copy event/step

* wip: api for assigning block to copy table

* feat: assigning copy event to copy table

* fix: log_id and tx_id both needed for TxLog

* tests: bus-mapping (calldatacopy root)

* tests: bus-mapping calldatacopy internal

* tests: bus-mapping codecopy

* fix: is_code is handled for bytecode copying

* tests: busmapping for logs

* fix: box copy circuit

* feat: lt gadget to constrain is_pad for copy circuit

* add todos

* add lookup into copy table

* feat(copy-table): lookup copy-pair | fmt | clippy

* feat(evm_circuit): setup api for copy table lookup

* fix(calldatacopy): copy table lookup instead of constraining internal state

* fix: use condition instead of select for looking up copy table

* chore: remove redundant auxiliary data fields/structs

* fix(busmapping): add RW (memory) entries

* fix(tests): busmapping calldatacopy root RW memory writes

* fix(tests): busmapping for codecopy, add RW memory writes

* fix(tests): busmapping logs, add RW entries and txlog data entries

* add copy lookup from codecopy op exec

* add copy lookup for logs op exec

* fix: copy rwc inc assignment in bus-mapping and table

* chore: remove redundant copy pairs fixed lookup

* calldatacopy gadget tests are passed now

* chore:  formatting, linting

* fix: codecopy tests passing (code hash is LE bytes)

* fix(copy-table): addr assignment for tx log

* fix: copy events by pc handles multiple copy events in a block

* fix opcode for log

* feat: use binary number chip instead of iszerochip for tag constraining

* fix: compilation after rebasing

* chore: comments on the iszero gadget

* chore: refactor (1 - x) to not(x)

* chore: rebase and fix compilation

* chore: docs and renaming -> copy circuit

* Update zkevm-circuits/src/evm_circuit/execution/calldatacopy.rs

Co-authored-by: Eduard S. <[email protected]>

* chore: remove duplication of code() and to_vec()

* fix: resolve collision possibility in hashmap for copy events

* fix: separate out constraints of copy circuit from evm circuit

* chore: describe separate fields in the copy lookup instead of one vec

* chore(bus-mapping): refactor copy steps generation in logs

* tests(copy_circuit): valid and invalid values for calldatacopy/codecopy

* refactor: use tuple instead of u256 for simplicity as key

* fix: move constraint to correct condition

* refactor(tests): remove code duplication, perturb different possible fields

* fix: stack(rlc) while copy_circuit assignments are not

Co-authored-by: Haichen Shen <[email protected]>
Co-authored-by: Eduard S. <[email protected]>
  • Loading branch information
3 people authored Jul 18, 2022
1 parent 3a6f02a commit b375530
Show file tree
Hide file tree
Showing 42 changed files with 2,007 additions and 2,045 deletions.
6 changes: 6 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions bus-mapping/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@ license = "MIT OR Apache-2.0"

[dependencies]
eth-types = { path = "../eth-types" }
gadgets = { path = "../gadgets" }
keccak256 = { path = "../keccak256" }
ethers-core = "0.6"
ethers-providers = "0.6"
halo2_proofs = { version = "0.1.0-beta.1" }
itertools = "0.10"
lazy_static = "1.4"
log = "0.4.14"
serde = {version = "1.0.130", features = ["derive"] }
serde_json = "1.0.66"
strum = "0.24"
strum_macros = "0.24"

[dev-dependencies]
hex = "0.4.3"
Expand Down
2 changes: 1 addition & 1 deletion bus-mapping/src/circuit_input_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub use call::{Call, CallContext, CallKind};
use core::fmt::Debug;
use eth_types::{self, Address, GethExecStep, GethExecTrace, Word};
use ethers_providers::JsonRpcClient;
pub use execution::{CopyDetails, ExecState, ExecStep, StepAuxiliaryData};
pub use execution::{CopyDataType, CopyEvent, CopyStep, ExecState, ExecStep, NumberOrHash};
pub use input_state_ref::CircuitInputStateRef;
use std::collections::HashMap;
pub use transaction::{Transaction, TransactionContext};
Expand Down
12 changes: 11 additions & 1 deletion bus-mapping/src/circuit_input_builder/block.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//! Block-related utility module
use super::transaction::Transaction;
use super::{transaction::Transaction, CopyEvent};
use crate::{
operation::{OperationContainer, RWCounter},
Error,
Expand Down Expand Up @@ -60,6 +60,8 @@ pub struct Block {
pub container: OperationContainer,
/// Transactions contained in the block
pub txs: Vec<Transaction>,
/// Copy events in this block.
pub copy_events: Vec<CopyEvent>,
code: HashMap<Hash, Vec<u8>>,
}

Expand Down Expand Up @@ -92,6 +94,7 @@ impl Block {
base_fee: eth_block.base_fee_per_gas.unwrap_or_default(),
container: OperationContainer::new(),
txs: Vec::new(),
copy_events: Vec::new(),
code: HashMap::new(),
})
}
Expand All @@ -106,3 +109,10 @@ impl Block {
&mut self.txs
}
}

impl Block {
/// Push a copy event to the block.
pub fn add_copy_event(&mut self, copy: CopyEvent) {
self.copy_events.push(copy);
}
}
179 changes: 89 additions & 90 deletions bus-mapping/src/circuit_input_builder/execution.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
//! Execution step related module.
use crate::{error::ExecError, exec_trace::OperationRef, operation::RWCounter};
use crate::{error::ExecError, exec_trace::OperationRef, operation::RWCounter, operation::RW};
use eth_types::{
evm_types::{Gas, GasCost, OpcodeId, ProgramCounter},
GethExecStep, U256,
GethExecStep, H256,
};
use gadgets::impl_expr;
use halo2_proofs::{arithmetic::FieldExt, plonk::Expression};
use strum_macros::EnumIter;

/// An execution step of the EVM.
#[derive(Clone, Debug)]
Expand Down Expand Up @@ -38,8 +41,6 @@ pub struct ExecStep {
pub bus_mapping_instance: Vec<OperationRef>,
/// Error generated by this step
pub error: Option<ExecError>,
/// Step auxiliary data
pub aux_data: Option<StepAuxiliaryData>,
}

impl ExecStep {
Expand All @@ -65,7 +66,6 @@ impl ExecStep {
log_id,
bus_mapping_instance: Vec::new(),
error: None,
aux_data: None,
}
}
}
Expand All @@ -86,7 +86,6 @@ impl Default for ExecStep {
log_id: 0,
bus_mapping_instance: Vec::new(),
error: None,
aux_data: None,
}
}
}
Expand All @@ -100,12 +99,6 @@ pub enum ExecState {
BeginTx,
/// Virtual step End Tx
EndTx,
/// Virtual step Copy To Memory
CopyToMemory,
/// Virtual step Copy To Log
CopyToLog,
/// Virtal step Copy Code To Memory
CopyCodeToMemory,
}

impl ExecState {
Expand Down Expand Up @@ -146,90 +139,96 @@ impl ExecState {
}
}

/// Provides specific details about the data copy for which an
/// [`StepAuxiliaryData`] holds info about.
#[derive(Clone, Copy, Debug)]
pub enum CopyDetails {
/// Origin of the copied bytes is or not the Tx CallData.
TxCallData(bool),
/// Origin of the copied bytes is bytecode. For which it's hash is provided.
Code(U256),
/// The bytes are being copied to a Log.
/// Call's state change's persistance and tx_id are provided.
/// the data start index when enter this copy step
Log((bool, usize, usize)),
/// Defines the various source/destination types for a copy event.
#[derive(Clone, Copy, Debug, PartialEq, Eq, EnumIter)]
pub enum CopyDataType {
/// When the source for the copy event is the bytecode table.
Bytecode = 1,
/// When the source/destination for the copy event is memory.
Memory,
/// When the source for the copy event is tx's calldata.
TxCalldata,
/// When the destination for the copy event is tx's log.
TxLog,
}

/// Auxiliary data of Execution step
#[derive(Clone, Copy, Debug)]
pub struct StepAuxiliaryData {
/// Source start address
pub(crate) src_addr: u64,
/// Destination address. (0x00..00 for Log related aux data).
pub(crate) dst_addr: u64,
/// Bytes left
pub(crate) bytes_left: u64,
/// Source end address
pub(crate) src_addr_end: u64,
/// Detail info about the copied data.
pub(crate) copy_details: CopyDetails,
}

impl StepAuxiliaryData {
/// Generates a new `StepAuxiliaryData` instance.
pub fn new(
src_addr: u64,
dst_addr: u64,
bytes_left: u64,
src_addr_end: u64,
copy_details: CopyDetails,
) -> Self {
Self {
src_addr,
dst_addr,
bytes_left,
src_addr_end,
copy_details,
}
}

/// Source start address
pub fn src_addr(&self) -> u64 {
self.src_addr
}

/// Destination address
pub fn dst_addr(&self) -> u64 {
self.dst_addr
}

/// Bytes left
pub fn bytes_left(&self) -> u64 {
self.bytes_left
}

/// Source end address
pub fn src_addr_end(&self) -> u64 {
self.src_addr_end
impl From<CopyDataType> for usize {
fn from(t: CopyDataType) -> Self {
t as usize
}
}

/// Indicate origin of the data to copy
pub fn copy_details(&self) -> CopyDetails {
self.copy_details
impl Default for CopyDataType {
fn default() -> Self {
Self::Memory
}
}

/// Returns true if the data origin is Code.
pub fn is_code_originated(&self) -> bool {
matches!(self.copy_details, CopyDetails::Code(_))
}
impl_expr!(CopyDataType);

/// Defines a single copy step in a copy event. This type is unified over the
/// source/destination row in the copy table.
#[derive(Clone, Debug, PartialEq)]
pub struct CopyStep {
/// Address (source/destination) for the copy step.
pub addr: u64,
/// Represents the source/destination's type.
pub tag: CopyDataType,
/// Whether this step is a read or write step.
pub rw: RW,
/// Byte value copied in this step.
pub value: u8,
/// Optional field which is enabled only for the source being `bytecode`,
/// and represents whether or not the byte is an opcode.
pub is_code: Option<bool>,
/// Represents whether or not the copy step is a padding row.
pub is_pad: bool,
/// Represents the current RW counter at this copy step.
pub rwc: RWCounter,
/// A decrementing value representing the RW counters left in the copy event
/// including the current step's RW counter.
pub rwc_inc_left: u64,
}

/// Returns true if the data origin is a Tx.
pub fn is_tx_originated(&self) -> bool {
matches!(self.copy_details, CopyDetails::TxCallData(_))
}
/// Defines an enum type that can hold either a number or a hash value.
#[derive(Clone, Debug, PartialEq)]
pub enum NumberOrHash {
/// Variant to indicate a number value.
Number(usize),
/// Variant to indicate a 256-bits hash value.
Hash(H256),
}

/// Returns true if the data is copied to Logs.
pub fn is_log_destinated(&self) -> bool {
matches!(self.copy_details, CopyDetails::Log(_))
}
/// Defines a copy event associated with EVM opcodes such as CALLDATACOPY,
/// CODECOPY, CREATE, etc. More information:
/// https://github.com/privacy-scaling-explorations/zkevm-specs/blob/master/specs/copy-proof.md.
#[derive(Clone, Debug)]
pub struct CopyEvent {
/// Represents the start address at the source of the copy event.
pub src_addr: u64,
/// Represents the end address at the source of the copy event.
pub src_addr_end: u64,
/// Represents the source type.
pub src_type: CopyDataType,
/// Represents the relevant ID for source.
pub src_id: NumberOrHash,
/// Represents the start address at the destination of the copy event.
pub dst_addr: u64,
/// Represents the destination type.
pub dst_type: CopyDataType,
/// Represents the relevant ID for destination.
pub dst_id: NumberOrHash,
/// An optional field to hold the log ID in case of the destination being
/// TxLog.
pub log_id: Option<u64>,
/// Represents the number of bytes copied as a part of this copy event.
pub length: u64,
/// Represents the list of copy steps in this copy event.
pub steps: Vec<CopyStep>,
/// Helper field for witness generation.
pub tx_id: usize,
/// Helper field for witness generation.
pub call_id: usize,
/// Helper field for witness generation.
pub pc: ProgramCounter,
}
17 changes: 8 additions & 9 deletions bus-mapping/src/circuit_input_builder/input_state_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use super::{
get_call_memory_offset_length, get_create_init_code, Block, BlockContext, Call, CallContext,
CallKind, CodeSource, ExecState, ExecStep, Transaction, TransactionContext,
CallKind, CodeSource, CopyEvent, ExecState, ExecStep, Transaction, TransactionContext,
};
use crate::{
error::{get_step_reported_error, ExecError},
Expand Down Expand Up @@ -43,18 +43,12 @@ impl<'a> CircuitInputStateRef<'a> {
pub fn new_step(&self, geth_step: &GethExecStep) -> Result<ExecStep, Error> {
let call_ctx = self.tx_ctx.call_ctx()?;

let pre_log_id = if self.tx.is_steps_empty() {
0
} else {
self.tx.last_step().log_id
};

Ok(ExecStep::new(
geth_step,
call_ctx.index,
self.block_ctx.rwc,
call_ctx.reversible_write_counter,
pre_log_id,
self.tx_ctx.log_id,
))
}

Expand Down Expand Up @@ -85,7 +79,7 @@ impl<'a> CircuitInputStateRef<'a> {
} else {
0
},
log_id: prev_step.log_id,
log_id: self.tx_ctx.log_id,
..Default::default()
}
}
Expand Down Expand Up @@ -784,6 +778,11 @@ impl<'a> CircuitInputStateRef<'a> {
Ok(())
}

/// Push a copy event to the state.
pub fn push_copy(&mut self, copy: CopyEvent) {
self.block.add_copy_event(copy);
}

pub(crate) fn get_step_err(
&self,
step: &GethExecStep,
Expand Down
Loading

0 comments on commit b375530

Please sign in to comment.