diff --git a/Cargo.lock b/Cargo.lock index 1c4c7eadf7..86a2ace235 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,11 +43,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if 1.0.0", - "cipher", + "cipher 0.3.0", "cpufeatures", "opaque-debug 0.3.0", ] +[[package]] +name = "aes" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "433cfd6710c9986c576a25ca913c39d66a6474107b406f34f91d4a8923395241" +dependencies = [ + "cfg-if 1.0.0", + "cipher 0.4.4", + "cpufeatures", +] + [[package]] name = "ahash" version = "0.7.6" @@ -175,6 +186,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "auto_impl" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "auto_impl" version = "1.0.1" @@ -464,9 +487,9 @@ dependencies = [ "ctor", "env_logger", "eth-types", - "ethers-core", - "ethers-providers", - "ethers-signers", + "ethers-core 1.0.2", + "ethers-providers 1.0.2", + "ethers-signers 1.0.2", "fp-evm", "gadgets", "halo2_proofs", @@ -553,6 +576,38 @@ dependencies = [ "serde", ] +[[package]] +name = "camino" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08a1ec454bc3eead8719cb56e15dbbfecdbc14e4b3a3ae4936cc6e31f5fc0d07" +dependencies = [ + "camino", + "cargo-platform", + "semver 1.0.14", + "serde", + "serde_json", + "thiserror", +] + [[package]] name = "cast" version = "0.3.0" @@ -610,6 +665,16 @@ dependencies = [ "generic-array 0.14.6", ] +[[package]] +name = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "circuit-benchmarks" version = "0.1.0" @@ -618,8 +683,8 @@ dependencies = [ "bus-mapping", "env_logger", "eth-types", - "ethers", - "ethers-signers", + "ethers 1.0.2", + "ethers-signers 1.0.2", "halo2_proofs", "itertools", "keccak256", @@ -800,6 +865,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb4a24b1aaf0fd0ce8b45161144d6f42cd91677fd5940fd431183eb023b3a2b8" +[[package]] +name = "convert_case" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec182b0ca2f35d8fc196cf3404988fd8b8c739a4d270ff118a398feb0cbec1ca" +dependencies = [ + "unicode-segmentation", +] + [[package]] name = "core-foundation" version = "0.9.3" @@ -1054,7 +1128,16 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher", + "cipher 0.3.0", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher 0.4.4", ] [[package]] @@ -1538,14 +1621,36 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f65b750ac950f2f825b36d08bef4cda4112e19a7b1a68f6e2bb499413e12440" dependencies = [ - "aes", - "ctr", + "aes 0.7.5", + "ctr 0.8.0", "digest 0.10.6", "hex", "hmac 0.12.1", "pbkdf2 0.11.0", "rand 0.8.5", - "scrypt", + "scrypt 0.8.1", + "serde", + "serde_json", + "sha2 0.10.6", + "sha3 0.10.6", + "thiserror", + "uuid", +] + +[[package]] +name = "eth-keystore" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" +dependencies = [ + "aes 0.8.2", + "ctr 0.9.2", + "digest 0.10.6", + "hex", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt 0.10.0", "serde", "serde_json", "sha2 0.10.6", @@ -1558,8 +1663,8 @@ dependencies = [ name = "eth-types" version = "0.1.0" dependencies = [ - "ethers-core", - "ethers-signers", + "ethers-core 1.0.2", + "ethers-signers 1.0.2", "halo2-mpt-circuits", "halo2_proofs", "hex", @@ -1596,6 +1701,23 @@ dependencies = [ "uint", ] +[[package]] +name = "ethabi" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +dependencies = [ + "ethereum-types 0.14.1", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3 0.10.6", + "thiserror", + "uint", +] + [[package]] name = "ethbloom" version = "0.12.1" @@ -1678,23 +1800,50 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16142eeb3155cfa5aec6be3f828a28513a28bd995534f945fa70e7d608f16c10" dependencies = [ - "ethers-addressbook", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-middleware", - "ethers-providers", - "ethers-signers", + "ethers-addressbook 0.17.0", + "ethers-contract 0.17.0", + "ethers-core 0.17.0", + "ethers-etherscan 0.17.0", + "ethers-middleware 0.17.0", + "ethers-providers 0.17.0", + "ethers-signers 0.17.0", "ethers-solc", ] +[[package]] +name = "ethers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11f26f9d8d80da18ca72aca51804c65eb2153093af3bec74fd5ce32aa0c1f665" +dependencies = [ + "ethers-addressbook 1.0.2", + "ethers-contract 1.0.2", + "ethers-core 1.0.2", + "ethers-etherscan 1.0.2", + "ethers-middleware 1.0.2", + "ethers-providers 1.0.2", + "ethers-signers 1.0.2", +] + [[package]] name = "ethers-addressbook" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e23f8992ecf45ea9dd2983696aabc566c108723585f07f5dc8c9efb24e52d3db" dependencies = [ - "ethers-core", + "ethers-core 0.17.0", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-addressbook" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe4be54dd2260945d784e06ccdeb5ad573e8f1541838cee13a1ab885485eaa0b" +dependencies = [ + "ethers-core 1.0.2", "once_cell", "serde", "serde_json", @@ -1706,8 +1855,8 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e0010fffc97c5abcf75a30fd75676b1ed917b2b82beb8270391333618e2847d" dependencies = [ - "ethers-core", - "ethers-providers", + "ethers-core 0.17.0", + "ethers-providers 0.17.0", "futures-util", "hex", "once_cell", @@ -1717,6 +1866,65 @@ dependencies = [ "thiserror", ] +[[package]] +name = "ethers-contract" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9c3c3e119a89f0a9a1e539e7faecea815f74ddcf7c90d0b00d1f524db2fdc9c" +dependencies = [ + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core 1.0.2", + "ethers-providers 1.0.2", + "futures-util", + "hex", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "ethers-contract-abigen" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d4e5ad46aede34901f71afdb7bb555710ed9613d88d644245c657dc371aa228" +dependencies = [ + "Inflector", + "cfg-if 1.0.0", + "dunce", + "ethers-core 1.0.2", + "eyre", + "getrandom 0.2.8", + "hex", + "proc-macro2", + "quote", + "regex", + "reqwest", + "serde", + "serde_json", + "syn", + "toml", + "url", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f192e8e4cf2b038318aae01e94e7644e0659a76219e94bcd3203df744341d61f" +dependencies = [ + "ethers-contract-abigen", + "ethers-core 1.0.2", + "hex", + "proc-macro2", + "quote", + "serde_json", + "syn", +] + [[package]] name = "ethers-core" version = "0.17.0" @@ -1726,9 +1934,9 @@ dependencies = [ "arrayvec 0.7.2", "bytes", "chrono", - "convert_case", + "convert_case 0.5.0", "elliptic-curve", - "ethabi", + "ethabi 17.2.0", "fastrlp", "generic-array 0.14.6", "hex", @@ -1747,18 +1955,66 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "ethers-core" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ade3e9c97727343984e1ceada4fdab11142d2ee3472d2c67027d56b1251d4f15" +dependencies = [ + "arrayvec 0.7.2", + "bytes", + "cargo_metadata", + "chrono", + "convert_case 0.6.0", + "elliptic-curve", + "ethabi 18.0.0", + "generic-array 0.14.6", + "hex", + "k256", + "once_cell", + "open-fastrlp", + "proc-macro2", + "rand 0.8.5", + "rlp", + "rlp-derive", + "serde", + "serde_json", + "strum", + "syn", + "thiserror", + "tiny-keccak", + "unicode-xid", +] + [[package]] name = "ethers-etherscan" version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b279a3d00bd219caa2f9a34451b4accbfa9a1eaafc26dcda9d572591528435f0" dependencies = [ - "ethers-core", + "ethers-core 0.17.0", + "getrandom 0.2.8", + "reqwest", + "semver 1.0.14", + "serde", + "serde-aux 3.1.0", + "serde_json", + "thiserror", + "tracing", +] + +[[package]] +name = "ethers-etherscan" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9713f525348e5dde025d09b0a4217429f8074e8ff22c886263cc191e87d8216" +dependencies = [ + "ethers-core 1.0.2", "getrandom 0.2.8", "reqwest", "semver 1.0.14", "serde", - "serde-aux", + "serde-aux 4.2.0", "serde_json", "thiserror", "tracing", @@ -1771,11 +2027,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1e7e8632d28175352b9454bbcb604643b6ca1de4d36dc99b3f86860d75c132b" dependencies = [ "async-trait", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-providers", - "ethers-signers", + "ethers-contract 0.17.0", + "ethers-core 0.17.0", + "ethers-etherscan 0.17.0", + "ethers-providers 0.17.0", + "ethers-signers 0.17.0", + "futures-locks", + "futures-util", + "instant", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-middleware" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e71df7391b0a9a51208ffb5c7f2d068900e99d6b3128d3a4849d138f194778b7" +dependencies = [ + "async-trait", + "auto_impl 0.5.0", + "ethers-contract 1.0.2", + "ethers-core 1.0.2", + "ethers-etherscan 1.0.2", + "ethers-providers 1.0.2", + "ethers-signers 1.0.2", "futures-locks", "futures-util", "instant", @@ -1796,9 +2078,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e46482e4d1e79b20c338fd9db9e166184eb387f0a4e7c05c5b5c0aa2e8c8900c" dependencies = [ "async-trait", - "auto_impl", + "auto_impl 1.0.1", + "base64 0.13.1", + "ethers-core 0.17.0", + "futures-core", + "futures-timer", + "futures-util", + "getrandom 0.2.8", + "hashers", + "hex", + "http", + "once_cell", + "parking_lot 0.11.2", + "pin-project", + "reqwest", + "serde", + "serde_json", + "thiserror", + "tokio", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-timer", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-providers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a9e0597aa6b2fdc810ff58bc95e4eeaa2c219b3e615ed025106ecb027407d8" +dependencies = [ + "async-trait", + "auto_impl 1.0.1", "base64 0.13.1", - "ethers-core", + "ethers-core 1.0.2", "futures-channel", "futures-core", "futures-timer", @@ -1836,8 +2153,26 @@ dependencies = [ "coins-bip32", "coins-bip39", "elliptic-curve", - "eth-keystore", - "ethers-core", + "eth-keystore 0.4.2", + "ethers-core 0.17.0", + "hex", + "rand 0.8.5", + "sha2 0.10.6", + "thiserror", +] + +[[package]] +name = "ethers-signers" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f41ced186867f64773db2e55ffdd92959e094072a1d09a5e5e831d443204f98" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "elliptic-curve", + "eth-keystore 0.5.0", + "ethers-core 1.0.2", "hex", "rand 0.8.5", "sha2 0.10.6", @@ -1853,7 +2188,7 @@ dependencies = [ "cfg-if 1.0.0", "colored", "dunce", - "ethers-core", + "ethers-core 0.17.0", "getrandom 0.2.8", "glob", "hex", @@ -1881,7 +2216,7 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4448c65b71e8e2b9718232d84d09045eeaaccb2320494e6bd6dbf7e58fec8ff" dependencies = [ - "auto_impl", + "auto_impl 1.0.1", "environmental", "ethereum", "evm-core", @@ -1926,7 +2261,7 @@ version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c79b9459ce64f1a28688397c4013764ce53cd57bb84efc16b5187fa9b05b13ad" dependencies = [ - "auto_impl", + "auto_impl 1.0.1", "environmental", "evm-core", "primitive-types 0.12.1", @@ -1944,6 +2279,16 @@ dependencies = [ "serde_json", ] +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "fake-simd" version = "0.1.2" @@ -1963,7 +2308,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "089263294bb1c38ac73649a6ad563dd9a5142c8dc0482be15b8b9acb22a1611e" dependencies = [ "arrayvec 0.7.2", - "auto_impl", + "auto_impl 1.0.1", "bytes", "ethereum-types 0.13.1", "fastrlp-derive", @@ -2926,6 +3271,12 @@ dependencies = [ "syn", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "indexmap" version = "1.9.2" @@ -2937,6 +3288,15 @@ dependencies = [ "serde", ] +[[package]] +name = "inout" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +dependencies = [ + "generic-array 0.14.6", +] + [[package]] name = "instant" version = "0.1.12" @@ -2979,7 +3339,7 @@ dependencies = [ "bus-mapping", "env_logger", "eth-types", - "ethers", + "ethers 0.17.0", "halo2_proofs", "hex", "lazy_static", @@ -3398,8 +3758,8 @@ name = "mock" version = "0.1.0" dependencies = [ "eth-types", - "ethers-core", - "ethers-signers", + "ethers-core 1.0.2", + "ethers-signers 1.0.2", "external-tracer", "itertools", "lazy_static", @@ -3579,6 +3939,31 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec 0.7.2", + "auto_impl 1.0.1", + "bytes", + "ethereum-types 0.14.1", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "os_str_bytes" version = "6.4.1" @@ -4669,7 +5054,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0c0fbb5f676da676c260ba276a8f43a8dc67cf02d1438423aeb1c677a7212686" dependencies = [ - "cipher", + "cipher 0.3.0", +] + +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher 0.4.4", ] [[package]] @@ -4746,7 +5140,19 @@ dependencies = [ "hmac 0.12.1", "password-hash 0.3.2", "pbkdf2 0.10.1", - "salsa20", + "salsa20 0.9.0", + "sha2 0.10.6", +] + +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac 0.12.1", + "pbkdf2 0.11.0", + "salsa20 0.10.2", "sha2 0.10.6", ] @@ -4859,6 +5265,16 @@ dependencies = [ "serde_json", ] +[[package]] +name = "serde-aux" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3dfe1b7eb6f9dcf011bd6fad169cdeaae75eda0d61b1a99a3f015b41b0cae39" +dependencies = [ + "serde", + "serde_json", +] + [[package]] name = "serde_cbor" version = "0.11.2" @@ -5688,8 +6104,8 @@ dependencies = [ "ctor", "env_logger", "eth-types", - "ethers-core", - "ethers-signers", + "ethers-core 1.0.2", + "ethers-signers 1.0.2", "external-tracer", "glob", "halo2_proofs", @@ -6122,6 +6538,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + [[package]] name = "unicode-width" version = "0.1.10" @@ -6756,14 +7178,15 @@ dependencies = [ name = "zkevm-circuits" version = "0.1.0" dependencies = [ + "ark-std", "array-init", "bus-mapping", "criterion", "ctor", "env_logger", "eth-types", - "ethers-core", - "ethers-signers", + "ethers-core 1.0.2", + "ethers-signers 1.0.2", "gadgets", "halo2_base", "halo2_ecc", diff --git a/bus-mapping/Cargo.toml b/bus-mapping/Cargo.toml index b70cb89917..8be1d4dc75 100644 --- a/bus-mapping/Cargo.toml +++ b/bus-mapping/Cargo.toml @@ -11,9 +11,9 @@ gadgets = { path = "../gadgets" } keccak256 = { path = "../keccak256" } mock = { path = "../mock", optional = true } -ethers-core = "0.17.0" -ethers-signers = "0.17.0" -ethers-providers = "0.17.0" +ethers-core = "1.0.2" +ethers-signers = "1.0.2" +ethers-providers = "1.0.2" halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } itertools = "0.10" lazy_static = "1.4" diff --git a/circuit-benchmarks/Cargo.toml b/circuit-benchmarks/Cargo.toml index 861cfc40f3..a59f805699 100644 --- a/circuit-benchmarks/Cargo.toml +++ b/circuit-benchmarks/Cargo.toml @@ -19,12 +19,13 @@ eth-types = { path = "../eth-types" } env_logger = "0.9" log="0.4" tokio = { version = "1.13", features = ["macros", "rt-multi-thread"] } -ethers-signers = "0.17.0" -ethers = { version = "0.17.0", features = ["ethers-solc"] } +ethers-signers = "1.0.2" +ethers = "1.0.2" mock = { path="../mock" } rand_chacha = "0.3" url="2.2.2" [features] -default = [] +default = ["benches"] benches = [] +onephase = [] \ No newline at end of file diff --git a/eth-types/Cargo.toml b/eth-types/Cargo.toml index a374bb9bad..914b972ac7 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 = "0.17.0" -ethers-signers = "0.17.0" +ethers-core = "1.0.2" +ethers-signers = "1.0.2" hex = "0.4" lazy_static = "1.4" halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } diff --git a/mock/Cargo.toml b/mock/Cargo.toml index 406341ab7d..dd4f3c2004 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 = "0.17.0" -ethers-core = "0.17.0" +ethers-signers = "1.0.2" +ethers-core = "1.0.2" rand_chacha = "0.3" rand = "0.8" diff --git a/mock/src/transaction.rs b/mock/src/transaction.rs index f230e14fee..6baae21531 100644 --- a/mock/src/transaction.rs +++ b/mock/src/transaction.rs @@ -77,6 +77,14 @@ lazy_static! { .gas_price(word!("0x4d2")) .input(Bytes::from(b"hello")) .build(), + MockTransaction::default() + .transaction_idx(7u64) + .from(AddrOrWallet::random(&mut rng)) + .to(AddrOrWallet::Addr(Address::zero())) + .nonce(word!("0x1234")) + .value(word!("0x54321")) + .gas_price(word!("0x100000000000")) + .build(), ] }; } diff --git a/testool/Cargo.toml b/testool/Cargo.toml index d8fbd1e17c..0aec1690db 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 = "0.17.0" -ethers-signers = "0.17.0" +ethers-core = "1.0.2" +ethers-signers = "1.0.2" external-tracer = { path="../external-tracer" } glob = "0.3" handlebars = "4.3" diff --git a/zkevm-circuits/Cargo.toml b/zkevm-circuits/Cargo.toml index bbe050607d..f586c54947 100644 --- a/zkevm-circuits/Cargo.toml +++ b/zkevm-circuits/Cargo.toml @@ -8,6 +8,7 @@ license = "MIT OR Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +ark-std = { version = "0.3", features = ["print-trace"] } halo2_proofs = { git = "https://github.com/privacy-scaling-explorations/halo2.git", tag = "v2023_02_02" } num = "0.4" sha3 = "0.10" @@ -15,8 +16,8 @@ array-init = "2.0.0" bus-mapping = { path = "../bus-mapping" } eth-types = { path = "../eth-types" } gadgets = { path = "../gadgets" } -ethers-core = "0.17.0" -ethers-signers = { version = "0.17.0", optional = true } +ethers-core = "1.0.2" +ethers-signers = { version = "1.0.2", optional = true } mock = { path = "../mock", optional = true } strum = "0.24" strum_macros = "0.24" @@ -44,17 +45,18 @@ rayon = "1.5" once_cell = "1.17.0" [dev-dependencies] +ark-std = { version = "0.3", features = ["print-trace"] } bus-mapping = { path = "../bus-mapping", features = ["test"] } criterion = "0.3" ctor = "0.1.22" -ethers-signers = "0.17.0" +ethers-signers = "1.0.2" hex = "0.4.3" itertools = "0.10.1" mock = { path = "../mock" } pretty_assertions = "1.0.0" [features] -default = ["test", "test-circuits", "onephase", "enable-sign-verify"] +default = ["test", "test-circuits"] test = ["ethers-signers", "mock"] test-circuits = [] warn-unimplemented = ["eth-types/warn-unimplemented"] diff --git a/zkevm-circuits/src/rlp_circuit.rs b/zkevm-circuits/src/rlp_circuit.rs index 5f19403ad9..094174114c 100644 --- a/zkevm-circuits/src/rlp_circuit.rs +++ b/zkevm-circuits/src/rlp_circuit.rs @@ -27,7 +27,7 @@ use halo2_proofs::{ // use crate::evm_circuit::table::FixedTableTag; use crate::util::{Challenges, SubCircuit, SubCircuitConfig}; use crate::witness::RlpTxTag::{ - ChainId, DataPrefix, Gas, GasPrice, Nonce, Prefix, SigR, SigS, SigV, To, + ChainId, DataPrefix, Gas, GasPrice, Nonce, SigR, SigS, SigV, To, TxPrefix, }; use crate::witness::{Block, Transaction}; use crate::{ @@ -40,10 +40,20 @@ use crate::{ witness::{RlpDataType, SignedTransaction}, }; +/// rlp witness byte +#[derive(Clone, Copy, Debug)] +pub struct RlpWitnessByte { + /// pure byte with place holder byte 00 + pub witness_byte: u8, + /// indicate the byte is place holder or not + pub place_holder: bool, +} + #[derive(Clone, Debug)] struct RlpTagROM { // TODO: we can merge these three cols into one col using LC as - // as their type are (u8, u8, u8) + // as their type are (u8, u8, u8, u8) + rlp_valid: Column, tag: Column, tag_next: Column, max_length: Column, @@ -70,8 +80,24 @@ pub struct RlpCircuitConfig { /// Placeholder row do not increase the index and mainly used for /// DataPrefix when |tx.data| = 1 and tx.data < 0x80. placeholder: Column, - /// Denotes the byte value at this row index from the RLP-encoded data. + /// Denotes the byte value at this row index depends on rlp valid or not. byte_value: Column, + /// Denotes whether or not the row is for decode logic. + /// TODO: combine with q_usable and make advice column if necessary + q_decode_usable: Column, + /// Denotes if the original rlp-encoded data is valid. + rlp_valid: Column, + /// Denotes the byte value at this row index from the original RLP-encoded + /// data. + input_byte_value: Column, + /// Denotes an accumulator for the byte value field over all input (bytes). + /// TODO: combine with the all_bytes_rlc_acc + input_bytes_rlc_acc: Column, + /// Denotes the bytes left, i.e., the r-index of the total input. + input_bytes_left: Column, + /// Denotes whether the decoding is ended, i.e., continously 1 from the + /// first padding row, otherwise 0. TODO: advice column + q_end_with_padding: Column, /// Denotes the RLC accumulator value used for call data bytes. calldata_bytes_rlc_acc: Column, /// Tag bits @@ -120,6 +146,26 @@ pub struct RlpCircuitConfig { value_lt_192: LtConfig, /// Lt chip to check: value < 248. value_lt_248: LtConfig, + // for input bytes value check + /// Lt chip to check: 127 < value. + input_value_gt_127: LtConfig, + /// Lt chip to check: 183 < value. + input_value_gt_183: LtConfig, + /// Lt chip to check: 191 < value. + input_value_gt_191: LtConfig, + /// Lt chip to check: 247 < value. + input_value_gt_247: LtConfig, + /// Lt chip to check: value < 129. + input_value_lt_129: LtConfig, + /// IsEq Chip to check: value == 128, + input_value_eq_128: IsEqualConfig, + /// Lt chip to check: value < 184. + input_value_lt_184: LtConfig, + /// Lt chip to check: value < 192. + input_value_lt_192: LtConfig, + /// Lt chip to check: value < 248. + input_value_lt_248: LtConfig, + /// Comparison chip to check: 0 <= length_acc. length_acc_cmp_0: ComparatorConfig, } @@ -137,6 +183,12 @@ impl RlpCircuitConfig { let rindex = meta.advice_column(); let placeholder = meta.advice_column(); let byte_value = meta.advice_column(); + let q_decode_usable = meta.fixed_column(); + let rlp_valid = meta.advice_column(); + let input_byte_value = meta.advice_column(); + let input_bytes_rlc_acc = meta.advice_column_in(SecondPhase); + let input_bytes_left = meta.advice_column(); + let q_end_with_padding = meta.fixed_column(); let calldata_bytes_rlc_acc = meta.advice_column_in(SecondPhase); let tag_length = meta.advice_column(); let length_acc = meta.advice_column(); @@ -150,11 +202,38 @@ impl RlpCircuitConfig { let is_dp_tag = meta.advice_column(); let tag_bits = BinaryNumberChip::configure(meta, q_usable, Some(rlp_table.tag)); let tag_rom = RlpTagROM { + rlp_valid: meta.fixed_column(), tag: meta.fixed_column(), tag_next: meta.fixed_column(), max_length: meta.fixed_column(), }; + macro_rules! debug_print { + ($column:expr) => { + log::debug!("locate {}: {:?}", stringify!($column), $column); + }; + } + + debug_print!(&q_usable); + debug_print!(&is_first); + debug_print!(&is_last); + debug_print!(&index); + debug_print!(&rindex); + debug_print!(&placeholder); + debug_print!(&byte_value); + debug_print!(&q_decode_usable); + debug_print!(&rlp_valid); + debug_print!(&input_byte_value); + debug_print!(&input_bytes_rlc_acc); + debug_print!(&input_bytes_left); + debug_print!(&q_end_with_padding); + debug_print!(&calldata_bytes_rlc_acc); + debug_print!(&tag_length); + debug_print!(&length_acc); + debug_print!(&all_bytes_rlc_acc); + debug_print!(&evm_word_rand); + debug_print!(&keccak_input_rand); + // Helper macro to declare booleans to check the current row tag. macro_rules! is_tx_tag { ($var:ident, $tag_variant:ident) => { @@ -163,7 +242,8 @@ impl RlpCircuitConfig { }; }; } - is_tx_tag!(is_prefix, Prefix); + is_tx_tag!(is_decode_prefix_tag, TxListPrefix); + is_tx_tag!(is_tx_prefix, TxPrefix); is_tx_tag!(is_nonce, Nonce); is_tx_tag!(is_gas_price, GasPrice); is_tx_tag!(is_gas, Gas); @@ -294,7 +374,7 @@ impl RlpCircuitConfig { ]); vec![ q_usable.expr() * (is_simple_tag - tags), - q_usable.expr() * (is_prefix_tag - is_prefix(meta)), + q_usable.expr() * (is_prefix_tag - is_tx_prefix(meta)), q_usable.expr() * (is_data_prefix_tag - is_data_prefix(meta)), ] }); @@ -359,7 +439,7 @@ impl RlpCircuitConfig { cb.require_equal( "tag::next == RlpTxTag::Prefix", meta.query_advice(rlp_table.tag, Rotation::next()), - RlpTxTag::Prefix.expr(), + RlpTxTag::TxPrefix.expr(), ); cb.require_equal( "tag_index::next == tag_index - 1", @@ -385,11 +465,11 @@ impl RlpCircuitConfig { meta.query_advice(rlp_table.tag_rindex, Rotation::next()), meta.query_advice(tag_length, Rotation::next()), ); - // we add +1 to account for the 2 additional rows for RlpLength and Rlp. + // no more RlpLength & Rlp cb.require_equal( - "rindex::next == length_acc + 1", + "rindex::next == length_acc", meta.query_advice(rindex, Rotation::next()), - meta.query_advice(length_acc, Rotation::cur()) + 1.expr(), + meta.query_advice(length_acc, Rotation::cur()) - 1.expr(), ); }); @@ -905,42 +985,44 @@ impl RlpCircuitConfig { // rindex == 0 for the end of an RLP(TxHash) instance cb.require_equal( "next(2) tag is Rlp => rindex == 0", - meta.query_advice(rindex, Rotation(2)), + meta.query_advice(rindex, Rotation::cur()), 0.expr(), ); - // RlpTxTag::RlpLength checks. - cb.require_equal( - "next tag is RlpLength", - meta.query_advice(rlp_table.tag, Rotation::next()), - RlpTxTag::RlpLength.expr(), - ); - cb.require_equal( - "tag_rindex::next == 1", - meta.query_advice(rlp_table.tag_rindex, Rotation::next()), - 1.expr(), - ); - cb.require_equal( - "tag::next == RlpLength => value_acc::next == index::cur", - meta.query_advice(rlp_table.value_acc, Rotation::next()), - meta.query_advice(index, Rotation::cur()), - ); - - // RlpTxTag::Rlp checks. - cb.require_equal( - "tag::Rotation(2) == RlpTxTag::Rlp", - meta.query_advice(rlp_table.tag, Rotation(2)), - RlpTxTag::Rlp.expr(), - ); - cb.require_equal( - "last tag is Rlp => value_acc::Rotation(2) == all_bytes_rlc_acc::cur()", - meta.query_advice(rlp_table.value_acc, Rotation(2)), - meta.query_advice(all_bytes_rlc_acc, Rotation::cur()), - ); - cb.require_equal( - "is_last::Rotation(2) == 1", - meta.query_advice(is_last, Rotation(2)), - 1.expr(), - ); + // // RlpTxTag::RlpLength checks. + // cb.require_equal( + // "next tag is RlpLength", + // meta.query_advice(rlp_table.tag, Rotation::next()), + // RlpTxTag::RlpLength.expr(), + // ); + // cb.require_equal( + // "tag_rindex::next == 1", + // meta.query_advice(rlp_table.tag_rindex, + // Rotation::next()), 1.expr(), + // ); + // cb.require_equal( + // "tag::next == RlpLength => value_acc::next == + // index::cur", meta.query_advice(rlp_table. + // value_acc, Rotation::next()), + // meta.query_advice(index, Rotation::cur()), + // ); + + // // RlpTxTag::Rlp checks. + // cb.require_equal( + // "tag::Rotation(2) == RlpTxTag::Rlp", + // meta.query_advice(rlp_table.tag, Rotation(2)), + // RlpTxTag::Rlp.expr(), + // ); + // cb.require_equal( + // "last tag is Rlp => value_acc::Rotation(2) == + // all_bytes_rlc_acc::cur()", + // meta.query_advice(rlp_table.value_acc, Rotation(2)), + // meta.query_advice(all_bytes_rlc_acc, Rotation::cur()), + // ); + // cb.require_equal( + // "is_last::Rotation(2) == 1", + // meta.query_advice(is_last, Rotation(2)), + // 1.expr(), + // ); }); cb.gate(and::expr(vec![ @@ -1012,7 +1094,8 @@ impl RlpCircuitConfig { cb.require_equal( "all_bytes_rlc_acc' == (all_bytes_rlc_acc * r) + byte_value'", meta.query_advice(all_bytes_rlc_acc, Rotation::next()), - meta.query_advice(all_bytes_rlc_acc, Rotation::cur()) * keccak_input_rand + meta.query_advice(all_bytes_rlc_acc, Rotation::cur()) + * keccak_input_rand.clone() + meta.query_advice(byte_value, Rotation::next()), ); }, @@ -1038,6 +1121,11 @@ impl RlpCircuitConfig { meta.query_advice(byte_value, Rotation::next()), meta.query_advice(byte_value, Rotation::cur()), ); + cb.require_equal( + "input_bytes_rlc_acc' == input_bytes_rlc_acc", + meta.query_advice(input_bytes_rlc_acc, Rotation::next()), + meta.query_advice(input_bytes_rlc_acc, Rotation::cur()), + ); }); cb.require_equal( @@ -1084,75 +1172,71 @@ impl RlpCircuitConfig { meta.create_gate("is_last == 1", |meta| { let mut cb = BaseConstraintBuilder::new(9); - cb.require_equal( - "is_last == 1 then tag == RlpTxTag::Rlp", - meta.query_advice(rlp_table.tag, Rotation::cur()), - RlpTxTag::Rlp.expr(), - ); + // cb.require_equal( + // "is_last == 1 then tag == RlpTxTag::Rlp", + // meta.query_advice(rlp_table.tag, Rotation::cur()), + // RlpTxTag::Rlp.expr(), + // ); + // no TxHash -> TxSign switch // if data_type::cur == TxHash // - tx_id does not change. // - TxSign rows follow. - cb.condition( - meta.query_advice(rlp_table.data_type, Rotation::cur()), - |cb| { - cb.require_equal( - "tx_id does not change", - meta.query_advice(rlp_table.tx_id, Rotation::cur()), - meta.query_advice(rlp_table.tx_id, Rotation::next()), - ); - cb.require_equal( - "TxSign rows follow TxHash rows", - meta.query_advice(rlp_table.data_type, Rotation::next()), - RlpDataType::TxSign.expr(), - ); - cb.require_equal( - "TxSign rows' first row is Prefix again", - meta.query_advice(rlp_table.tag, Rotation::next()), - RlpTxTag::Prefix.expr(), - ); - cb.require_equal( - "TxSign rows' first row starts with rlp_table.tag_rindex = tag_length", - meta.query_advice(rlp_table.tag_rindex, Rotation::next()), - meta.query_advice(tag_length, Rotation::next()), - ); - }, - ); - + // cb.condition( + // meta.query_advice(rlp_table.data_type, Rotation::cur()), + // |cb| { + // cb.require_equal( + // "tx_id does not change", + // meta.query_advice(rlp_table.tx_id, Rotation::cur()), + // meta.query_advice(rlp_table.tx_id, Rotation::next()), + // ); + // cb.require_equal( + // "TxSign rows follow TxHash rows", + // meta.query_advice(rlp_table.data_type, Rotation::next()), + // RlpDataType::TxSign.expr(), + // ); + // cb.require_equal( + // "TxSign rows' first row is Prefix again", + // meta.query_advice(rlp_table.tag, Rotation::next()), + // RlpTxTag::TxPrefix.expr(), + // ); + // cb.require_equal( + // "TxSign rows' first row starts with rlp_table.tag_rindex = + // tag_length", meta.query_advice(rlp_table.tag_rindex, + // Rotation::next()), meta.query_advice(tag_length, + // Rotation::next()), ); + // }, + // ); + + // no TxSign, so is_last ahead to next TxHash // if data_type::cur == TxSign and it was **not** // the last tx in the layout (tag::next != Padding) // - tx_id increments. // - TxHash rows follow. let is_tag_next_padding = tag_bits.value_equals(RlpTxTag::Padding, Rotation::next())(meta); - cb.condition( - and::expr(vec![ - not::expr(meta.query_advice(rlp_table.data_type, Rotation::cur())), - not::expr(is_tag_next_padding), - ]), - |cb| { - cb.require_equal( - "tx_id increments", - meta.query_advice(rlp_table.tx_id, Rotation::cur()) + 1.expr(), - meta.query_advice(rlp_table.tx_id, Rotation::next()), - ); - cb.require_equal( - "TxHash rows follow TxSign rows", - meta.query_advice(rlp_table.data_type, Rotation::next()), - RlpDataType::TxHash.expr(), - ); - cb.require_equal( - "TxHash rows' first row is Prefix again", - meta.query_advice(rlp_table.tag, Rotation::next()), - RlpTxTag::Prefix.expr(), - ); - cb.require_equal( - "TxSign rows' first row starts with rlp_table.tag_rindex = tag_length", - meta.query_advice(rlp_table.tag_rindex, Rotation::next()), - meta.query_advice(tag_length, Rotation::next()), - ); - }, - ); + cb.condition(not::expr(is_tag_next_padding), |cb| { + cb.require_equal( + "tx_id increments", + meta.query_advice(rlp_table.tx_id, Rotation::cur()) + 1.expr(), + meta.query_advice(rlp_table.tx_id, Rotation::next()), + ); + cb.require_equal( + "TxHash rows follow TxSign rows", + meta.query_advice(rlp_table.data_type, Rotation::next()), + RlpDataType::TxHash.expr(), + ); + cb.require_equal( + "TxHash rows' first row is Prefix again", + meta.query_advice(rlp_table.tag, Rotation::next()), + RlpTxTag::TxPrefix.expr(), + ); + cb.require_equal( + "TxSign rows' first row starts with rlp_table.tag_rindex = tag_length", + meta.query_advice(rlp_table.tag_rindex, Rotation::next()), + meta.query_advice(tag_length, Rotation::next()), + ); + }); cb.gate(and::expr(vec![ meta.query_fixed(q_usable, Rotation::cur()), @@ -1186,156 +1270,701 @@ impl RlpCircuitConfig { "value_acc == 0", meta.query_advice(rlp_table.value_acc, Rotation::cur()), ); + cb.require_zero( + "input_bytes_left == 0", + meta.query_advice(input_bytes_left, Rotation::cur()), + ); }); cb.gate(meta.query_fixed(q_usable, Rotation::cur())) }); - Self { - minimum_rows: meta.minimum_rows(), - q_usable, - is_first, - is_last, - rlp_table: *rlp_table, - index, - rindex, - placeholder, - byte_value, - calldata_bytes_rlc_acc, - tag_bits, - tag_rom, - tag_length, - length_acc, - all_bytes_rlc_acc, - is_simple_tag, - is_prefix_tag, - is_dp_tag, - tag_index_cmp_1, - tag_index_length_cmp, - tag_length_cmp_1, - tag_index_lt_10, - tag_index_lt_34, - value_gt_127, - value_gt_183, - value_gt_191, - value_gt_247, - value_lt_129, - value_eq_128, - value_lt_184, - value_lt_192, - value_lt_248, - length_acc_cmp_0, - } - } + ////////////////////////////////////////////////////////////////////////// + ///// Below are constraints for rlp decoding & validness check /////////// + ////////////////////////////////////////////////////////////////////////// + // Step 1: copy input data to output table according to rlp_valid flag + meta.create_gate("process input data to output table", |meta| { + let mut cb = BaseConstraintBuilder::new(5); + let curr_byte_value = meta.query_advice(byte_value, Rotation::cur()); + let curr_input_byte = meta.query_advice(input_byte_value, Rotation::cur()); + let is_rlp_valid = meta.query_advice(rlp_valid, Rotation::cur()); + + // output_table == decoded_table * rlp_valid + // TODO: could be ifx/elsex + let is_first = meta.query_advice(is_first, Rotation::cur()); + cb.condition(not::expr(is_first.expr()), |cb| { + cb.require_equal( + "input bytes == rlp.bytes * rlp_valid", + curr_byte_value.clone(), + curr_input_byte.clone() * is_rlp_valid.clone(), + ); + }); - pub(crate) fn assign( - &self, - layouter: &mut impl Layouter, - signed_txs: &[SignedTransaction], - k: usize, - challenges: &Challenges>, - ) -> Result<(), Error> { - let keccak_input_rand = challenges.keccak_input(); - let tag_chip = BinaryNumberChip::construct(self.tag_bits); - let tag_index_cmp_1_chip = ComparatorChip::construct(self.tag_index_cmp_1.clone()); - let tag_index_length_cmp_chip = - ComparatorChip::construct(self.tag_index_length_cmp.clone()); - let tag_length_cmp_1_chip = ComparatorChip::construct(self.tag_length_cmp_1.clone()); + cb.condition(not::expr(is_rlp_valid.clone()) * is_first.expr(), |cb| { + cb.require_equal( + "input bytes [0] == 148 if not valid", + curr_byte_value.clone(), + 148.expr(), + ); + }); - let tag_index_lt_10_chip = LtChip::construct(self.tag_index_lt_10); - let tag_index_lt_34_chip = LtChip::construct(self.tag_index_lt_34); + cb.condition(is_rlp_valid.expr() * is_first.expr(), |cb| { + cb.require_equal( + "input bytes == rlp.bytes * rlp_valid", + curr_byte_value.clone(), + curr_input_byte.clone() * is_rlp_valid.clone(), + ); + }); - let value_gt_127_chip = LtChip::construct(self.value_gt_127); - let value_gt_183_chip = LtChip::construct(self.value_gt_183); - let value_gt_191_chip = LtChip::construct(self.value_gt_191); - let value_gt_247_chip = LtChip::construct(self.value_gt_247); - let value_lt_129_chip = LtChip::construct(self.value_lt_129); - let value_eq_128_chip = IsEqualChip::construct(self.value_eq_128.clone()); - let value_lt_184_chip = LtChip::construct(self.value_lt_184); - let value_lt_192_chip = LtChip::construct(self.value_lt_192); - let value_lt_248_chip = LtChip::construct(self.value_lt_248); + cb.condition( + and::expr([ + not::expr(meta.query_fixed(q_end_with_padding, Rotation::next())), + not::expr(meta.query_advice(placeholder, Rotation::cur())), + ]), + |cb| { + cb.require_equal( + "input_bytes_rlc_acc' == (input_bytes_rlc_acc * r) + byte_value'", + meta.query_advice(input_bytes_rlc_acc, Rotation::next()), + meta.query_advice(input_bytes_rlc_acc, Rotation::cur()) + * keccak_input_rand.clone() + + meta.query_advice(input_byte_value, Rotation::next()), + ); + }, + ); - let length_acc_cmp_0_chip = ComparatorChip::construct(self.length_acc_cmp_0.clone()); + let q_decode_usable = meta.query_fixed(q_decode_usable, Rotation::cur()); + cb.gate(q_decode_usable) + }); - debug_assert!( - k >= self.minimum_rows, - "k: {}, minimum_rows: {}", - k, - self.minimum_rows, - ); - let padding_end_offset = k - self.minimum_rows + 1; - layouter.assign_region( - || "assign tag rom", - |mut region| { - for (i, (tag, tag_next, max_length)) in [ - (RlpTxTag::Nonce, RlpTxTag::GasPrice, 10), - (RlpTxTag::GasPrice, RlpTxTag::Gas, 34), - (RlpTxTag::Gas, RlpTxTag::To, 10), - (RlpTxTag::To, RlpTxTag::Value, 22), - (RlpTxTag::Value, RlpTxTag::DataPrefix, 34), - (RlpTxTag::ChainId, RlpTxTag::Zero, 10), - (RlpTxTag::SigV, RlpTxTag::SigR, 10), - (RlpTxTag::SigR, RlpTxTag::SigS, 34), - (RlpTxTag::SigS, RlpTxTag::RlpLength, 34), - ] - .into_iter() - .enumerate() - { - let offset = i; - region.assign_fixed( - || "tag", - self.tag_rom.tag, - offset, - || Value::known(F::from(tag as u64)), - )?; - region.assign_fixed( - || "tag_next", - self.tag_rom.tag_next, - offset, - || Value::known(F::from(tag_next as u64)), - )?; - region.assign_fixed( - || "max_length", - self.tag_rom.max_length, - offset, - || Value::known(F::from(max_length)), - )?; - } + // Step 2: constraint decoding tag transition + meta.lookup_any("decoded (valid, tag, tag_next) in tag_ROM", |meta| { + let is_rlp_valid = meta.query_advice(rlp_valid, Rotation::cur()); + let tag = meta.query_advice(rlp_table.tag, Rotation::cur()); + let tag_next = meta.query_advice(rlp_table.tag, Rotation::next()); + let rom_rlp_valid = meta.query_fixed(tag_rom.rlp_valid, Rotation::cur()); + let rom_tag = meta.query_fixed(tag_rom.tag, Rotation::cur()); + let rom_tag_next = meta.query_fixed(tag_rom.tag_next, Rotation::cur()); + let q_decode_usable = meta.query_fixed(q_decode_usable, Rotation::cur()); + let (_, tag_idx_eq_one) = tag_index_cmp_1.expr(meta, None); + let condition = q_decode_usable * tag_idx_eq_one; - Ok(()) - }, - )?; + vec![ + (condition.expr() * is_rlp_valid, rom_rlp_valid), + (condition.expr() * tag, rom_tag), + (condition * tag_next, rom_tag_next), + ] + }); - layouter.assign_region( - || "assign RLP-encoded data", - |mut region| { - let mut offset = 0; - let simple_tags = [ - Nonce, - GasPrice, - Gas, - To, - RlpTxTag::Value, - SigV, - SigR, - SigS, - ChainId, - ]; + // Re-apply key common contraints to decoding column + // This makes sure that rlp_valid is correctly set as this part computers the + // rlp_valid. + // Actually we only checks the decoding length and tag switching because these + // are merely the 2 possbile ways. + // 1. check length. (by length_acc) + // 2. check tag movement. (by lookup) + macro_rules! make_value_cmp_gadget { + ($var:ident > $num:expr) => { + let $var = LtChip::configure( + meta, + cmp_lt_enabled, + |_meta| $num.expr(), + |meta| meta.query_advice(input_byte_value, Rotation::cur()), + ); + }; + ($var:ident < $num:expr) => { + let $var = LtChip::configure( + meta, + cmp_lt_enabled, + |meta| meta.query_advice(input_byte_value, Rotation::cur()), + |_meta| $num.expr(), + ); + }; + ($var:ident == $num:expr) => { + let $var = IsEqualChip::configure( + meta, + cmp_lt_enabled, + |meta| meta.query_advice(input_byte_value, Rotation::cur()), + |_meta| $num.expr(), + ); + }; + } - for (signed_tx_idx, signed_tx) in signed_txs.iter().enumerate() { - if signed_tx.tx.hash != get_dummy_tx_hash(signed_tx.tx.chain_id) { - log::debug!( - "rlp circuit assign {}th tx at offset:{}, tx hash {:?}", - signed_tx_idx, - offset, - signed_tx.tx.hash - ); - } - // tx hash (signed tx) - let mut all_bytes_rlc_acc = Value::known(F::zero()); - let tx_hash_rows = signed_tx.gen_witness(challenges); - let has_placeholder = - signed_tx.tx.call_data.len() == 1 && signed_tx.tx.call_data[0] < 0x80; + make_value_cmp_gadget!(input_value_gt_247 > 247); + make_value_cmp_gadget!(input_value_gt_127 > 127); + make_value_cmp_gadget!(input_value_gt_183 > 183); + make_value_cmp_gadget!(input_value_gt_191 > 191); + make_value_cmp_gadget!(input_value_lt_129 < 129); + make_value_cmp_gadget!(input_value_eq_128 == 128); + make_value_cmp_gadget!(input_value_lt_184 < 184); + make_value_cmp_gadget!(input_value_lt_192 < 192); + make_value_cmp_gadget!(input_value_lt_248 < 248); + + meta.create_gate("Common constraints for decoding columns", |meta| { + let mut cb = BaseConstraintBuilder::new(10); + + let (tindex_lt, tindex_eq) = tag_index_cmp_1.expr(meta, None); + assert_eq!(tindex_lt.degree(), 1, "{}", tindex_lt.degree()); + assert_eq!(tindex_eq.degree(), 2, "{}", tindex_lt.degree()); + let (tlength_lt, tlength_eq) = tag_length_cmp_1.expr(meta, None); + let (tindex_lt_tlength, tindex_eq_tlength) = tag_index_length_cmp.expr(meta, None); + let (_, length_acc_eq_0) = length_acc_cmp_0.expr(meta, None); + let is_simple_tag = meta.query_advice(is_simple_tag, Rotation::cur()); + let is_dp_tag = meta.query_advice(is_dp_tag, Rotation::cur()); + let is_rlp_valid = meta.query_advice(rlp_valid, Rotation::cur()); + + ////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////// RlpHeaderTag::Prefix ////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + // TODO: merge to tx prefix + cb.condition(is_decode_prefix_tag(meta), |cb| { + // tag_index < 10 + cb.require_equal( + "tag_index < 10", + tag_index_lt_10.is_lt(meta, None), + 1.expr(), + ); + + // tag_index >= 1 + cb.require_zero( + "tag_index >= 1", + not::expr(or::expr([tindex_lt.clone(), tindex_eq.clone()])), + ); + }); + + // if tag_index > 1 + cb.condition(is_decode_prefix_tag(meta) * tindex_lt.clone() * is_rlp_valid.clone(), |cb| { + cb.require_equal( + "tag::next == RlpTxTag::TxListPrefix", + meta.query_advice(rlp_table.tag, Rotation::next()), + RlpTxTag::TxListPrefix.expr(), + ); + cb.require_equal( + "tag_index::next == tag_index - 1", + meta.query_advice(rlp_table.tag_rindex, Rotation::next()), + meta.query_advice(rlp_table.tag_rindex, Rotation::cur()) - 1.expr(), + ); + cb.require_equal( + "tag_length::next == tag_length", + meta.query_advice(tag_length, Rotation::next()), + meta.query_advice(tag_length, Rotation::cur()), + ); + }); + + // if tag_index == 1, RlpArrayPrefix -> RlpTxPrefix (another array prefix for legacy Tx) + cb.condition(is_decode_prefix_tag(meta) * tindex_eq.clone() * is_rlp_valid.clone(), |cb| { + cb.require_equal( + "next row below array prefix is tx prefix", + meta.query_advice(is_prefix_tag, Rotation::next()), + 1.expr(), + ); + // cb.require_equal( + // "tag::next == RlpTxTag::TxPrefix", + // meta.query_advice(rlp_table.tag, Rotation::next()), + // RlpTxTag::TxPrefix.expr(), + // ); + cb.require_equal( + "tag_index::next == tag_length::next", + meta.query_advice(rlp_table.tag_rindex, Rotation::next()), + meta.query_advice(tag_length, Rotation::next()), + ); + cb.require_equal( + "byte_left::curr == length_acc", + meta.query_advice(input_bytes_left, Rotation::cur()), + meta.query_advice(length_acc, Rotation::cur()), + ); + }); + + // if tag_index == tag_length && tag_length > 1 + cb.condition( + is_decode_prefix_tag(meta) * tindex_eq_tlength.clone() * tlength_lt.clone() * is_rlp_valid.clone(), + |cb| { + cb.require_equal("247 < input_value", input_value_gt_247.is_lt(meta, None), 1.expr()); + // cb.require_equal("value < 256", value_lt_256.is_lt(meta, None), 1.expr()); + cb.require_equal( + "tag_index::next == value - 0xf7", + meta.query_advice(rlp_table.tag_rindex, Rotation::next()), + meta.query_advice(byte_value, Rotation::cur()) - 247.expr(), + ); + cb.require_zero( + "length_acc == 0", + meta.query_advice(length_acc, Rotation::cur()), + ); + }, + ); + + // if tag_index < tag_length && tag_length > 1 + cb.condition( + is_decode_prefix_tag(meta) * tindex_lt_tlength.clone() * tlength_lt.clone() * is_rlp_valid.clone(), + |cb| { + cb.require_equal( + "length_acc == (length_acc::prev * 256) + value", + meta.query_advice(length_acc, Rotation::cur()), + meta.query_advice(length_acc, Rotation::prev()) * 256.expr() + + meta.query_advice(byte_value, Rotation::cur()), + ); + }, + ); + + // check the value is decodable. + cb.condition( + is_decode_prefix_tag(meta) * tindex_eq_tlength.clone() * tlength_lt.clone(), + |cb| { + cb.require_equal("247 < input_value", input_value_gt_247.is_lt(meta, None), is_rlp_valid.clone()); + }, + ); + + // bytes left count-down if 2 rows are not padding + cb.condition( + and::expr([ + not::expr(is_padding(meta)), + not::expr(meta.query_fixed(q_end_with_padding, Rotation::next()))]), + |cb| { + cb.require_equal( + "input_bytes_left::next == input_bytes_left::cur - 1", + meta.query_advice(input_bytes_left, Rotation::next()), + meta.query_advice(input_bytes_left, Rotation::cur()) - 1.expr(), + ); + }, + ); + + // rlp_valid keeps unchanged if next row is not padding + cb.condition( + not::expr(meta.query_fixed(q_end_with_padding, Rotation::next())), + |cb| { + cb.require_equal( + "rlp_valid keeps unchanged", + is_rlp_valid.clone(), + meta.query_advice(rlp_valid, Rotation::next()), + ); + }, + ); + + ////////////////////////////////////////////////////////////////////////////////////// + //////// RlpTxTag::Nonce, GasPrice, Gas, To, Value, ChainID, SigV, SigR, SigS //////// + ////////////////////////////////////////////////////////////////////////////////////// + // if tag_index == tag_length && tag_length == 1 + cb.condition( + is_simple_tag.clone() * tindex_eq_tlength.clone() * tlength_eq.clone(), + |cb| { + cb.require_equal("byte_value < 129", input_value_lt_129.is_lt(meta, None), is_rlp_valid.clone()); + }, + ); + + // if tag_index == tag_length && tag_length > 1 + cb.condition( + is_simple_tag.clone() * tindex_eq_tlength.clone() * tlength_lt.clone(), + |cb| { + cb.require_equal("127 < value", input_value_gt_127.is_lt(meta, None), is_rlp_valid.clone()); + cb.require_equal("value < 184", input_value_lt_184.is_lt(meta, None), is_rlp_valid.clone()); + }, + ); + + ////////////////////////////////////////////////////////////////////////////////////// + ///////////////////////////////// RlpTxTag::DataPrefix /////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + // if length_acc == 0 + // support txHash type only + cb.condition( + is_dp_tag.expr() * tindex_eq.clone() * length_acc_eq_0, + |cb| { + cb.require_boolean("TxHash type RLP only", meta.query_advice(rlp_table.data_type, Rotation::cur()) + - RlpDataType::TxSign.expr()); + } + ); + + // if tag_index == tag_length && tag_length > 1 + cb.condition( + is_dp_tag.expr() * tindex_eq_tlength.clone() * tlength_lt.clone(), + |cb| { + cb.require_equal("value > 183", input_value_gt_183.is_lt(meta, None), is_rlp_valid.clone()); + cb.require_equal("value < 192", input_value_lt_192.is_lt(meta, None), is_rlp_valid.clone()); + }, + ); + + // if tag_index == tag_length && tag_length == 1 + cb.condition( + is_dp_tag.expr() * tindex_eq_tlength * tlength_eq, + |cb| { + cb.require_equal("value < 184", input_value_lt_184.is_lt(meta, None), is_rlp_valid.clone()); + }, + ); + + ////////////////////////////////////////////////////////////////////////////////////// + //////////////////////////////////// RlpTxTag::Data ////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + // null constraint for data + + cb.gate(meta.query_fixed(q_decode_usable, Rotation::cur())) + }); + + //////////////////////////////////////////////////////////////// + /////////////////// RlpTxTag::Padding ////////////////////////// + //////////////////////////////////////////////////////////////// + // last row of the tabl must be padding. + meta.create_gate("bytes_left to 0 and circuit end with padding", |meta| { + let mut cb = BaseConstraintBuilder::new(5); + let q_decode_usable_curr = meta.query_fixed(q_decode_usable, Rotation::cur()); + let curr_q_end_with_padding = meta.query_fixed(q_end_with_padding, Rotation::cur()); + let next_q_end_with_padding = meta.query_fixed(q_end_with_padding, Rotation::next()); + let bytes_left = meta.query_advice(input_bytes_left, Rotation::cur()); + + cb.require_boolean("q_end is bool", next_q_end_with_padding.clone()); + + cb.condition(next_q_end_with_padding.expr(), |cb| { + cb.require_zero("no bytes left", bytes_left); + + cb.require_equal( + "q_end_with_padding after last q_usable", + q_decode_usable_curr.clone(), + 1.expr(), + ); + }); + + // TODO: at least one padding if not fixed q_end_with_padding + cb.require_equal( + "circuit end with padding", + curr_q_end_with_padding.clone(), + is_padding(meta), + ); + + cb.gate(q_decode_usable_curr.clone()) + }); + + Self { + minimum_rows: meta.minimum_rows(), + q_usable, + is_first, + is_last, + rlp_table: *rlp_table, + index, + rindex, + placeholder, + byte_value, + q_decode_usable, + rlp_valid, + input_byte_value, + input_bytes_rlc_acc, + input_bytes_left, + q_end_with_padding, + calldata_bytes_rlc_acc, + tag_bits, + tag_rom, + tag_length, + length_acc, + all_bytes_rlc_acc, + is_simple_tag, + is_prefix_tag, + is_dp_tag, + tag_index_cmp_1, + tag_index_length_cmp, + tag_length_cmp_1, + tag_index_lt_10, + tag_index_lt_34, + value_gt_127, + value_gt_183, + value_gt_191, + value_gt_247, + value_lt_129, + value_eq_128, + value_lt_184, + value_lt_192, + value_lt_248, + input_value_gt_127, + input_value_gt_183, + input_value_gt_191, + input_value_gt_247, + input_value_lt_129, + input_value_eq_128, + input_value_lt_184, + input_value_lt_192, + input_value_lt_248, + length_acc_cmp_0, + } + } + + pub(crate) fn assign( + &self, + layouter: &mut impl Layouter, + input_bytes: &[RlpWitnessByte], + valid: bool, + signed_txs: &[SignedTransaction], + k: usize, + challenges: &Challenges>, + ) -> Result<(), Error> { + let keccak_input_rand = challenges.keccak_input(); + let tag_chip = BinaryNumberChip::construct(self.tag_bits); + let tag_index_cmp_1_chip = ComparatorChip::construct(self.tag_index_cmp_1.clone()); + let tag_index_length_cmp_chip = + ComparatorChip::construct(self.tag_index_length_cmp.clone()); + let tag_length_cmp_1_chip = ComparatorChip::construct(self.tag_length_cmp_1.clone()); + + let tag_index_lt_10_chip = LtChip::construct(self.tag_index_lt_10); + let tag_index_lt_34_chip = LtChip::construct(self.tag_index_lt_34); + + let value_gt_127_chip = LtChip::construct(self.value_gt_127); + let value_gt_183_chip = LtChip::construct(self.value_gt_183); + let value_gt_191_chip = LtChip::construct(self.value_gt_191); + let value_gt_247_chip = LtChip::construct(self.value_gt_247); + let value_lt_129_chip = LtChip::construct(self.value_lt_129); + let value_eq_128_chip = IsEqualChip::construct(self.value_eq_128.clone()); + let value_lt_184_chip = LtChip::construct(self.value_lt_184); + let value_lt_192_chip = LtChip::construct(self.value_lt_192); + let value_lt_248_chip = LtChip::construct(self.value_lt_248); + + let length_acc_cmp_0_chip = ComparatorChip::construct(self.length_acc_cmp_0.clone()); + + // input bytes related + let input_value_gt_127_chip = LtChip::construct(self.input_value_gt_127); + let input_value_gt_183_chip = LtChip::construct(self.input_value_gt_183); + let input_value_gt_191_chip = LtChip::construct(self.input_value_gt_191); + let input_value_gt_247_chip = LtChip::construct(self.input_value_gt_247); + let input_value_lt_129_chip = LtChip::construct(self.input_value_lt_129); + let input_value_eq_128_chip = IsEqualChip::construct(self.input_value_eq_128.clone()); + let input_value_lt_184_chip = LtChip::construct(self.input_value_lt_184); + let input_value_lt_192_chip = LtChip::construct(self.input_value_lt_192); + let input_value_lt_248_chip = LtChip::construct(self.input_value_lt_248); + + debug_assert!( + k >= self.minimum_rows, + "k: {}, minimum_rows: {}", + k, + self.minimum_rows, + ); + let padding_end_offset = k - self.minimum_rows + 1; + layouter.assign_region( + || "assign tag rom", + |mut region| { + for (i, (rlp_valid, tag, tag_next, max_length)) in [ + (true, RlpTxTag::Nonce, RlpTxTag::GasPrice, 10), + (true, RlpTxTag::GasPrice, RlpTxTag::Gas, 34), + (true, RlpTxTag::Gas, RlpTxTag::To, 10), + (true, RlpTxTag::To, RlpTxTag::Value, 22), + (true, RlpTxTag::Value, RlpTxTag::DataPrefix, 34), + (true, RlpTxTag::ChainId, RlpTxTag::Zero, 10), + (true, RlpTxTag::DataPrefix, RlpTxTag::Data, 10), + (true, RlpTxTag::DataPrefix, RlpTxTag::SigV, 1), + (true, RlpTxTag::Data, RlpTxTag::SigV, 24 * 1024), // 24k bytes + (true, RlpTxTag::SigV, RlpTxTag::SigR, 10), + (true, RlpTxTag::SigR, RlpTxTag::SigS, 34), + // (true, RlpTxTag::SigS, RlpTxTag::RlpLength, 34), + (true, RlpTxTag::SigS, RlpTxTag::TxPrefix, 34), /* No RlpLength so SigS to + * Nonce */ + (true, RlpTxTag::SigS, RlpTxTag::Padding, 34), // If last, SigS to Padding + (true, RlpTxTag::TxListPrefix, RlpTxTag::TxPrefix, 10), + (true, RlpTxTag::TxPrefix, RlpTxTag::Nonce, 10), + (false, RlpTxTag::TxListPrefix, RlpTxTag::Padding, 1), + ] + .into_iter() + .enumerate() + { + let offset = i; + region.assign_fixed( + || "tag", + self.tag_rom.rlp_valid, + offset, + || Value::known(F::from(rlp_valid as u64)), + )?; + region.assign_fixed( + || "tag", + self.tag_rom.tag, + offset, + || Value::known(F::from(tag as u64)), + )?; + region.assign_fixed( + || "tag_next", + self.tag_rom.tag_next, + offset, + || Value::known(F::from(tag_next as u64)), + )?; + region.assign_fixed( + || "max_length", + self.tag_rom.max_length, + offset, + || Value::known(F::from(max_length)), + )?; + } + + Ok(()) + }, + )?; + + layouter.assign_region( + || "assign RLP-encoded data", + |mut region| { + let mut offset = 0; + let simple_tags = [ + Nonce, + GasPrice, + Gas, + To, + RlpTxTag::Value, + SigV, + SigR, + SigS, + ChainId, + ]; + + let txlist_prefix_len = { + if input_bytes[0].witness_byte <= 0xF7 { + // invalid case + 1usize + } else { + input_bytes[0].witness_byte as usize - 0xF7 + 1 + } + }; + + let total_bytes = { + if valid { + input_bytes.len() + } else { + 1usize + } + }; + + // fill input bytes + let mut all_bytes_rlc_acc = Value::known(F::zero()); + let mut bytes_left = total_bytes; + for (i, value) in input_bytes.iter().enumerate() { + region.assign_advice( + || format!("input byte [{}]", offset), + self.input_byte_value, + offset + i as usize, + || Value::known(F::from(value.witness_byte as u64)), + )?; + + region.assign_advice( + || format!("rlp valid: {}", offset), + self.rlp_valid, + offset + i as usize, + || Value::known(F::from(valid as u64)), + )?; + + region.assign_fixed( + || format!("decoder usable: {}", offset), + self.q_decode_usable, + offset + i as usize, + || Value::known(F::from(valid as u64)), + )?; + + if bytes_left > 0 && !value.place_holder { + bytes_left -= 1; + region.assign_advice( + || format!("bytes left: {}", offset), + self.input_bytes_left, + offset + i as usize, + || Value::known(F::from(bytes_left as u64)), + )?; + } + + all_bytes_rlc_acc = all_bytes_rlc_acc + .zip(keccak_input_rand) + .map(|(acc, rand)| acc * rand + F::from(value.witness_byte as u64)); + region.assign_advice( + || format!("value: {}", offset + i), + self.input_bytes_rlc_acc, + offset + i as usize, + || all_bytes_rlc_acc, + )?; + + input_value_eq_128_chip.assign( + &mut region, + offset + i as usize, + Value::known(F::from(value.witness_byte as u64)), + Value::known(F::from(128u64)), + )?; + + for (chip, lhs, rhs) in [ + (&input_value_gt_127_chip, 127, value.witness_byte), + (&input_value_gt_183_chip, 183, value.witness_byte), + (&input_value_gt_191_chip, 191, value.witness_byte), + (&input_value_gt_247_chip, 247, value.witness_byte), + (&input_value_lt_129_chip, value.witness_byte as usize, 129), + (&input_value_lt_184_chip, value.witness_byte as usize, 184), + (&input_value_lt_192_chip, value.witness_byte as usize, 192), + (&input_value_lt_248_chip, value.witness_byte as usize, 248), + ] { + chip.assign( + &mut region, + offset + i as usize, + F::from(lhs as u64), + F::from(rhs as u64), + )?; + } + } + + let mut length_acc = 0u64; + // fill txlist prefix + // TODO: merge to row loop + for (i, value) in input_bytes.iter().take(txlist_prefix_len).enumerate() { + // value + let rlp_table = &self.rlp_table; + region.assign_advice( + || format!("value: {}", offset + i), + self.byte_value, + offset + i, + || Value::known(F::from(value.witness_byte as u64)), + )?; + let tag_rindex = txlist_prefix_len as u64 - i as u64; + region.assign_advice( + || format!("tag_rindex: {}", offset + i), + rlp_table.tag_rindex, + offset + i, + || Value::known(F::from(tag_rindex)), + )?; + region.assign_advice( + || format!("tag: {}", offset), + rlp_table.tag, + offset + i as usize, + || Value::known(F::from(RlpTxTag::TxListPrefix as u64)), + )?; + region.assign_advice( + || format!("tag_length: {}", offset + i), + self.tag_length, + offset + i, + || Value::known(F::from(txlist_prefix_len as u64)), + )?; + if i > 0 { + length_acc = length_acc * 256 + value.witness_byte as u64; + region.assign_advice( + || format!("length_acc: {}", offset + i), + self.length_acc, + offset + i, + || Value::known(F::from(length_acc)), + )?; + } + + tag_chip.assign(&mut region, offset + i, &RlpTxTag::TxListPrefix)?; + + for (chip, lhs, rhs) in [(&tag_index_cmp_1_chip, 1, tag_rindex as u64)] { + chip.assign(&mut region, offset + i, F::from(lhs as u64), F::from(rhs))?; + } + + for (chip, lhs, rhs) in [(&tag_index_lt_10_chip, tag_rindex, 10)] { + chip.assign( + &mut region, + offset + i, + F::from(lhs as u64), + F::from(rhs as u64), + )?; + } + } + + // jump to tx begin pos + offset = txlist_prefix_len; + for (signed_tx_idx, signed_tx) in signed_txs.iter().enumerate() { + if signed_tx.tx.hash != get_dummy_tx_hash(signed_tx.tx.chain_id) { + log::debug!( + "rlp circuit assign {}th tx at offset:{}, tx hash {:?}", + signed_tx_idx, + offset, + signed_tx.tx.hash + ); + } + // tx hash (signed tx) + let mut all_bytes_rlc_acc = Value::known(F::zero()); + let tx_hash_rows = signed_tx.gen_witness(challenges); + let has_placeholder = + signed_tx.tx.call_data.len() == 1 && signed_tx.tx.call_data[0] < 0x80; let n_rows = if has_placeholder { tx_hash_rows.len() - 1 } else { @@ -1343,9 +1972,10 @@ impl RlpCircuitConfig { }; for (idx, row) in tx_hash_rows .iter() - .chain(signed_tx.rlp_rows(keccak_input_rand).iter()) + // .chain(signed_tx.rlp_rows(keccak_input_rand).iter()) .enumerate() { + log::trace!("offset {}, write row {}:\n\t{:?}", offset, idx, row); let prev_row_placeholder = row.tag == RlpTxTag::Data && has_placeholder; let cur_row_placeholder = row.tag == DataPrefix && has_placeholder; // update value accumulator over the entire RLP encoding. @@ -1371,15 +2001,15 @@ impl RlpCircuitConfig { || Value::known(F::from((idx == 0) as u64)), )?; // advices - let rindex = (n_rows + 2 - row.index) as u64; // rindex decreases from n_rows+1 to 0 + let rindex = (n_rows - row.index) as u64; // rindex decreases from n_rows - 1 to 0 let rlp_table = &self.rlp_table; let is_simple_tag = simple_tags.iter().filter(|tag| **tag == row.tag).count(); - let is_prefix_tag = (row.tag == Prefix).into(); + let is_prefix_tag = (row.tag == TxPrefix).into(); let is_dp_tag = (row.tag == DataPrefix).into(); for (name, column, value) in [ - ("is_last", self.is_last, (row.index == n_rows + 2).into()), + ("is_last", self.is_last, (row.index == n_rows).into()), ("tx_id", rlp_table.tx_id, row.tx_id as u64), ("tag", rlp_table.tag, (row.tag as u64)), ("is_simple_tag", self.is_simple_tag, is_simple_tag as u64), @@ -1484,158 +2114,16 @@ impl RlpCircuitConfig { offset += 1; } - - // tx sign (unsigned tx) - let mut all_bytes_rlc_acc = Value::known(F::zero()); - let tx_sign_rows = signed_tx.tx.gen_witness(challenges); - let has_placeholder = - signed_tx.tx.call_data.len() == 1 && signed_tx.tx.call_data[0] < 0x80; - let n_rows = if has_placeholder { - tx_sign_rows.len() - 1 - } else { - tx_sign_rows.len() - }; - for (idx, row) in tx_sign_rows - .iter() - .chain(signed_tx.tx.rlp_rows(challenges.keccak_input()).iter()) - .enumerate() - { - let prev_row_placeholder = row.tag == RlpTxTag::Data && has_placeholder; - let cur_row_placeholder = row.tag == DataPrefix && has_placeholder; - // update value accumulator over the entire RLP encoding. - if !prev_row_placeholder { - // prev row has already accumulate the byte_value - all_bytes_rlc_acc = all_bytes_rlc_acc - .zip(keccak_input_rand) - .map(|(acc, rand)| acc * rand + F::from(row.value as u64)); - } - - // q_usable - region.assign_fixed( - || format!("q_usable: {}", offset), - self.q_usable, - offset, - || Value::known(F::one()), - )?; - // is_first - region.assign_advice( - || format!("assign is_first {}", offset), - self.is_first, - offset, - || Value::known(F::from((idx == 0) as u64)), - )?; - // advices - let rindex = (n_rows + 2 - row.index) as u64; // rindex decreases from n_rows+1 to 0 - let rlp_table = &self.rlp_table; - let is_simple_tag = - simple_tags.iter().filter(|tag| **tag == row.tag).count(); - let is_prefix_tag = (row.tag == Prefix).into(); - let is_dp_tag = (row.tag == DataPrefix).into(); - for (name, column, value) in [ - ("is_last", self.is_last, (row.index == n_rows + 2).into()), - ("tx_id", rlp_table.tx_id, row.tx_id as u64), - ("tag", rlp_table.tag, row.tag as u64), - ("is_simple_tag", self.is_simple_tag, is_simple_tag as u64), - ("is_prefix_tag", self.is_prefix_tag, is_prefix_tag), - ("is_dp_tag", self.is_dp_tag, is_dp_tag), - ("tag_rindex", rlp_table.tag_rindex, row.tag_rindex as u64), - ( - "tag_length_eq_one", - rlp_table.tag_length_eq_one, - (row.tag_length == 1) as u64, - ), - ("data_type", rlp_table.data_type, row.data_type as u64), - ("index", self.index, row.index as u64), - ("rindex", self.rindex, rindex), - ("placeholder", self.placeholder, cur_row_placeholder as u64), - ("byte value", self.byte_value, row.value as u64), - ("tag_length", self.tag_length, row.tag_length as u64), - ("length_acc", self.length_acc, row.length_acc), - ] { - region.assign_advice( - || format!("assign {} {}", name, offset), - column, - offset, - || Value::known(F::from(value)), - )?; - } - for (name, column, value) in [ - ("rlp_table::value_acc", rlp_table.value_acc, row.value_acc), - ( - "calldata_bytes_rlc_acc", - self.calldata_bytes_rlc_acc, - row.value_rlc_acc, - ), - ( - "all_bytes_rlc_acc", - self.all_bytes_rlc_acc, - all_bytes_rlc_acc, - ), - ] { - region.assign_advice( - || format!("assign {} {}", name, offset), - column, - offset, - || value, - )?; - } - - tag_chip.assign(&mut region, offset, &row.tag)?; - - for (chip, lhs, rhs) in [ - (&tag_index_cmp_1_chip, 1, row.tag_rindex as u64), - ( - &tag_index_length_cmp_chip, - row.tag_rindex, - row.tag_length as u64, - ), - (&tag_length_cmp_1_chip, 1, row.tag_length as u64), - (&length_acc_cmp_0_chip, 0, row.length_acc), - ] { - chip.assign(&mut region, offset, F::from(lhs as u64), F::from(rhs))?; - } - - value_eq_128_chip.assign( - &mut region, - offset, - Value::known(F::from(row.value as u64)), - Value::known(F::from(128u64)), - )?; - - for (chip, lhs, rhs) in [ - (&tag_index_lt_10_chip, row.tag_rindex, 10), - (&tag_index_lt_34_chip, row.tag_rindex, 34), - ] { - chip.assign( - &mut region, - offset, - F::from(lhs as u64), - F::from(rhs as u64), - )?; - } - - for (chip, lhs, rhs) in [ - (&value_gt_127_chip, 127, row.value), - (&value_gt_183_chip, 183, row.value), - (&value_gt_191_chip, 191, row.value), - (&value_gt_247_chip, 247, row.value), - (&value_lt_129_chip, row.value as usize, 129), - (&value_lt_184_chip, row.value as usize, 184), - (&value_lt_192_chip, row.value as usize, 192), - (&value_lt_248_chip, row.value as usize, 248), - ] { - chip.assign( - &mut region, - offset, - F::from(lhs as u64), - F::from(rhs as u64), - )?; - } - - offset += 1; - } } + // q_end with padding + region.assign_fixed( + || format!("assign q_end_with_padding {}", offset), + self.q_end_with_padding, + offset, + || Value::known(F::one()), + )?; + // TODO: speed up the assignment of padding rows let padding_start_offset = offset; // end with padding rows. @@ -1681,6 +2169,19 @@ impl RlpCircuitConfig { || Value::known(F::one()), )?; + // enable decode usable logic + region.assign_fixed( + || format!("decode usable in padding row, offset: {}", offset), + self.q_decode_usable, + offset, + || Value::known(F::one()), + )?; + region.assign_fixed( + || format!("q_end_with_padding row, offset: {}", offset), + self.q_end_with_padding, + offset, + || Value::known(F::one()), + )?; Ok(()) } } @@ -1705,12 +2206,61 @@ impl SubCircuitConfig for RlpCircuitConfig { #[derive(Clone, Debug)] pub struct RlpCircuit { /// Rlp encoding inputs - pub inputs: Vec, + pub inputs: Vec, /// Max txs pub max_txs: usize, /// Size of the circuit pub size: usize, - _marker: PhantomData, + /// witness data + pub witness: Vec, + /// decoded txs + pub signed_txs: Vec, + /// rlp is valid + pub rlp_valid: bool, + /// marker + pub _marker: PhantomData, +} + +impl RlpCircuit { + /// new RlpCircuit + pub fn new(inputs: &Vec, k: usize, max_txs: usize) -> Self { + let (inputs_witness, signed_txs, valid) = decode_tx_list_rlp_witness(inputs); + log::info!( + "input_witness.len() = {}, txs.len() = {}, valid = {}.", + inputs_witness.len(), + signed_txs.len(), + valid, + ); + Self { + inputs: inputs.clone(), + max_txs: max_txs, + size: 1 << k, + witness: inputs_witness, + signed_txs: signed_txs.clone(), + rlp_valid: valid, + _marker: PhantomData, + } + } + + /// new RlpCircuit from forged witness + pub fn new_from_fake_witness( + inputs: &Vec, + inputs_witness: &Vec, + signed_txs: Vec, + rlp_valid: bool, + k: usize, + max_txs: usize, + ) -> Self { + Self { + inputs: inputs.clone(), + max_txs: max_txs, + size: 1 << k, + witness: inputs_witness.clone(), + signed_txs: signed_txs.clone(), + rlp_valid: rlp_valid, + _marker: PhantomData, + } + } } impl Default for RlpCircuit { @@ -1719,6 +2269,9 @@ impl Default for RlpCircuit { inputs: vec![], max_txs: 0, size: 0, + witness: vec![], + signed_txs: vec![], + rlp_valid: false, _marker: PhantomData, } } @@ -1747,11 +2300,15 @@ impl SubCircuit for RlpCircuit { })) .collect::>(); + // TODO: remove Self { - inputs: signed_txs, + inputs: vec![], max_txs: block.circuits_params.max_txs, // FIXME: this hard-coded size is used to pass unit test, we should use 1 << k instead. size: 1 << 18, + witness: vec![], + signed_txs: signed_txs, + rlp_valid: false, _marker: Default::default(), } } @@ -1762,7 +2319,14 @@ impl SubCircuit for RlpCircuit { challenges: &Challenges>, layouter: &mut impl Layouter, ) -> Result<(), Error> { - config.assign(layouter, &self.inputs, self.size, challenges) + config.assign( + layouter, + &self.witness, + self.rlp_valid, + &self.signed_txs, + self.size, + challenges, + ) } fn min_num_rows_block(block: &crate::witness::Block) -> (usize, usize) { @@ -1784,6 +2348,122 @@ impl SubCircuit for RlpCircuit { } } +/// generate decode witness, the main problem is the placeholder, +/// others are vertically continous bytes. +/// so far there is only 1 place_holder type i.e., for a [x<0x80] +/// calldata bytes. +/// TODO: we ignore the this case now for POC. +fn decode_tx_list_rlp_witness( + rlp_bytes: &Vec, +) -> (Vec, Vec, bool) { + if rlp_bytes[0] <= 0xF7 { + // not a tx list + log::debug!("invalid rlp txlist, starts with {}.", rlp_bytes[0]); + ( + rlp_bytes + .iter() + .map(|b| RlpWitnessByte { + witness_byte: *b, + place_holder: false, + }) + .collect(), + vec![], + false, + ) + } else if let Ok(decode_txs) = rlp::Rlp::new(&rlp_bytes).as_list() { + // decodable rlp + log::debug!("decode_txs = {:?}", &decode_txs); + let txs: Vec = decode_txs; + let signed_txs = txs + .iter() + .enumerate() + .map(|(tx_id, eth_tx)| { + let is_create = eth_tx.to.is_none(); + let sig = eth_types::Signature { + r: eth_tx.r, + s: eth_tx.s, + v: eth_tx.v.as_u64(), + }; + let (rlp_unsigned, rlp_signed) = { + let mut legacy_tx = ethers_core::types::TransactionRequest::new() + .from(eth_tx.from) + .nonce(eth_tx.nonce) + .gas_price(eth_tx.gas_price.unwrap()) + .gas(eth_tx.gas) + .value(eth_tx.value) + .data(eth_tx.input.clone()) + .chain_id(eth_tx.chain_id.unwrap().as_u64()); + if !is_create { + legacy_tx = legacy_tx.to(eth_tx.to.unwrap()); + } + + let unsigned = legacy_tx.rlp().to_vec(); + + let signed = legacy_tx.rlp_signed(&sig).to_vec(); + + (unsigned, signed) + }; + let tx = Transaction { + block_number: 0, + id: tx_id, + hash: eth_tx.hash, + nonce: eth_tx.nonce.as_u64(), + gas: eth_tx.gas.as_u64(), + gas_price: eth_tx.gas_price.unwrap(), + caller_address: eth_tx.from, + callee_address: eth_tx.to, + is_create, + value: eth_tx.value, + call_data: eth_tx.input.to_vec(), + call_data_length: eth_tx.input.len(), + call_data_gas_cost: eth_tx + .input + .iter() + .fold(0, |acc, byte| acc + if *byte == 0 { 4 } else { 16 }), + chain_id: eth_tx.chain_id.unwrap().as_u64(), + rlp_unsigned, + rlp_signed, + v: sig.v, + r: sig.r, + s: sig.s, + calls: vec![], + steps: vec![], + }; + //TODO: support this placeholder type + assert!(tx.call_data_length != 1); + SignedTransaction::from(&tx) + }) + .collect(); + + // write rlp bytes with place holder(TODO) + let mut rlp_witness_bytes: Vec = vec![]; + // TODO: place_holder in calldata + for i in 0..rlp_bytes.len() { + rlp_witness_bytes.push(RlpWitnessByte { + witness_byte: rlp_bytes[i], + place_holder: false, + }); + } + + (rlp_witness_bytes, signed_txs, true) + } else { + // non decodable rlp with correct txlist header + log::debug!( + "non decodable rlp txlist, starts with {:?}.", + &rlp_bytes[0..10] + ); + let mut rlp_witness_bytes: Vec = vec![]; + for i in 0..rlp_bytes.len() { + rlp_witness_bytes.push(RlpWitnessByte { + witness_byte: rlp_bytes[i], + place_holder: false, + }); + } + + (rlp_witness_bytes, vec![], false) + } +} + impl Circuit for RlpCircuit { type Config = (RlpCircuitConfig, Challenges); type FloorPlanner = SimpleFloorPlanner; @@ -1809,7 +2489,9 @@ impl Circuit for RlpCircuit { let challenges = challenges.values(&layouter); config.assign( &mut layouter, - self.inputs.as_slice(), + self.witness.as_slice(), + self.rlp_valid, + &self.signed_txs, self.size, &challenges, ) @@ -1818,23 +2500,87 @@ impl Circuit for RlpCircuit { #[cfg(test)] mod tests { + use ark_std::{end_timer, start_timer}; + use ethers_core::utils::rlp; + use rand::SeedableRng; + use rand_chacha::ChaCha20Rng; + + use std::io::Read; use std::marker::PhantomData; - use eth_types::Field; + use super::Field; + use super::{decode_tx_list_rlp_witness, RlpWitnessByte}; + use halo2_proofs::plonk::{create_proof, keygen_pk, keygen_vk, verify_proof}; + use halo2_proofs::poly::kzg::commitment::{KZGCommitmentScheme, ParamsKZG, ParamsVerifierKZG}; + use halo2_proofs::poly::kzg::multiopen::{ProverSHPLONK, VerifierSHPLONK}; + use halo2_proofs::poly::kzg::strategy::SingleStrategy; use halo2_proofs::{dev::MockProver, halo2curves::bn256::Fr}; + use halo2_proofs::{ + halo2curves::bn256::{Bn256, G1Affine}, + poly::commitment::ParamsProver, + transcript::{ + Blake2bRead, Blake2bWrite, Challenge255, TranscriptReadBuffer, TranscriptWriterBuffer, + }, + }; + use mock::CORRECT_MOCK_TXS; use crate::evm_circuit::witness::SignedTransaction; use super::RlpCircuit; - fn verify_txs(k: u32, inputs: Vec, max_txs: usize, success: bool) { - let circuit = RlpCircuit:: { - inputs, - max_txs, - size: 1 << k, - _marker: PhantomData, - }; + fn verify_normal_rlp_circuit( + k: u32, + inputs: Vec, + max_txs: usize, + success: bool, + expected_txs_len: usize, + expected_rlp_valid: bool, + ) where + RlpCircuit: halo2_proofs::plonk::Circuit, + { + let circuit: RlpCircuit = + RlpCircuit::::new(&inputs, k as usize, max_txs); + + assert_eq!(expected_txs_len, circuit.signed_txs.len()); + assert_eq!(expected_rlp_valid, circuit.rlp_valid); + + const NUM_BLINDING_ROWS: usize = 8; + let instance = vec![]; + let prover = MockProver::::run(k, &circuit, instance).unwrap(); + let err = prover.verify_par(); + let print_failures = true; + if err.is_err() && print_failures { + if let Some(e) = err.err() { + for s in e.iter() { + println!("{}", s); + } + } + } + let err = prover.verify_par(); + assert_eq!(err.is_ok(), success); + } + + fn verify_rlp_circuit_with_fake_witness( + k: u32, + max_txs: usize, + inputs: Vec, + inputs_witness: &Vec, + signed_txs: Vec, + rlp_valid: bool, + success: bool, + ) where + RlpCircuit: halo2_proofs::plonk::Circuit, + { + let circuit: RlpCircuit = + RlpCircuit::::new_from_fake_witness( + &inputs, + inputs_witness, + signed_txs, + rlp_valid, + k as usize, + max_txs, + ); const NUM_BLINDING_ROWS: usize = 8; let instance = vec![]; @@ -1852,39 +2598,236 @@ mod tests { assert_eq!(err.is_ok(), success); } + fn branch_rlp(k: u32, inputs: Vec, max_txs: usize) + where + RlpCircuit: halo2_proofs::plonk::Circuit, + { + let circuit: RlpCircuit = + RlpCircuit::::new(&inputs, k as usize, max_txs); + + const NUM_BLINDING_ROWS: usize = 8; + let mut rng = ChaCha20Rng::seed_from_u64(42); + + let general_params = ParamsKZG::::setup(k as u32, &mut rng); + let verifier_params: ParamsVerifierKZG = general_params.verifier_params().clone(); + + // Initialize the proving key + let vk = keygen_vk(&general_params, &circuit).expect("keygen_vk should not fail"); + let pk = keygen_pk(&general_params, vk, &circuit).expect("keygen_pk should not fail"); + // Create a proof + let mut transcript = Blake2bWrite::<_, G1Affine, Challenge255<_>>::init(vec![]); + + // Bench proof generation time + let proof_message = format!("{} {} with degree = {}", "gen proof of", "rlp circuit", k); + let start2 = start_timer!(|| proof_message); + create_proof::< + KZGCommitmentScheme, + ProverSHPLONK<'_, Bn256>, + Challenge255, + ChaCha20Rng, + Blake2bWrite, G1Affine, Challenge255>, + RlpCircuit, + >( + &general_params, + &pk, + &[circuit], + &[&[]], + rng, + &mut transcript, + ) + .expect("proof generation should not fail"); + let proof = transcript.finalize(); + end_timer!(start2); + + // Bench verification time + let start3 = start_timer!(|| format!("{} {}", 1, "rlp verify")); + let mut verifier_transcript = Blake2bRead::<_, G1Affine, Challenge255<_>>::init(&proof[..]); + let strategy = SingleStrategy::new(&general_params); + + verify_proof::< + KZGCommitmentScheme, + VerifierSHPLONK<'_, Bn256>, + Challenge255, + Blake2bRead<&[u8], G1Affine, Challenge255>, + SingleStrategy<'_, Bn256>, + >( + &verifier_params, + pk.get_vk(), + strategy, + &[&[]], + &mut verifier_transcript, + ) + .expect("failed to verify bench circuit"); + end_timer!(start3); + } + + // #[test] + // fn rlp_circuit_tx_1() { + // verify_txs::(8, vec![CORRECT_MOCK_TXS[0].clone().into()], 1, + // true); verify_txs::(8, + // vec![CORRECT_MOCK_TXS[4].clone().into()], 1, true); + + // // test against the case in which tx.data has only one byte and is + // // less than 0x80 + // let mut mock_tx = CORRECT_MOCK_TXS[0].clone(); + // mock_tx.input(vec![0x3f].into()); + // verify_txs::(8, vec![mock_tx.into()], 1, true); + // } + #[test] - fn rlp_circuit_tx_1() { - verify_txs::(8, vec![CORRECT_MOCK_TXS[0].clone().into()], 1, true); - verify_txs::(8, vec![CORRECT_MOCK_TXS[4].clone().into()], 1, true); - - // test against the case in which tx.data has only one byte and is less than - // 0x80 - let mut mock_tx = CORRECT_MOCK_TXS[0].clone(); - mock_tx.input(vec![0x3f].into()); - verify_txs::(8, vec![mock_tx.into()], 1, true); + fn rlp_circuit_tx_empty() { + let txs: Vec = vec![]; + let inputs = rlp::encode_list(&txs).into(); + verify_normal_rlp_circuit::(8, inputs, 10, true, 0, false); } #[test] fn rlp_circuit_tx_2() { - verify_txs::(8, vec![CORRECT_MOCK_TXS[1].clone().into()], 2, true); + let txs: Vec = vec![CORRECT_MOCK_TXS[6].clone().into()]; + let inputs = rlp::encode_list(&txs); + verify_normal_rlp_circuit::(8, inputs.into(), 2, true, 1, true); } #[test] fn rlp_circuit_tx_3() { - verify_txs::(20, vec![CORRECT_MOCK_TXS[2].clone().into()], 2, true); + let txs: Vec = vec![CORRECT_MOCK_TXS[2].clone().into()]; + let inputs = rlp::encode_list(&txs); + verify_normal_rlp_circuit::(20, inputs.into(), 50, true, 1, true); } #[test] fn rlp_circuit_multi_txs() { - verify_txs::( + let txs: Vec = vec![ + CORRECT_MOCK_TXS[0].clone().into(), + CORRECT_MOCK_TXS[1].clone().into(), + CORRECT_MOCK_TXS[2].clone().into(), + ]; + let inputs = rlp::encode_list(&txs).into(); + + verify_normal_rlp_circuit::(10, inputs, 5, true, 3, true); + } + + #[test] + fn rlp_circuit_tx_invalid_prefix_to_empty() { + let txs: Vec = vec![]; + let mut inputs: Vec = rlp::encode_list(&txs).into(); + inputs[0] = 0xC2; + verify_normal_rlp_circuit::(8, inputs, 10, true, 0, false); + + let txs: Vec = vec![CORRECT_MOCK_TXS[0].clone().into()]; + let mut inputs: Vec = rlp::encode_list(&txs).into(); + inputs[0] = 0xC8; + verify_normal_rlp_circuit::(8, inputs, 10, true, 0, false); + } + + /// field pos prefix data + /// array 00 f8 6f + /// tx prefix 02 f8 6d + /// nonce 04 82 1234 + /// gas price 07 86 100000000000 + /// gas limit 0e 83 0f4240 + /// to 12 94 0000000000000000000000000000000000000000 + /// value 27 83 054321 + /// data 2b 80 N/A + /// sign_v 2c 82 0a98 + /// sign_r 2f a0 a8193..{32bytes}..cf23 + /// sign_s 50 a0 409f8..{32bytes}..dc01 + /// padding 71 00 00 + + #[test] + fn rlp_circuit_tx_invalid_field() { + let txs: Vec = vec![CORRECT_MOCK_TXS[6].clone().into()]; + let inputs: Vec = rlp::encode_list(&txs).into(); + let mut invalid_inputs = vec![0; inputs.len()]; + + invalid_inputs[..].copy_from_slice(inputs.as_slice()); + invalid_inputs[2] = 0xC2; + verify_normal_rlp_circuit::(8, invalid_inputs.clone(), 10, true, 0, false); + + invalid_inputs[..].copy_from_slice(inputs.as_slice()); + invalid_inputs[4] = 0x12; + verify_normal_rlp_circuit::(8, invalid_inputs.clone(), 10, true, 0, false); + + // invalid_inputs[..].copy_from_slice(inputs.as_slice()); + // invalid_inputs[50] = 0xa1; + // verify_normal_rlp_circuit::(8, invalid_inputs.clone(), 10, true, + // 0, false); + } + + #[test] + fn rlp_circuit_tx_wrong_flag_for_empty_txs() { + let txs: Vec = vec![]; + let inputs = rlp::encode_list(&txs).into(); + let (inputs_witness, signed_txs, valid_and_not_empty) = decode_tx_list_rlp_witness(&inputs); + assert!(valid_and_not_empty == false); + verify_rlp_circuit_with_fake_witness::( + 8, 10, - vec![ - CORRECT_MOCK_TXS[0].clone().into(), - CORRECT_MOCK_TXS[1].clone().into(), - CORRECT_MOCK_TXS[2].clone().into(), - ], - 5, + inputs, + &inputs_witness, + signed_txs, + true, // fake witness + false, + ); + } + + #[test] + fn rlp_circuit_tx_wrong_flag_for_single_tx() { + let txs: Vec = vec![CORRECT_MOCK_TXS[6].clone().into()]; + let inputs = rlp::encode_list(&txs).into(); + let (inputs_witness, signed_txs, valid_and_not_empty) = decode_tx_list_rlp_witness(&inputs); + assert!(valid_and_not_empty == true); + + let mut invalid_inputs = vec![ + RlpWitnessByte { + witness_byte: 0, + place_holder: false + }; + inputs.len() + ]; + + invalid_inputs[..].copy_from_slice(inputs_witness.as_slice()); + invalid_inputs[2] = RlpWitnessByte { + witness_byte: 0xC2, + place_holder: false, + }; + + verify_rlp_circuit_with_fake_witness::( + 8, + 10, + inputs, + &invalid_inputs, + signed_txs, true, + false, ); } } + +#[cfg(test)] +mod rlp_test { + use ethers_core::utils::rlp; + use hex; + + use crate::witness::SignedTransaction; + + #[test] + fn test_decode() { + let tx: SignedTransaction = mock::CORRECT_MOCK_TXS[1].clone().into(); + let rlp_tx = rlp::encode(&tx); + println!("{:?}", hex::encode(rlp_tx)); + + let txs: Vec = vec![ + mock::CORRECT_MOCK_TXS[0].clone().into(), + mock::CORRECT_MOCK_TXS[1].clone().into(), + // mock::CORRECT_MOCK_TXS[2].clone().into(), + ]; + let rlp_txs = rlp::encode_list(&txs); + println!("{:?}", hex::encode(rlp_txs.clone())); + + let dec_txs = rlp::Rlp::new(rlp_txs.to_vec().as_slice()) + .as_list::() + .unwrap(); + println!("{:?}", dec_txs); + } +} diff --git a/zkevm-circuits/src/witness/rlp_encode/tx.rs b/zkevm-circuits/src/witness/rlp_encode/tx.rs index d979621571..a3340c8874 100644 --- a/zkevm-circuits/src/witness/rlp_encode/tx.rs +++ b/zkevm-circuits/src/witness/rlp_encode/tx.rs @@ -19,8 +19,11 @@ pub enum RlpTxTag { #[default] Padding = 0, /// Denotes the prefix bytes indicating the “length of length” and/or + /// “length” of the tx_list’s RLP-encoding. + TxListPrefix, + /// Denotes the prefix bytes indicating the “length of length” and/or /// “length” of the tx’s RLP-encoding. - Prefix, + TxPrefix, /// Denotes the byte(s) for the tx’s nonce. Nonce, /// Denotes the byte(s) for the tx’s gas price. @@ -75,7 +78,7 @@ impl RlpWitnessGen for Transaction { rlp_data.as_ref(), &mut rows, RlpDataType::TxSign, - RlpTxTag::Prefix, + RlpTxTag::TxPrefix, 0, ); let idx = handle_u64( @@ -220,7 +223,7 @@ impl RlpWitnessGen for SignedTransaction { rlp_data.as_ref(), &mut rows, RlpDataType::TxHash, - RlpTxTag::Prefix, + RlpTxTag::TxPrefix, 0, ); let idx = handle_u64( @@ -398,12 +401,12 @@ mod tests { assert_eq!(tx_rlp.len(), witness_rows.len()); // prefix verification - assert_eq!(witness_rows[0].tag, RlpTxTag::Prefix); + assert_eq!(witness_rows[0].tag, RlpTxTag::TxPrefix); assert_eq!(witness_rows[0].tag_rindex, 2); assert_eq!(witness_rows[0].tag_length, 2); assert_eq!(witness_rows[0].length_acc, 0); assert_eq!(witness_rows[0].value, 248); - assert_eq!(witness_rows[1].tag, RlpTxTag::Prefix); + assert_eq!(witness_rows[1].tag, RlpTxTag::TxPrefix); assert_eq!(witness_rows[1].tag_rindex, 1); assert_eq!(witness_rows[1].tag_length, 2); assert_eq!(witness_rows[1].length_acc, 84); @@ -495,17 +498,17 @@ mod tests { assert_eq!(tx_rlp.len(), witness_rows.len()); // prefix verification - assert_eq!(witness_rows[0].tag, RlpTxTag::Prefix); + assert_eq!(witness_rows[0].tag, RlpTxTag::TxPrefix); assert_eq!(witness_rows[0].tag_rindex, 3); assert_eq!(witness_rows[0].tag_length, 3); assert_eq!(witness_rows[0].length_acc, 0); assert_eq!(witness_rows[0].value, 249); - assert_eq!(witness_rows[1].tag, RlpTxTag::Prefix); + assert_eq!(witness_rows[1].tag, RlpTxTag::TxPrefix); assert_eq!(witness_rows[1].tag_rindex, 2); assert_eq!(witness_rows[1].tag_length, 3); assert_eq!(witness_rows[1].length_acc, 8); assert_eq!(witness_rows[1].value, 8); - assert_eq!(witness_rows[2].tag, RlpTxTag::Prefix); + assert_eq!(witness_rows[2].tag, RlpTxTag::TxPrefix); assert_eq!(witness_rows[2].tag_rindex, 1); assert_eq!(witness_rows[2].tag_length, 3); assert_eq!(witness_rows[2].length_acc, 2091);