diff --git a/Cargo.lock b/Cargo.lock index f46f0b5226..09b2865f5d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -305,7 +305,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] @@ -314,7 +314,7 @@ version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] @@ -423,9 +423,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.3" +version = "0.15.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" +checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" dependencies = [ "camino", "cargo-platform", @@ -658,7 +658,7 @@ dependencies = [ "bech32", "blake2", "digest 0.10.6", - "generic-array 0.14.6", + "generic-array 0.14.7", "hex", "ripemd", "serde", @@ -874,7 +874,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "rand_core", "subtle", "zeroize", @@ -886,7 +886,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "typenum", ] @@ -896,7 +896,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", "subtle", ] @@ -1130,7 +1130,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] @@ -1249,7 +1249,7 @@ dependencies = [ "der", "digest 0.10.6", "ff", - "generic-array 0.14.6", + "generic-array 0.14.7", "group", "pkcs8", "rand_core", @@ -1325,6 +1325,17 @@ dependencies = [ "winapi", ] +[[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" @@ -1533,7 +1544,7 @@ dependencies = [ "convert_case", "elliptic-curve", "ethabi", - "generic-array 0.14.6", + "generic-array 0.14.7", "getrandom", "hex", "k256", @@ -1995,9 +2006,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.6" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", @@ -2245,7 +2256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", - "generic-array 0.14.6", + "generic-array 0.14.7", "hmac 0.8.1", ] @@ -2450,7 +2461,7 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array 0.14.6", + "generic-array 0.14.7", ] [[package]] @@ -2527,7 +2538,7 @@ checksum = "21b6b32576413a8e69b90e952e4a026476040d81017b80445deda5f2d3921857" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix", + "rustix 0.36.8", "windows-sys 0.45.0", ] @@ -2726,6 +2737,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f" + [[package]] name = "lock_api" version = "0.4.9" @@ -3058,7 +3075,7 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] @@ -3071,7 +3088,7 @@ checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "windows-sys 0.45.0", ] @@ -3486,18 +3503,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.51" +version = "1.0.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d727cae5b39d21da60fa540906919ad737832fe0b1c165da3a34d6548c849d6" +checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8856d8364d252a14d474036ea1358d63c9e6965c8e5c1885c18f73d70bff9c7b" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" dependencies = [ "proc-macro2", ] @@ -3584,6 +3601,15 @@ 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 = "redox_users" version = "0.4.3" @@ -3591,7 +3617,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] @@ -3773,10 +3799,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f43abb88211988493c1abb44a70efa56ff0ce98f233b7b276146f1f3f7ba9644" dependencies = [ "bitflags", - "errno", + "errno 0.2.8", + "io-lifetimes", + "libc", + "linux-raw-sys 0.1.4", + "windows-sys 0.45.0", +] + +[[package]] +name = "rustix" +version = "0.37.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b24138615de35e32031d041a09032ef3487a616d901ca4db224e7d557efae2" +dependencies = [ + "bitflags", + "errno 0.3.1", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.7", "windows-sys 0.45.0", ] @@ -3897,7 +3937,7 @@ checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928" dependencies = [ "base16ct", "der", - "generic-array 0.14.6", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -3996,9 +4036,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.93" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cad406b69c91885b5107daf2c29572f6c8cdb3c66826821e286c533490c0bc76" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -4312,15 +4352,15 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af18f7ae1acd354b992402e9ec5864359d693cd8a79dcbef59f76891701c1e95" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" dependencies = [ "cfg-if", "fastrand", - "redox_syscall", - "rustix", - "windows-sys 0.42.0", + "redox_syscall 0.3.5", + "rustix 0.37.3", + "windows-sys 0.45.0", ] [[package]] @@ -4921,26 +4961,20 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-sys" -version = "0.42.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" 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", + "windows-targets 0.42.1", ] [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets", + "windows-targets 0.48.0", ] [[package]] @@ -4949,13 +4983,28 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" 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", + "windows_aarch64_gnullvm 0.42.1", + "windows_aarch64_msvc 0.42.1", + "windows_i686_gnu 0.42.1", + "windows_i686_msvc 0.42.1", + "windows_x86_64_gnu 0.42.1", + "windows_x86_64_gnullvm 0.42.1", + "windows_x86_64_msvc 0.42.1", +] + +[[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]] @@ -4964,42 +5013,84 @@ version = "0.42.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +[[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.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +[[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.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +[[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.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +[[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.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +[[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.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +[[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.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +[[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.3.3" @@ -5104,6 +5195,7 @@ dependencies = [ "ethers-core", "ethers-signers", "gadgets", + "geth-utils", "halo2_proofs 0.2.0", "hex", "integer", diff --git a/bus-mapping/Cargo.toml b/bus-mapping/Cargo.toml index 96facd7d54..f16b988878 100644 --- a/bus-mapping/Cargo.toml +++ b/bus-mapping/Cargo.toml @@ -12,8 +12,8 @@ keccak256 = { path = "../keccak256" } mock = { path = "../mock", optional = true } ark-std = { version = "0.3", features = ["print-trace"] } -ethers-core = "2.0.0" -ethers-providers = "2.0.0" +ethers-core = "=2.0.0" +ethers-providers = "=2.0.0" halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_10_22" } itertools = "0.10" lazy_static = "1.4" diff --git a/bus-mapping/src/circuit_input_builder.rs b/bus-mapping/src/circuit_input_builder.rs index 1573ac4a1c..25bfddd78c 100644 --- a/bus-mapping/src/circuit_input_builder.rs +++ b/bus-mapping/src/circuit_input_builder.rs @@ -21,7 +21,6 @@ pub use block::{Block, BlockContext}; pub use call::{Call, CallContext, CallKind}; use core::fmt::Debug; use eth_types::sign_types::{pk_bytes_le, pk_bytes_swap_endianness, SignData}; -use eth_types::ToWord; use eth_types::{self, geth_types, Address, GethExecStep, GethExecTrace, Word}; use ethers_providers::JsonRpcClient; pub use execution::{ @@ -400,38 +399,33 @@ impl BuilderClient

{ // self.cli.trace_block_by_number(block_num.into()).await?; // fetch up to 256 blocks - let mut n_blocks = std::cmp::min(256, block_num as usize); - let mut next_hash = eth_block.parent_hash; - let mut prev_state_root: Option = None; - let mut history_hashes = vec![Word::default(); n_blocks]; - while n_blocks > 0 { - n_blocks -= 1; - - // TODO: consider replacing it with `eth_getHeaderByHash`, it's faster - let header = self.cli.get_block_by_hash(next_hash).await?; - - // set the previous state root - if prev_state_root.is_none() { - prev_state_root = Some(header.state_root.to_word()); - } - - // latest block hash is the last item - let block_hash = header - .hash - .ok_or(Error::EthTypeError(eth_types::Error::IncompleteBlock))? - .to_word(); - history_hashes[n_blocks] = block_hash; - - // continue - next_hash = header.parent_hash; - } + let n_blocks = std::cmp::min(256, block_num as usize); + // let mut next_hash = eth_block.parent_hash; + // let mut prev_state_root: Option = None; + let history_hashes = vec![Word::default(); n_blocks]; + // while n_blocks > 0 { + // n_blocks -= 1; + + // // TODO: consider replacing it with `eth_getHeaderByHash`, it's faster + // let header = self.cli.get_block_by_hash(next_hash).await?; + + // // set the previous state root + // if prev_state_root.is_none() { + // prev_state_root = Some(header.state_root.to_word()); + // } + + // // latest block hash is the last item + // let block_hash = header + // .hash + // .ok_or(Error::EthTypeError(eth_types::Error::IncompleteBlock))? + // .to_word(); + // history_hashes[n_blocks] = block_hash; + + // // continue + // next_hash = header.parent_hash; + // } - Ok(( - eth_block, - geth_traces, - history_hashes, - prev_state_root.unwrap_or_default(), - )) + Ok((eth_block, geth_traces, history_hashes, Default::default())) } /// Step 2. Get State Accesses from TxExecTraces diff --git a/bus-mapping/src/public_input_builder.rs b/bus-mapping/src/public_input_builder.rs index 8d379787b9..7ccaad488c 100644 --- a/bus-mapping/src/public_input_builder.rs +++ b/bus-mapping/src/public_input_builder.rs @@ -70,25 +70,3 @@ pub async fn get_txs_rlp( } }) } - -#[cfg(test)] -mod tests { - use ethers_core::utils::rlp; - use ethers_providers::Http; - use std::str::FromStr; - - use super::*; - #[tokio::test] - async fn test() { - let l1_provider = - Http::from_str("https://l1rpc.internal.taiko.xyz").expect("Http geth url"); - let l1_geth_client = GethClient::new(l1_provider); - let propose_tx_hash = H256::from_slice( - &hex::decode("6384692336baecbdcafb0bfe84437372d3ec2727a4c6bd7a6cf66644773b8124") - .unwrap(), - ); - let tx = get_txs_rlp(&l1_geth_client, propose_tx_hash).await.unwrap(); - let txs: Vec = rlp::Rlp::new(&tx).as_list().unwrap(); - println!("{:?}", txs); - } -} diff --git a/circuit-benchmarks/Cargo.toml b/circuit-benchmarks/Cargo.toml index 3611b4175f..2bbf8b6f88 100644 --- a/circuit-benchmarks/Cargo.toml +++ b/circuit-benchmarks/Cargo.toml @@ -17,7 +17,7 @@ rand = "0.8" itertools = "0.10" eth-types = { path = "../eth-types" } env_logger = "0.9" -ethers-signers = "2.0.0" +ethers-signers = "=2.0.0" mock = { path = "../mock" } rand_chacha = "0.3" snark-verifier = { git = "https://github.com/privacy-scaling-explorations/snark-verifier", tag = "v2022_12_23", default-features = false, features = [ @@ -26,7 +26,7 @@ snark-verifier = { git = "https://github.com/privacy-scaling-explorations/snark- "system_halo2", ] } clap = { version = "4.0", features = ["derive"] } -ethers-providers = "2.0.0" +ethers-providers = "=2.0.0" tokio = { version = "1.22", features = ["full"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/circuit-benchmarks/examples/pi_circuit_integration.rs b/circuit-benchmarks/examples/pi_circuit_integration.rs index a88e9e8a16..01ca5b1388 100644 --- a/circuit-benchmarks/examples/pi_circuit_integration.rs +++ b/circuit-benchmarks/examples/pi_circuit_integration.rs @@ -1,6 +1,6 @@ //! PI circuit benchmarks use ark_std::{end_timer, start_timer}; -use eth_types::{Bytes, U256}; +use eth_types::{Bytes, H256, U256}; use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}; use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG}; use halo2_proofs::{ @@ -41,11 +41,7 @@ mod test { const MAX_CALLDATA: usize = 65536 * 16; let public_data = generate_publicdata::(); - let circuit = PiTestCircuit::(PiCircuit::::new( - MAX_TXS, - MAX_CALLDATA, - randomness, - )); + let circuit = PiTestCircuit::(PiCircuit::::new(public_data)); let public_inputs = circuit.0.instance(); let instance: Vec<&[Fr]> = public_inputs.iter().map(|input| &input[..]).collect(); let instances = &[&instance[..]][..]; @@ -186,11 +182,7 @@ mod test { fn new_pi_circuit( ) -> PiTestCircuit { let public_data = generate_publicdata::(); - let circuit = PiTestCircuit::(PiCircuit::::new( - MAX_TXS, - MAX_CALLDATA, - randomness, - )); + let circuit = PiTestCircuit::(PiCircuit::::new(public_data)); circuit } } @@ -255,9 +247,7 @@ trait InstancesExport { fn instances(&self) -> Vec>; } -impl InstancesExport - for PiTestCircuit -{ +impl InstancesExport for PiTestCircuit { fn num_instance() -> Vec { vec![2] } @@ -305,12 +295,11 @@ fn evm_verify(deployment_code: Vec, instances: Vec>, proof: Vec) 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 deploy = evm.deploy(caller, deployment_code.into(), 0.into()); + println!("deploy exit reason: {:?}", deploy.exit_reason); + let verifier = deploy.address.unwrap(); + let result = evm.call_raw(caller, verifier, calldata.into(), 0.into()); dbg!(result.gas_used); @@ -412,13 +401,12 @@ fn load_circuit_pk>( } use bus_mapping::circuit_input_builder::{BuilderClient, CircuitsParams}; -use bus_mapping::public_input_builder::get_txs_rlp; use bus_mapping::rpc::GethClient; use bus_mapping::Error; use clap::Parser; use serde::{Deserialize, Serialize}; use std::str::FromStr; -use zkevm_circuits::evm_circuit::witness::block_convert; +use zkevm_circuits::evm_circuit::witness::{block_convert, Taiko}; use zkevm_circuits::tx_circuit::PrimeField; #[cfg(feature = "http_provider")] @@ -429,22 +417,73 @@ use ethers_providers::Ws; #[derive(Parser, Debug)] #[clap(version, about)] pub(crate) struct ProverCmdConfig { - /// l1_geth_url - l1_geth_url: Option, - /// propose tx hash - propose_tx_hash: Option, /// l2_geth_url l2_geth_url: Option, /// block_num block_num: Option, /// prover address - address: Option, + prover: Option, + + /// l1 signal service address + l1_signal_service: Option, + /// l2 signal service address + l2_signal_service: Option, + /// l2 contract address + l2_contract: Option, + block_hash: Option, + parent_hash: Option, + /// meta hash + meta_hash: Option, + /// signal root + signal_root: Option, + /// extra message + graffiti: Option, + gas_used: Option, + /// parent gas used + parent_gas_used: Option, + /// block max gas limit + block_max_gas_limit: Option, + /// max bytes per tx list + max_bytes_per_tx_list: Option, + /// max transactions per block + max_transactions_per_block: Option, /// generate yul yul_output: Option, /// output_file output: Option, } +impl ProverCmdConfig { + fn as_taiko_witness(&self) -> Taiko { + Taiko { + l1_signal_service: parse_address(&self.l1_signal_service), + l2_signal_service: parse_address(&self.l2_signal_service), + l2_contract: parse_address(&self.l2_contract), + meta_hash: parse_hash(&self.meta_hash), + block_hash: parse_hash(&self.block_hash), + parent_hash: parse_hash(&self.parent_hash), + signal_root: parse_hash(&self.signal_root), + graffiti: parse_hash(&self.graffiti), + prover: parse_address(&self.prover), + parent_gas_used: self.parent_gas_used.unwrap(), + gas_used: self.gas_used.unwrap(), + block_max_gas_limit: self.block_max_gas_limit.unwrap(), + max_bytes_per_tx_list: self.max_bytes_per_tx_list.unwrap(), + max_transactions_per_block: self.max_transactions_per_block.unwrap(), + } + } +} + +fn parse_hash(input: &Option) -> H256 { + H256::from_slice(&hex::decode(input.as_ref().unwrap().as_bytes()).expect("parse_hash")) +} + +fn parse_address(input: &Option) -> Address { + eth_types::Address::from_slice( + &hex::decode(input.as_ref().unwrap().as_bytes()).expect("parse_address"), + ) +} + #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct CircuitConfig { pub block_gas_limit: usize, @@ -507,24 +546,9 @@ async fn main() -> Result<(), Error> { let config = ProverCmdConfig::parse(); let block_num = config.block_num.map_or_else(|| 1, |n| n); - let prover = eth_types::Address::from_slice( - &hex::decode(config.address.expect("needs prover").as_bytes()).expect("parse_address"), - ); #[cfg(feature = "http_provider")] - let l1_provider = Http::from_str(&config.l1_geth_url.unwrap()).expect("Http geth url"); - #[cfg(not(feature = "http_provider"))] - let l1_provider = Ws::connect(&config.l1_geth_url.unwrap()) - .await - .expect("l1 ws rpc connected"); - let l1_geth_client = GethClient::new(l1_provider); - let propose_tx_hash = eth_types::H256::from_slice( - &hex::decode(config.propose_tx_hash.unwrap().as_bytes()).expect("parse_hash"), - ); - let txs_rlp = get_txs_rlp(&l1_geth_client, propose_tx_hash).await?; - - #[cfg(feature = "http_provider")] - let l2_provider = Http::from_str(&config.l2_geth_url.unwrap()).expect("Http geth url"); + let l2_provider = Http::from_str(config.l2_geth_url.as_ref().unwrap()).expect("Http geth url"); #[cfg(not(feature = "http_provider"))] let l2_provider = Ws::connect(&config.l2_geth_url.unwrap()) .await @@ -550,19 +574,13 @@ async fn main() -> Result<(), Error> { let builder = BuilderClient::new(l2_geth_client, circuit_params.clone()).await?; let (builder, _) = builder.gen_inputs(block_num).await?; let block = block_convert(&builder.block, &builder.code_db).unwrap(); + let taiko = config.as_taiko_witness(); select_circuit_config!( txs, { - let public_data = PublicData::new(&block, prover, txs_rlp); + let public_data = PublicData::new(&block, &taiko); log::info!("using CIRCUIT_CONFIG = {:?}", CIRCUIT_CONFIG); - let circuit = - PiTestCircuit::( - PiCircuit::new( - CIRCUIT_CONFIG.max_txs, - CIRCUIT_CONFIG.max_calldata, - public_data, - ), - ); + let circuit = PiTestCircuit::(PiCircuit::new(public_data)); assert!(block.txs.len() <= CIRCUIT_CONFIG.max_txs); let params = get_circuit_params::<0>(CIRCUIT_CONFIG.min_k as usize); @@ -579,15 +597,11 @@ async fn main() -> Result<(), Error> { let deployment_code = if config.yul_output.is_some() { gen_evm_verifier( - ¶ms, - pk.get_vk(), - PiTestCircuit::< - Fr, - { CIRCUIT_CONFIG.max_txs }, - { CIRCUIT_CONFIG.max_calldata }, - >::num_instance(), - config.yul_output - ) + ¶ms, + pk.get_vk(), + PiTestCircuit::::num_instance(), + config.yul_output, + ) } else { vec![] }; @@ -619,8 +633,7 @@ async fn main() -> Result<(), Error> { let output_file = if let Some(output) = config.output { output } else { - let l1_tx_hash = propose_tx_hash.to_string(); - format!("./block-{}_proof-new.json", &l1_tx_hash) + format!("./block-{}_proof-new.json", config.block_num.unwrap()) }; File::create(output_file) .expect("open output_file") diff --git a/circuit-benchmarks/examples/super_circuit_integration.rs b/circuit-benchmarks/examples/super_circuit_integration.rs index 520184eb74..eb41454765 100644 --- a/circuit-benchmarks/examples/super_circuit_integration.rs +++ b/circuit-benchmarks/examples/super_circuit_integration.rs @@ -70,7 +70,7 @@ fn bench_super_circuit_prover() { block.sign(&wallets); - type TestSuperCircuit = SuperCircuit::; + type TestSuperCircuit = SuperCircuit; let (_, circuit, instance, _) = TestSuperCircuit::build(block).unwrap(); let instance_refs: Vec<&[Fr]> = instance.iter().map(|v| &v[..]).collect(); diff --git a/eth-types/Cargo.toml b/eth-types/Cargo.toml index ae6f02febd..29aeb54380 100644 --- a/eth-types/Cargo.toml +++ b/eth-types/Cargo.toml @@ -6,8 +6,8 @@ authors = ["The appliedzkp team"] license = "MIT OR Apache-2.0" [dependencies] -ethers-core = "2.0.0" -ethers-signers = "2.0.0" +ethers-core = "=2.0.0" +ethers-signers = "=2.0.0" hex = "0.4" lazy_static = "1.4" halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2022_10_22" } diff --git a/integration-tests/Cargo.toml b/integration-tests/Cargo.toml index 48f6b0b77d..a7dd192ac5 100644 --- a/integration-tests/Cargo.toml +++ b/integration-tests/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] lazy_static = "1.4" -ethers = { version = "2.0.0", features = ["ethers-solc"] } +ethers = { version = "=2.0.0", features = ["ethers-solc"] } serde_json = "1.0.66" serde = { version = "1.0.130", features = ["derive"] } bus-mapping = { path = "../bus-mapping" } diff --git a/mock/Cargo.toml b/mock/Cargo.toml index f621f3a46d..b8396f703e 100644 --- a/mock/Cargo.toml +++ b/mock/Cargo.toml @@ -10,7 +10,7 @@ eth-types = { path = "../eth-types" } external-tracer = { path = "../external-tracer" } lazy_static = "1.4" itertools = "0.10.3" -ethers-signers = "2.0.0" -ethers-core = "2.0.0" +ethers-signers = "=2.0.0" +ethers-core = "=2.0.0" rand_chacha = "0.3" rand = "0.8" diff --git a/rust-toolchain b/rust-toolchain index 24b6d11f20..bf867e0ae5 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2022-08-23 +nightly diff --git a/testool/Cargo.toml b/testool/Cargo.toml index 1ed3076ea9..06245aef0d 100644 --- a/testool/Cargo.toml +++ b/testool/Cargo.toml @@ -10,8 +10,8 @@ bus-mapping = { path = "../bus-mapping" } clap = { version = "3.1", features = ["derive"] } env_logger = "0.9" eth-types = { path = "../eth-types" } -ethers-core = "2.0.0" -ethers-signers = "2.0.0" +ethers-core = "=2.0.0" +ethers-signers = "=2.0.0" external-tracer = { path = "../external-tracer" } glob = "0.3" handlebars = "4.3" diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index 8338f19202..a1f1511701 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -15,8 +15,8 @@ array-init = "2.0.0" bus-mapping = { path = "../bus-mapping" } eth-types = { path = "../eth-types" } gadgets = { path = "../gadgets" } -ethers-core = "2.0.0" -ethers-signers = { version = "2.0.0", optional = true } +ethers-core = "=2.0.0" +ethers-signers = { version = "=2.0.0", optional = true } mock = { path = "../mock", optional = true } strum = "0.24" strum_macros = "0.24" @@ -25,6 +25,7 @@ rand = "0.8" itertools = "0.10.3" lazy_static = "1.4" keccak256 = { path = "../keccak256" } +geth-utils = { path = "../geth-utils" } log = "0.4" env_logger = "0.9" ecdsa = { git = "https://github.com/privacy-scaling-explorations/halo2wrong", tag = "v2022_10_22" } @@ -48,7 +49,7 @@ hex = "0.4.3" bus-mapping = { path = "../bus-mapping", features = ["test"] } criterion = "0.3" ctor = "0.1.22" -ethers-signers = "2.0.0" +ethers-signers = "=2.0.0" hex = "0.4.3" itertools = "0.10.1" mock = { path = "../mock" } diff --git a/zkevm-circuits/src/pi_circuit2.rs b/zkevm-circuits/src/pi_circuit2.rs index a389be4085..fac698f14b 100644 --- a/zkevm-circuits/src/pi_circuit2.rs +++ b/zkevm-circuits/src/pi_circuit2.rs @@ -1,59 +1,27 @@ //! Use the hash value as public input. -//! -//! We will use three lookup tables to implement the circuit. -//! 1. rlp_table: txs -> rlp -//! 2. compress_table: rlp -> compress -//! 3. hash_table: compress -> hash -//! -//! The dataflow: -//! ``` -//! +----------+ +-----------+ +------------+ -//! | txs +---------> compress? +-------> hash | -//! | | | | | | -//! +----------+ +-----------+ +------------+ -//! ``` use crate::evm_circuit::util::constraint_builder::BaseConstraintBuilder; -use eth_types::{geth_types::BlockConstants, H256}; -use eth_types::{ - geth_types::Transaction, Address, BigEndianHash, Field, ToBigEndian, ToLittleEndian, ToScalar, - Word, -}; -use eth_types::{sign_types::SignData, Bytes}; -use ethers_core::utils::keccak256; -use halo2_proofs::plonk::{Expression, Instance}; -use itertools::Itertools; -use rlp::{Rlp, RlpStream}; -use std::marker::PhantomData; - -use crate::table::TxFieldTag; -use crate::table::TxTable; -use crate::table::{BlockTable, KeccakTable2}; +use crate::table::{BlockTable, KeccakTable}; use crate::util::{random_linear_combine_word as rlc, Challenges, SubCircuit, SubCircuitConfig}; use crate::witness; -use gadgets::is_zero::IsZeroChip; -use gadgets::util::{not, or, Expr}; +use eth_types::ToWord; +use eth_types::{geth_types::BlockConstants, H256}; +use eth_types::{Address, Field, ToBigEndian, ToLittleEndian, ToScalar, Word}; +use ethers_core::utils::keccak256; +use gadgets::util::{or, select, Expr}; +use halo2_proofs::plonk::{Expression, Fixed, Instance, SecondPhase}; use halo2_proofs::{ circuit::{AssignedCell, Layouter, Region, SimpleFloorPlanner, Value}, - plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Fixed, Selector}, + plonk::{Advice, Circuit, Column, ConstraintSystem, Error, Selector}, poly::Rotation, }; -use lazy_static::lazy_static; - -/// Fixed by the spec -const TX_LEN: usize = 10; -const BLOCK_LEN: usize = 7 + 256; -const EXTRA_LEN: usize = 2; -const ZERO_BYTE_GAS_COST: u64 = 4; -const NONZERO_BYTE_GAS_COST: u64 = 16; +use std::marker::PhantomData; + const MAX_DEGREE: usize = 10; +const RPI_CELL_IDX: usize = 0; +const RPI_RLC_ACC_CELL_IDX: usize = 1; const BYTE_POW_BASE: u64 = 1 << 8; - -lazy_static! { - static ref OMMERS_HASH: H256 = H256::from_slice( - &hex::decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347").unwrap() - ); -} +const RPI_BYTES_LEN: usize = 32 * 10; /// Values of the block table (as in the spec) #[derive(Clone, Default, Debug)] @@ -65,162 +33,137 @@ pub struct BlockValues { difficulty: Word, base_fee: Word, // NOTE: BaseFee was added by EIP-1559 and is ignored in legacy headers. chain_id: u64, - history_hashes: Vec, -} - -/// Values of the tx table (as in the spec) -#[derive(Default, Debug, Clone)] -pub struct TxValues { - nonce: Word, - gas: Word, //gas limit - gas_price: Word, - from_addr: Address, - to_addr: Address, - is_create: u64, - value: Word, - call_data_len: u64, - call_data_gas_cost: u64, - tx_sign_hash: [u8; 32], -} - -/// Extra values (not contained in block or tx tables) -#[derive(Default, Debug, Clone)] -pub struct ExtraValues { - // block_hash: H256, - state_root: H256, - prev_state_root: H256, + block_hash: Word, } /// PublicData contains all the values that the PiCircuit recieves as input #[derive(Debug, Clone, Default)] -pub struct PublicData { - /// chain id - pub chain_id: Word, - /// History hashes contains the most recent 256 block hashes in history, - /// where the latest one is at history_hashes[history_hashes.len() - 1]. - pub history_hashes: Vec, - /// Block Transactions - pub transactions: Vec, - /// Block State Root - pub state_root: H256, - /// Previous block root - pub prev_state_root: H256, - /// Constants related to Ethereum block - pub block_constants: BlockConstants, - - /// Prover address - pub prover: Address, - - // private values - block_rlp: Bytes, - block_hash: H256, - block_hash_hi: F, - block_hash_lo: F, - - txs_rlp: Bytes, - txs_hash: H256, - txs_hash_hi: F, - txs_hash_lo: F, +pub struct PublicData { + /// l1 signal service address + pub l1_signal_service: Word, + /// l2 signal service address + pub l2_signal_service: Word, + /// l2 contract address + pub l2_contract: Word, + /// meta hash + pub meta_hash: Word, + /// block hash value + pub block_hash: Word, + /// the parent block hash + pub parent_hash: Word, + /// signal root + pub signal_root: Word, + /// extra message + pub graffiti: Word, + /// union field + pub field9: Word, // prover[96:256]+parentGasUsed[64:96]+gasUsed[32:64] + /// union field + pub field10: Word, /* blockMaxGasLimit[192:256]+maxTransactionsPerBlock[128: + * 192]+maxBytesPerTxList[64:128] */ + + // privates + // Prover address + prover: Address, + // parent block gas used + parent_gas_used: u32, + // block gas used + gas_used: u32, + // blockMaxGasLimit + block_max_gas_limit: u64, + // maxTransactionsPerBlock: u64, + max_transactions_per_block: u64, + // maxBytesPerTxList: u64, + max_bytes_per_tx_list: u64, + + block_constants: BlockConstants, + chain_id: Word, } -pub(super) fn rlp_opt(rlp: &mut rlp::RlpStream, opt: &Option) { - if let Some(inner) = opt { - rlp.append(inner); - } else { - rlp.append(&""); - } +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum FieldType { + None, + BlockHash, } -impl PublicData { - fn get_block_rlp_rlc(&self, challenges: &Challenges>) -> Value { - use crate::evm_circuit::util::rlc; - let randomness = challenges.keccak_input(); - randomness.map(|randomness| rlc::value(self.block_rlp.iter().rev(), randomness)) - } - - fn get_txs_rlp_rlc(&self, challenges: &Challenges>) -> Value { - use crate::evm_circuit::util::rlc; - let randomness = challenges.keccak_input(); - randomness.map(|randomness| rlc::value(self.txs_rlp.iter().rev(), randomness)) - } - - fn split_hash(hash: [u8; 32]) -> (F, F) { - let hi = hash.iter().take(16).fold(F::zero(), |acc, byte| { - acc * F::from(BYTE_POW_BASE) + F::from(*byte as u64) - }); - - let lo = hash.iter().skip(16).fold(F::zero(), |acc, byte| { - acc * F::from(BYTE_POW_BASE) + F::from(*byte as u64) - }); - (hi, lo) +impl PublicData { + fn assignments(&self) -> [(&'static str, FieldType, [u8; 32]); 10] { + use FieldType::*; + [ + ( + "l1_signal_service", + None, + self.l1_signal_service.to_be_bytes(), + ), + ( + "l2_signal_service", + None, + self.l2_signal_service.to_be_bytes(), + ), + ("l2_contract", None, self.l2_contract.to_be_bytes()), + ("meta_hash", None, self.meta_hash.to_be_bytes()), + ("parent_hash", None, self.parent_hash.to_be_bytes()), + ("block_hash", BlockHash, self.block_hash.to_be_bytes()), + ("signal_root", None, self.signal_root.to_be_bytes()), + ("graffiti", None, self.graffiti.to_be_bytes()), + ( + "prover+parentGasUsed+gasUsed", + None, + self.field9.to_be_bytes(), + ), + ( + "blockMaxGasLimit+maxTransactionsPerBlock+maxBytesPerTxList", + None, + self.field10.to_be_bytes(), + ), + ] } - fn get_txs_hash(txs_rlp: &Bytes) -> (H256, F, F) { - let hash = keccak256(&txs_rlp); - let (hi, lo) = Self::split_hash(hash); - (hash.into(), hi, lo) + fn rpi_bytes(&self) -> Vec { + self.assignments().iter().flat_map(|v| v.2).collect() } - fn get_block_hash( - block: &witness::Block, - prover: Address, - txs_hash: H256, - ) -> (Bytes, H256, F, F) { - let mut stream = RlpStream::new(); - stream.begin_unbounded_list(); - stream - .append(&block.eth_block.parent_hash) - .append(&*OMMERS_HASH); - rlp_opt(&mut stream, &block.eth_block.author); - stream - .append(&block.eth_block.state_root) - .append(&block.eth_block.transactions_root) - .append(&block.eth_block.receipts_root); - rlp_opt(&mut stream, &block.eth_block.logs_bloom); - stream.append(&block.eth_block.difficulty); - rlp_opt(&mut stream, &block.eth_block.number); - stream - .append(&block.eth_block.gas_limit) - .append(&block.eth_block.gas_used) - .append(&block.eth_block.timestamp) - .append(&block.eth_block.extra_data.as_ref()); - rlp_opt(&mut stream, &block.eth_block.mix_hash); - rlp_opt(&mut stream, &block.eth_block.nonce); - // rlp_opt(&mut stream, &block.eth_block.base_fee_per_gas); - stream.append(&prover).append(&txs_hash); - stream.finalize_unbounded_list(); - let out: bytes::Bytes = stream.out().into(); - let rlp = out.into(); - let hash = keccak256(&rlp); - // append prover and txs_hash - let (hi, lo) = Self::split_hash(hash); - (rlp, hash.into(), hi, lo) + fn default() -> Self { + Self::new::(&witness::Block::default(), &witness::Taiko::default()) } - fn decode_txs_rlp(txs_rlp: &Bytes) -> Vec { - Rlp::new(txs_rlp).as_list().expect("invalid txs rlp") - } + /// create PublicData from block and taiko + pub fn new(block: &witness::Block, taiko: &witness::Taiko) -> Self { + // left shift x by n bits + fn left_shift(x: T, n: u32) -> Word { + assert!(n < 256); + if n < 128 { + return x.to_word() * Word::from(2u128.pow(n)); + } + let mut bits = [0; 32]; + bits[..16].copy_from_slice(2u128.pow(n - 128).to_be_bytes().as_ref()); + bits[16..].copy_from_slice(0u128.to_be_bytes().as_ref()); + x.to_word() * Word::from(&bits[..]) + } - fn default() -> Self { - Self::new( - &witness::Block::default(), - Address::default(), - Bytes::default(), - ) - } + let field9 = left_shift(taiko.prover, 96) + + left_shift(taiko.parent_gas_used as u64, 64) + + left_shift(taiko.gas_used as u64, 32); - /// create PublicData from block and prover - pub fn new(block: &witness::Block, prover: Address, txs_rlp: Bytes) -> Self { - let txs = Self::decode_txs_rlp(&txs_rlp); - let (txs_hash, txs_hash_hi, txs_hash_lo) = Self::get_txs_hash(&txs_rlp); - let (block_rlp, block_hash, block_hash_hi, block_hash_lo) = - Self::get_block_hash(block, prover, txs_hash); + let field10 = left_shift(taiko.block_max_gas_limit, 192) + + left_shift(taiko.max_transactions_per_block, 128) + + left_shift(taiko.max_bytes_per_tx_list, 64); PublicData { - chain_id: block.context.chain_id, - history_hashes: block.context.history_hashes.clone(), - transactions: txs, - state_root: block.eth_block.state_root, - prev_state_root: H256::from_uint(&block.prev_state_root), + l1_signal_service: taiko.l1_signal_service.to_word(), + l2_signal_service: taiko.l2_signal_service.to_word(), + l2_contract: taiko.l2_contract.to_word(), + meta_hash: taiko.meta_hash.to_word(), + block_hash: taiko.block_hash.to_word(), + parent_hash: taiko.parent_hash.to_word(), + signal_root: taiko.signal_root.to_word(), + graffiti: taiko.graffiti.to_word(), + prover: taiko.prover, + parent_gas_used: taiko.parent_gas_used, + gas_used: taiko.gas_used, + block_max_gas_limit: taiko.block_max_gas_limit, + max_transactions_per_block: taiko.max_transactions_per_block, + max_bytes_per_tx_list: taiko.max_bytes_per_tx_list, + field9, + field10, block_constants: BlockConstants { coinbase: block.context.coinbase, timestamp: block.context.timestamp, @@ -229,28 +172,18 @@ impl PublicData { gas_limit: block.context.gas_limit.into(), base_fee: block.context.base_fee, }, - block_rlp, - block_hash, - block_hash_hi, - block_hash_lo, - txs_rlp, - txs_hash, - txs_hash_hi, - txs_hash_lo, - prover, + chain_id: block.context.chain_id, } } + fn get_pi(&self) -> H256 { + let rpi_bytes = self.rpi_bytes(); + let rpi_keccak = keccak256(rpi_bytes); + H256(rpi_keccak) + } + /// Returns struct with values for the block table pub fn get_block_table_values(&self) -> BlockValues { - let history_hashes = [ - vec![H256::zero(); 256 - self.history_hashes.len()], - self.history_hashes - .iter() - .map(|&hash| H256::from(hash.to_be_bytes())) - .collect(), - ] - .concat(); BlockValues { coinbase: self.block_constants.coinbase, gas_limit: self.block_constants.gas_limit.as_u64(), @@ -259,116 +192,44 @@ impl PublicData { difficulty: self.block_constants.difficulty, base_fee: self.block_constants.base_fee, chain_id: self.chain_id.as_u64(), - history_hashes, - } - } - - /// Returns struct with values for the tx table - pub fn get_tx_table_values(&self) -> Vec { - let chain_id: u64 = self - .chain_id - .try_into() - .expect("Error converting chain_id to u64"); - let mut tx_vals = vec![]; - for tx in &self.txs() { - let sign_data: SignData = tx - .sign_data(chain_id) - .expect("Error computing tx_sign_hash"); - let mut msg_hash_le = [0u8; 32]; - msg_hash_le.copy_from_slice(sign_data.msg_hash.to_bytes().as_slice()); - tx_vals.push(TxValues { - nonce: tx.nonce, - gas_price: tx.gas_price, - gas: tx.gas_limit, - from_addr: tx.from, - to_addr: tx.to.unwrap_or_else(Address::zero), - is_create: (tx.to.is_none() as u64), - value: tx.value, - call_data_len: tx.call_data.0.len() as u64, - call_data_gas_cost: tx.call_data.0.iter().fold(0, |acc, byte| { - acc + if *byte == 0 { - ZERO_BYTE_GAS_COST - } else { - NONZERO_BYTE_GAS_COST - } - }), - tx_sign_hash: msg_hash_le, - }); - } - tx_vals - } - - /// Returns struct with the extra values - pub fn get_extra_values(&self) -> ExtraValues { - ExtraValues { - // block_hash: self.hash.unwrap_or_else(H256::zero), - state_root: self.state_root, - prev_state_root: self.prev_state_root, + block_hash: self.block_hash, } } - - fn txs(&self) -> Vec { - self.transactions.iter().map(Transaction::from).collect() - } } /// Config for PiCircuit #[derive(Clone, Debug)] pub struct PiCircuitConfig { - /// Max number of supported transactions - max_txs: usize, - /// Max number of supported calldata bytes - max_calldata: usize, + rpi_field_bytes: Column, + rpi_field_bytes_acc: Column, + rpi_rlc_acc: Column, + q_field_start: Selector, + q_field_step: Selector, + q_field_end: Selector, + is_field_rlc: Column, - rpi: Column, - rpi_rlc_acc: Column, // rlp input q_start: Selector, q_not_end: Selector, - rpi_encoding: Column, // rlc_acc, rlp_rlc, rlp_len, hash_hi, hash_lo - q_rpi_encoding: Selector, + is_byte: Column, pi: Column, // keccak_hi, keccak_lo - // rlp_table - // rlc(txlist) -> rlc(rlp(txlist)) - rlp_table: [Column; 3], // [input, len, output] - // keccak_table - // rlc(compressed) -> rlc(keccak(compressed) - keccak_table: KeccakTable2, + + q_keccak: Selector, + keccak_table: KeccakTable, // External tables - q_block_table: Selector, block_table: BlockTable, - // tx table - q_tx_table: Selector, - tx_table: TxTable, // txlist hash, pi hash - q_tx_calldata: Selector, - q_calldata_start: Selector, - tx_id_inv: Column, - tx_value_inv: Column, - tx_id_diff_inv: Column, - fixed_u16: Column, - calldata_gas_cost: Column, - is_final: Column, - _marker: PhantomData, } /// Circuit configuration arguments pub struct PiCircuitConfigArgs { - /// Max number of supported transactions - pub max_txs: usize, - /// Max number of supported calldata bytes - pub max_calldata: usize, - /// TxTable - pub tx_table: TxTable, /// BlockTable pub block_table: BlockTable, - /// RlpTable - pub rlp_table: [Column; 3], /// KeccakTable - pub keccak_table: KeccakTable2, + pub keccak_table: KeccakTable, /// Challenges pub challenges: Challenges>, } @@ -380,1087 +241,338 @@ impl SubCircuitConfig for PiCircuitConfig { fn new( meta: &mut ConstraintSystem, Self::ConfigArgs { - max_txs, - max_calldata, block_table, - tx_table, - rlp_table, keccak_table, challenges, }: Self::ConfigArgs, ) -> Self { - let q_block_table = meta.selector(); - let q_tx_table = meta.complex_selector(); - let q_tx_calldata = meta.complex_selector(); - let q_calldata_start = meta.complex_selector(); - - let rpi = meta.advice_column(); - let rpi_rlc_acc = meta.advice_column(); - let rpi_encoding = meta.advice_column(); - let q_rpi_encoding = meta.complex_selector(); + let rpi_field_bytes = meta.advice_column(); + let rpi_field_bytes_acc = meta.advice_column_in(SecondPhase); + let rpi_rlc_acc = meta.advice_column_in(SecondPhase); + let q_field_start = meta.complex_selector(); + let q_field_step = meta.complex_selector(); + let q_field_end = meta.complex_selector(); let q_start = meta.complex_selector(); let q_not_end = meta.complex_selector(); - - // Tx Table - let tx_id = tx_table.tx_id; - let tx_value = tx_table.value; - let tag = tx_table.tag; - let index = tx_table.index; - let tx_id_inv = meta.advice_column(); - let tx_value_inv = meta.advice_column(); - let tx_id_diff_inv = meta.advice_column(); - // The difference of tx_id of adjacent rows in calldata part of tx table - // lies in the interval [0, 2^16] if their tx_id both do not equal to zero. - // We do not use 2^8 for the reason that a large block may have more than - // 2^8 transfer transactions which have 21000*2^8 (~ 5.376M) gas. - let fixed_u16 = meta.fixed_column(); - let calldata_gas_cost = meta.advice_column(); - let is_final = meta.advice_column(); + let is_byte = meta.fixed_column(); + let is_field_rlc = meta.fixed_column(); let pi = meta.instance_column(); - meta.enable_equality(rpi); + let q_keccak = meta.complex_selector(); + + meta.enable_equality(rpi_field_bytes); + meta.enable_equality(rpi_field_bytes_acc); meta.enable_equality(rpi_rlc_acc); - meta.enable_equality(rpi_encoding); + meta.enable_equality(block_table.value); meta.enable_equality(pi); - // rlc_acc - meta.create_gate("rpi_rlc_acc_next = rpi_rlc_acc * r + rpi_next", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let q_not_end = meta.query_selector(q_not_end); - let rpi_rlc_acc_next = meta.query_advice(rpi_rlc_acc, Rotation::next()); - let rpi_rlc_acc = meta.query_advice(rpi_rlc_acc, Rotation::cur()); - let rpi_next = meta.query_advice(rpi, Rotation::next()); - let r = challenges.evm_word(); - - cb.require_equal("left=right", rpi_rlc_acc_next, rpi_rlc_acc * r + rpi_next); - cb.gate(q_not_end) - }); - - meta.create_gate("rpi_rlc_acc[0] = rpi[0]", |meta| { - let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - let q_start = meta.query_selector(q_start); - let rpi_rlc_acc = meta.query_advice(rpi_rlc_acc, Rotation::cur()); - let rpi = meta.query_advice(rpi, Rotation::cur()); - - cb.require_equal("", rpi_rlc_acc, rpi); - - cb.gate(q_start) - }); - - meta.lookup_any("lookup rlp", |meta| { - let q_rpi_encoding = meta.query_selector(q_rpi_encoding); - - let rpi_rlc_acc = meta.query_advice(rpi_encoding, Rotation(0)); - let rpi_rlp_rlc = meta.query_advice(rpi_encoding, Rotation(1)); - let rpi_rlp_len = meta.query_advice(rpi_encoding, Rotation(2)); - vec![ - ( - q_rpi_encoding.expr() * rpi_rlc_acc, - meta.query_advice(rlp_table[0], Rotation::cur()), - ), - ( - q_rpi_encoding.expr() * rpi_rlp_rlc, - meta.query_advice(rlp_table[1], Rotation::cur()), - ), - ( - q_rpi_encoding * rpi_rlp_len, - meta.query_advice(rlp_table[2], Rotation::cur()), - ), - ] - }); - - meta.lookup_any("lookup keccak", |meta| { - let q_rpi_encoding = meta.query_selector(q_rpi_encoding); - - let rpi_rlp_rlc = meta.query_advice(rpi_encoding, Rotation(1)); - let rpi_rlp_len = meta.query_advice(rpi_encoding, Rotation(2)); - let rpi_hash_hi = meta.query_advice(rpi_encoding, Rotation(3)); - let rpi_hash_lo = meta.query_advice(rpi_encoding, Rotation(4)); - vec![ - ( - q_rpi_encoding.expr(), - meta.query_advice(keccak_table.is_enabled, Rotation::cur()), - ), - ( - q_rpi_encoding.expr() * rpi_rlp_rlc, - meta.query_advice(keccak_table.input_rlc, Rotation::cur()), - ), - ( - q_rpi_encoding.expr() * rpi_rlp_len, - meta.query_advice(keccak_table.input_len, Rotation::cur()), - ), - ( - q_rpi_encoding.expr() * rpi_hash_hi, - meta.query_advice(keccak_table.output_hi, Rotation::cur()), - ), - ( - q_rpi_encoding * rpi_hash_lo, - meta.query_advice(keccak_table.output_lo, Rotation::cur()), - ), - ] - }); - - // 0.2 Block table -> value column match with raw_public_inputs at expected - // offset - meta.create_gate("block_table[i] = block[i]", |meta| { - let q_block_table = meta.query_selector(q_block_table); - let block_value = meta.query_advice(block_table.value, Rotation::cur()); - let rpi_block_value = meta.query_advice(rpi, Rotation::cur()); - vec![q_block_table * (block_value - rpi_block_value)] - }); - - let offset = BLOCK_LEN + 1 + EXTRA_LEN + 3; - let tx_table_len = max_txs * TX_LEN + 1; - - // 0.3 Tx table -> {tx_id, index, value} column match with raw_public_inputs - // at expected offset - meta.create_gate("tx_table.tx_id[i] == rpi[i]", |meta| { - // row.q_tx_table * row.tx_table.tx_id - // == row.q_tx_table * row_offset_tx_table_tx_id.raw_public_inputs - let q_tx_table = meta.query_selector(q_tx_table); - let tx_id = meta.query_advice(tx_table.tx_id, Rotation::cur()); - let rpi_tx_id = meta.query_advice(rpi, Rotation(offset as i32)); - - vec![q_tx_table * (tx_id - rpi_tx_id)] - }); - - meta.create_gate("tx_table.index[i] == rpi[tx_table_len + i]", |meta| { - // row.q_tx_table * row.tx_table.tx_index - // == row.q_tx_table * row_offset_tx_table_tx_index.raw_public_inputs - let q_tx_table = meta.query_selector(q_tx_table); - let tx_index = meta.query_advice(tx_table.index, Rotation::cur()); - let rpi_tx_index = meta.query_advice(rpi, Rotation((offset + tx_table_len) as i32)); - - vec![q_tx_table * (tx_index - rpi_tx_index)] - }); - - meta.create_gate("tx_table.tx_value[i] == rpi[2* tx_table_len + i]", |meta| { - // (row.q_tx_calldata | row.q_tx_table) * row.tx_table.tx_value - // == (row.q_tx_calldata | row.q_tx_table) * - // row_offset_tx_table_tx_value.raw_public_inputs - let q_tx_table = meta.query_selector(q_tx_table); - let tx_value = meta.query_advice(tx_value, Rotation::cur()); - let q_tx_calldata = meta.query_selector(q_tx_calldata); - let rpi_tx_value = meta.query_advice(rpi, Rotation((offset + 2 * tx_table_len) as i32)); - - vec![or::expr([q_tx_table, q_tx_calldata]) * (tx_value - rpi_tx_value)] - }); - - let tx_id_is_zero_config = IsZeroChip::configure( - meta, - |meta| meta.query_selector(q_tx_calldata), - |meta| meta.query_advice(tx_table.tx_id, Rotation::cur()), - tx_id_inv, - ); - let tx_value_is_zero_config = IsZeroChip::configure( - meta, - |meta| { - or::expr([ - meta.query_selector(q_tx_table), - meta.query_selector(q_tx_calldata), - ]) - }, - |meta| meta.query_advice(tx_value, Rotation::cur()), - tx_value_inv, - ); - let _tx_id_diff_is_zero_config = IsZeroChip::configure( - meta, - |meta| meta.query_selector(q_tx_calldata), + // field bytes + meta.create_gate( + "rpi_field_bytes_acc[i+1] = rpi_field_bytes_acc[i] * t + rpi_bytes[i+1]", |meta| { - meta.query_advice(tx_table.tx_id, Rotation::next()) - - meta.query_advice(tx_table.tx_id, Rotation::cur()) + let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); + + let q_field_step = meta.query_selector(q_field_step); + let rpi_field_bytes_acc_next = + meta.query_advice(rpi_field_bytes_acc, Rotation::next()); + let rpi_field_bytes_acc = meta.query_advice(rpi_field_bytes_acc, Rotation::cur()); + let rpi_field_bytes_next = meta.query_advice(rpi_field_bytes, Rotation::next()); + let is_field_rlc = meta.query_fixed(is_field_rlc, Rotation::next()); + let randomness = challenges.evm_word(); + let t = select::expr(is_field_rlc, randomness, BYTE_POW_BASE.expr()); + cb.require_equal( + "rpi_field_bytes_acc[i+1] = rpi_field_bytes_acc[i] * t + rpi_bytes[i+1]", + rpi_field_bytes_acc_next, + rpi_field_bytes_acc * t + rpi_field_bytes_next, + ); + cb.gate(q_field_step) }, - tx_id_diff_inv, ); + meta.create_gate("rpi_field_bytes_acc[0] = rpi_field_bytes[0]", |meta| { + let mut cb = BaseConstraintBuilder::new(MAX_DEGREE); - meta.lookup_any("tx_id_diff", |meta| { - let tx_id_next = meta.query_advice(tx_id, Rotation::next()); - let tx_id = meta.query_advice(tx_id, Rotation::cur()); - let tx_id_inv_next = meta.query_advice(tx_id_inv, Rotation::next()); - let tx_id_diff_inv = meta.query_advice(tx_id_diff_inv, Rotation::cur()); - let fixed_u16_table = meta.query_fixed(fixed_u16, Rotation::cur()); - - let tx_id_next_nonzero = tx_id_next.expr() * tx_id_inv_next; - let tx_id_not_equal_to_next = (tx_id_next.expr() - tx_id.expr()) * tx_id_diff_inv; - let tx_id_diff_minus_one = tx_id_next - tx_id - 1.expr(); - - vec![( - tx_id_diff_minus_one * tx_id_next_nonzero * tx_id_not_equal_to_next, - fixed_u16_table, - )] + let q_field_start = meta.query_selector(q_field_start); + let rpi_field_bytes_acc = meta.query_advice(rpi_field_bytes_acc, Rotation::cur()); + let rpi_field_bytes = meta.query_advice(rpi_field_bytes, Rotation::cur()); + + cb.require_equal( + "rpi_field_bytes_acc[0] = rpi_field_bytes[0]", + rpi_field_bytes_acc, + rpi_field_bytes, + ); + cb.gate(q_field_start) }); - meta.create_gate("calldata constraints", |meta| { - let q_is_calldata = meta.query_selector(q_tx_calldata); - let q_calldata_start = meta.query_selector(q_calldata_start); - let tx_idx = meta.query_advice(tx_id, Rotation::cur()); - let tx_idx_next = meta.query_advice(tx_id, Rotation::next()); - let tx_idx_inv_next = meta.query_advice(tx_id_inv, Rotation::next()); - let tx_idx_diff_inv = meta.query_advice(tx_id_diff_inv, Rotation::cur()); - let idx = meta.query_advice(index, Rotation::cur()); - let idx_next = meta.query_advice(index, Rotation::next()); - let value_next = meta.query_advice(tx_value, Rotation::next()); - let value_next_inv = meta.query_advice(tx_value_inv, Rotation::next()); - - let gas_cost = meta.query_advice(calldata_gas_cost, Rotation::cur()); - let gas_cost_next = meta.query_advice(calldata_gas_cost, Rotation::next()); - let is_final = meta.query_advice(is_final, Rotation::cur()); - - let is_tx_id_nonzero = not::expr(tx_id_is_zero_config.expr()); - let is_tx_id_next_nonzero = tx_idx_next.expr() * tx_idx_inv_next.expr(); - - let is_value_zero = tx_value_is_zero_config.expr(); - let is_value_nonzero = not::expr(tx_value_is_zero_config.expr()); - - let is_value_next_nonzero = value_next.expr() * value_next_inv.expr(); - let is_value_next_zero = not::expr(is_value_next_nonzero.expr()); - - // gas = value == 0 ? 4 : 16 - let gas = ZERO_BYTE_GAS_COST.expr() * is_value_zero.expr() - + NONZERO_BYTE_GAS_COST.expr() * is_value_nonzero.expr(); - let gas_next = ZERO_BYTE_GAS_COST.expr() * is_value_next_zero - + NONZERO_BYTE_GAS_COST.expr() * is_value_next_nonzero; - - // if tx_id == 0 then idx == 0, tx_id_next == 0 - let default_calldata_row_constraint1 = tx_id_is_zero_config.expr() * idx.expr(); - let default_calldata_row_constraint2 = tx_id_is_zero_config.expr() * tx_idx_next.expr(); - let default_calldata_row_constraint3 = tx_id_is_zero_config.expr() * is_final.expr(); - let default_calldata_row_constraint4 = tx_id_is_zero_config.expr() * gas_cost.expr(); - - // if tx_id != 0 then - // 1. tx_id_next == tx_id: idx_next == idx + 1, gas_cost_next == gas_cost + - // gas_next, is_final == false; - // 2. tx_id_next == tx_id + 1 + x (where x is in [0, 2^16)): idx_next == 0, - // gas_cost_next == gas_next, is_final == true; - // 3. tx_id_next == 0: is_final == true, idx_next == 0, gas_cost_next == 0; - // either case 1, case 2 or case 3 holds. - - let tx_id_equal_to_next = - 1.expr() - (tx_idx_next.expr() - tx_idx.expr()) * tx_idx_diff_inv.expr(); - let idx_of_same_tx_constraint = - tx_id_equal_to_next.clone() * (idx_next.expr() - idx.expr() - 1.expr()); - let idx_of_next_tx_constraint = (tx_idx_next.expr() - tx_idx.expr()) * idx_next.expr(); - - let gas_cost_of_same_tx_constraint = tx_id_equal_to_next.clone() - * (gas_cost_next.expr() - gas_cost.expr() - gas_next.expr()); - let gas_cost_of_next_tx_constraint = is_tx_id_next_nonzero.expr() - * (tx_idx_next.expr() - tx_idx.expr()) - * (gas_cost_next.expr() - gas_next.expr()); - - let is_final_of_same_tx_constraint = tx_id_equal_to_next * is_final.expr(); - let is_final_of_next_tx_constraint = - (tx_idx_next.expr() - tx_idx.expr()) * (is_final.expr() - 1.expr()); - - // if tx_id != 0 then - // 1. q_calldata_start * (index - 0) == 0 and - // 2. q_calldata_start * (gas_cost - gas) == 0. + // keccak in rpi + meta.lookup_any("keccak(rpi)", |meta| { + let is_enabled = meta.query_advice(keccak_table.is_enabled, Rotation::cur()); + let input_rlc = meta.query_advice(keccak_table.input_rlc, Rotation::cur()); + let input_len = meta.query_advice(keccak_table.input_len, Rotation::cur()); + let output_rlc = meta.query_advice(keccak_table.output_rlc, Rotation::cur()); + let q_keccak = meta.query_selector(q_keccak); + + let rpi_rlc = meta.query_advice(rpi_field_bytes_acc, Rotation::cur()); + let output = meta.query_advice(rpi_rlc_acc, Rotation::cur()); vec![ - q_is_calldata.expr() * default_calldata_row_constraint1, - q_is_calldata.expr() * default_calldata_row_constraint2, - q_is_calldata.expr() * default_calldata_row_constraint3, - q_is_calldata.expr() * default_calldata_row_constraint4, - q_is_calldata.expr() * is_tx_id_nonzero.expr() * idx_of_same_tx_constraint, - q_is_calldata.expr() * is_tx_id_nonzero.expr() * idx_of_next_tx_constraint, - q_is_calldata.expr() * is_tx_id_nonzero.expr() * gas_cost_of_same_tx_constraint, - q_is_calldata.expr() * is_tx_id_nonzero.expr() * gas_cost_of_next_tx_constraint, - q_is_calldata.expr() * is_tx_id_nonzero.expr() * is_final_of_same_tx_constraint, - q_is_calldata.expr() * is_tx_id_nonzero.expr() * is_final_of_next_tx_constraint, - q_calldata_start.expr() * is_tx_id_nonzero.expr() * (idx - 0.expr()), - q_calldata_start.expr() * is_tx_id_nonzero.expr() * (gas_cost - gas), + (q_keccak.expr() * 1.expr(), is_enabled), + (q_keccak.expr() * rpi_rlc, input_rlc), + (q_keccak.expr() * RPI_BYTES_LEN.expr(), input_len), + (q_keccak * output, output_rlc), ] }); - // Test if tx tag equals to CallDataLength - let tx_tag_is_cdl_config = IsZeroChip::configure( - meta, - |meta| meta.query_selector(q_tx_table), - |meta| meta.query_fixed(tag, Rotation::cur()) - TxFieldTag::CallDataLength.expr(), - tx_id_inv, - ); - - meta.create_gate( - "call_data_gas_cost should be zero if call_data_length is zero", - |meta| { - let q_tx_table = meta.query_selector(q_tx_table); - - let is_calldata_length_zero = tx_value_is_zero_config.expr(); - let is_calldata_length_row = tx_tag_is_cdl_config.expr(); - let calldata_cost = meta.query_advice(tx_value, Rotation::next()); + // is byte + meta.lookup_any("is_byte", |meta| { + let q_field_step = meta.query_selector(q_field_start); + let q_field_end = meta.query_selector(q_field_end); + let is_field = or::expr([q_field_step, q_field_end]); + let rpi_field_bytes = meta.query_advice(rpi_field_bytes, Rotation::cur()); - vec![q_tx_table * is_calldata_length_row * is_calldata_length_zero * calldata_cost] - }, - ); - - meta.lookup_any("gas_cost in tx table", |meta| { - let q_tx_table = meta.query_selector(q_tx_table); - let is_final = meta.query_advice(is_final, Rotation::cur()); - - let tx_id = meta.query_advice(tx_id, Rotation::cur()); - - // calldata gas cost assigned in the tx table - // CallDataGasCost is on the next row of CallDataLength - let calldata_cost_assigned = meta.query_advice(tx_value, Rotation::next()); - // calldata gas cost calculated in call data - let calldata_cost_calc = meta.query_advice(calldata_gas_cost, Rotation::cur()); - - let is_calldata_length_row = tx_tag_is_cdl_config.expr(); - let is_calldata_length_nonzero = not::expr(tx_value_is_zero_config.expr()); - - // lookup (tx_id, true, is_calldata_length_nonzero * is_calldata_cost * - // gas_cost) in the table (tx_id, is_final, gas_cost) - // if q_tx_table is true - let condition = q_tx_table * is_calldata_length_nonzero * is_calldata_length_row; - - vec![ - (condition.expr() * tx_id.expr(), tx_id), - (condition.expr() * 1.expr(), is_final), - ( - condition.expr() * calldata_cost_assigned, - calldata_cost_calc, - ), - ] + let is_byte = meta.query_fixed(is_byte, Rotation::cur()); + vec![(is_field * rpi_field_bytes, is_byte)] }); Self { - max_txs, - max_calldata, - block_table, - q_block_table, - q_tx_table, - q_tx_calldata, - q_calldata_start, - tx_table, - tx_id_inv, - tx_value_inv, - tx_id_diff_inv, - fixed_u16, - calldata_gas_cost, - is_final, - pi, - - rpi, + rpi_field_bytes, + rpi_field_bytes_acc, rpi_rlc_acc, - rpi_encoding, - q_rpi_encoding, + q_field_start, + q_field_step, + q_field_end, + q_start, q_not_end, + is_byte, + is_field_rlc, + + pi, // keccak_hi, keccak_lo - rlp_table, + q_keccak, keccak_table, + + block_table, + _marker: PhantomData, } } } impl PiCircuitConfig { - /// Return the number of rows in the circuit - #[inline] - fn circuit_block_len(&self) -> usize { - // +1 empty row in block table - // +3 prover, txs_hash_hi, txs_hash_lo - // EXTRA_LEN: state_root, prev_root - // total = 269 - BLOCK_LEN + 1 + EXTRA_LEN + 3 - } - - #[inline] - fn circuit_txs_len(&self) -> usize { - 3 * (TX_LEN * self.max_txs + 1) + self.max_calldata - } - - fn assign_tx_empty_row(&self, region: &mut Region<'_, F>, offset: usize) -> Result<(), Error> { - region.assign_advice( - || "tx_id", - self.tx_table.tx_id, - offset, - || Value::known(F::zero()), - )?; - region.assign_advice( - || "tx_id_inv", - self.tx_id_inv, - offset, - || Value::known(F::zero()), - )?; - region.assign_fixed( - || "tag", - self.tx_table.tag, - offset, - || Value::known(F::from(TxFieldTag::Null as u64)), - )?; - region.assign_advice( - || "index", - self.tx_table.index, - offset, - || Value::known(F::zero()), - )?; - region.assign_advice( - || "tx_value", - self.tx_table.value, - offset, - || Value::known(F::zero()), - )?; - region.assign_advice( - || "tx_value_inv", - self.tx_value_inv, - offset, - || Value::known(F::zero()), - )?; - region.assign_advice( - || "is_final", - self.is_final, - offset, - || Value::known(F::zero()), - )?; - region.assign_advice( - || "gas_cost", - self.calldata_gas_cost, - offset, - || Value::known(F::zero()), - )?; - Ok(()) - } - - /// Assigns a tx_table row and stores the values in a vec for the - /// raw_public_inputs column #[allow(clippy::too_many_arguments)] - fn assign_tx_row( + fn assign_pi_field( &self, region: &mut Region<'_, F>, - offset: usize, - tx_id: usize, - tag: TxFieldTag, - index: usize, - tx_value: Value, - rpi_vals: &mut [Value], - ) -> Result<(), Error> { - let tx_id = F::from(tx_id as u64); - // tx_id_inv = (tag - CallDataLength)^(-1) - let tx_id_inv = if tag != TxFieldTag::CallDataLength { - let x = F::from(tag as u64) - F::from(TxFieldTag::CallDataLength as u64); - x.invert().unwrap_or(F::zero()) + offset: &mut usize, + _annotation: &'static str, + field_bytes: &[u8], + rpi_rlc_acc: &mut Value, + challenges: &Challenges>, + keccak_hi_lo: bool, + ) -> Result>, Error> { + let len = field_bytes.len(); + let mut field_rlc_acc = Value::known(F::zero()); + let (use_rlc, t) = if len * 8 > F::CAPACITY as usize { + (F::one(), challenges.evm_word()) } else { - F::zero() + (F::zero(), Value::known(F::from(BYTE_POW_BASE))) }; - let tag = F::from(tag as u64); - let index = F::from(index as u64); - let tx_value = tx_value; - let tx_value_inv = tx_value.map(|v| v.invert().unwrap_or(F::zero())); - - self.q_tx_table.enable(region, offset)?; - - // Assign vals to Tx_table - region.assign_advice( - || "tx_id", - self.tx_table.tx_id, - offset, - || Value::known(tx_id), - )?; - region.assign_fixed(|| "tag", self.tx_table.tag, offset, || Value::known(tag))?; - region.assign_advice( - || "index", - self.tx_table.index, - offset, - || Value::known(index), - )?; - region.assign_advice(|| "tx_value", self.tx_table.value, offset, || tx_value)?; - region.assign_advice( - || "tx_id_inv", - self.tx_id_inv, - offset, - || Value::known(tx_id_inv), - )?; - region.assign_advice( - || "tx_value_inverse", - self.tx_value_inv, - offset, - || tx_value_inv, - )?; - - // Assign vals to raw_public_inputs column - let tx_table_len = TX_LEN * self.max_txs + 1; - - let id_offset = self.circuit_block_len(); - let index_offset = id_offset + tx_table_len; - let value_offset = index_offset + tx_table_len; - - region.assign_advice( - || "txlist.tx_id", - self.rpi, - offset + id_offset, - || Value::known(tx_id), - )?; - - region.assign_advice( - || "txlist.tx_index", - self.rpi, - offset + index_offset, - || Value::known(index), - )?; - - region.assign_advice( - || "txlist.tx_value", - self.rpi, - offset + value_offset, - || tx_value, - )?; - - // Add copy to vec - rpi_vals[offset] = Value::known(tx_id); - rpi_vals[offset + tx_table_len] = Value::known(index); - rpi_vals[offset + 2 * tx_table_len] = tx_value; - - Ok(()) - } - - /// Assigns one calldata row - #[allow(clippy::too_many_arguments)] - fn assign_tx_calldata_row( - &self, - region: &mut Region<'_, F>, - offset: usize, - tx_id: usize, - tx_id_next: usize, - index: usize, - tx_value: F, - is_final: bool, - gas_cost: F, - rpi_vals: &mut [Value], - ) -> Result<(), Error> { - let tx_id = F::from(tx_id as u64); - let tx_id_inv = tx_id.invert().unwrap_or(F::zero()); - let tx_id_diff = F::from(tx_id_next as u64) - tx_id; - let tx_id_diff_inv = tx_id_diff.invert().unwrap_or(F::zero()); - let tag = F::from(TxFieldTag::CallData as u64); - let index = F::from(index as u64); - let tx_value = tx_value; - let tx_value_inv = tx_value.invert().unwrap_or(F::zero()); - let is_final = if is_final { F::one() } else { F::zero() }; - - // Assign vals to raw_public_inputs column - let tx_table_len = TX_LEN * self.max_txs + 1; - let calldata_offset = tx_table_len + offset; - - self.q_tx_calldata.enable(region, calldata_offset)?; - - // Assign vals to Tx_table - region.assign_advice( - || "tx_id", - self.tx_table.tx_id, - calldata_offset, - || Value::known(tx_id), - )?; - region.assign_advice( - || "tx_id_inv", - self.tx_id_inv, - calldata_offset, - || Value::known(tx_id_inv), - )?; - region.assign_fixed( - || "tag", - self.tx_table.tag, - calldata_offset, - || Value::known(tag), - )?; - region.assign_advice( - || "index", - self.tx_table.index, - calldata_offset, - || Value::known(index), - )?; - region.assign_advice( - || "tx_value", - self.tx_table.value, - calldata_offset, - || Value::known(tx_value), - )?; - region.assign_advice( - || "tx_value_inv", - self.tx_value_inv, - calldata_offset, - || Value::known(tx_value_inv), - )?; - region.assign_advice( - || "tx_id_diff_inv", - self.tx_id_diff_inv, - calldata_offset, - || Value::known(tx_id_diff_inv), - )?; - region.assign_advice( - || "is_final", - self.is_final, - calldata_offset, - || Value::known(is_final), - )?; - region.assign_advice( - || "gas_cost", - self.calldata_gas_cost, - calldata_offset, - || Value::known(gas_cost), - )?; - - let value_offset = 3 * tx_table_len; - region.assign_advice( - || "raw_pi.tx_value", - self.rpi, - offset + value_offset + self.circuit_block_len(), - || Value::known(tx_value), - )?; + let randomness = if keccak_hi_lo { + challenges.evm_word() + } else { + challenges.keccak_input() + }; + let mut cells = vec![None; field_bytes.len() + 2]; + for (i, byte) in field_bytes.iter().enumerate() { + let row_offset = *offset + i; + + region.assign_fixed( + || "is_field_rlc", + self.is_field_rlc, + row_offset, + || Value::known(use_rlc), + )?; - // Add copy to vec - rpi_vals[offset + value_offset] = Value::known(tx_value); + // assign field bytes + let field_byte_cell = region.assign_advice( + || "field bytes", + self.rpi_field_bytes, + row_offset, + || Value::known(F::from(*byte as u64)), + )?; - Ok(()) + field_rlc_acc = field_rlc_acc * t + Value::known(F::from(*byte as u64)); + let rpi_cell = region.assign_advice( + || "field bytes acc", + self.rpi_field_bytes_acc, + row_offset, + || field_rlc_acc, + )?; + *rpi_rlc_acc = *rpi_rlc_acc * randomness + Value::known(F::from(*byte as u64)); + let rpi_rlc_acc_cell = region.assign_advice( + || "rpi_rlc_acc", + self.rpi_rlc_acc, + row_offset, + || *rpi_rlc_acc, + )?; + // setup selector + if i == 0 { + self.q_field_start.enable(region, row_offset)?; + } + // the last offset of field + if i == field_bytes.len() - 1 { + self.q_field_end.enable(region, row_offset)?; + cells[RPI_CELL_IDX] = Some(rpi_cell); + cells[RPI_RLC_ACC_CELL_IDX] = Some(rpi_rlc_acc_cell); + } else { + self.q_field_step.enable(region, row_offset)?; + } + cells[2 + i] = Some(field_byte_cell); + } + *offset += field_bytes.len(); + Ok(cells.into_iter().map(|cell| cell.unwrap()).collect()) } #[allow(clippy::type_complexity)] - fn assign_block( + fn assign_block_table( &self, region: &mut Region<'_, F>, - public_data: &PublicData, + public_data: &PublicData, challenges: &Challenges>, - ) -> Result< - ( - AssignedCell, // block hash hi - AssignedCell, // block hash lo - AssignedCell, // txs hash hi - AssignedCell, // txs hash lo - Value, // block_rlc_acc - ), - Error, - > { + ) -> Result, Error> { let block_values = public_data.get_block_table_values(); - let extra_values = public_data.get_extra_values(); let randomness = challenges.evm_word(); - self.q_start.enable(region, 0)?; - let mut rlc_acc = Value::known(F::zero()); - let mut cells = vec![]; - for (offset, (name, val, not_in_table)) in [ - ("zero", Value::known(F::zero()), false), + let mut block_hash_cell = None; + for (offset, (name, val)) in [ ( "coinbase", Value::known(block_values.coinbase.to_scalar().unwrap()), - false, - ), - ( - "gas_limit", - Value::known(F::from(block_values.gas_limit)), - false, - ), - ("number", Value::known(F::from(block_values.number)), false), - ( - "timestamp", - Value::known(F::from(block_values.timestamp)), - false, ), + ("timestamp", Value::known(F::from(block_values.timestamp))), + ("number", Value::known(F::from(block_values.number))), ( "difficulty", randomness.map(|randomness| rlc(block_values.difficulty.to_le_bytes(), randomness)), - false, ), + ("gas_limit", Value::known(F::from(block_values.gas_limit))), ( "base_fee", randomness.map(|randomness| rlc(block_values.base_fee.to_le_bytes(), randomness)), - false, ), + ("chain_id", Value::known(F::from(block_values.chain_id))), ( - "chain_id", - Value::known(F::from(block_values.chain_id)), - false, + "block_hash", + randomness.map(|randomness| rlc(block_values.block_hash.to_le_bytes(), randomness)), ), ] .into_iter() - .chain(block_values.history_hashes.iter().map(|h| { - ( - "prev_hash", - randomness.map(|v| rlc(h.to_fixed_bytes(), v)), - false, - ) - })) - .chain([ - ( - "state.root", - randomness.map(|v| rlc(extra_values.state_root.to_fixed_bytes(), v)), - false, - ), - ( - "parent_block.hash", - randomness.map(|v| rlc(extra_values.prev_state_root.to_fixed_bytes(), v)), - false, - ), - ( - "prover", - Value::known(public_data.prover.to_scalar().unwrap()), - true, - ), - ("txs_hash_hi", Value::known(public_data.txs_hash_hi), true), - ("txs_hash_lo", Value::known(public_data.txs_hash_lo), true), - ]) .enumerate() { - if offset < self.circuit_block_len() - 1 { - self.q_not_end.enable(region, offset)?; - } - let val_cell = region.assign_advice(|| name, self.rpi, offset, || val)?; - rlc_acc = rlc_acc * randomness + val; - region.assign_advice(|| name, self.rpi_rlc_acc, offset, || rlc_acc)?; - if not_in_table { - cells.push(val_cell); - } else { - self.q_block_table.enable(region, offset)?; - region.assign_advice(|| name, self.block_table.value, offset, || val)?; - } - } - - let mut offset = 0; - self.q_rpi_encoding.enable(region, offset)?; - region.assign_advice(|| "block_rlc_acc", self.rpi_encoding, offset, || rlc_acc)?; - offset += 1; - let block_rlp_rlc = public_data.get_block_rlp_rlc(challenges); - region.assign_advice( - || "block_rlp_rlc", - self.rpi_encoding, - offset, - || block_rlp_rlc, - )?; - offset += 1; - region.assign_advice( - || "block_rlp_len", - self.rpi_encoding, - offset, - || Value::known(F::from(public_data.block_rlp.len() as u64)), - )?; - offset += 1; - let block_hash_hi_cell = region.assign_advice( - || "block_hash_hi", - self.rpi_encoding, - offset, - || Value::known(public_data.block_hash_hi), - )?; - offset += 1; - let block_hash_lo_cell = region.assign_advice( - || "block_hash_lo", - self.rpi_encoding, - offset, - || Value::known(public_data.block_hash_lo), - )?; - - Ok(( - block_hash_hi_cell, - block_hash_lo_cell, - cells[1].clone(), - cells[2].clone(), - rlc_acc, - )) - } - - #[allow(clippy::type_complexity)] - fn assign_txs( - &self, - region: &mut Region<'_, F>, - public_data: &PublicData, - challenges: &Challenges>, - rpi_vals: Vec>, - ) -> Result<(AssignedCell, AssignedCell, Value), Error> { - self.q_start.enable(region, 0)?; - - let r = challenges.evm_word(); - - let last = rpi_vals.len() - 1; - let mut rlc_acc = Value::known(F::zero()); - for (offset, val) in rpi_vals.iter().enumerate() { - if offset != last { - self.q_not_end - .enable(region, offset + self.circuit_block_len())?; - } - rlc_acc = rlc_acc * r + val; - region.assign_advice( - || "txs_rlc_acc", - self.rpi_rlc_acc, - offset + self.circuit_block_len(), - || rlc_acc, - )?; + block_hash_cell = + Some(region.assign_advice(|| name, self.block_table.value, offset, || val)?); } - let mut offset = 5; - self.q_rpi_encoding.enable(region, offset)?; - region.assign_advice(|| "txs_rlc_acc", self.rpi_encoding, offset, || rlc_acc)?; - offset += 1; - let txs_rlp_rlc = public_data.get_txs_rlp_rlc(challenges); - region.assign_advice(|| "txs_rlp_rlc", self.rpi_encoding, offset, || txs_rlp_rlc)?; - offset += 1; - region.assign_advice( - || "txs_rlp_len", - self.rpi_encoding, - offset, - || Value::known(F::from(public_data.txs_rlp.len() as u64)), - )?; - offset += 1; - let txs_hash_hi_cell = region.assign_advice( - || "txs_hash_hi", - self.rpi_encoding, - offset, - || Value::known(public_data.txs_hash_hi), - )?; - offset += 1; - let txs_hash_lo_cell = region.assign_advice( - || "txs_hash_lo", - self.rpi_encoding, - offset, - || Value::known(public_data.txs_hash_lo), - )?; - - Ok((txs_hash_hi_cell, txs_hash_lo_cell, rlc_acc)) - } - - fn assign_rlp_table( - &self, - layouter: &mut impl Layouter, - challenges: &Challenges>, - txs_rlc_acc: Value, - block_rlc_acc: Value, - public_data: &PublicData, - ) -> Result<(), Error> { - layouter.assign_region( - || "rlp table", - |mut region| { - let block_rlp_rlc = public_data.get_block_rlp_rlc(challenges); - let txs_rlp_rlc = public_data.get_txs_rlp_rlc(challenges); - for (offset, vals) in [ - [ - Value::known(F::zero()), - Value::known(F::zero()), - Value::known(F::zero()), - ], - [ - txs_rlc_acc, - txs_rlp_rlc, - Value::known(F::from(public_data.txs_rlp.len() as u64)), - ], - [ - block_rlc_acc, - block_rlp_rlc, - Value::known(F::from(public_data.block_rlp.len() as u64)), - ], - ] - .iter() - .enumerate() - { - for (val, row) in vals.iter().zip_eq(self.rlp_table.iter()) { - region.assign_advice(|| "", *row, offset, || *val)?; - } - } - Ok(()) - }, - )?; - Ok(()) - } - - fn assign_fixed_u16(&self, layouter: &mut impl Layouter) -> Result<(), Error> { - layouter.assign_region( - || "fixed u16 table", - |mut region| { - for i in 0..(1 << 16) { - region.assign_fixed( - || format!("row_{}", i), - self.fixed_u16, - i, - || Value::known(F::from(i as u64)), - )?; - } - - Ok(()) - }, - ) + Ok(block_hash_cell.unwrap()) } fn assign( &self, layouter: &mut impl Layouter, - public_data: &PublicData, + public_data: &PublicData, challenges: &Challenges>, ) -> Result<(), Error> { - self.assign_fixed_u16(layouter)?; - let (public_inputs, txs_rlc_acc, block_rlc_acc) = layouter.assign_region( + let pi = layouter.assign_region( || "region 0", - |mut region| { + |ref mut region| { // Assign block table - let ( - block_hash_hi_cell, - block_hash_lo_cell, - txs_hash_hi_cell, - txs_hash_lo_cell, - block_rlc_acc, - ) = self.assign_block(&mut region, public_data, challenges)?; - - // Assign Tx table + let block_table_hash_cell = + self.assign_block_table(region, public_data, challenges)?; + let mut rpi_rlc_acc = Value::known(F::zero()); let mut offset = 0; - let txs = public_data.get_tx_table_values(); - assert!(txs.len() <= self.max_txs); - let tx_default = TxValues::default(); - - let circuit_txs_len = self.circuit_txs_len(); - let mut rpi_vals = vec![Value::known(F::zero()); circuit_txs_len]; - - // Add empty row - self.assign_tx_row( - &mut region, - offset, - 0, - TxFieldTag::Null, - 0, - Value::known(F::zero()), - &mut rpi_vals, - )?; - offset += 1; - - let randomness = challenges.evm_word(); - - for i in 0..self.max_txs { - let tx = if i < txs.len() { &txs[i] } else { &tx_default }; - - for (tag, value) in &[ - ( - TxFieldTag::Nonce, - randomness.map(|randomness| rlc(tx.nonce.to_le_bytes(), randomness)), - ), - ( - TxFieldTag::Gas, - randomness.map(|randomness| rlc(tx.gas.to_le_bytes(), randomness)), - ), - ( - TxFieldTag::GasPrice, - randomness.map(|v| rlc(tx.gas_price.to_le_bytes(), v)), - ), - ( - TxFieldTag::CallerAddress, - Value::known(tx.from_addr.to_scalar().expect("tx.from too big")), - ), - ( - TxFieldTag::CalleeAddress, - Value::known(tx.to_addr.to_scalar().expect("tx.to too big")), - ), - (TxFieldTag::IsCreate, Value::known(F::from(tx.is_create))), - ( - TxFieldTag::Value, - randomness.map(|randomness| rlc(tx.value.to_le_bytes(), randomness)), - ), - ( - TxFieldTag::CallDataLength, - Value::known(F::from(tx.call_data_len)), - ), - ( - TxFieldTag::CallDataGasCost, - Value::known(F::from(tx.call_data_gas_cost)), - ), - ( - TxFieldTag::TxSignHash, - randomness.map(|randomness| rlc(tx.tx_sign_hash, randomness)), - ), - ] { - self.assign_tx_row( - &mut region, - offset, - i + 1, - *tag, - 0, - *value, - &mut rpi_vals, + let mut rpi_rlc_acc_cell = None; + for (annotation, field_type, field_bytes) in public_data.assignments() { + let cells = self.assign_pi_field( + region, + &mut offset, + annotation, + &field_bytes, + &mut rpi_rlc_acc, + challenges, + false, + )?; + if field_type == FieldType::BlockHash { + region.constrain_equal( + block_table_hash_cell.cell(), + cells[RPI_CELL_IDX].cell(), )?; - offset += 1; } + rpi_rlc_acc_cell = Some(cells[RPI_RLC_ACC_CELL_IDX].clone()); } - // Tx Table CallData - let mut calldata_count = 0; - self.q_calldata_start.enable(&mut region, offset)?; - // the call data bytes assignment starts at offset 0 - offset = 0; - let txs = public_data.txs(); - for (i, tx) in public_data.txs().iter().enumerate() { - let call_data_length = tx.call_data.0.len(); - let mut gas_cost = F::zero(); - for (index, byte) in tx.call_data.0.iter().enumerate() { - assert!(calldata_count < self.max_calldata); - let is_final = index == call_data_length - 1; - gas_cost += if *byte == 0 { - F::from(ZERO_BYTE_GAS_COST) - } else { - F::from(NONZERO_BYTE_GAS_COST) - }; - let tx_id_next = if is_final { - let mut j = i + 1; - while j < txs.len() && txs[j].call_data.0.is_empty() { - j += 1; - } - if j >= txs.len() { - 0 - } else { - j + 1 - } - } else { - i + 1 - }; - - self.assign_tx_calldata_row( - &mut region, - offset, - i + 1, - tx_id_next as usize, - index, - F::from(*byte as u64), - is_final, - gas_cost, - &mut rpi_vals, + + // input_rlc in self.rpi_field_bytes_acc + // input_len in self.rpi_len_acc + // output_rlc in self.rpi_rlc_acc + let keccak_row = offset; + let rpi_rlc_acc_cell = rpi_rlc_acc_cell.unwrap(); + rpi_rlc_acc_cell.copy_advice( + || "keccak(rpi)_input", + region, + self.rpi_field_bytes_acc, + keccak_row, + )?; + let keccak = public_data.get_pi(); + let mut keccak_input = keccak.to_fixed_bytes(); + keccak_input.reverse(); + let keccak_rlc = challenges + .evm_word() + .map(|randomness| rlc(keccak_input, randomness)); + let keccak_output_cell = region.assign_advice( + || "keccak(rpi)_output", + self.rpi_rlc_acc, + keccak_row, + || keccak_rlc, + )?; + self.q_keccak.enable(region, keccak_row)?; + + rpi_rlc_acc = Value::known(F::zero()); + offset += 1; + let mut pi = Vec::with_capacity(2); + + for (idx, (annotation, field_bytes)) in [ + ( + "high_16_bytes_of_keccak_rpi", + &keccak.to_fixed_bytes()[..16], + ), + ("low_16_bytes_of_keccak_rpi", &keccak.to_fixed_bytes()[16..]), + ] + .into_iter() + .enumerate() + { + let cells = self.assign_pi_field( + region, + &mut offset, + annotation, + field_bytes, + &mut rpi_rlc_acc, + challenges, + true, + )?; + pi.push(cells[RPI_CELL_IDX].clone()); + if idx == 1 { + region.constrain_equal( + keccak_output_cell.cell(), + cells[RPI_RLC_ACC_CELL_IDX].cell(), )?; - offset += 1; - calldata_count += 1; } } - for _ in calldata_count..self.max_calldata { - self.assign_tx_calldata_row( - &mut region, - offset, - 0, // tx_id - 0, - 0, - F::zero(), - false, - F::zero(), - &mut rpi_vals, - )?; - offset += 1; - } - // NOTE: we add this empty row so as to pass mock prover's check - // otherwise it will emit CellNotAssigned Error - let tx_table_len = TX_LEN * self.max_txs + 1; - self.assign_tx_empty_row(&mut region, tx_table_len + offset)?; - - let (origin_txs_hash_hi_cell, origin_txs_hash_lo_cell, txs_rlc_acc) = - self.assign_txs(&mut region, public_data, challenges, rpi_vals)?; - // assert two txs hash are equal - region.constrain_equal(txs_hash_hi_cell.cell(), origin_txs_hash_hi_cell.cell())?; - region.constrain_equal(txs_hash_lo_cell.cell(), origin_txs_hash_lo_cell.cell())?; - Ok(( - [block_hash_hi_cell, block_hash_lo_cell], - txs_rlc_acc, - block_rlc_acc, - )) + + Ok(pi) }, )?; - // assign rlp table - self.assign_rlp_table( - layouter, - challenges, - txs_rlc_acc, - block_rlc_acc, - public_data, - )?; - - // constraint public inputs - for (offset, cell) in public_inputs.iter().enumerate() { - layouter.constrain_instance(cell.cell(), self.pi, offset)?; + for (idx, cell) in pi.into_iter().enumerate() { + layouter.constrain_instance(cell.cell(), self.pi, idx)?; } Ok(()) } @@ -1469,38 +581,24 @@ impl PiCircuitConfig { /// Public Inputs Circuit #[derive(Clone, Default, Debug)] pub struct PiCircuit { - max_txs: usize, - max_calldata: usize, /// PublicInputs data known by the verifier - pub public_data: PublicData, + pub public_data: PublicData, _marker: PhantomData, } impl PiCircuit { /// Creates a new PiCircuit - pub fn new(max_txs: usize, max_calldata: usize, public_data: PublicData) -> Self { + pub fn new(public_data: PublicData) -> Self { Self { - max_txs, - max_calldata, public_data, _marker: PhantomData, } } /// create a new PiCircuit with extra data - /// prover: for l2 - /// txs_rlp: get from l1 contract - pub fn new_from_block_with_extra( - block: &witness::Block, - prover: Address, - txs_rlp: Bytes, - ) -> Self { - PiCircuit::new( - block.circuits_params.max_txs, - block.circuits_params.max_calldata, - PublicData::new(block, prover, txs_rlp), - ) + pub fn new_from_block_with_extra(block: &witness::Block, taiko: &witness::Taiko) -> Self { + PiCircuit::new(PublicData::new(block, taiko)) } } @@ -1508,19 +606,30 @@ impl SubCircuit for PiCircuit { type Config = PiCircuitConfig; fn new_from_block(block: &witness::Block) -> Self { - PiCircuit::new( - block.circuits_params.max_txs, - block.circuits_params.max_calldata, - PublicData::new(block, Address::default(), Bytes::default()), - ) + PiCircuit::new(PublicData::new(block, &witness::Taiko::default())) } /// Compute the public inputs for this circuit. fn instance(&self) -> Vec> { - vec![vec![ - self.public_data.block_hash_hi, - self.public_data.block_hash_lo, - ]] + let keccak_rpi = self.public_data.get_pi(); + let keccak_hi = keccak_rpi + .to_fixed_bytes() + .iter() + .take(16) + .fold(F::zero(), |acc, byte| { + acc * F::from(BYTE_POW_BASE) + F::from(*byte as u64) + }); + + let keccak_lo = keccak_rpi + .to_fixed_bytes() + .iter() + .skip(16) + .fold(F::zero(), |acc, byte| { + acc * F::from(BYTE_POW_BASE) + F::from(*byte as u64) + }); + + let public_inputs = vec![keccak_hi, keccak_lo]; + vec![public_inputs] } /// Make the assignments to the PiCircuit @@ -1530,6 +639,21 @@ impl SubCircuit for PiCircuit { challenges: &Challenges>, layouter: &mut impl Layouter, ) -> Result<(), Error> { + layouter.assign_region( + || "is_byte table", + |mut region| { + for i in 0..(1 << 8) { + region.assign_fixed( + || format!("row_{}", i), + config.is_byte, + i, + || Value::known(F::from(i as u64)), + )?; + } + + Ok(()) + }, + )?; config.assign(layouter, &self.public_data, challenges) } } @@ -1543,15 +667,11 @@ impl SubCircuit for PiCircuit { /// Test Circuit for PiCircuit #[cfg(any(feature = "test", test))] #[derive(Default, Clone)] -pub struct PiTestCircuit( - pub PiCircuit, -); +pub struct PiTestCircuit(pub PiCircuit); #[cfg(any(feature = "test", test))] -impl Circuit - for PiTestCircuit -{ - type Config = PiCircuitConfig; +impl Circuit for PiTestCircuit { + type Config = (PiCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; fn without_witnesses(&self) -> Self { @@ -1560,41 +680,38 @@ impl Circuit fn configure(meta: &mut ConstraintSystem) -> Self::Config { let block_table = BlockTable::construct(meta); - let tx_table = TxTable::construct(meta); - let rlp_table = array_init::array_init(|_| meta.advice_column()); - let keccak_table = KeccakTable2::construct(meta); - let challenges = Challenges::mock(100.expr(), 100.expr()); - PiCircuitConfig::new( - meta, - PiCircuitConfigArgs { - max_txs: MAX_TXS, - max_calldata: MAX_CALLDATA, - block_table, - tx_table, - rlp_table, - keccak_table, - challenges, - }, + let keccak_table = KeccakTable::construct(meta); + let challenges = Challenges::construct(meta); + let challenge_exprs = challenges.exprs(meta); + // let challenge_exprs = Challenges::mock(100.expr(), 100.expr()); + + ( + PiCircuitConfig::new( + meta, + PiCircuitConfigArgs { + block_table, + keccak_table, + challenges: challenge_exprs, + }, + ), + challenges, ) } fn synthesize( &self, - config: Self::Config, + (config, challenges): Self::Config, mut layouter: impl Layouter, ) -> Result<(), Error> { - // let challenges = challenges.values(&mut layouter); - let challenges = Challenges::mock(Value::known(F::from(100)), Value::known(F::from(100))); + let challenges = challenges.values(&mut layouter); + // let challenges = Challenges::mock(Value::known(F::from(100)), + // Value::known(F::from(100))); + let public_data = &self.0.public_data; // assign keccak table - config.keccak_table.dev_load( - &mut layouter, - vec![ - &public_data.txs_rlp.to_vec(), - &public_data.block_rlp.to_vec(), - ], - &challenges, - )?; + config + .keccak_table + .dev_load(&mut layouter, vec![&public_data.rpi_bytes()], &challenges)?; self.0.synthesize_sub(&config, &challenges, &mut layouter) } @@ -1605,26 +722,27 @@ mod pi_circuit_test { use super::*; - use crate::test_util::rand_tx; use eth_types::{H64, U256, U64}; use halo2_proofs::{ dev::{MockProver, VerifyFailure}, halo2curves::bn256::Fr, }; + use lazy_static::lazy_static; use pretty_assertions::assert_eq; - use rand::SeedableRng; - use rand_chacha::ChaCha20Rng; - fn run( + lazy_static! { + static ref OMMERS_HASH: H256 = H256::from_slice( + &hex::decode("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347") + .unwrap(), + ); + } + + fn run( k: u32, - public_data: PublicData, + public_data: PublicData, pi: Option>>, ) -> Result<(), Vec> { - let circuit = PiTestCircuit::(PiCircuit::new( - MAX_TXS, - MAX_CALLDATA, - public_data, - )); + let circuit = PiTestCircuit::(PiCircuit::new(public_data)); let public_inputs = pi.unwrap_or_else(|| circuit.0.instance()); let prover = match MockProver::run(k, &circuit, public_inputs) { @@ -1632,26 +750,6 @@ mod pi_circuit_test { Err(e) => panic!("{:#?}", e), }; let res = prover.verify(); - let hash_byte_hi: Vec = circuit - .0 - .public_data - .block_hash - .as_bytes() - .iter() - .take(16) - .copied() - .collect(); - let hash_byte_lo: Vec = circuit - .0 - .public_data - .block_hash - .as_bytes() - .iter() - .skip(16) - .copied() - .collect(); - let _s1 = hex::encode(hash_byte_hi); - let _s2 = hex::encode(hash_byte_lo); res } @@ -1659,27 +757,22 @@ mod pi_circuit_test { fn test_default_pi() { const MAX_TXS: usize = 2; const MAX_CALLDATA: usize = 8; - let public_data = PublicData::default(); + let mut public_data = PublicData::default::(); + public_data.meta_hash = OMMERS_HASH.to_word(); + public_data.block_hash = OMMERS_HASH.to_word(); let k = 17; - assert_eq!( - run::(k, public_data, None), - Ok(()) - ); + assert_eq!(run::(k, public_data, None), Ok(())); } #[test] fn test_fail_pi_hash() { const MAX_TXS: usize = 2; const MAX_CALLDATA: usize = 8; - let public_data = PublicData::default(); + let public_data = PublicData::default::(); let k = 17; - match run::( - k, - public_data, - Some(vec![vec![Fr::zero(), Fr::one()]]), - ) { + match run::(k, public_data, Some(vec![vec![Fr::zero(), Fr::one()]])) { Ok(_) => unreachable!("this case must fail"), Err(errs) => { assert_eq!(errs.len(), 4); @@ -1697,7 +790,7 @@ mod pi_circuit_test { fn test_fail_pi_prover() { const MAX_TXS: usize = 2; const MAX_CALLDATA: usize = 8; - let mut public_data = PublicData::default(); + let mut public_data = PublicData::default::(); let address_bytes = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, ]; @@ -1706,7 +799,7 @@ mod pi_circuit_test { let prover: Fr = public_data.prover.to_scalar().unwrap(); let k = 17; - match run::( + match run::( k, public_data, Some(vec![vec![prover, Fr::zero(), Fr::one()]]), @@ -1726,32 +819,16 @@ mod pi_circuit_test { #[test] fn test_simple_pi() { - const MAX_TXS: usize = 8; - const MAX_CALLDATA: usize = 200; - - let mut rng = ChaCha20Rng::seed_from_u64(2); - - let mut public_data = PublicData::default(); + let mut public_data = PublicData::default::(); let chain_id = 1337u64; public_data.chain_id = Word::from(chain_id); - let n_tx = 4; - for i in 0..n_tx { - let eth_tx = eth_types::Transaction::from(&rand_tx(&mut rng, chain_id, i & 2 == 0)); - public_data.transactions.push(eth_tx); - } - let k = 17; - assert_eq!( - run::(k, public_data, None), - Ok(()) - ); + assert_eq!(run::(k, public_data, None), Ok(())); } #[test] fn test_verify() { - const MAX_TXS: usize = 8; - const MAX_CALLDATA: usize = 200; let prover = Address::from_slice(&hex::decode("Df08F82De32B8d460adbE8D72043E3a7e25A3B39").unwrap()); @@ -1774,13 +851,10 @@ mod pi_circuit_test { block.eth_block.nonce = Some(H64::from([0, 0, 0, 0, 0, 0, 0, 0])); block.eth_block.base_fee_per_gas = Some(U256::from(0)); - let public_data = PublicData::new(&block, prover, Default::default()); + let public_data = PublicData::new(&block, &witness::Taiko::default()); let k = 17; - assert_eq!( - run::(k, public_data, None), - Ok(()) - ); + assert_eq!(run::(k, public_data, None), Ok(())); } } diff --git a/zkevm-circuits/src/table.rs b/zkevm-circuits/src/table.rs index 3ff0fdc750..a4eecdd9e3 100644 --- a/zkevm-circuits/src/table.rs +++ b/zkevm-circuits/src/table.rs @@ -459,6 +459,7 @@ impl RwTable { } /// The types of proofs in the MPT table +#[derive(Debug, Clone, Copy)] pub enum ProofType { /// Nonce updated NonceChanged = AccountFieldTag::Nonce as isize, @@ -677,7 +678,7 @@ impl BlockTable { Self { tag: meta.advice_column(), index: meta.advice_column(), - value: meta.advice_column(), + value: meta.advice_column_in(SecondPhase), } } diff --git a/zkevm-circuits/src/witness.rs b/zkevm-circuits/src/witness.rs index 22bca9affd..d542e47751 100644 --- a/zkevm-circuits/src/witness.rs +++ b/zkevm-circuits/src/witness.rs @@ -16,3 +16,5 @@ mod step; pub use step::ExecStep; mod tx; pub use tx::Transaction; +mod taiko; +pub use taiko::Taiko; diff --git a/zkevm-circuits/src/witness/taiko.rs b/zkevm-circuits/src/witness/taiko.rs new file mode 100644 index 0000000000..c394870d8e --- /dev/null +++ b/zkevm-circuits/src/witness/taiko.rs @@ -0,0 +1,36 @@ +//! extra witness for taiko circuits + +use eth_types::{Address, Hash, H256}; + +/// Taiko witness +#[derive(Debug, Default)] +pub struct Taiko { + /// l1 signal service address + pub l1_signal_service: Address, + /// l2 signal service address + pub l2_signal_service: Address, + /// l2 contract address + pub l2_contract: Address, + /// meta hash + pub meta_hash: Hash, + /// block hash value + pub block_hash: Hash, + /// the parent block hash + pub parent_hash: Hash, + /// signal root + pub signal_root: Hash, + /// extra message + pub graffiti: H256, + /// Prover address + pub prover: Address, + /// gas used + pub gas_used: u32, + /// parent gas used + pub parent_gas_used: u32, + /// blockMaxGasLimit + pub block_max_gas_limit: u64, + /// maxTransactionsPerBlock + pub max_transactions_per_block: u64, + /// maxBytesPerTxList + pub max_bytes_per_tx_list: u64, +}