From a02a2ecb973228563c9494fe47c41cc2bb59916f Mon Sep 17 00:00:00 2001 From: BGluth Date: Thu, 12 Oct 2023 11:07:11 -0600 Subject: [PATCH 1/4] Updated `mir-protocol` --> `0xPolygonZero` - Recently the underlying org name on Github changed to `0xPolygonZero`. - This was causing some issues with dependencies downstream where a dependency pointing to the old org name was seen as a different dependency that was using the new org name. - Using a `[patch] section in `Cargo.toml` was running into issues where we couldn't get it to get all dependency versions using a single org name. --- README.md | 10 +++++----- evm/Cargo.toml | 4 ++-- plonky2/Cargo.toml | 2 +- plonky2/README.md | 2 +- plonky2/src/hash/poseidon_goldilocks.rs | 2 +- plonky2/src/plonk/circuit_builder.rs | 2 +- plonky2/src/util/reducing.rs | 2 +- starky/Cargo.toml | 2 +- 8 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index ed20b8e9a6..ab40a5c918 100644 --- a/README.md +++ b/README.md @@ -178,8 +178,8 @@ Plonky2's default hash function is Poseidon, configured with 8 full rounds, 22 p ## Links -- [System Zero](https://github.com/mir-protocol/system-zero), a zkVM built on top of Starky (no longer maintained) -- [Waksman](https://github.com/mir-protocol/plonky2-waksman), Plonky2 gadgets for permutation checking using Waksman networks (no longer maintained) -- [Insertion](https://github.com/mir-protocol/plonky2-insertion), Plonky2 gadgets for insertion into a list (no longer maintained) -- [u32](https://github.com/mir-protocol/plonky2-u32), Plonky2 gadgets for u32 arithmetic (no longer actively maintained) -- [ECDSA](https://github.com/mir-protocol/plonky2-ecdsa), Plonky2 gadgets for the ECDSA algorithm (no longer actively maintained) +- [System Zero](https://github.com/0xPolygonZero/system-zero), a zkVM built on top of Starky (no longer maintained) +- [Waksman](https://github.com/0xPolygonZero/plonky2-waksman), Plonky2 gadgets for permutation checking using Waksman networks (no longer maintained) +- [Insertion](https://github.com/0xPolygonZero/plonky2-insertion), Plonky2 gadgets for insertion into a list (no longer maintained) +- [u32](https://github.com/0xPolygonZero/plonky2-u32), Plonky2 gadgets for u32 arithmetic (no longer actively maintained) +- [ECDSA](https://github.com/0xPolygonZero/plonky2-ecdsa), Plonky2 gadgets for the ECDSA algorithm (no longer actively maintained) diff --git a/evm/Cargo.toml b/evm/Cargo.toml index 998e2effec..e328aa0c97 100644 --- a/evm/Cargo.toml +++ b/evm/Cargo.toml @@ -4,7 +4,7 @@ description = "Implementation of STARKs for the Ethereum Virtual Machine" version = "0.1.1" authors = ["Daniel Lubarov ", "William Borgeaud "] readme = "README.md" -repository = "https://github.com/mir-protocol/plonky2" +repository = "https://github.com/0xPolygonZero/plonky2" keywords = ["EVM", "STARK", "Ethereum"] categories = ["cryptography"] edition = "2021" @@ -13,7 +13,7 @@ edition = "2021" anyhow = "1.0.40" bytes = "1.4.0" env_logger = "0.10.0" -eth_trie_utils = { git = "https://github.com/mir-protocol/eth_trie_utils.git", rev = "e9ec4ec2aa2ae976b7c699ef40c1ffc716d87ed5" } +eth_trie_utils = { git = "https://github.com/0xPolygonZero/eth_trie_utils.git", rev = "e9ec4ec2aa2ae976b7c699ef40c1ffc716d87ed5" } ethereum-types = "0.14.0" hex = { version = "0.4.3", optional = true } hex-literal = "0.4.1" diff --git a/plonky2/Cargo.toml b/plonky2/Cargo.toml index fc6df1b4f3..ad586679de 100644 --- a/plonky2/Cargo.toml +++ b/plonky2/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.4" license = "MIT OR Apache-2.0" authors = ["Daniel Lubarov ", "William Borgeaud ", "Nicholas Ward "] readme = "README.md" -repository = "https://github.com/mir-protocol/plonky2" +repository = "https://github.com/0xPolygonZero/plonky2" keywords = ["cryptography", "SNARK", "PLONK", "FRI"] categories = ["cryptography"] edition = "2021" diff --git a/plonky2/README.md b/plonky2/README.md index ed55704582..7d3a3d65bd 100644 --- a/plonky2/README.md +++ b/plonky2/README.md @@ -1,6 +1,6 @@ # Plonky2 -Plonky2 is a SNARK implementation based on techniques from PLONK and FRI. It is the successor of [Plonky](https://github.com/mir-protocol/plonky), which was based on PLONK and Halo. +Plonky2 is a SNARK implementation based on techniques from PLONK and FRI. It is the successor of [Plonky](https://github.com/0xPolygonZero/plonky), which was based on PLONK and Halo. Plonky2 is built for speed, and features a highly efficient recursive circuit. On a Macbook Pro, recursive proofs can be generated in about 170 ms. diff --git a/plonky2/src/hash/poseidon_goldilocks.rs b/plonky2/src/hash/poseidon_goldilocks.rs index c784a1db01..e2c72d858f 100644 --- a/plonky2/src/hash/poseidon_goldilocks.rs +++ b/plonky2/src/hash/poseidon_goldilocks.rs @@ -1,7 +1,7 @@ //! Implementations for Poseidon over Goldilocks field of widths 8 and 12. //! //! These contents of the implementations *must* be generated using the -//! `poseidon_constants.sage` script in the `mir-protocol/hash-constants` +//! `poseidon_constants.sage` script in the `0xPolygonZero/hash-constants` //! repository. #[cfg(not(all(target_arch = "aarch64", target_feature = "neon")))] diff --git a/plonky2/src/plonk/circuit_builder.rs b/plonky2/src/plonk/circuit_builder.rs index bd436f2c85..67db68649a 100644 --- a/plonky2/src/plonk/circuit_builder.rs +++ b/plonky2/src/plonk/circuit_builder.rs @@ -906,7 +906,7 @@ impl, const D: usize> CircuitBuilder { /// In PLONK's permutation argument, there's a slight chance of division by zero. We can /// mitigate this by randomizing some unused witness elements, so if proving fails with /// division by zero, the next attempt will have an (almost) independent chance of success. - /// See https://github.com/mir-protocol/plonky2/issues/456 + /// See https://github.com/0xPolygonZero/plonky2/issues/456 fn randomize_unused_pi_wires(&mut self, pi_gate: usize) { for wire in PublicInputGate::wires_public_inputs_hash().end..self.config.num_wires { self.add_simple_generator(RandomValueGenerator { diff --git a/plonky2/src/util/reducing.rs b/plonky2/src/util/reducing.rs index aaf905d5b8..bde484e875 100644 --- a/plonky2/src/util/reducing.rs +++ b/plonky2/src/util/reducing.rs @@ -20,7 +20,7 @@ use crate::plonk::circuit_builder::CircuitBuilder; /// scale the second one by `a^(r-1-k)`, and add them up. /// This struct abstract away these operations by implementing Horner's method and keeping track /// of the number of multiplications by `a` to compute the scaling factor. -/// See for more details and discussions. +/// See for more details and discussions. #[derive(Debug, Clone)] pub struct ReducingFactor { base: F, diff --git a/starky/Cargo.toml b/starky/Cargo.toml index da0ad1b723..62a67ee78e 100644 --- a/starky/Cargo.toml +++ b/starky/Cargo.toml @@ -5,7 +5,7 @@ version = "0.1.2" license = "MIT OR Apache-2.0" authors = ["Daniel Lubarov ", "William Borgeaud "] readme = "README.md" -repository = "https://github.com/mir-protocol/plonky2" +repository = "https://github.com/0xPolygonZero/plonky2" keywords = ["cryptography", "STARK", "FRI"] categories = ["cryptography"] edition = "2021" From c9391be0244b5aba207dfc72cac100028b4eea3e Mon Sep 17 00:00:00 2001 From: Robin Salen <30937548+Nashtare@users.noreply.github.com> Date: Mon, 16 Oct 2023 08:53:42 -0400 Subject: [PATCH 2/4] Update check_ctls with extra looking values (#1290) --- evm/src/cross_table_lookup.rs | 17 +++- evm/src/prover.rs | 27 +++++-- evm/src/verifier.rs | 146 ++++++++++++++++++++++++++++++++++ 3 files changed, 182 insertions(+), 8 deletions(-) diff --git a/evm/src/cross_table_lookup.rs b/evm/src/cross_table_lookup.rs index 2ab9dbf86f..621403f912 100644 --- a/evm/src/cross_table_lookup.rs +++ b/evm/src/cross_table_lookup.rs @@ -838,13 +838,13 @@ pub(crate) mod testutils { type MultiSet = HashMap, Vec<(Table, usize)>>; /// Check that the provided traces and cross-table lookups are consistent. - #[allow(unused)] // TODO: used later? pub(crate) fn check_ctls( trace_poly_values: &[Vec>], cross_table_lookups: &[CrossTableLookup], + extra_memory_looking_values: &[Vec], ) { for (i, ctl) in cross_table_lookups.iter().enumerate() { - check_ctl(trace_poly_values, ctl, i); + check_ctl(trace_poly_values, ctl, i, extra_memory_looking_values); } } @@ -852,6 +852,7 @@ pub(crate) mod testutils { trace_poly_values: &[Vec>], ctl: &CrossTableLookup, ctl_index: usize, + extra_memory_looking_values: &[Vec], ) { let CrossTableLookup { looking_tables, @@ -868,6 +869,18 @@ pub(crate) mod testutils { } process_table(trace_poly_values, looked_table, &mut looked_multiset); + // Extra looking values for memory + if ctl_index == Table::Memory as usize { + for row in extra_memory_looking_values.iter() { + // The table and the row index don't matter here, as we just want to enforce + // that the special extra values do appear when looking against the Memory table. + looking_multiset + .entry(row.to_vec()) + .or_default() + .push((Table::Cpu, 0)); + } + } + let empty = &vec![]; // Check that every row in the looking tables appears in the looked table the same number of times. for (row, looking_locations) in &looking_multiset { diff --git a/evm/src/prover.rs b/evm/src/prover.rs index 5aa9dc6f6f..c5729a573f 100644 --- a/evm/src/prover.rs +++ b/evm/src/prover.rs @@ -1,5 +1,3 @@ -use std::any::type_name; - use anyhow::{ensure, Result}; use itertools::Itertools; use once_cell::sync::Lazy; @@ -35,6 +33,10 @@ use crate::lookup::{lookup_helper_columns, Lookup, LookupCheckVars}; use crate::proof::{AllProof, PublicValues, StarkOpeningSet, StarkProof, StarkProofWithMetadata}; use crate::stark::Stark; use crate::vanishing_poly::eval_vanishing_poly; +#[cfg(test)] +use crate::{ + cross_table_lookup::testutils::check_ctls, verifier::testutils::get_memory_extra_looking_values, +}; /// Generate traces, then create all STARK proofs. pub fn prove( @@ -142,7 +144,7 @@ where prove_with_commitments( all_stark, config, - trace_poly_values, + &trace_poly_values, trace_commitments, ctl_data_per_table, &mut challenger, @@ -151,6 +153,15 @@ where )? ); + #[cfg(test)] + { + check_ctls( + &trace_poly_values, + &all_stark.cross_table_lookups, + &get_memory_extra_looking_values(&public_values), + ); + } + Ok(AllProof { stark_proofs, ctl_challenges, @@ -161,7 +172,7 @@ where fn prove_with_commitments( all_stark: &AllStark, config: &StarkConfig, - trace_poly_values: [Vec>; NUM_TABLES], + trace_poly_values: &[Vec>; NUM_TABLES], trace_commitments: Vec>, ctl_data_per_table: [CtlData; NUM_TABLES], challenger: &mut Challenger, @@ -365,7 +376,9 @@ where challenger.observe_cap(&auxiliary_polys_cap); let alphas = challenger.get_n_challenges(config.num_challenges); - if cfg!(test) { + + #[cfg(test)] + { check_constraints( stark, trace_commitment, @@ -378,6 +391,7 @@ where num_lookup_columns, ); } + let quotient_polys = timed!( timing, "compute quotient polys", @@ -606,6 +620,7 @@ where .collect() } +#[cfg(test)] /// Check that all constraints evaluate to zero on `H`. /// Can also be used to check the degree of the constraints by evaluating on a larger subgroup. fn check_constraints<'a, F, C, S, const D: usize>( @@ -705,7 +720,7 @@ fn check_constraints<'a, F, C, S, const D: usize>( assert!( v.iter().all(|x| x.is_zero()), "Constraint failed in {}", - type_name::() + std::any::type_name::() ); } } diff --git a/evm/src/verifier.rs b/evm/src/verifier.rs index d3f06c01f6..04450b4606 100644 --- a/evm/src/verifier.rs +++ b/evm/src/verifier.rs @@ -455,6 +455,152 @@ fn eval_l_0_and_l_last(log_n: usize, x: F) -> (F, F) { (z_x * invs[0], z_x * invs[1]) } +#[cfg(test)] +pub(crate) mod testutils { + use super::*; + + /// Output all the extra memory rows that don't appear in the CPU trace but are + /// necessary to correctly check the MemoryStark CTL. + pub(crate) fn get_memory_extra_looking_values( + public_values: &PublicValues, + ) -> Vec> + where + F: RichField + Extendable, + { + // Add metadata and tries writes. + let fields = [ + ( + GlobalMetadata::BlockBeneficiary, + U256::from_big_endian(&public_values.block_metadata.block_beneficiary.0), + ), + ( + GlobalMetadata::BlockTimestamp, + public_values.block_metadata.block_timestamp, + ), + ( + GlobalMetadata::BlockNumber, + public_values.block_metadata.block_number, + ), + ( + GlobalMetadata::BlockRandom, + public_values.block_metadata.block_random.into_uint(), + ), + ( + GlobalMetadata::BlockDifficulty, + public_values.block_metadata.block_difficulty, + ), + ( + GlobalMetadata::BlockGasLimit, + public_values.block_metadata.block_gaslimit, + ), + ( + GlobalMetadata::BlockChainId, + public_values.block_metadata.block_chain_id, + ), + ( + GlobalMetadata::BlockBaseFee, + public_values.block_metadata.block_base_fee, + ), + ( + GlobalMetadata::BlockCurrentHash, + h2u(public_values.block_hashes.cur_hash), + ), + ( + GlobalMetadata::BlockGasUsed, + public_values.block_metadata.block_gas_used, + ), + ( + GlobalMetadata::TxnNumberBefore, + public_values.extra_block_data.txn_number_before, + ), + ( + GlobalMetadata::TxnNumberAfter, + public_values.extra_block_data.txn_number_after, + ), + ( + GlobalMetadata::BlockGasUsedBefore, + public_values.extra_block_data.gas_used_before, + ), + ( + GlobalMetadata::BlockGasUsedAfter, + public_values.extra_block_data.gas_used_after, + ), + ( + GlobalMetadata::StateTrieRootDigestBefore, + h2u(public_values.trie_roots_before.state_root), + ), + ( + GlobalMetadata::TransactionTrieRootDigestBefore, + h2u(public_values.trie_roots_before.transactions_root), + ), + ( + GlobalMetadata::ReceiptTrieRootDigestBefore, + h2u(public_values.trie_roots_before.receipts_root), + ), + ( + GlobalMetadata::StateTrieRootDigestAfter, + h2u(public_values.trie_roots_after.state_root), + ), + ( + GlobalMetadata::TransactionTrieRootDigestAfter, + h2u(public_values.trie_roots_after.transactions_root), + ), + ( + GlobalMetadata::ReceiptTrieRootDigestAfter, + h2u(public_values.trie_roots_after.receipts_root), + ), + ]; + + let segment = F::from_canonical_u32(Segment::GlobalMetadata as u32); + let mut extra_looking_rows = Vec::new(); + + fields.map(|(field, val)| { + extra_looking_rows.push(add_extra_looking_row(segment, field as usize, val)) + }); + + // Add block bloom writes. + let bloom_segment = F::from_canonical_u32(Segment::GlobalBlockBloom as u32); + for index in 0..8 { + let val = public_values.block_metadata.block_bloom[index]; + extra_looking_rows.push(add_extra_looking_row(bloom_segment, index, val)); + } + + for index in 0..8 { + let val = public_values.extra_block_data.block_bloom_before[index]; + extra_looking_rows.push(add_extra_looking_row(bloom_segment, index + 8, val)); + } + for index in 0..8 { + let val = public_values.extra_block_data.block_bloom_after[index]; + extra_looking_rows.push(add_extra_looking_row(bloom_segment, index + 16, val)); + } + + // Add Blockhashes writes. + let block_hashes_segment = F::from_canonical_u32(Segment::BlockHashes as u32); + for index in 0..256 { + let val = h2u(public_values.block_hashes.prev_hashes[index]); + extra_looking_rows.push(add_extra_looking_row(block_hashes_segment, index, val)); + } + + extra_looking_rows + } + + fn add_extra_looking_row(segment: F, index: usize, val: U256) -> Vec + where + F: RichField + Extendable, + { + let mut row = vec![F::ZERO; 13]; + row[0] = F::ZERO; // is_read + row[1] = F::ZERO; // context + row[2] = segment; + row[3] = F::from_canonical_usize(index); + + for j in 0..VALUE_LIMBS { + row[j + 4] = F::from_canonical_u32((val >> (j * 32)).low_u32()); + } + row[12] = F::ONE; // timestamp + row + } +} #[cfg(test)] mod tests { use plonky2::field::goldilocks_field::GoldilocksField; From 29fdd3e372c721d65ada7363a1554202e7ab0e7b Mon Sep 17 00:00:00 2001 From: Robin Salen <30937548+Nashtare@users.noreply.github.com> Date: Mon, 16 Oct 2023 08:53:59 -0400 Subject: [PATCH 3/4] minor: use explicit builder.assert_zero for readability (#1293) --- evm/src/fixed_recursive_verifier.rs | 15 ++++++--------- evm/src/recursive_verifier.rs | 19 +++++++++---------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/evm/src/fixed_recursive_verifier.rs b/evm/src/fixed_recursive_verifier.rs index 1e76a30e4c..42919a97eb 100644 --- a/evm/src/fixed_recursive_verifier.rs +++ b/evm/src/fixed_recursive_verifier.rs @@ -819,12 +819,11 @@ where // Connect intermediary values for gas_used and bloom filters to the block's final values. We only plug on the right, so there is no need to check the left-handside block. Self::connect_final_block_values_to_intermediary(builder, rhs); - let zero = builder.zero(); let has_not_parent_block = builder.sub(one, has_parent_block.target); // Check that the genesis block number is 0. let gen_block_constr = builder.mul(has_not_parent_block, rhs.block_metadata.block_number); - builder.connect(gen_block_constr, zero); + builder.assert_zero(gen_block_constr); // Check that the genesis block has the predetermined state trie root in `ExtraBlockData`. Self::connect_genesis_block(builder, rhs, has_not_parent_block); @@ -837,7 +836,6 @@ where ) where F: RichField + Extendable, { - let zero = builder.zero(); for (&limb0, limb1) in x .trie_roots_before .state_root @@ -846,7 +844,7 @@ where { let mut constr = builder.sub(limb0, limb1); constr = builder.mul(has_not_parent_block, constr); - builder.connect(constr, zero); + builder.assert_zero(constr); } } @@ -879,16 +877,15 @@ where where F: RichField + Extendable, { - let zero = builder.constant(F::ZERO); // The initial number of transactions is 0. - builder.connect(x.extra_block_data.txn_number_before, zero); + builder.assert_zero(x.extra_block_data.txn_number_before); // The initial gas used is 0. - builder.connect(x.extra_block_data.gas_used_before[0], zero); - builder.connect(x.extra_block_data.gas_used_before[1], zero); + builder.assert_zero(x.extra_block_data.gas_used_before[0]); + builder.assert_zero(x.extra_block_data.gas_used_before[1]); // The initial bloom filter is all zeroes. for t in x.extra_block_data.block_bloom_before { - builder.connect(t, zero); + builder.assert_zero(t); } // The transactions and receipts tries are empty at the beginning of the block. diff --git a/evm/src/recursive_verifier.rs b/evm/src/recursive_verifier.rs index d88d847184..7464eb1715 100644 --- a/evm/src/recursive_verifier.rs +++ b/evm/src/recursive_verifier.rs @@ -619,14 +619,11 @@ fn add_data_write, const D: usize>( debug_assert!(val.len() <= VALUE_LIMBS); let len = core::cmp::min(val.len(), VALUE_LIMBS); - let zero = builder.zero(); - let one = builder.one(); - let row = builder.add_virtual_targets(13); - // is_read - builder.connect(row[0], zero); - // context - builder.connect(row[1], zero); + // is_read = false + builder.assert_zero(row[0]); + // context = 0 + builder.assert_zero(row[1]); // segment builder.connect(row[2], segment); // virtual @@ -635,14 +632,16 @@ fn add_data_write, const D: usize>( // values for j in 0..len { + // connect the actual value limbs builder.connect(row[4 + j], val[j]); } for j in len..VALUE_LIMBS { - builder.connect(row[4 + j], zero); + // assert that the remaining limbs are 0 + builder.assert_zero(row[4 + j]); } - // timestamp - builder.connect(row[12], one); + // timestamp = 1 + builder.assert_one(row[12]); let combined = challenge.combine_base_circuit(builder, &row); builder.mul(running_product, combined) From 817e3e78e0cb25b6c61eea9a5ee72e8c8f607a39 Mon Sep 17 00:00:00 2001 From: Linda Guiga <101227802+LindaGuiga@users.noreply.github.com> Date: Wed, 18 Oct 2023 17:32:43 -0400 Subject: [PATCH 4/4] Combine DUP and SWAP (#1254) * Combine dup and swap flags. * Add comments --- evm/src/cpu/columns/ops.rs | 3 +-- evm/src/cpu/control_flow.rs | 5 ++--- evm/src/cpu/decode.rs | 7 +++---- evm/src/cpu/dup_swap.rs | 15 ++++++++++----- evm/src/cpu/gas.rs | 3 +-- evm/src/cpu/stack.rs | 3 +-- evm/src/witness/transition.rs | 6 ++---- 7 files changed, 20 insertions(+), 22 deletions(-) diff --git a/evm/src/cpu/columns/ops.rs b/evm/src/cpu/columns/ops.rs index feeb3f5f75..270b0ab871 100644 --- a/evm/src/cpu/columns/ops.rs +++ b/evm/src/cpu/columns/ops.rs @@ -22,8 +22,7 @@ pub struct OpsColumnsView { pub jumpdest: T, pub push0: T, pub push: T, - pub dup: T, - pub swap: T, + pub dup_swap: T, pub get_context: T, pub set_context: T, pub mstore_32bytes: T, diff --git a/evm/src/cpu/control_flow.rs b/evm/src/cpu/control_flow.rs index a192ffb13f..2f496b514a 100644 --- a/evm/src/cpu/control_flow.rs +++ b/evm/src/cpu/control_flow.rs @@ -8,7 +8,7 @@ use crate::constraint_consumer::{ConstraintConsumer, RecursiveConstraintConsumer use crate::cpu::columns::{CpuColumnsView, COL_MAP}; use crate::cpu::kernel::aggregator::KERNEL; -const NATIVE_INSTRUCTIONS: [usize; 18] = [ +const NATIVE_INSTRUCTIONS: [usize; 17] = [ COL_MAP.op.binary_op, COL_MAP.op.ternary_op, COL_MAP.op.fp254_op, @@ -24,8 +24,7 @@ const NATIVE_INSTRUCTIONS: [usize; 18] = [ COL_MAP.op.jumpdest, COL_MAP.op.push0, // not PUSH (need to increment by more than 1) - COL_MAP.op.dup, - COL_MAP.op.swap, + COL_MAP.op.dup_swap, COL_MAP.op.get_context, COL_MAP.op.set_context, // not EXIT_KERNEL (performs a jump) diff --git a/evm/src/cpu/decode.rs b/evm/src/cpu/decode.rs index 4e2bff5c29..a4756684a2 100644 --- a/evm/src/cpu/decode.rs +++ b/evm/src/cpu/decode.rs @@ -23,7 +23,7 @@ use crate::cpu::columns::{CpuColumnsView, COL_MAP}; /// behavior. /// Note: invalid opcodes are not represented here. _Any_ opcode is permitted to decode to /// `is_invalid`. The kernel then verifies that the opcode was _actually_ invalid. -const OPCODES: [(u8, usize, bool, usize); 17] = [ +const OPCODES: [(u8, usize, bool, usize); 16] = [ // (start index of block, number of top bits to check (log2), kernel-only, flag column) // ADD, MUL, SUB, DIV, MOD, LT, GT and BYTE flags are handled partly manually here, and partly through the Arithmetic table CTL. // ADDMOD, MULMOD and SUBMOD flags are handled partly manually here, and partly through the Arithmetic table CTL. @@ -39,9 +39,8 @@ const OPCODES: [(u8, usize, bool, usize); 17] = [ (0x58, 0, false, COL_MAP.op.pc), (0x5b, 0, false, COL_MAP.op.jumpdest), (0x5f, 0, false, COL_MAP.op.push0), - (0x60, 5, false, COL_MAP.op.push), // 0x60-0x7f - (0x80, 4, false, COL_MAP.op.dup), // 0x80-0x8f - (0x90, 4, false, COL_MAP.op.swap), // 0x90-0x9f + (0x60, 5, false, COL_MAP.op.push), // 0x60-0x7f + (0x80, 5, false, COL_MAP.op.dup_swap), // 0x80-0x9f (0xee, 0, true, COL_MAP.op.mstore_32bytes), (0xf6, 0, true, COL_MAP.op.get_context), (0xf7, 0, true, COL_MAP.op.set_context), diff --git a/evm/src/cpu/dup_swap.rs b/evm/src/cpu/dup_swap.rs index d5bc49a007..0cc6c67c8f 100644 --- a/evm/src/cpu/dup_swap.rs +++ b/evm/src/cpu/dup_swap.rs @@ -114,7 +114,8 @@ fn eval_packed_dup( nv: &CpuColumnsView

, yield_constr: &mut ConstraintConsumer

, ) { - let filter = lv.op.dup; + // DUP opcodes have 0 at the 5-th position, while SWAP opcodes have 1. + let filter = lv.op.dup_swap * (P::ONES - lv.opcode_bits[4]); let write_channel = &lv.mem_channels[1]; let read_channel = &lv.mem_channels[2]; @@ -139,8 +140,10 @@ fn eval_ext_circuit_dup, const D: usize>( yield_constr: &mut RecursiveConstraintConsumer, ) { let zero = builder.zero_extension(); - - let filter = lv.op.dup; + let one = builder.one_extension(); + // DUP opcodes have 0 at the 5-th position, while SWAP opcodes have 1. + let mut filter = builder.sub_extension(one, lv.opcode_bits[4]); + filter = builder.mul_extension(lv.op.dup_swap, filter); let write_channel = &lv.mem_channels[1]; let read_channel = &lv.mem_channels[2]; @@ -187,7 +190,8 @@ fn eval_packed_swap( ) { let n_plus_one = n + P::ONES; - let filter = lv.op.swap; + // DUP opcodes have 0 at the 5-th position, while SWAP opcodes have 1. + let filter = lv.op.dup_swap * lv.opcode_bits[4]; let in1_channel = &lv.mem_channels[0]; let in2_channel = &lv.mem_channels[1]; @@ -215,7 +219,8 @@ fn eval_ext_circuit_swap, const D: usize>( let one = builder.one_extension(); let n_plus_one = builder.add_extension(n, one); - let filter = lv.op.swap; + // DUP opcodes have 0 at the 5-th position, while SWAP opcodes have 1. + let filter = builder.mul_extension(lv.op.dup_swap, lv.opcode_bits[4]); let in1_channel = &lv.mem_channels[0]; let in2_channel = &lv.mem_channels[1]; diff --git a/evm/src/cpu/gas.rs b/evm/src/cpu/gas.rs index 1434efd93d..1a908d6df4 100644 --- a/evm/src/cpu/gas.rs +++ b/evm/src/cpu/gas.rs @@ -34,8 +34,7 @@ const SIMPLE_OPCODES: OpsColumnsView> = OpsColumnsView { jumpdest: G_JUMPDEST, push0: G_BASE, push: G_VERYLOW, - dup: G_VERYLOW, - swap: G_VERYLOW, + dup_swap: G_VERYLOW, get_context: KERNEL_ONLY_INSTR, set_context: KERNEL_ONLY_INSTR, mstore_32bytes: KERNEL_ONLY_INSTR, diff --git a/evm/src/cpu/stack.rs b/evm/src/cpu/stack.rs index 31d0405cea..db0c480d3d 100644 --- a/evm/src/cpu/stack.rs +++ b/evm/src/cpu/stack.rs @@ -109,8 +109,7 @@ pub(crate) const STACK_BEHAVIORS: OpsColumnsView> = OpsCol disable_other_channels: true, }), push: None, // TODO - dup: None, - swap: None, + dup_swap: None, get_context: Some(StackBehavior { num_pops: 0, pushes: true, diff --git a/evm/src/witness/transition.rs b/evm/src/witness/transition.rs index 00030110dd..312b8591f4 100644 --- a/evm/src/witness/transition.rs +++ b/evm/src/witness/transition.rs @@ -162,8 +162,7 @@ fn fill_op_flag(op: Operation, row: &mut CpuColumnsView) { *match op { Operation::Push(0) => &mut flags.push0, Operation::Push(1..) => &mut flags.push, - Operation::Dup(_) => &mut flags.dup, - Operation::Swap(_) => &mut flags.swap, + Operation::Dup(_) | Operation::Swap(_) => &mut flags.dup_swap, Operation::Iszero | Operation::Eq => &mut flags.eq_iszero, Operation::Not => &mut flags.not, Operation::Syscall(_, _, _) => &mut flags.syscall, @@ -195,8 +194,7 @@ fn get_op_special_length(op: Operation) -> Option { let behavior_opt = match op { Operation::Push(0) => STACK_BEHAVIORS.push0, Operation::Push(1..) => STACK_BEHAVIORS.push, - Operation::Dup(_) => STACK_BEHAVIORS.dup, - Operation::Swap(_) => STACK_BEHAVIORS.swap, + Operation::Dup(_) | Operation::Swap(_) => STACK_BEHAVIORS.dup_swap, Operation::Iszero => IS_ZERO_STACK_BEHAVIOR, Operation::Not => STACK_BEHAVIORS.not, Operation::Syscall(_, _, _) => STACK_BEHAVIORS.syscall,