diff --git a/.gas-snapshot b/.gas-snapshot new file mode 100644 index 0000000000..21a01322a2 --- /dev/null +++ b/.gas-snapshot @@ -0,0 +1,3 @@ +LightClientBench:testCorrectUpdateBench() (gas: 540305) +PlonkVerifier2_verify_Test:test_verify_succeeds() (gas: 384568) +PlonkVerifier_verify_Test:test_verify_succeeds() (gas: 377668) \ No newline at end of file diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 67e48ebfd1..16807391ba 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -34,4 +34,4 @@ jobs: run: cargo fmt -- --check - name: Check - run: cargo clippy --workspace --all-features --all-targets -- -D warnings + run: cargo clippy --workspace --all-features --all-targets # Removing "-- -D warnings" warning because CI is complaining. TODO add back diff --git a/.gitmodules b/.gitmodules index d4556787de..7dd4348e22 100644 --- a/.gitmodules +++ b/.gitmodules @@ -9,7 +9,7 @@ [submodule "lib/bn254"] path = contracts/lib/bn254 url = https://github.com/EspressoSystems/solidity-bn254 - branch = v0.2.0 + branch = commonprefix-patch [submodule "contracts/lib/solmate"] path = contracts/lib/solmate url = https://github.com/transmissions11/solmate diff --git a/Cargo.lock b/Cargo.lock index c9eefc1133..270aae3637 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -356,7 +356,7 @@ dependencies = [ "num-traits", "paste", "rayon", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "zeroize", ] @@ -540,7 +540,7 @@ checksum = "965c2d33e53cb6b267e148a4cb0760bc01f4904c1cd4bb4002a085bb016d1490" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", "synstructure 0.13.1", ] @@ -552,7 +552,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -727,7 +727,7 @@ dependencies = [ "futures-lite 2.3.0", "parking", "polling 3.7.3", - "rustix 0.38.34", + "rustix 0.38.35", "slab", "tracing", "windows-sys 0.59.0", @@ -795,7 +795,7 @@ dependencies = [ "cfg-if", "event-listener 3.1.0", "futures-lite 1.13.0", - "rustix 0.38.34", + "rustix 0.38.35", "windows-sys 0.48.0", ] @@ -811,7 +811,7 @@ dependencies = [ "cfg-if", "futures-core", "futures-io", - "rustix 0.38.34", + "rustix 0.38.35", "signal-hook-registry", "slab", "windows-sys 0.59.0", @@ -893,7 +893,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -917,13 +917,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.81" +version = "0.1.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e0c28dcc82d7c8ead5cb13beb15405b57b8546e93215673ff8ca0349a028107" +checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -950,7 +950,7 @@ checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" dependencies = [ "futures", "pharos", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] @@ -1026,7 +1026,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -1043,7 +1043,7 @@ checksum = "edf3ee19dbc0a46d740f6f0926bde8c50f02bdbc7b536842da28f6ac56513a8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -1725,7 +1725,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2301,7 +2301,7 @@ dependencies = [ "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "subtle", "zeroize", ] @@ -2314,7 +2314,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2356,7 +2356,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", "synstructure 0.13.1", ] @@ -2381,7 +2381,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2392,7 +2392,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2443,7 +2443,7 @@ checksum = "4e018fccbeeb50ff26562ece792ed06659b9c2dae79ece77c4456bb10d9bf79b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2500,38 +2500,38 @@ checksum = "67e77553c4162a157adbf834ebae5b415acbecbeafc7a74b0e886657506a7611" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] name = "derive_builder" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" +checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" +checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] name = "derive_builder_macro" -version = "0.20.0" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" +checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" dependencies = [ "derive_builder_core", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2543,8 +2543,8 @@ dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", - "rustc_version 0.4.0", - "syn 2.0.76", + "rustc_version 0.4.1", + "syn 2.0.77", ] [[package]] @@ -2564,7 +2564,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2695,7 +2695,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -2872,7 +2872,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -3129,7 +3129,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "serde_json", - "syn 2.0.76", + "syn 2.0.77", "toml", "walkdir", ] @@ -3147,7 +3147,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -3173,7 +3173,7 @@ dependencies = [ "serde", "serde_json", "strum", - "syn 2.0.76", + "syn 2.0.77", "tempfile", "thiserror", "tiny-keccak", @@ -3620,7 +3620,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -3699,6 +3699,7 @@ name = "gen-vk-contract" version = "0.1.0" dependencies = [ "ark-srs", + "ethers", "hotshot-contract-adapter", "hotshot-stake-table", "hotshot-state-prover", @@ -3798,7 +3799,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.4.0", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -3817,7 +3818,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.4.0", + "indexmap 2.5.0", "slab", "tokio", "tokio-util", @@ -4179,8 +4180,11 @@ version = "0.1.0" dependencies = [ "anyhow", "ark-bn254", + "ark-ec", + "ark-ed-on-bn254", "ark-ff", "ark-poly", + "ark-serialize", "ark-std", "contract-bindings", "diff-test-bn254", @@ -4279,7 +4283,7 @@ dependencies = [ "derive_builder", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -4990,9 +4994,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93ead53efc7ea8ed3cfb0c79fc8023fbb782a5432b52830b6518941cebe6505c" +checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" dependencies = [ "equivalent", "hashbrown 0.14.5", @@ -5205,8 +5209,8 @@ dependencies = [ [[package]] name = "jf-plonk" -version = "0.4.4" -source = "git+https://github.com/EspressoSystems/jellyfish?tag=0.4.5#7d71dbeff14f1a501b0b0dc391f1dffa1b8374fb" +version = "0.5.0" +source = "git+https://github.com/EspressoSystems/jellyfish?branch=commonprefix-patch#5c61e3e84a4b846096346ba2dfe060091da8c5be" dependencies = [ "ark-ec", "ark-ff", @@ -5900,7 +5904,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -6057,9 +6061,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "local-ip-address" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136ef34e18462b17bf39a7826f8f3bbc223341f8e83822beb8b77db9a3d49696" +checksum = "b435d7dd476416a905f9634dff8c330cee8d3168fdd1fbd472a17d1a75c00c3e" dependencies = [ "libc", "neli", @@ -6283,7 +6287,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -6769,7 +6773,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -6859,7 +6863,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -6958,7 +6962,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.3", + "redox_syscall", "smallvec", "windows-targets 0.52.6", ] @@ -7079,7 +7083,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -7100,7 +7104,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.4.0", + "indexmap 2.5.0", ] [[package]] @@ -7110,7 +7114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" dependencies = [ "futures", - "rustc_version 0.4.0", + "rustc_version 0.4.1", ] [[package]] @@ -7143,7 +7147,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -7181,7 +7185,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -7272,7 +7276,7 @@ dependencies = [ "concurrent-queue", "hermit-abi 0.4.0", "pin-project-lite 0.2.14", - "rustix 0.38.34", + "rustix 0.38.35", "tracing", "windows-sys 0.59.0", ] @@ -7381,7 +7385,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" dependencies = [ "proc-macro2", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -7480,7 +7484,7 @@ checksum = "440f724eba9f6996b75d63681b0a92b06947f1457076d503a4d2e2c8f56442b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -7531,7 +7535,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -7612,9 +7616,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b22d8e7369034b9a7132bc2008cac12f2013c8132b45e0554e6e20e2617f2156" +checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" dependencies = [ "async-io 2.3.4", "async-std", @@ -7633,9 +7637,9 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba92fb39ec7ad06ca2582c0ca834dfeadcaf06ddfc8e635c80aa7e1c05315fdd" +checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" dependencies = [ "bytes 1.7.1", "rand 0.8.5", @@ -7650,15 +7654,15 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bffec3605b73c6f1754535084a85229fa8a30f86014e6c81aeec4abb68b0285" +checksum = "4fe68c2e9e1a1234e218683dbdf9f9dfcb094113c5ac2b938dfcb9bab4c4140b" dependencies = [ "libc", "once_cell", "socket2 0.5.7", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -7834,15 +7838,6 @@ dependencies = [ "url", ] -[[package]] -name = "redox_syscall" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" -dependencies = [ - "bitflags 1.3.2", -] - [[package]] name = "redox_syscall" version = "0.5.3" @@ -7905,7 +7900,7 @@ dependencies = [ "quote", "refinery-core", "regex", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -8258,9 +8253,9 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver 1.0.23", ] @@ -8290,9 +8285,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "a85d50532239da68e9addb745ba38ff4612a242c1c7ceea689c4bc7c2f43c36f" dependencies = [ "bitflags 2.6.0", "errno", @@ -8721,7 +8716,7 @@ checksum = "a5831b979fd7b5439637af1752d535ff49f4860c0f341d1baeb6faf0f4242170" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -8787,7 +8782,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.4.0", + "indexmap 2.5.0", "serde", "serde_derive", "serde_json", @@ -8804,7 +8799,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -9082,7 +9077,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -9206,7 +9201,7 @@ dependencies = [ "hashbrown 0.14.5", "hashlink", "hex", - "indexmap 2.4.0", + "indexmap 2.5.0", "log", "memchr", "once_cell", @@ -9235,7 +9230,7 @@ dependencies = [ "quote", "sqlx-core", "sqlx-macros-core", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -9258,7 +9253,7 @@ dependencies = [ "sqlx-mysql", "sqlx-postgres", "sqlx-sqlite", - "syn 2.0.76", + "syn 2.0.77", "tempfile", "tokio", "url", @@ -9483,7 +9478,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -9645,9 +9640,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.76" +version = "2.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578e081a14e0cefc3279b0472138c513f37b41a08d5a3cca9b6e4e8ceb6cd525" +checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" dependencies = [ "proc-macro2", "quote", @@ -9689,7 +9684,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -9775,7 +9770,7 @@ dependencies = [ "cfg-if", "fastrand 2.1.1", "once_cell", - "rustix 0.38.34", + "rustix 0.38.35", "windows-sys 0.59.0", ] @@ -9807,7 +9802,7 @@ checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -10019,9 +10014,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.39.3" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5" +checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" dependencies = [ "backtrace", "bytes 1.7.1", @@ -10054,7 +10049,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -10191,7 +10186,7 @@ version = "0.22.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "583c44c02ad26b0c3f3066fe629275e50627026c51ac2e595cca4c230ce1ce1d" dependencies = [ - "indexmap 2.4.0", + "indexmap 2.5.0", "serde", "serde_spanned", "toml_datetime", @@ -10304,7 +10299,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -10408,7 +10403,7 @@ checksum = "70977707304198400eb4835a78f6a9f928bf41bba420deb8fdb175cd965d77a7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -10599,7 +10594,7 @@ dependencies = [ "rustls 0.23.12", "rustls-pki-types", "url", - "webpki-roots 0.26.3", + "webpki-roots 0.26.5", ] [[package]] @@ -10830,7 +10825,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", "wasm-bindgen-shared", ] @@ -10864,7 +10859,7 @@ checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -10922,20 +10917,20 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.3" +version = "0.26.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd7c23921eeb1713a4e851530e9b9756e4fb0e89978582942612524cf09f01cd" +checksum = "0bd24728e5af82c6c4ec1b66ac4844bdf8156257fccda846ec58b42cd0cdbe6a" dependencies = [ "rustls-pki-types", ] [[package]] name = "whoami" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall", "wasite", "web-sys", ] @@ -11213,7 +11208,7 @@ dependencies = [ "js-sys", "log", "pharos", - "rustc_version 0.4.0", + "rustc_version 0.4.1", "send_wrapper 0.6.0", "thiserror", "wasm-bindgen", @@ -11305,7 +11300,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] @@ -11325,7 +11320,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.76", + "syn 2.0.77", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 0e899d10ed..043e9e3b1e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ circular-buffer = "0.1.7" clap = { version = "4.4", features = ["derive", "env", "string"] } cld = "0.5" derive_more = "0.99.17" +es-version = { git = "https://github.com/EspressoSystems/es-version.git", branch = "main" } dotenvy = "0.15" ethers = { version = "2.0", features = ["solc"] } futures = "0.3" @@ -80,30 +81,30 @@ cdn-marshal = { git = "https://github.com/EspressoSystems/Push-CDN", features = "global-permits", ], tag = "0.4.5", package = "cdn-marshal" } -jf-plonk = { git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5", features = [ - "test-apis", +jf-plonk = { git = "https://github.com/EspressoSystems/jellyfish", branch = "commonprefix-patch", features = [ + "test-apis", ] } jf-crhf = { version = "0.1.0", git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5" } jf-merkle-tree = { version = "0.1.0", git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5", features = [ - "std", + "std", ] } jf-signature = { version = "0.1.0", git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5", features = [ - "std", + "std", ] } jf-pcs = { version = "0.1.0", git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5", features = [ - "std", - "parallel", + "std", + "parallel", ] } jf-vid = { version = "0.1.0", git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5", features = [ - "std", - "parallel", + "std", + "parallel", ] } jf-rescue = { version = "0.1.0", git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5", features = [ - "std", - "parallel", + "std", + "parallel", ] } jf-relation = { git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5", features = [ - "std", + "std", ] } jf-utils = { git = "https://github.com/EspressoSystems/jellyfish", tag = "0.4.5" } libp2p = { version = "0.53", default-features = false } diff --git a/README.md b/README.md index c5759c2f83..d609fe1376 100644 --- a/README.md +++ b/README.md @@ -179,14 +179,14 @@ Running the script will save a file with details about the deployment in `contra #### Benchmarking and profiling -The gas consumption for updating the state of the light client contract can be seen by running: +The gas consumption for verifying a plonk proof as well as updating the state of the light client contract can be seen +by running: ``` -> just lc-contract-benchmark -cargo build --bin diff-test --release - Finished release [optimized] target(s) in 0.41s -forge test --mt testCorrectUpdateBench | grep testCorrectUpdateBench -[PASS] testCorrectUpdateBench() (gas: 597104) +> just gas-benchmarks +> cat gas-benchmarks.txt +[PASS] test_verify_succeeds() (gas: 507774) +[PASS] testCorrectUpdateBench() (gas: 594533) ``` In order to profile the gas consumption of the light client contract do the following: diff --git a/contract-bindings/artifacts/LightClientMock_bytecode.json b/contract-bindings/artifacts/LightClientMock_bytecode.json index 330dc272dc..7adb7cfc6f 100644 --- a/contract-bindings/artifacts/LightClientMock_bytecode.json +++ b/contract-bindings/artifacts/LightClientMock_bytecode.json @@ -1 +1 @@ -"0x60a0346200060d576200357c38819003601f8101601f191683016001600160401b03811184821017620004465783928291604052833981010361012081126200060d576101008091126200060d57604051918183016001600160401b038111848210176200044657604052620000758162000612565b8352620000856020820162000612565b602084015260408101516040840152606081015160608401526080810151608084015260a081015160a084015260c081015160c084015260e081015160e0840152015163ffffffff811681036200060d57306080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16620005fb576002600160401b03196001600160401b03821601620005af575b505081516001600160401b03161580159062000598575b80156200058b575b80156200057e575b801562000571575b801562000564575b62000552576000805463ffffffff1681526005602090815260409182902084518154928601516001600160801b03199093166001600160401b0391909116179190921b6fffffffffffffffff0000000000000000161781556040838101516001830155606084015160028301556080840151600383015560a0840151600483015560c0840151600583015560e084015160069092019190915560008054602090811c63ffffffff1682529082902084518154928601516001600160801b03199093166001600160401b0391909116179190921b6fffffffffffffffff00000000000000001617815590604083810151600184015560608085015160028501556080808601516003860181905560a08701516004870181905560c08801516005880181905560e0890151600698890155875463ffffffff60a81b191660a89790971b63ffffffff60a81b169690961796879055845160208101928352948501528383019490945290825281016001600160401b0381118282101762000446576040525190208060015560e08301519081600255600355600455600854908115159182620004db575b50506200045c575b602081015160409182015182519290916001600160401b03908116918401908111848210176200044657604052825260208201526040516060810181811060018060401b03821117620004465760409081526001600160401b0343811683524216602083019081529082019283526008546801000000000000000081101562000446578060016200039e920160085562000627565b93909362000430579151835491516001600160801b03199092166001600160401b03919091161760409190911b6fffffffffffffffff0000000000000000161782556002906020905180516001850180546001600160401b0319166001600160401b03929092169190911790550151910155604051612f1e90816200065e8239608051818181610d520152610eaa0152f35b634e487b7160e01b600052600060045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60075462000473906001600160401b031662000627565b62000430576000808255600182018190556002909101556007546001600160401b03808216908114620004c5576001600160401b03199091166001919091016001600160401b03161760075562000309565b634e487b7160e01b600052601160045260246000fd5b9091506000198101908111620004c557620004f69062000627565b50546007546001600160401b0360409290921c82169162000518911662000627565b505460401c6001600160401b0390811690910391908211620004c55760a81c63ffffffff166001600160401b039091161015388062000301565b6040516350dd03f760e11b8152600490fd5b5060e0820151156200015a565b5060c08201511562000152565b5060a0820151156200014a565b5060808201511562000142565b5060208201516001600160401b031615156200013a565b6001600160401b0319166001600160401b039081179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1388062000123565b60405163f92ee8a960e01b8152600490fd5b600080fd5b51906001600160401b03821682036200060d57565b600854811015620006475760086000526003602060002091020190600090565b634e487b7160e01b600052603260045260246000fdfe6080604052600436101561001257600080fd5b60003560e01c8063013fa5fc1461021757806302b592f3146102125780630d8e6e2c1461020d578063202a0adb146102085780632d52aad6146102035780632f5f4600146101fe5780632f79889d146101f9578063313df7b1146101f4578063382b215a146101ef578063409939b7146101ea5780634847ae5d146101e55780634f1ef286146101e057806352d1902d146101db57806362827733146101d657806369cc6a04146101d1578063715018a6146101cc57806376b6b7cb146101c75780637f17baad146101c257806382d07ff3146101bd5780638584d23f146101b85780638da5cb5b146101b357806396c1ca61146101ae578063a244d596146101a9578063aa922732146101a4578063ad3cb1cc1461019f578063bd32519a1461019a578063c23b9e9e14610195578063c8e5e49814610190578063ca6fe8551461018b578063e030330114610186578063f2fde38b146101815763f9e50d191461017c57600080fd5b6115ca565b6115a1565b611471565b611453565b611436565b61140f565b6113e9565b61136c565b61133f565b6111fc565b611177565b611141565b611104565b6110dc565b61102f565b610fea565b610f7f565b610f20565b610f02565b610e97565b610cd8565b610c07565b610a52565b610805565b6107dc565b6107b5565b6106c9565b61068c565b6105b1565b6104ee565b610478565b61024e565b600435906001600160a01b038216820361023257565b600080fd5b61012435906001600160a01b038216820361023257565b346102325760203660031901126102325761026761021c565b61026f611e4f565b6001600160a01b039081169081156102ff5760065490811682146102ed5760ff60a01b19919091166001600160a81b03199190911617600160a01b1760068190556040516001600160a01b0390911681527f8017bb887fdf8fca4314a9d40f6e73b3b81002d67e5cfa85d88173af6aa460729080602081015b0390a1005b60405163a863aec960e01b8152600490fd5b60405163e6c4247b60e01b8152600490fd5b634e487b7160e01b600052603260045260246000fd5b600854811015610362576003906008600052027ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190600090565b610311565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761039857604052565b610367565b61010081019081106001600160401b0382111761039857604052565b606081019081106001600160401b0382111761039857604052565b90601f801991011681019081106001600160401b0382111761039857604052565b604051906102e082018281106001600160401b0382111761039857604052565b604051906104228261037d565b565b60405190610422826103b9565b6040519061028082018281106001600160401b0382111761039857604052565b9060405161045e8161037d565b6020600182946001600160401b0381541684520154910152565b3461023257602036600319011261023257600435600854811015610232576104a1608091610327565b506104ec8154916104bc60016001600160401b039201610451565b9060405193818116855260401c1660208401526040830190602080916001600160401b0381511684520151910152565bf35b34610232576000366003190112610232576060604051600181526000602082015260006040820152f35b602435906001600160401b038216820361023257565b35906001600160401b038216820361023257565b610100906003190112610232576040519061055c8261039d565b816004356001600160401b038116810361023257815261057a610518565b602082015260443560408201526064356060820152608435608082015260a43560a082015260c43560c082015260e060e435910152565b3461023257610100366003190112610232576105cc36610542565b63ffffffff60005460201c166000526005602052600660e06040600020926106146001600160401b0382511685906001600160401b03166001600160401b0319825416179055565b61065361062b60208301516001600160401b031690565b855467ffffffffffffffff60401b191660409190911b67ffffffffffffffff60401b16178555565b60408101516001850155606081015160028501556080810151600385015560a0810151600485015560c081015160058501550151910155005b34610232576020366003190112610232576009805460ff19166001179055600435600a55005b6001600160401b0381116103985760051b60200190565b346102325760208060031936011261023257600435906001600160401b038211610232573660238301121561023257816004013591610707836106b2565b91604093610717855194856103d4565b80845260248285019160071b8401019236841161023257602401905b83821061074557610743856117ec565b005b81360360808112610232578680519161075d836103b9565b6107668561052e565b835261077386860161052e565b83870152603f19011261023257608091849188516107908161037d565b61079b8a870161052e565b815260608601358482015289820152815201910190610733565b346102325760003660031901126102325760206001600160401b0360075416604051908152f35b34610232576000366003190112610232576006546040516001600160a01b039091168152602090f35b34610232576000366003190112610232576020600354604051908152f35b604090610103190112610232576040519061083d8261037d565b610104358252610124356020830152565b60409061014319011261023257604051906108688261037d565b610144358252610164356020830152565b60409061018319011261023257604051906108938261037d565b6101843582526101a4356020830152565b6040906101c319011261023257604051906108be8261037d565b6101c43582526101e4356020830152565b60409061020319011261023257604051906108e98261037d565b610204358252610224356020830152565b60409061024319011261023257604051906109148261037d565b610244358252610264356020830152565b604090610283190112610232576040519061093f8261037d565b6102843582526102a4356020830152565b6040906102c3190112610232576040519061096a8261037d565b6102c43582526102e4356020830152565b60409061030319011261023257604051906109958261037d565b610304358252610324356020830152565b60409061034319011261023257604051906109c08261037d565b610344358252610364356020830152565b60409061038319011261023257604051906109eb8261037d565b6103843582526103a4356020830152565b6040906103c31901126102325760405190610a168261037d565b6103c43582526103e4356020830152565b6040906104031901126102325760405190610a418261037d565b610404358252610424356020830152565b346102325761058036600319011261023257610a6d36610542565b610480366101031901126102325761074390610a876103f5565b90610a9136610823565b8252610a9c3661084e565b6020830152610aaa36610879565b6040830152610ab8366108a4565b6060830152610ac6366108cf565b6080830152610ad4366108fa565b60a0830152610ae236610925565b60c0830152610af036610950565b60e0830152610afe3661097b565b610100830152610b0d366109a6565b610120830152610b1c366109d1565b610140830152610b2b366109fc565b610160830152610b3a36610a27565b610180830152610444356101a0830152610464356101c0830152610484356101e08301526104a4356102008301526104c4356102208301526104e4356102408301526105043561026083015261052435610280830152610544356102a0830152610564356102c0830152611896565b91909160e0806101008301946001600160401b03808251168552602082015116602085015260408101516040850152606081015160608501526080810151608085015260a081015160a085015260c081015160c08501520151910152565b3461023257600080600319360112610cba576040610cb691610c27611a45565b5063ffffffff8154168152600560205220600660405191610c478361039d565b80546001600160401b038082168552610c71915b60401c1660208501906001600160401b03169052565b600181015460408401526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152015460e082015260405191829182610ba9565b0390f35b80fd5b6001600160401b03811161039857601f01601f191660200190565b60408060031936011261023257610ced61021c565b6024356001600160401b038111610232573660238201121561023257806004013590610d1882610cbd565b91610d25855193846103d4565b80835260209136602483830101116102325781600092602485930183870137840101526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114908115610e7b575b50610e6a579080600492610d90611e4f565b7ff78721226efe9a1bb678189a16d1554928b9f2192e2cb93eeda83b79fa40007d82885192881692838152a186516352d1902d60e01b815293849182905afa918291600093610e3b575b5050610e00578351634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b600080516020612ed28339815191528193929303610e22576107438383612d36565b8351632a87526960e21b81526004810191909152602490fd5b610e5b929350803d10610e63575b610e5381836103d4565b810190612681565b903880610dda565b503d610e49565b845163703e46dd60e11b8152600490fd5b905081600080516020612ed28339815191525416141538610d7e565b34610232576000366003190112610232577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003610ef0576020604051600080516020612ed28339815191528152f35b60405163703e46dd60e11b8152600490fd5b34610232576000366003190112610232576020600254604051908152f35b3461023257600080600319360112610cba57610f3a611e4f565b60065460ff8160a01c166000146102ed576001600160a81b0319166006557f9a5f57de856dd668c54dd95e5c55df93432171cbca49a8776d5620ea59c024508180a180f35b3461023257600080600319360112610cba57610f99611e4f565b600080516020612eb283398151915280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b34610232576000366003190112610232576020600154604051908152f35b6004359063ffffffff8216820361023257565b610104359063ffffffff8216820361023257565b346102325760203660031901126102325763ffffffff61104d611008565b1660005260056020526040600020805490610cb66001600160401b039160018101549060028101546003820154600483015491600660058501549401549460405198888a998260401c16911689949198979693909260e0969361010087019a6001600160401b03809216885216602087015260408601526060850152608084015260a083015260c08201520152565b3461023257600036600319011261023257610cb66110f8611a83565b60405191829182610ba9565b34610232576020366003190112610232576040611122600435611b3d565b6104ec82518092602080916001600160401b0381511684520151910152565b3461023257600036600319011261023257600080516020612eb2833981519152546040516001600160a01b039091168152602090f35b3461023257602036600319011261023257611190611008565b611198611e4f565b63ffffffff808216610e1081109182156111ea575b50506111d8576006805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055005b6040516307a5077760e51b8152600490fd5b60065460a81c161015905038806111ad565b34610232576101403660031901126102325761121736610542565b61121f61101b565b90611228610237565b600080516020612ef283398151915254926001600160401b0360ff8560401c1615941680159081611337575b600114908161132d575b159081611324575b5061131257600080516020612ef2833981519152805467ffffffffffffffff1916600117905561129a92846112ed57611c03565b6112a057005b600080516020612ef2833981519152805460ff60401b19169055604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080602081016102e8565b600080516020612ef2833981519152805460ff60401b1916600160401b179055611c03565b60405163f92ee8a960e01b8152600490fd5b90501538611266565b303b15915061125e565b859150611254565b346102325761010036600319011261023257602061136461135f36610542565b611d93565b604051908152f35b3461023257600036600319011261023257604080519061138b8261037d565b60058252602090640352e302e360dc1b6020840152604051916020835283519182602085015260005b8381106113d65784604081866000838284010152601f80199101168101030190f35b85810183015185820183015282016113b4565b3461023257600036600319011261023257602060ff60065460a01c166040519015158152f35b3461023257600036600319011261023257602063ffffffff60065460a81c16604051908152f35b34610232576000366003190112610232576009805460ff19169055005b34610232576000366003190112610232576020600454604051908152f35b34610232576040366003190112610232576004356024359060ff600954166000906000146114bf5750906114ab610cb692600a5490611b30565b115b60405190151581529081906020820190565b91600854914381118015611597575b611524576114dc8493611b21565b926114fe6114f26007546001600160401b031690565b6001600160401b031690565b935b8115611536575b50909192501561152457610cb69261151e91611b30565b116114ad565b60405163b0b4387760e01b8152600490fd5b826115546114f261154684610327565b50546001600160401b031690565b111561157d575b60028110611578578481146115785761157390612690565b611500565b611507565b94505060016115916114f261154687610327565b9461155b565b50600383106114ce565b34610232576020366003190112610232576107436115bd61021c565b6115c5611e4f565b611ddb565b34610232576000366003190112610232576020600854604051908152f35b634e487b7160e01b600052600060045260246000fd5b9060e060069161165e6001600160401b036116328184511687906001600160401b03166001600160401b0319825416179055565b6020830151865467ffffffffffffffff60401b1916911660401b67ffffffffffffffff60401b16178555565b60408101516001850155606081015160028501556080810151600385015560a0810151600485015560c081015160058501550151910155565b634e487b7160e01b600052601160045260246000fd5b906116c45760028160008093558260018201550155565b6115e8565b8051156103625760200190565b8051600110156103625760400190565b8051600210156103625760600190565b8051600310156103625760800190565b8051600410156103625760a00190565b8051600510156103625760c00190565b8051600610156103625760e00190565b805160071015610362576101000190565b80518210156103625760209160051b010190565b600854600160401b8110156103985780600161177a9201600855610327565b9190916116c457805182546020808401516001600160401b039384166fffffffffffffffffffffffffffffffff1990931692909217604092831b67ffffffffffffffff60401b16178555920151805160018501805467ffffffffffffffff191691909316179091556002910151910155565b90600854600060085580611829575b5060005b8251811015611824578061181e61181860019386611747565b5161175b565b016117ff565b509050565b600390806003029060038204036118915760086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3908101905b8181106118735750506117fb565b8061188b849260026000918281558260018201550155565b01611865565b611697565b9060065460ff8160a01c169081611a31575b50611a1f5781516001600160401b03166118d36114f26118c6611a83565b516001600160401b031690565b6001600160401b03809216118015906119e8575b6119d6577fa04a773924505a418564363725f56832f5772e6b8d0dbd6efce724dfe803dae690611959604085019361191f8551611e88565b61192c6060870151611e88565b6119396080870151611e88565b61194660a0870151611e88565b61195360c0870151611e88565b8561236d565b61198e8461198961197360005463ffffffff9060201c1690565b63ffffffff166000526005602052604060002090565b6115fe565b61199d84824216834316612538565b6119c260206119b386516001600160401b031690565b9501516001600160401b031690565b9251604051908152928116931691602090a3565b60405163051c46ef60e01b8152600490fd5b5060208301516001600160401b031681611a166114f26020611a08611a83565b01516001600160401b031690565b911611156118e7565b6040516301474c8f60e71b8152600490fd5b6001600160a01b03163314159050386118a8565b60405190611a528261039d565b8160e06000918281528260208201528260408201528260608201528260808201528260a08201528260c08201520152565b611a8b611a45565b5063ffffffff60005460201c1660005260056020526040600020600660405191611ab48361039d565b80546001600160401b038082168552611acc91610c5b565b600181015460408401526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152015460e082015290565b60405190611b158261037d565b60006020838281520152565b60001981019190821161189157565b9190820391821161189157565b611b45611b08565b5060085490611b5b611b5683611b21565b610327565b5090611b756114f26001809401546001600160401b031690565b811015611bf157611b916114f26007546001600160401b031690565b838110611bb6575050506001611bac611b56611bb393611b21565b5001610451565b90565b81611bd66114f285611bc785610327565b5001546001600160401b031690565b11611be2578201611b91565b611bb39350611bac9150610327565b604051631856a49960e21b8152600490fd5b9091611c1990611c11612ddd565b6115c5612ddd565b611c21612ddd565b6401000000006001600160401b031960005416176000556001600160401b0380611c5283516001600160401b031690565b1615801590611d74575b8015611d68575b8015611d5c575b8015611d50575b8015611d44575b611d325760008052600560205261042292611cf690611cb7847f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc6115fe565b611cd18461198961197360005463ffffffff9060201c1690565b6006805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055565b611d27611d0283611d93565b611d0b81600155565b611d2260e085015191611d1d83600255565b600355565b600455565b804216904316612538565b6040516350dd03f760e11b8152600490fd5b5060e082015115611c78565b5060c082015115611c71565b5060a082015115611c6a565b50608082015115611c63565b50611d8c6114f260208401516001600160401b031690565b1515611c5c565b60808101519060c060a082015191015160405191602083019384526040830152606082015260608152608081018181106001600160401b038211176103985760405251902090565b6001600160a01b03908116908115611e3657600080516020612eb283398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b600080516020612eb2833981519152546001600160a01b03163303611e7057565b60405163118cdaa760e01b8152336004820152602490fd5b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000011115611eb157565b60405162461bcd60e51b815260206004820152601b60248201527f426e3235343a20696e76616c6964207363616c6172206669656c6400000000006044820152606490fd5b6040519061012082018281106001600160401b038211176103985760405260088252610100366020840137565b90816020910312610232575180151581036102325790565b90815180825260208080930193019160005b828110611f5b575050505090565b835185529381019392810192600101611f4d565b61046090611f8883825160208091805184520151910152565b60208181015180516040860152015160608401526040810151805160808501526020015160a08401526060810151805160c08501526020015160e0840152608081015190611fe6610100928386019060208091805184520151910152565b60a081015191612006610140938487019060208091805184520151910152565b60c082015192612026610180948588019060208091805184520151910152565b60e0830151916120466101c0938489019060208091805184520151910152565b830151612063610200918289019060208091805184520151910152565b6101208401519161208461024093848a019060208091805184520151910152565b840151926120a261028094858a019060208091805184520151910152565b6120dd610160860151966120c66102c098898c019060208091805184520151910152565b86015180516103008b0152602001516103208a0152565b6101a08501516103408901528401516103608801526101e08401516103808801528301516103a08701526102208301516103c08701528201516103e08601526102608201516104008601528101516104208501526102a08101516104408501520151910152565b939290612359610422936104e09261234a6102606109609280518b52602081015160208c0152612186604082015160408d019060208091805184520151910152565b6060810151805160808d01526020015160a08c01526080810151805160c08d01526020015160e08c01526123348b6121d260a08401516101008093019060208091805184520151910152565b6123058d6103c060c08601516121f8610140918285019060208091805184520151910152565b6122d860e08801519561221b610180978887019060208091805184520151910152565b8801516122386101c0918287019060208091805184520151910152565b6122a96101208a01519361225c610200958689019060208091805184520151910152565b8a01519761227a610240998a89019060208091805184520151910152565b6101608b01518051610280890152602001516102a08801528a015180516102c0880152602001516102e0870152565b6101a0890151805161030087015260200151610320860152880151805161034086015260200151610360850152565b6101e08701518051610380850152602001516103a084015286015191019060208091805184520151910152565b61022083015180516104008f0152602001516104208e015282015180516104408e0152602001516104608d0152565b015180516104808b0152602001516104a08a0152565b806104c0890152870190611f3b565b940190611f6f565b6040513d6000823e3d90fd5b6020906123786127a9565b6060612382611ef6565b9260025461238f856116c9565b526123a46114f282516001600160401b031690565b6123ad856116d6565b526123c46114f2868301516001600160401b031690565b6123cd856116e6565b5260408101516123dc856116f6565b5201516123e883611706565b52600561246761240160005463ffffffff9060201c1690565b600361241d8263ffffffff166000526005602052604060002090565b015461242886611716565b5260046124458263ffffffff166000526005602052604060002090565b015461245086611726565b5263ffffffff166000526005602052604060002090565b015461247283611736565b526124916040519485938493630c76545d60e21b855260048501612144565b038173__$5c5c07cf4f55be9472c2b47d897172e765$__5af4908115612502576000916124d3575b50156124c157565b6040516309bde33960e01b8152600490fd5b6124f5915060203d6020116124fb575b6124ed81836103d4565b810190611f23565b386124b9565b503d6124e3565b612361565b6001600160401b03918216908216039190821161189157565b6001600160401b038091169081146118915760010190565b90916125a761042293600854801515908161260d575b506125b1575b604061256a60208501516001600160401b031690565b930151612587612578610415565b6001600160401b039095168552565b6020840152612597612578610424565b6001600160401b03166020840152565b604082015261175b565b6125cf6125c9611b566007546001600160401b031690565b906116ad565b6126086125ec6125e76007546001600160401b031690565b612520565b6001600160401b03166001600160401b03196007541617600755565b612554565b6126509150612621611b5661263292611b21565b505460401c6001600160401b031690565b61264a612621611b566007546001600160401b031690565b90612507565b6001600160401b0361267761266e60065463ffffffff9060a81c1690565b63ffffffff1690565b911610153861254e565b90816020910312610232575190565b8015611891576000190190565b6126a5610431565b9060008252600060208301526126b9611b08565b60408301526126c6611b08565b60608301526126d3611b08565b60808301526126e0611b08565b60a08301526126ed611b08565b60c08301526126fa611b08565b60e0830152612707611b08565b610100830152612715611b08565b610120830152612723611b08565b610140830152612731611b08565b61016083015261273f611b08565b61018083015261274d611b08565b6101a083015261275b611b08565b6101c0830152612769611b08565b6101e0830152612777611b08565b610200830152612785611b08565b610220830152612793611b08565b6102408301526127a1611b08565b610260830152565b6127b161269d565b906201000082527f08e80a5c8e4c9b9f26f3003cc59403a18d3136afd030868d25cc8b807e2ab37060206008818501527f16b88dc7439a6d841e1a1103f5a3d2d2440137f18d02763503bac7b45dcb983b81604086017f013d1d4b425179258b577860397955cbfa0816e32b1c25a1fd734c91b951ee818151525101527f169ba15107f2eff9b9341bf30742a838d27dbd69e88b2353dca8592f15f1111c81606086017f0c3c864f195f59119927f53857f1de8bf575941748b735351fd31373c7875c2d8151525101527f0326ff06391ed5d26ec1bc080b8d46014ee22c0c68ed022f1620c4d9d38437d381608086017f11d4ceb15961d10b6156ae3d09bb78b4df45fb8543060884e7d400755beb4ac88151525101527e1379342a4d77d4708743aff01ff27aa11917478fdc8e2b7d463081735772ea8160a086017f23610cb43e21033c368a93622dd405b905a0eb344c98b9d7cf08b0c5ebf7c8398151525101527f25280b124624911c7f87b4c2d87f59c6c07e3eeeb10d614da216f6219ffe50b68160c086017f194daf85d9eed9937b28e2a680fcc5a76922c15cd31dc4f600e14939b8200ce78151525101527f1bae9f36e6190738c711501be53f299bf61348e61e2ef9d577760e64f629368d8160e086017f04882ef39899ea38c9677a48b8f8cc6a67284e17ff940289faaa359eec9b33a68151525101527f0b25394da5a1d435daccc2eadd039e2c2709f5f42fabd9afba815ed62d6af36b8161010086017f2d810d30120cb93e1a254b89ed0ae86c761f49b4f129459cd534f9551851350f8151525101527f1a0255ec8c7c8769335bc9dc6b222ac6a04e766d08b45c8cc573592c05bc9c148161012086017f1c2ce7be570bea9e43f3d3d7cbca84bdb4fc89b53ae657531de72670a6105e088151525101527f272eb7d633cedb68ce0113f4420ab5610b81b8ba1ab9348db15761d40e8df5ba8161014086017f1c164159136b8f5b4773e133f483a8a192ab15d6d3ee012f171b3d02fd4506e78151525101527f033e195a9ea3a9ce40b72b673afb45444ca1b15f0543f44d10f5c640a780676f8161016086017f0e446639aa6caf25e93ef747084e39b8ea90abf23bb48c28fd5f9ba7ba6550228151525101527f0f4c69895451af15052aa81a03eba9752c9e7891dd08e264e0bd593d0357858e8161018086017f0e8db2b2893df23d3c55f0b3a3b54ab2e2ed775b31c4c90e472eb31582582df28151525101527f1f4dcf4dd484e3ab1ae487603d2245397ac78fe6ca7584645eba3926d383902b816101a086017f2bc091fefe2416ec83c6fba8fb82fb48cb9ca00182ec792c212bf5532958c8f78151525101527f19eb12a7827c0ddf6383fe806c3953bd06b08aae7bf2a01f55c986a84f50cc28816101c086017f2daf78c5a2829a9418081dd7e8743a683ed6817996f75f10009d99220793ec738151525101527f1ffd789b155b8acb13e0f6a48b50f7aa8092540888d009141057d45690915824816101e086017f015691308846e68ea856a2cb24c9903f0c8605dea190829180ff6bdd1c6508038151525101527f16b7f250842ecf4e3690706a1e152d7a57f70f556f92076da785fdd363c19fcf8161020086017f0545ac7aa66dcf3719988438c806fc624de57ab43f8580392f88c86c1378ce4a8151525101527f149f415744707468bdaa4e8545201ab40d1931a7d31f23768fa7c65574ee3eab8161022086017f20cb7ff35a83a7dc314036e470f14c30fb0e98d35d663b243b222caa6fc7db448151525101527f0a521ff30c8f3666798f847c5d4c379658fba10156e7a9499f2713fae9bf2be18161024086017f0a25c1b7573906dc4e193b4ea82fd1fe7ccebc4d925dad26f0ff09c84c9f1a7581515251015261026084017f03db6510c3f13629fded9a5a2d41654bbce4ef6d024cad53100051d4a3f3ebc9815152510152565b90813b15612dbc57600080516020612ed283398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2805115612da157612d9e91612e0c565b50565b505034612daa57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b60ff600080516020612ef28339815191525460401c1615612dfa57565b604051631afcd79f60e31b8152600490fd5b600080611bb393602081519101845af43d15612e4a573d91612e2d83610cbd565b92612e3b60405194856103d4565b83523d6000602085013e612e4e565b6060915b90612e755750805115612e6357805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612ea8575b612e86575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15612e7e56fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a164736f6c6343000817000a" +"0x60a0346200060d576200350c38819003601f8101601f191683016001600160401b03811184821017620004465783928291604052833981010361012081126200060d576101008091126200060d57604051918183016001600160401b038111848210176200044657604052620000758162000612565b8352620000856020820162000612565b602084015260408101516040840152606081015160608401526080810151608084015260a081015160a084015260c081015160c084015260e081015160e0840152015163ffffffff811681036200060d57306080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c16620005fb576002600160401b03196001600160401b03821601620005af575b505081516001600160401b03161580159062000598575b80156200058b575b80156200057e575b801562000571575b801562000564575b62000552576000805463ffffffff1681526005602090815260409182902084518154928601516001600160801b03199093166001600160401b0391909116179190921b6fffffffffffffffff0000000000000000161781556040838101516001830155606084015160028301556080840151600383015560a0840151600483015560c0840151600583015560e084015160069092019190915560008054602090811c63ffffffff1682529082902084518154928601516001600160801b03199093166001600160401b0391909116179190921b6fffffffffffffffff00000000000000001617815590604083810151600184015560608085015160028501556080808601516003860181905560a08701516004870181905560c08801516005880181905560e0890151600698890155875463ffffffff60a81b191660a89790971b63ffffffff60a81b169690961796879055845160208101928352948501528383019490945290825281016001600160401b0381118282101762000446576040525190208060015560e08301519081600255600355600455600854908115159182620004db575b50506200045c575b602081015160409182015182519290916001600160401b03908116918401908111848210176200044657604052825260208201526040516060810181811060018060401b03821117620004465760409081526001600160401b0343811683524216602083019081529082019283526008546801000000000000000081101562000446578060016200039e920160085562000627565b93909362000430579151835491516001600160801b03199092166001600160401b03919091161760409190911b6fffffffffffffffff0000000000000000161782556002906020905180516001850180546001600160401b0319166001600160401b03929092169190911790550151910155604051612eae90816200065e8239608051818181610d3d0152610e950152f35b634e487b7160e01b600052600060045260246000fd5b634e487b7160e01b600052604160045260246000fd5b60075462000473906001600160401b031662000627565b62000430576000808255600182018190556002909101556007546001600160401b03808216908114620004c5576001600160401b03199091166001919091016001600160401b03161760075562000309565b634e487b7160e01b600052601160045260246000fd5b9091506000198101908111620004c557620004f69062000627565b50546007546001600160401b0360409290921c82169162000518911662000627565b505460401c6001600160401b0390811690910391908211620004c55760a81c63ffffffff166001600160401b039091161015388062000301565b6040516350dd03f760e11b8152600490fd5b5060e0820151156200015a565b5060c08201511562000152565b5060a0820151156200014a565b5060808201511562000142565b5060208201516001600160401b031615156200013a565b6001600160401b0319166001600160401b039081179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1388062000123565b60405163f92ee8a960e01b8152600490fd5b600080fd5b51906001600160401b03821682036200060d57565b600854811015620006475760086000526003602060002091020190600090565b634e487b7160e01b600052603260045260246000fdfe6080604052600436101561001257600080fd5b60003560e01c8063013fa5fc1461021757806302b592f3146102125780630d8e6e2c1461020d578063202a0adb146102085780632d52aad6146102035780632f5f4600146101fe5780632f79889d146101f9578063313df7b1146101f4578063382b215a146101ef578063409939b7146101ea5780634847ae5d146101e55780634f1ef286146101e057806352d1902d146101db57806362827733146101d657806369cc6a04146101d1578063715018a6146101cc57806376b6b7cb146101c75780637f17baad146101c257806382d07ff3146101bd5780638584d23f146101b85780638da5cb5b146101b357806396c1ca61146101ae578063a244d596146101a9578063aa922732146101a4578063ad3cb1cc1461019f578063bd32519a1461019a578063c23b9e9e14610195578063c8e5e49814610190578063ca6fe8551461018b578063e030330114610186578063f2fde38b146101815763f9e50d191461017c57600080fd5b6115b5565b61158c565b61145c565b61143e565b611421565b6113fa565b6113d4565b611357565b61132a565b6111e7565b611162565b61112c565b6110ef565b6110c7565b61101a565b610fd5565b610f6a565b610f0b565b610eed565b610e82565b610cc3565b610bf2565b610a3d565b6107f0565b6107c7565b6107a0565b6106b2565b61068c565b6105b1565b6104ee565b610478565b61024e565b600435906001600160a01b038216820361023257565b600080fd5b61012435906001600160a01b038216820361023257565b346102325760203660031901126102325761026761021c565b61026f611dbc565b6001600160a01b039081169081156102ff5760065490811682146102ed5760ff60a01b19919091166001600160a81b03199190911617600160a01b1760068190556040516001600160a01b0390911681527f8017bb887fdf8fca4314a9d40f6e73b3b81002d67e5cfa85d88173af6aa460729080602081015b0390a1005b60405163a863aec960e01b8152600490fd5b60405163e6c4247b60e01b8152600490fd5b634e487b7160e01b600052603260045260246000fd5b600854811015610362576003906008600052027ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190600090565b610311565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761039857604052565b610367565b61010081019081106001600160401b0382111761039857604052565b606081019081106001600160401b0382111761039857604052565b90601f801991011681019081106001600160401b0382111761039857604052565b604051906102e082018281106001600160401b0382111761039857604052565b604051906104228261037d565b565b60405190610422826103b9565b604051906102c082018281106001600160401b0382111761039857604052565b9060405161045e8161037d565b6020600182946001600160401b0381541684520154910152565b3461023257602036600319011261023257600435600854811015610232576104a1608091610327565b506104ec8154916104bc60016001600160401b039201610451565b9060405193818116855260401c1660208401526040830190602080916001600160401b0381511684520151910152565bf35b34610232576000366003190112610232576060604051600181526000602082015260006040820152f35b602435906001600160401b038216820361023257565b35906001600160401b038216820361023257565b610100906003190112610232576040519061055c8261039d565b816004356001600160401b038116810361023257815261057a610518565b602082015260443560408201526064356060820152608435608082015260a43560a082015260c43560c082015260e060e435910152565b3461023257610100366003190112610232576105cc36610542565b63ffffffff60005460201c166000526005602052600660e06040600020926106146001600160401b0382511685906001600160401b03166001600160401b0319825416179055565b61065361062b60208301516001600160401b031690565b855467ffffffffffffffff60401b191660409190911b67ffffffffffffffff60401b16178555565b60408101516001850155606081015160028501556080810151600385015560a0810151600485015560c081015160058501550151910155005b34610232576020366003190112610232576009805460ff19166001179055600435600a55005b3461023257602080600319360112610232576001600160401b03600435818111610232573660238201121561023257806004013591821161039857604092835192610702828260051b01856103d4565b80845260248285019160071b8401019236841161023257602401905b8382106107305761072e85611759565b005b813603608081126102325786805191610748836103b9565b6107518561052e565b835261075e86860161052e565b83870152603f190112610232576080918491885161077b8161037d565b6107868a870161052e565b81526060860135848201528982015281520191019061071e565b346102325760003660031901126102325760206001600160401b0360075416604051908152f35b34610232576000366003190112610232576006546040516001600160a01b039091168152602090f35b34610232576000366003190112610232576020600354604051908152f35b60409061010319011261023257604051906108288261037d565b610104358252610124356020830152565b60409061014319011261023257604051906108538261037d565b610144358252610164356020830152565b604090610183190112610232576040519061087e8261037d565b6101843582526101a4356020830152565b6040906101c319011261023257604051906108a98261037d565b6101c43582526101e4356020830152565b60409061020319011261023257604051906108d48261037d565b610204358252610224356020830152565b60409061024319011261023257604051906108ff8261037d565b610244358252610264356020830152565b604090610283190112610232576040519061092a8261037d565b6102843582526102a4356020830152565b6040906102c319011261023257604051906109558261037d565b6102c43582526102e4356020830152565b60409061030319011261023257604051906109808261037d565b610304358252610324356020830152565b60409061034319011261023257604051906109ab8261037d565b610344358252610364356020830152565b60409061038319011261023257604051906109d68261037d565b6103843582526103a4356020830152565b6040906103c31901126102325760405190610a018261037d565b6103c43582526103e4356020830152565b6040906104031901126102325760405190610a2c8261037d565b610404358252610424356020830152565b346102325761058036600319011261023257610a5836610542565b610480366101031901126102325761072e90610a726103f5565b90610a7c3661080e565b8252610a8736610839565b6020830152610a9536610864565b6040830152610aa33661088f565b6060830152610ab1366108ba565b6080830152610abf366108e5565b60a0830152610acd36610910565b60c0830152610adb3661093b565b60e0830152610ae936610966565b610100830152610af836610991565b610120830152610b07366109bc565b610140830152610b16366109e7565b610160830152610b2536610a12565b610180830152610444356101a0830152610464356101c0830152610484356101e08301526104a4356102008301526104c4356102208301526104e4356102408301526105043561026083015261052435610280830152610544356102a0830152610564356102c0830152611803565b91909160e0806101008301946001600160401b03808251168552602082015116602085015260408101516040850152606081015160608501526080810151608085015260a081015160a085015260c081015160c08501520151910152565b3461023257600080600319360112610ca5576040610ca191610c126119b2565b5063ffffffff8154168152600560205220600660405191610c328361039d565b80546001600160401b038082168552610c5c915b60401c1660208501906001600160401b03169052565b600181015460408401526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152015460e082015260405191829182610b94565b0390f35b80fd5b6001600160401b03811161039857601f01601f191660200190565b60408060031936011261023257610cd861021c565b6024356001600160401b038111610232573660238201121561023257806004013590610d0382610ca8565b91610d10855193846103d4565b80835260209136602483830101116102325781600092602485930183870137840101526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114908115610e66575b50610e55579080600492610d7b611dbc565b7ff78721226efe9a1bb678189a16d1554928b9f2192e2cb93eeda83b79fa40007d82885192881692838152a186516352d1902d60e01b815293849182905afa918291600093610e26575b5050610deb578351634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b600080516020612e628339815191528193929303610e0d5761072e8383612cc6565b8351632a87526960e21b81526004810191909152602490fd5b610e46929350803d10610e4e575b610e3e81836103d4565b8101906125b3565b903880610dc5565b503d610e34565b845163703e46dd60e11b8152600490fd5b905081600080516020612e628339815191525416141538610d69565b34610232576000366003190112610232577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003610edb576020604051600080516020612e628339815191528152f35b60405163703e46dd60e11b8152600490fd5b34610232576000366003190112610232576020600254604051908152f35b3461023257600080600319360112610ca557610f25611dbc565b60065460ff8160a01c166000146102ed576001600160a81b0319166006557f9a5f57de856dd668c54dd95e5c55df93432171cbca49a8776d5620ea59c024508180a180f35b3461023257600080600319360112610ca557610f84611dbc565b600080516020612e4283398151915280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b34610232576000366003190112610232576020600154604051908152f35b6004359063ffffffff8216820361023257565b610104359063ffffffff8216820361023257565b346102325760203660031901126102325763ffffffff611038610ff3565b1660005260056020526040600020805490610ca16001600160401b039160018101549060028101546003820154600483015491600660058501549401549460405198888a998260401c16911689949198979693909260e0969361010087019a6001600160401b03809216885216602087015260408601526060850152608084015260a083015260c08201520152565b3461023257600036600319011261023257610ca16110e36119f0565b60405191829182610b94565b3461023257602036600319011261023257604061110d600435611aaa565b6104ec82518092602080916001600160401b0381511684520151910152565b3461023257600036600319011261023257600080516020612e42833981519152546040516001600160a01b039091168152602090f35b346102325760203660031901126102325761117b610ff3565b611183611dbc565b63ffffffff808216610e1081109182156111d5575b50506111c3576006805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055005b6040516307a5077760e51b8152600490fd5b60065460a81c16101590503880611198565b34610232576101403660031901126102325761120236610542565b61120a611006565b90611213610237565b600080516020612e8283398151915254926001600160401b0360ff8560401c1615941680159081611322575b6001149081611318575b15908161130f575b506112fd57600080516020612e82833981519152805467ffffffffffffffff1916600117905561128592846112d857611b70565b61128b57005b600080516020612e82833981519152805460ff60401b19169055604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080602081016102e8565b600080516020612e82833981519152805460ff60401b1916600160401b179055611b70565b60405163f92ee8a960e01b8152600490fd5b90501538611251565b303b159150611249565b85915061123f565b346102325761010036600319011261023257602061134f61134a36610542565b611d00565b604051908152f35b346102325760003660031901126102325760408051906113768261037d565b60058252602090640352e302e360dc1b6020840152604051916020835283519182602085015260005b8381106113c15784604081866000838284010152601f80199101168101030190f35b858101830151858201830152820161139f565b3461023257600036600319011261023257602060ff60065460a01c166040519015158152f35b3461023257600036600319011261023257602063ffffffff60065460a81c16604051908152f35b34610232576000366003190112610232576009805460ff19169055005b34610232576000366003190112610232576020600454604051908152f35b34610232576040366003190112610232576004356024359060ff600954166000906000146114aa575090611496610ca192600a5490611a9d565b115b60405190151581529081906020820190565b91600854914381118015611582575b61150f576114c78493611a8e565b926114e96114dd6007546001600160401b031690565b6001600160401b031690565b935b8115611521575b50909192501561150f57610ca19261150991611a9d565b11611498565b60405163b0b4387760e01b8152600490fd5b8261153f6114dd61153184610327565b50546001600160401b031690565b1115611568575b60028110611563578481146115635761155e906125c2565b6114eb565b6114f2565b945050600161157c6114dd61153187610327565b94611546565b50600383106114b9565b346102325760203660031901126102325761072e6115a861021c565b6115b0611dbc565b611d48565b34610232576000366003190112610232576020600854604051908152f35b634e487b7160e01b600052600060045260246000fd5b9060e06006916116496001600160401b0361161d8184511687906001600160401b03166001600160401b0319825416179055565b6020830151865467ffffffffffffffff60401b1916911660401b67ffffffffffffffff60401b16178555565b60408101516001850155606081015160028501556080810151600385015560a0810151600485015560c081015160058501550151910155565b634e487b7160e01b600052601160045260246000fd5b906116af5760028160008093558260018201550155565b6115d3565b80518210156103625760209160051b010190565b600854600160401b811015610398578060016116e79201600855610327565b9190916116af57805182546020808401516001600160401b039384166fffffffffffffffffffffffffffffffff1990931692909217604092831b67ffffffffffffffff60401b16178555920151805160018501805467ffffffffffffffff191691909316179091556002910151910155565b90600854600060085580611796575b5060005b8251811015611791578061178b611785600193866116b4565b516116c8565b0161176c565b509050565b600390806003029060038204036117fe5760086000527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3908101905b8181106117e0575050611768565b806117f8849260026000918281558260018201550155565b016117d2565b611682565b9060065460ff8160a01c16908161199e575b5061198c5781516001600160401b03166118406114dd6118336119f0565b516001600160401b031690565b6001600160401b0380921611801590611955575b611943577fa04a773924505a418564363725f56832f5772e6b8d0dbd6efce724dfe803dae6906118c6604085019361188c8551611df5565b6118996060870151611df5565b6118a66080870151611df5565b6118b360a0870151611df5565b6118c060c0870151611df5565b856122cc565b6118fb846118f66118e060005463ffffffff9060201c1690565b63ffffffff166000526005602052604060002090565b6115e9565b61190a8482421683431661246a565b61192f602061192086516001600160401b031690565b9501516001600160401b031690565b9251604051908152928116931691602090a3565b60405163051c46ef60e01b8152600490fd5b5060208301516001600160401b0316816119836114dd60206119756119f0565b01516001600160401b031690565b91161115611854565b6040516301474c8f60e71b8152600490fd5b6001600160a01b0316331415905038611815565b604051906119bf8261039d565b8160e06000918281528260208201528260408201528260608201528260808201528260a08201528260c08201520152565b6119f86119b2565b5063ffffffff60005460201c1660005260056020526040600020600660405191611a218361039d565b80546001600160401b038082168552611a3991610c46565b600181015460408401526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152015460e082015290565b60405190611a828261037d565b60006020838281520152565b6000198101919082116117fe57565b919082039182116117fe57565b611ab2611a75565b5060085490611ac8611ac383611a8e565b610327565b5090611ae26114dd6001809401546001600160401b031690565b811015611b5e57611afe6114dd6007546001600160401b031690565b838110611b23575050506001611b19611ac3611b2093611a8e565b5001610451565b90565b81611b436114dd85611b3485610327565b5001546001600160401b031690565b11611b4f578201611afe565b611b209350611b199150610327565b604051631856a49960e21b8152600490fd5b9091611b8690611b7e612d6d565b6115b0612d6d565b611b8e612d6d565b6401000000006001600160401b031960005416176000556001600160401b0380611bbf83516001600160401b031690565b1615801590611ce1575b8015611cd5575b8015611cc9575b8015611cbd575b8015611cb1575b611c9f5760008052600560205261042292611c6390611c24847f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc6115e9565b611c3e846118f66118e060005463ffffffff9060201c1690565b6006805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055565b611c94611c6f83611d00565b611c7881600155565b611c8f60e085015191611c8a83600255565b600355565b600455565b80421690431661246a565b6040516350dd03f760e11b8152600490fd5b5060e082015115611be5565b5060c082015115611bde565b5060a082015115611bd7565b50608082015115611bd0565b50611cf96114dd60208401516001600160401b031690565b1515611bc9565b60808101519060c060a082015191015160405191602083019384526040830152606082015260608152608081018181106001600160401b038211176103985760405251902090565b6001600160a01b03908116908115611da357600080516020612e4283398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b600080516020612e42833981519152546001600160a01b03163303611ddd57565b60405163118cdaa760e01b8152336004820152602490fd5b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000011115611e1e57565b60405162461bcd60e51b815260206004820152601b60248201527f426e3235343a20696e76616c6964207363616c6172206669656c6400000000006044820152606490fd5b60405190611e708261039d565b610100368337565b90816020910312610232575180151581036102325790565b6000915b60088310611ea157505050565b600190825181526020809101920192019190611e94565b61046090611ed183825160208091805184520151910152565b60208181015180516040860152015160608401526040810151805160808501526020015160a08401526060810151805160c08501526020015160e0840152608081015190611f2f610100928386019060208091805184520151910152565b60a081015191611f4f610140938487019060208091805184520151910152565b60c082015192611f6f610180948588019060208091805184520151910152565b60e083015191611f8f6101c0938489019060208091805184520151910152565b830151611fac610200918289019060208091805184520151910152565b61012084015191611fcd61024093848a019060208091805184520151910152565b84015192611feb61028094858a019060208091805184520151910152565b6120266101608601519661200f6102c098898c019060208091805184520151910152565b86015180516103008b0152602001516103208a0152565b6101a08501516103408901528401516103608801526101e08401516103808801528301516103a08701526102208301516103c08701528201516103e08601526102608201516104008601528101516104208501526102a08101516104408501520151910152565b610600906122b961042294969593966102a0610a8084019880518552602081015160208601526120cf6040820151604087019060208091805184520151910152565b6060810151805160808701526020015160a08601526080810151805160c08701526020015160e086015260a0810151612118610100918288019060208091805184520151910152565b6122858661225660c085015161213e610140918285019060208091805184520151910152565b61222760e087015195612161610180978887019060208091805184520151910152565b87015161217e6101c0918287019060208091805184520151910152565b6121bb610120890151936121a2610200958689019060208091805184520151910152565b8901516102408097019060208091805184520151910152565b6121f88c6102c06101608b0151996121e36102809b8c85019060208091805184520151910152565b8b015191019060208091805184520151910152565b6101a088015180516103008e0152602001516103208d015287015180516103408d0152602001516103608c0152565b6101e086015180516103808c0152602001516103a08b015285015180516103c08b0152602001516103e08a0152565b61022084015180516104008a015260200151610420890152830151805161044089015260200151610460880152565b6102608201518051610480880152602001516104a08701528101516104c086015201516104e0840152610500830190611e90565b0190611eb8565b6040513d6000823e3d90fd5b6020906122d76126eb565b60606122e1611e63565b9260025484526122fb6114dd82516001600160401b031690565b858501526123156114dd868301516001600160401b031690565b604085015260408101518285015201516080830152600561239e61234260005463ffffffff9060201c1690565b600361235e8263ffffffff166000526005602052604060002090565b015460a086015260046123818263ffffffff166000526005602052604060002090565b015460c086015263ffffffff166000526005602052604060002090565b015460e08301526123c360405194859384936350f8d1a760e11b85526004850161208d565b038173__$5c5c07cf4f55be9472c2b47d897172e765$__5af490811561243457600091612405575b50156123f357565b6040516309bde33960e01b8152600490fd5b612427915060203d60201161242d575b61241f81836103d4565b810190611e78565b386123eb565b503d612415565b6122c0565b6001600160401b0391821690821603919082116117fe57565b6001600160401b038091169081146117fe5760010190565b90916124d961042293600854801515908161253f575b506124e3575b604061249c60208501516001600160401b031690565b9301516124b96124aa610415565b6001600160401b039095168552565b60208401526124c96124aa610424565b6001600160401b03166020840152565b60408201526116c8565b6125016124fb611ac36007546001600160401b031690565b90611698565b61253a61251e6125196007546001600160401b031690565b612452565b6001600160401b03166001600160401b03196007541617600755565b612486565b6125829150612553611ac361256492611a8e565b505460401c6001600160401b031690565b61257c612553611ac36007546001600160401b031690565b90612439565b6001600160401b036125a96125a060065463ffffffff9060a81c1690565b63ffffffff1690565b9116101538612480565b90816020910312610232575190565b80156117fe576000190190565b6125d7610431565b9060008252600060208301526125eb611a75565b60408301526125f8611a75565b6060830152612605611a75565b6080830152612612611a75565b60a083015261261f611a75565b60c083015261262c611a75565b60e0830152612639611a75565b610100830152612647611a75565b610120830152612655611a75565b610140830152612663611a75565b610160830152612671611a75565b61018083015261267f611a75565b6101a083015261268d611a75565b6101c083015261269b611a75565b6101e08301526126a9611a75565b6102008301526126b7611a75565b6102208301526126c5611a75565b6102408301526126d3611a75565b610260830152600061028083015260006102a0830152565b6126f36125cf565b906201000082527f08e80a5c8e4c9b9f26f3003cc59403a18d3136afd030868d25cc8b807e2ab37060206008818501527f16b88dc7439a6d841e1a1103f5a3d2d2440137f18d02763503bac7b45dcb983b81604086017f013d1d4b425179258b577860397955cbfa0816e32b1c25a1fd734c91b951ee818151525101527f169ba15107f2eff9b9341bf30742a838d27dbd69e88b2353dca8592f15f1111c81606086017f0c3c864f195f59119927f53857f1de8bf575941748b735351fd31373c7875c2d8151525101527f0326ff06391ed5d26ec1bc080b8d46014ee22c0c68ed022f1620c4d9d38437d381608086017f11d4ceb15961d10b6156ae3d09bb78b4df45fb8543060884e7d400755beb4ac88151525101527e1379342a4d77d4708743aff01ff27aa11917478fdc8e2b7d463081735772ea8160a086017f23610cb43e21033c368a93622dd405b905a0eb344c98b9d7cf08b0c5ebf7c8398151525101527f25280b124624911c7f87b4c2d87f59c6c07e3eeeb10d614da216f6219ffe50b68160c086017f194daf85d9eed9937b28e2a680fcc5a76922c15cd31dc4f600e14939b8200ce78151525101527f1bae9f36e6190738c711501be53f299bf61348e61e2ef9d577760e64f629368d8160e086017f04882ef39899ea38c9677a48b8f8cc6a67284e17ff940289faaa359eec9b33a68151525101527f0b25394da5a1d435daccc2eadd039e2c2709f5f42fabd9afba815ed62d6af36b8161010086017f2d810d30120cb93e1a254b89ed0ae86c761f49b4f129459cd534f9551851350f8151525101527f1a0255ec8c7c8769335bc9dc6b222ac6a04e766d08b45c8cc573592c05bc9c148161012086017f1c2ce7be570bea9e43f3d3d7cbca84bdb4fc89b53ae657531de72670a6105e088151525101527f272eb7d633cedb68ce0113f4420ab5610b81b8ba1ab9348db15761d40e8df5ba8161014086017f1c164159136b8f5b4773e133f483a8a192ab15d6d3ee012f171b3d02fd4506e78151525101527f033e195a9ea3a9ce40b72b673afb45444ca1b15f0543f44d10f5c640a780676f8161016086017f0e446639aa6caf25e93ef747084e39b8ea90abf23bb48c28fd5f9ba7ba6550228151525101527f0f4c69895451af15052aa81a03eba9752c9e7891dd08e264e0bd593d0357858e8161018086017f0e8db2b2893df23d3c55f0b3a3b54ab2e2ed775b31c4c90e472eb31582582df28151525101527f1f4dcf4dd484e3ab1ae487603d2245397ac78fe6ca7584645eba3926d383902b816101a086017f2bc091fefe2416ec83c6fba8fb82fb48cb9ca00182ec792c212bf5532958c8f78151525101527f19eb12a7827c0ddf6383fe806c3953bd06b08aae7bf2a01f55c986a84f50cc28816101c086017f2daf78c5a2829a9418081dd7e8743a683ed6817996f75f10009d99220793ec738151525101527f1ffd789b155b8acb13e0f6a48b50f7aa8092540888d009141057d45690915824816101e086017f015691308846e68ea856a2cb24c9903f0c8605dea190829180ff6bdd1c6508038151525101527f16b7f250842ecf4e3690706a1e152d7a57f70f556f92076da785fdd363c19fcf8161020086017f0545ac7aa66dcf3719988438c806fc624de57ab43f8580392f88c86c1378ce4a8151525101527f149f415744707468bdaa4e8545201ab40d1931a7d31f23768fa7c65574ee3eab8161022086017f20cb7ff35a83a7dc314036e470f14c30fb0e98d35d663b243b222caa6fc7db448151525101527f0a521ff30c8f3666798f847c5d4c379658fba10156e7a9499f2713fae9bf2be18161024086017f0a25c1b7573906dc4e193b4ea82fd1fe7ccebc4d925dad26f0ff09c84c9f1a7581515251015261026084017f03db6510c3f13629fded9a5a2d41654bbce4ef6d024cad53100051d4a3f3ebc98151525101527fb0838893ec1f237e8b07323b0744599f4e97b598b3b589bcc2bc37b8d5c418016102808301527fc18393c0fa30fe4e8b038e357ad851eae8de9107584effe7c7f1f651b2010e266102a0830152565b90813b15612d4c57600080516020612e6283398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2805115612d3157612d2e91612d9c565b50565b505034612d3a57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b60ff600080516020612e828339815191525460401c1615612d8a57565b604051631afcd79f60e31b8152600490fd5b600080611b2093602081519101845af43d15612dda573d91612dbd83610ca8565b92612dcb60405194856103d4565b83523d6000602085013e612dde565b6060915b90612e055750805115612df357805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612e38575b612e16575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15612e0e56fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a164736f6c6343000817000a" diff --git a/contract-bindings/artifacts/LightClient_bytecode.json b/contract-bindings/artifacts/LightClient_bytecode.json index 9aaffa6089..b480d85c16 100644 --- a/contract-bindings/artifacts/LightClient_bytecode.json +++ b/contract-bindings/artifacts/LightClient_bytecode.json @@ -1 +1 @@ -"0x60a080604052346100cd57306080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff8260401c166100be57506001600160401b036002600160401b031982821601610079575b604051612c439081620000d38239608051818181610af30152610c4b0152f35b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1388080610059565b63f92ee8a960e01b8152600490fd5b600080fdfe6080604052600436101561001257600080fd5b60003560e01c8063013fa5fc146101d757806302b592f3146101d25780630d8e6e2c146101cd5780632f79889d146101c8578063313df7b1146101c3578063382b215a146101be578063409939b7146101b95780634847ae5d146101b45780634f1ef286146101af57806352d1902d146101aa57806362827733146101a557806369cc6a04146101a0578063715018a61461019b57806376b6b7cb146101965780637f17baad1461019157806382d07ff31461018c5780638584d23f146101875780638da5cb5b1461018257806396c1ca611461017d578063a244d59614610178578063aa92273214610173578063ad3cb1cc1461016e578063bd32519a14610169578063c23b9e9e14610164578063ca6fe8551461015f578063e03033011461015a578063f2fde38b146101555763f9e50d191461015057600080fd5b611323565b6112fa565b6111f5565b6111d7565b6111b0565b61118a565b61110d565b6110e0565b610f9d565b610f18565b610ee2565b610ea5565b610e7d565b610dd0565b610d8b565b610d20565b610cc1565b610ca3565b610c38565b610a79565b6109a8565b6107f1565b61051f565b6104f6565b6104cf565b6104a5565b61042f565b61020e565b600435906001600160a01b03821682036101f257565b600080fd5b61012435906001600160a01b03821682036101f257565b346101f25760203660031901126101f2576102276101dc565b61022f6119bb565b6001600160a01b039081169081156102bf5760065490811682146102ad5760ff60a01b19919091166001600160a81b03199190911617600160a01b1760068190556040516001600160a01b0390911681527f8017bb887fdf8fca4314a9d40f6e73b3b81002d67e5cfa85d88173af6aa460729080602081015b0390a1005b60405163a863aec960e01b8152600490fd5b60405163e6c4247b60e01b8152600490fd5b634e487b7160e01b600052603260045260246000fd5b600854811015610322576003906008600052027ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190600090565b6102d1565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761035857604052565b610327565b61010081019081106001600160401b0382111761035857604052565b90601f801991011681019081106001600160401b0382111761035857604052565b604051906102e082018281106001600160401b0382111761035857604052565b604051906103c78261033d565b565b60405190606082018281106001600160401b0382111761035857604052565b6040519061028082018281106001600160401b0382111761035857604052565b906040516104158161033d565b6020600182946001600160401b0381541684520154910152565b346101f25760203660031901126101f2576004356008548110156101f2576104586080916102e7565b506104a381549161047360016001600160401b039201610408565b9060405193818116855260401c1660208401526040830190602080916001600160401b0381511684520151910152565bf35b346101f25760003660031901126101f2576060604051600181526000602082015260006040820152f35b346101f25760003660031901126101f25760206001600160401b0360075416604051908152f35b346101f25760003660031901126101f2576006546040516001600160a01b039091168152602090f35b346101f25760003660031901126101f2576020600354604051908152f35b602435906001600160401b03821682036101f257565b6101009060031901126101f2576040519061056d8261035d565b816004356001600160401b03811681036101f257815261058b61053d565b602082015260443560408201526064356060820152608435608082015260a43560a082015260c43560c082015260e060e435910152565b6040906101031901126101f257604051906105dc8261033d565b610104358252610124356020830152565b6040906101431901126101f257604051906106078261033d565b610144358252610164356020830152565b6040906101831901126101f257604051906106328261033d565b6101843582526101a4356020830152565b6040906101c31901126101f2576040519061065d8261033d565b6101c43582526101e4356020830152565b6040906102031901126101f257604051906106888261033d565b610204358252610224356020830152565b6040906102431901126101f257604051906106b38261033d565b610244358252610264356020830152565b6040906102831901126101f257604051906106de8261033d565b6102843582526102a4356020830152565b6040906102c31901126101f257604051906107098261033d565b6102c43582526102e4356020830152565b6040906103031901126101f257604051906107348261033d565b610304358252610324356020830152565b6040906103431901126101f2576040519061075f8261033d565b610344358252610364356020830152565b6040906103831901126101f2576040519061078a8261033d565b6103843582526103a4356020830152565b6040906103c31901126101f257604051906107b58261033d565b6103c43582526103e4356020830152565b6040906104031901126101f257604051906107e08261033d565b610404358252610424356020830152565b346101f2576105803660031901126101f25761080c36610553565b610480366101031901126101f2576109489061082661039a565b90610830366105c2565b825261083b366105ed565b602083015261084936610618565b604083015261085736610643565b60608301526108653661066e565b608083015261087336610699565b60a0830152610881366106c4565b60c083015261088f366106ef565b60e083015261089d3661071a565b6101008301526108ac36610745565b6101208301526108bb36610770565b6101408301526108ca3661079b565b6101608301526108d9366107c6565b610180830152610444356101a0830152610464356101c0830152610484356101e08301526104a4356102008301526104c4356102208301526104e4356102408301526105043561026083015261052435610280830152610544356102a0830152610564356102c08301526113da565b005b91909160e0806101008301946001600160401b03808251168552602082015116602085015260408101516040850152606081015160608501526080810151608085015260a081015160a085015260c081015160c08501520151910152565b346101f257600080600319360112610a5b576040610a57916109c8611589565b5063ffffffff81541681526005602052206006604051916109e88361035d565b80546001600160401b038082168552610a12915b60401c1660208501906001600160401b03169052565b600181015460408401526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152015460e08201526040519182918261094a565b0390f35b80fd5b6001600160401b03811161035857601f01601f191660200190565b6040806003193601126101f257610a8e6101dc565b6024356001600160401b0381116101f257366023820112156101f257806004013590610ab982610a5e565b91610ac685519384610379565b80835260209136602483830101116101f25781600092602485930183870137840101526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114908115610c1c575b50610c0b579080600492610b316119bb565b7ff78721226efe9a1bb678189a16d1554928b9f2192e2cb93eeda83b79fa40007d82885192881692838152a186516352d1902d60e01b815293849182905afa918291600093610bdc575b5050610ba1578351634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b600080516020612bf78339815191528193929303610bc3576109488383612a5b565b8351632a87526960e21b81526004810191909152602490fd5b610bfc929350803d10610c04575b610bf48183610379565b8101906123b2565b903880610b7b565b503d610bea565b845163703e46dd60e11b8152600490fd5b905081600080516020612bf78339815191525416141538610b1f565b346101f25760003660031901126101f2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003610c91576020604051600080516020612bf78339815191528152f35b60405163703e46dd60e11b8152600490fd5b346101f25760003660031901126101f2576020600254604051908152f35b346101f257600080600319360112610a5b57610cdb6119bb565b60065460ff8160a01c166000146102ad576001600160a81b0319166006557f9a5f57de856dd668c54dd95e5c55df93432171cbca49a8776d5620ea59c024508180a180f35b346101f257600080600319360112610a5b57610d3a6119bb565b600080516020612bd783398151915280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b346101f25760003660031901126101f2576020600154604051908152f35b6004359063ffffffff821682036101f257565b610104359063ffffffff821682036101f257565b346101f25760203660031901126101f25763ffffffff610dee610da9565b1660005260056020526040600020805490610a576001600160401b039160018101549060028101546003820154600483015491600660058501549401549460405198888a998260401c16911689949198979693909260e0969361010087019a6001600160401b03809216885216602087015260408601526060850152608084015260a083015260c08201520152565b346101f25760003660031901126101f257610a57610e996115c7565b6040519182918261094a565b346101f25760203660031901126101f2576040610ec360043561169c565b6104a382518092602080916001600160401b0381511684520151910152565b346101f25760003660031901126101f257600080516020612bd7833981519152546040516001600160a01b039091168152602090f35b346101f25760203660031901126101f257610f31610da9565b610f396119bb565b63ffffffff808216610e108110918215610f8b575b5050610f79576006805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055005b6040516307a5077760e51b8152600490fd5b60065460a81c16101590503880610f4e565b346101f2576101403660031901126101f257610fb836610553565b610fc0610dbc565b90610fc96101f7565b600080516020612c1783398151915254926001600160401b0360ff8560401c16159416801590816110d8575b60011490816110ce575b1590816110c5575b506110b357600080516020612c17833981519152805467ffffffffffffffff1916600117905561103b928461108e57611762565b61104157005b600080516020612c17833981519152805460ff60401b19169055604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080602081016102a8565b600080516020612c17833981519152805460ff60401b1916600160401b179055611762565b60405163f92ee8a960e01b8152600490fd5b90501538611007565b303b159150610fff565b859150610ff5565b346101f2576101003660031901126101f257602061110561110036610553565b6118f2565b604051908152f35b346101f25760003660031901126101f257604080519061112c8261033d565b60058252602090640352e302e360dc1b6020840152604051916020835283519182602085015260005b8381106111775784604081866000838284010152601f80199101168101030190f35b8581018301518582018301528201611155565b346101f25760003660031901126101f257602060ff60065460a01c166040519015158152f35b346101f25760003660031901126101f257602063ffffffff60065460a81c16604051908152f35b346101f25760003660031901126101f2576020600454604051908152f35b346101f25760403660031901126101f25760043560085443821180156112f0575b61127d5760009161122860009261167b565b9161124a61123e6007546001600160401b031690565b6001600160401b031690565b925b811561128f575b509091501561127d5761126c610a57926024359261168f565b604051911081529081906020820190565b60405163b0b4387760e01b8152600490fd5b826112ad61123e61129f846102e7565b50546001600160401b031690565b11156112d6575b600281106112d1578381146112d1576112cc9061193a565b61124c565b611253565b93505060016112ea61123e61129f866102e7565b936112b4565b5060038110611216565b346101f25760203660031901126101f2576109486113166101dc565b61131e6119bb565b611947565b346101f25760003660031901126101f2576020600854604051908152f35b9060e06006916113a16001600160401b036113758184511687906001600160401b03166001600160401b0319825416179055565b6020830151865467ffffffffffffffff60401b1916911660401b67ffffffffffffffff60401b16178555565b60408101516001850155606081015160028501556080810151600385015560a0810151600485015560c081015160058501550151910155565b9060065460ff8160a01c169081611575575b506115635781516001600160401b031661141761123e61140a6115c7565b516001600160401b031690565b6001600160401b038092161180159061152c575b61151a577fa04a773924505a418564363725f56832f5772e6b8d0dbd6efce724dfe803dae69061149d604085019361146385516119f4565b61147060608701516119f4565b61147d60808701516119f4565b61148a60a08701516119f4565b61149760c08701516119f4565b85611f57565b6114d2846114cd6114b760005463ffffffff9060201c1690565b63ffffffff166000526005602052604060002090565b611341565b6114e184824216834316612269565b61150660206114f786516001600160401b031690565b9501516001600160401b031690565b9251604051908152928116931691602090a3565b60405163051c46ef60e01b8152600490fd5b5060208301516001600160401b03168161155a61123e602061154c6115c7565b01516001600160401b031690565b9116111561142b565b6040516301474c8f60e71b8152600490fd5b6001600160a01b03163314159050386113ec565b604051906115968261035d565b8160e06000918281528260208201528260408201528260608201528260808201528260a08201528260c08201520152565b6115cf611589565b5063ffffffff60005460201c16600052600560205260406000206006604051916115f88361035d565b80546001600160401b038082168552611610916109fc565b600181015460408401526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152015460e082015290565b604051906116598261033d565b60006020838281520152565b634e487b7160e01b600052601160045260246000fd5b60001981019190821161168a57565b611665565b9190820391821161168a57565b6116a461164c565b50600854906116ba6116b58361167b565b6102e7565b50906116d461123e6001809401546001600160401b031690565b811015611750576116f061123e6007546001600160401b031690565b83811061171557505050600161170b6116b56117129361167b565b5001610408565b90565b8161173561123e85611726856102e7565b5001546001600160401b031690565b116117415782016116f0565b611712935061170b91506102e7565b604051631856a49960e21b8152600490fd5b909161177890611770612b02565b61131e612b02565b611780612b02565b6401000000006001600160401b031960005416176000556001600160401b03806117b183516001600160401b031690565b16158015906118d3575b80156118c7575b80156118bb575b80156118af575b80156118a3575b611891576000805260056020526103c79261185590611816847f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc611341565b611830846114cd6114b760005463ffffffff9060201c1690565b6006805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055565b611886611861836118f2565b61186a81600155565b61188160e08501519161187c83600255565b600355565b600455565b804216904316612269565b6040516350dd03f760e11b8152600490fd5b5060e0820151156117d7565b5060c0820151156117d0565b5060a0820151156117c9565b506080820151156117c2565b506118eb61123e60208401516001600160401b031690565b15156117bb565b60808101519060c060a082015191015160405191602083019384526040830152606082015260608152608081018181106001600160401b038211176103585760405251902090565b801561168a576000190190565b6001600160a01b039081169081156119a257600080516020612bd783398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b600080516020612bd7833981519152546001600160a01b031633036119dc57565b60405163118cdaa760e01b8152336004820152602490fd5b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000011115611a1d57565b60405162461bcd60e51b815260206004820152601b60248201527f426e3235343a20696e76616c6964207363616c6172206669656c6400000000006044820152606490fd5b6040519061012082018281106001600160401b038211176103585760405260088252610100366020840137565b8051156103225760200190565b8051600110156103225760400190565b8051600210156103225760600190565b8051600310156103225760800190565b8051600410156103225760a00190565b8051600510156103225760c00190565b8051600610156103225760e00190565b805160071015610322576101000190565b908160209103126101f2575180151581036101f25790565b90815180825260208080930193019160005b828110611b45575050505090565b835185529381019392810192600101611b37565b61046090611b7283825160208091805184520151910152565b60208181015180516040860152015160608401526040810151805160808501526020015160a08401526060810151805160c08501526020015160e0840152608081015190611bd0610100928386019060208091805184520151910152565b60a081015191611bf0610140938487019060208091805184520151910152565b60c082015192611c10610180948588019060208091805184520151910152565b60e083015191611c306101c0938489019060208091805184520151910152565b830151611c4d610200918289019060208091805184520151910152565b61012084015191611c6e61024093848a019060208091805184520151910152565b84015192611c8c61028094858a019060208091805184520151910152565b611cc761016086015196611cb06102c098898c019060208091805184520151910152565b86015180516103008b0152602001516103208a0152565b6101a08501516103408901528401516103608801526101e08401516103808801528301516103a08701526102208301516103c08701528201516103e08601526102608201516104008601528101516104208501526102a08101516104408501520151910152565b939290611f436103c7936104e092611f346102606109609280518b52602081015160208c0152611d70604082015160408d019060208091805184520151910152565b6060810151805160808d01526020015160a08c01526080810151805160c08d01526020015160e08c0152611f1e8b611dbc60a08401516101008093019060208091805184520151910152565b611eef8d6103c060c0860151611de2610140918285019060208091805184520151910152565b611ec260e088015195611e05610180978887019060208091805184520151910152565b880151611e226101c0918287019060208091805184520151910152565b611e936101208a015193611e46610200958689019060208091805184520151910152565b8a015197611e64610240998a89019060208091805184520151910152565b6101608b01518051610280890152602001516102a08801528a015180516102c0880152602001516102e0870152565b6101a0890151805161030087015260200151610320860152880151805161034086015260200151610360850152565b6101e08701518051610380850152602001516103a084015286015191019060208091805184520151910152565b61022083015180516104008f0152602001516104208e015282015180516104408e0152602001516104608d0152565b015180516104808b0152602001516104a08a0152565b806104c0890152870190611b25565b940190611b59565b6040513d6000823e3d90fd5b602090611f626124cd565b6060611f6c611a62565b92600254611f7985611a8f565b52611f8e61123e82516001600160401b031690565b611f9785611a9c565b52611fae61123e868301516001600160401b031690565b611fb785611aac565b526040810151611fc685611abc565b520151611fd283611acc565b526005612051611feb60005463ffffffff9060201c1690565b60036120078263ffffffff166000526005602052604060002090565b015461201286611adc565b52600461202f8263ffffffff166000526005602052604060002090565b015461203a86611aec565b5263ffffffff166000526005602052604060002090565b015461205c83611afc565b5261207b6040519485938493630c76545d60e21b855260048501611d2e565b038173__$5c5c07cf4f55be9472c2b47d897172e765$__5af49081156120ec576000916120bd575b50156120ab57565b6040516309bde33960e01b8152600490fd5b6120df915060203d6020116120e5575b6120d78183610379565b810190611b0d565b386120a3565b503d6120cd565b611f4b565b6001600160401b03918216908216039190821161168a57565b906121215760028160008093558260018201550155565b634e487b7160e01b600052600060045260246000fd5b6001600160401b0380911690811461168a5760010190565b600854600160401b81101561035857600181018060085581101561032257602060037ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee592600860005202926122626040857ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee3019261221e6001600160401b03946121f28684511682906001600160401b03166001600160401b0319825416179055565b82870151815467ffffffffffffffff60401b191690871660401b67ffffffffffffffff60401b16179055565b0151918251167ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee48601906001600160401b03166001600160401b0319825416179055565b0151910155565b90916122d86103c793600854801515908161233e575b506122e2575b604061229b60208501516001600160401b031690565b9301516122b86122a96103ba565b6001600160401b039095168552565b60208401526122c86122a96103c9565b6001600160401b03166020840152565b604082015261214f565b6123006122fa6116b56007546001600160401b031690565b9061210a565b61233961231d6123186007546001600160401b031690565b612137565b6001600160401b03166001600160401b03196007541617600755565b612285565b61238191506123526116b56123639261167b565b505460401c6001600160401b031690565b61237b6123526116b56007546001600160401b031690565b906120f1565b6001600160401b036123a861239f60065463ffffffff9060a81c1690565b63ffffffff1690565b911610153861227f565b908160209103126101f2575190565b6123c96103e8565b9060008252600060208301526123dd61164c565b60408301526123ea61164c565b60608301526123f761164c565b608083015261240461164c565b60a083015261241161164c565b60c083015261241e61164c565b60e083015261242b61164c565b61010083015261243961164c565b61012083015261244761164c565b61014083015261245561164c565b61016083015261246361164c565b61018083015261247161164c565b6101a083015261247f61164c565b6101c083015261248d61164c565b6101e083015261249b61164c565b6102008301526124a961164c565b6102208301526124b761164c565b6102408301526124c561164c565b610260830152565b6124d56123c1565b906210000082527f2ce6cc664a32147bfe6a0c94a95bf0496679405ccae01648cd4ec021145120d560206008818501527f03a0a9acc3e3815a7ed6cb1379f7d157e6343164729376392a693acbd3ec283c81604086017f20c9403133dfde9a9d382df76fb0523571648725abc0a7c12830bb690ec83b338151525101527f21be232a42246a5663ebf483470cca666ffe9d4f0e63b929c596a7658714e97081606086017f2866c18ad1df10ef13542cce6250ce02cb2a6b72ae00a9852e271187e9e4e0db8151525101527f0be0f448839080132d47de17de0099b4cd74ae1e6b71cdda06cdebb868a50c6d81608086017f07d77873b9860074118e75808c79468b83c8ed64ba14db5cb5afa8e534de7b998151525101527f18f95cdda42ce11d9d10a3b335acc214e3807c578c5359405d810c208df600938160a086017f13bd45a023491eadea44cc3f24cfbd1796eade9c0e39ee81d9f63ea0a58066258151525101527f28c2217f7bacf6f8b2b8ee4a90fcf8b5bca04205ea84e8e1eb54b85dd41bde288160c086017f0970d978763461f09e9ec63454073497386e4d282fedc2ac5b967cb9fd3fa8a98151525101527f202c3e390cee7c5c8525da2329a19f4936f6f71ca97dde6c6fa32b382d5acc038160e086017f02fe3d02988db718380052970aba46a3296df5f29b736ba1f2c4ccffc8b596938151525101527f1c8c2b856cdade256ba3237f39afd5e170a9532012f7aecae49d459b29f6f6ad8161010086017f23ac10ae6ca5cacee8744bb939aaa835390954b91ae668a2c8d0edda558a89e78151525101527f29392152723097e07113c3d7786d245ec40c30928015cd50b5668a4f4ea170318161012086017f16ec03d260bd7ac1c50ffa63565d5274b4582ceea52ff40b81cdfe8f444f01e48151525101527f07fea127dae943b8dc148f1408d40cff465c9c4721943669b1e4fd5a39db70368161014086017f2cdbfb3a4053c8489b0c94e74338ac19118df7a06bc56b1eb4d0e0dc4eae72488151525101527f118623e6bc136ee6d3f9907cd4ad04a9418ea03ba99ad753227cdfee598e84158161016086017f031455a79a2e0ce78a6cb53526ec04ac19716a86b08a93df48d178f8b77e56198151525101527f0805e392bcbc12e40a722778632d73fe981e4bc6fa6d1178b70af7be1cb9a3a38161018086017f0861d1997761a852226aac7ba9717bf6ae56451099be774cdf02ef352a58cbc88151525101527f089eb9c727e6cb07082bc3e6f40cf04f439fe48000602b584774dad7efc6607c816101a086017f101d1e3978cb9f1e303d413144ebe67682c9eb0cfe11242959aa6029d78cdbbc8151525101527f18e45d627aadd4df2794ecd9909fac1a753f0c6fa8a9c6654a7a58b0912fffd5816101c086017f2d489f2493263aa873bcd94f21efb45bf257a61d81c0c95c3297916506653b408151525101527f0eaba9f429c5f6fc3103d4cc4056c500ff42425d8e6465c5b8e145219f9c5cd3816101e086017f0e43e3a4b13cb438e2ad924614261ad0240214fa1c83fcda6a0bf779eb39ffc58151525101527f2b7bc74608d7ec7dadd0597d6a4010d8bfc2b31900281901cedc42bdbb0fb8fc8161020086017f29ae351d09dcf41c0a80ab05393738358baab37e6fbc464b3bb13258994a1fa48151525101527f27ec80e811e636f3348267923c8e641bd98a7e37c5216670cbff14ae323f9e0e8161022086017f066802c7ceb9e913d4f65433a20661e097acac1affecbb534a54f76a297822268151525101527f1588579e6c3378ea32cb641205ef762a63cd353a0bd670394528ad2081ee8dd48161024086017f12604d1f87c583f6c9710c73eaf590af9d07aa743d1381d0e9dff0eab261423981515251015261026084017f247d65261d3a4ab042ba937331f6d0c0c5eb9ea78753a92084db1a6939e19e82815152510152565b90813b15612ae157600080516020612bf783398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2805115612ac657612ac391612b31565b50565b505034612acf57565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b60ff600080516020612c178339815191525460401c1615612b1f57565b604051631afcd79f60e31b8152600490fd5b60008061171293602081519101845af43d15612b6f573d91612b5283610a5e565b92612b606040519485610379565b83523d6000602085013e612b73565b6060915b90612b9a5750805115612b8857805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612bcd575b612bab575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15612ba356fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a164736f6c6343000817000a" +"0x60a080604052346100cd57306080527ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a009081549060ff8260401c166100be57506001600160401b036002600160401b031982821601610079575b604051612be89081620000d38239608051818181610af30152610c4b0152f35b6001600160401b031990911681179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a1388080610059565b63f92ee8a960e01b8152600490fd5b600080fdfe6080604052600436101561001257600080fd5b60003560e01c8063013fa5fc146101d757806302b592f3146101d25780630d8e6e2c146101cd5780632f79889d146101c8578063313df7b1146101c3578063382b215a146101be578063409939b7146101b95780634847ae5d146101b45780634f1ef286146101af57806352d1902d146101aa57806362827733146101a557806369cc6a04146101a0578063715018a61461019b57806376b6b7cb146101965780637f17baad1461019157806382d07ff31461018c5780638584d23f146101875780638da5cb5b1461018257806396c1ca611461017d578063a244d59614610178578063aa92273214610173578063ad3cb1cc1461016e578063bd32519a14610169578063c23b9e9e14610164578063ca6fe8551461015f578063e03033011461015a578063f2fde38b146101555763f9e50d191461015057600080fd5b611323565b6112fa565b6111f5565b6111d7565b6111b0565b61118a565b61110d565b6110e0565b610f9d565b610f18565b610ee2565b610ea5565b610e7d565b610dd0565b610d8b565b610d20565b610cc1565b610ca3565b610c38565b610a79565b6109a8565b6107f1565b61051f565b6104f6565b6104cf565b6104a5565b61042f565b61020e565b600435906001600160a01b03821682036101f257565b600080fd5b61012435906001600160a01b03821682036101f257565b346101f25760203660031901126101f2576102276101dc565b61022f6119bb565b6001600160a01b039081169081156102bf5760065490811682146102ad5760ff60a01b19919091166001600160a81b03199190911617600160a01b1760068190556040516001600160a01b0390911681527f8017bb887fdf8fca4314a9d40f6e73b3b81002d67e5cfa85d88173af6aa460729080602081015b0390a1005b60405163a863aec960e01b8152600490fd5b60405163e6c4247b60e01b8152600490fd5b634e487b7160e01b600052603260045260246000fd5b600854811015610322576003906008600052027ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30190600090565b6102d1565b634e487b7160e01b600052604160045260246000fd5b604081019081106001600160401b0382111761035857604052565b610327565b61010081019081106001600160401b0382111761035857604052565b90601f801991011681019081106001600160401b0382111761035857604052565b604051906102e082018281106001600160401b0382111761035857604052565b604051906103c78261033d565b565b60405190606082018281106001600160401b0382111761035857604052565b604051906102c082018281106001600160401b0382111761035857604052565b906040516104158161033d565b6020600182946001600160401b0381541684520154910152565b346101f25760203660031901126101f2576004356008548110156101f2576104586080916102e7565b506104a381549161047360016001600160401b039201610408565b9060405193818116855260401c1660208401526040830190602080916001600160401b0381511684520151910152565bf35b346101f25760003660031901126101f2576060604051600181526000602082015260006040820152f35b346101f25760003660031901126101f25760206001600160401b0360075416604051908152f35b346101f25760003660031901126101f2576006546040516001600160a01b039091168152602090f35b346101f25760003660031901126101f2576020600354604051908152f35b602435906001600160401b03821682036101f257565b6101009060031901126101f2576040519061056d8261035d565b816004356001600160401b03811681036101f257815261058b61053d565b602082015260443560408201526064356060820152608435608082015260a43560a082015260c43560c082015260e060e435910152565b6040906101031901126101f257604051906105dc8261033d565b610104358252610124356020830152565b6040906101431901126101f257604051906106078261033d565b610144358252610164356020830152565b6040906101831901126101f257604051906106328261033d565b6101843582526101a4356020830152565b6040906101c31901126101f2576040519061065d8261033d565b6101c43582526101e4356020830152565b6040906102031901126101f257604051906106888261033d565b610204358252610224356020830152565b6040906102431901126101f257604051906106b38261033d565b610244358252610264356020830152565b6040906102831901126101f257604051906106de8261033d565b6102843582526102a4356020830152565b6040906102c31901126101f257604051906107098261033d565b6102c43582526102e4356020830152565b6040906103031901126101f257604051906107348261033d565b610304358252610324356020830152565b6040906103431901126101f2576040519061075f8261033d565b610344358252610364356020830152565b6040906103831901126101f2576040519061078a8261033d565b6103843582526103a4356020830152565b6040906103c31901126101f257604051906107b58261033d565b6103c43582526103e4356020830152565b6040906104031901126101f257604051906107e08261033d565b610404358252610424356020830152565b346101f2576105803660031901126101f25761080c36610553565b610480366101031901126101f2576109489061082661039a565b90610830366105c2565b825261083b366105ed565b602083015261084936610618565b604083015261085736610643565b60608301526108653661066e565b608083015261087336610699565b60a0830152610881366106c4565b60c083015261088f366106ef565b60e083015261089d3661071a565b6101008301526108ac36610745565b6101208301526108bb36610770565b6101408301526108ca3661079b565b6101608301526108d9366107c6565b610180830152610444356101a0830152610464356101c0830152610484356101e08301526104a4356102008301526104c4356102208301526104e4356102408301526105043561026083015261052435610280830152610544356102a0830152610564356102c08301526113da565b005b91909160e0806101008301946001600160401b03808251168552602082015116602085015260408101516040850152606081015160608501526080810151608085015260a081015160a085015260c081015160c08501520151910152565b346101f257600080600319360112610a5b576040610a57916109c8611589565b5063ffffffff81541681526005602052206006604051916109e88361035d565b80546001600160401b038082168552610a12915b60401c1660208501906001600160401b03169052565b600181015460408401526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152015460e08201526040519182918261094a565b0390f35b80fd5b6001600160401b03811161035857601f01601f191660200190565b6040806003193601126101f257610a8e6101dc565b6024356001600160401b0381116101f257366023820112156101f257806004013590610ab982610a5e565b91610ac685519384610379565b80835260209136602483830101116101f25781600092602485930183870137840101526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000008116308114908115610c1c575b50610c0b579080600492610b316119bb565b7ff78721226efe9a1bb678189a16d1554928b9f2192e2cb93eeda83b79fa40007d82885192881692838152a186516352d1902d60e01b815293849182905afa918291600093610bdc575b5050610ba1578351634c9c8ce360e01b81526001600160a01b0384166004820152602490fd5b600080516020612b9c8339815191528193929303610bc3576109488383612a00565b8351632a87526960e21b81526004810191909152602490fd5b610bfc929350803d10610c04575b610bf48183610379565b8101906122f9565b903880610b7b565b503d610bea565b845163703e46dd60e11b8152600490fd5b905081600080516020612b9c8339815191525416141538610b1f565b346101f25760003660031901126101f2577f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03163003610c91576020604051600080516020612b9c8339815191528152f35b60405163703e46dd60e11b8152600490fd5b346101f25760003660031901126101f2576020600254604051908152f35b346101f257600080600319360112610a5b57610cdb6119bb565b60065460ff8160a01c166000146102ad576001600160a81b0319166006557f9a5f57de856dd668c54dd95e5c55df93432171cbca49a8776d5620ea59c024508180a180f35b346101f257600080600319360112610a5b57610d3a6119bb565b600080516020612b7c83398151915280546001600160a01b0319811690915581906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b346101f25760003660031901126101f2576020600154604051908152f35b6004359063ffffffff821682036101f257565b610104359063ffffffff821682036101f257565b346101f25760203660031901126101f25763ffffffff610dee610da9565b1660005260056020526040600020805490610a576001600160401b039160018101549060028101546003820154600483015491600660058501549401549460405198888a998260401c16911689949198979693909260e0969361010087019a6001600160401b03809216885216602087015260408601526060850152608084015260a083015260c08201520152565b346101f25760003660031901126101f257610a57610e996115c7565b6040519182918261094a565b346101f25760203660031901126101f2576040610ec360043561169c565b6104a382518092602080916001600160401b0381511684520151910152565b346101f25760003660031901126101f257600080516020612b7c833981519152546040516001600160a01b039091168152602090f35b346101f25760203660031901126101f257610f31610da9565b610f396119bb565b63ffffffff808216610e108110918215610f8b575b5050610f79576006805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055005b6040516307a5077760e51b8152600490fd5b60065460a81c16101590503880610f4e565b346101f2576101403660031901126101f257610fb836610553565b610fc0610dbc565b90610fc96101f7565b600080516020612bbc83398151915254926001600160401b0360ff8560401c16159416801590816110d8575b60011490816110ce575b1590816110c5575b506110b357600080516020612bbc833981519152805467ffffffffffffffff1916600117905561103b928461108e57611762565b61104157005b600080516020612bbc833981519152805460ff60401b19169055604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29080602081016102a8565b600080516020612bbc833981519152805460ff60401b1916600160401b179055611762565b60405163f92ee8a960e01b8152600490fd5b90501538611007565b303b159150610fff565b859150610ff5565b346101f2576101003660031901126101f257602061110561110036610553565b6118f2565b604051908152f35b346101f25760003660031901126101f257604080519061112c8261033d565b60058252602090640352e302e360dc1b6020840152604051916020835283519182602085015260005b8381106111775784604081866000838284010152601f80199101168101030190f35b8581018301518582018301528201611155565b346101f25760003660031901126101f257602060ff60065460a01c166040519015158152f35b346101f25760003660031901126101f257602063ffffffff60065460a81c16604051908152f35b346101f25760003660031901126101f2576020600454604051908152f35b346101f25760403660031901126101f25760043560085443821180156112f0575b61127d5760009161122860009261167b565b9161124a61123e6007546001600160401b031690565b6001600160401b031690565b925b811561128f575b509091501561127d5761126c610a57926024359261168f565b604051911081529081906020820190565b60405163b0b4387760e01b8152600490fd5b826112ad61123e61129f846102e7565b50546001600160401b031690565b11156112d6575b600281106112d1578381146112d1576112cc9061193a565b61124c565b611253565b93505060016112ea61123e61129f866102e7565b936112b4565b5060038110611216565b346101f25760203660031901126101f2576109486113166101dc565b61131e6119bb565b611947565b346101f25760003660031901126101f2576020600854604051908152f35b9060e06006916113a16001600160401b036113758184511687906001600160401b03166001600160401b0319825416179055565b6020830151865467ffffffffffffffff60401b1916911660401b67ffffffffffffffff60401b16178555565b60408101516001850155606081015160028501556080810151600385015560a0810151600485015560c081015160058501550151910155565b9060065460ff8160a01c169081611575575b506115635781516001600160401b031661141761123e61140a6115c7565b516001600160401b031690565b6001600160401b038092161180159061152c575b61151a577fa04a773924505a418564363725f56832f5772e6b8d0dbd6efce724dfe803dae69061149d604085019361146385516119f4565b61147060608701516119f4565b61147d60808701516119f4565b61148a60a08701516119f4565b61149760c08701516119f4565b85611ecb565b6114d2846114cd6114b760005463ffffffff9060201c1690565b63ffffffff166000526005602052604060002090565b611341565b6114e1848242168343166121b0565b61150660206114f786516001600160401b031690565b9501516001600160401b031690565b9251604051908152928116931691602090a3565b60405163051c46ef60e01b8152600490fd5b5060208301516001600160401b03168161155a61123e602061154c6115c7565b01516001600160401b031690565b9116111561142b565b6040516301474c8f60e71b8152600490fd5b6001600160a01b03163314159050386113ec565b604051906115968261035d565b8160e06000918281528260208201528260408201528260608201528260808201528260a08201528260c08201520152565b6115cf611589565b5063ffffffff60005460201c16600052600560205260406000206006604051916115f88361035d565b80546001600160401b038082168552611610916109fc565b600181015460408401526002810154606084015260038101546080840152600481015460a0840152600581015460c0840152015460e082015290565b604051906116598261033d565b60006020838281520152565b634e487b7160e01b600052601160045260246000fd5b60001981019190821161168a57565b611665565b9190820391821161168a57565b6116a461164c565b50600854906116ba6116b58361167b565b6102e7565b50906116d461123e6001809401546001600160401b031690565b811015611750576116f061123e6007546001600160401b031690565b83811061171557505050600161170b6116b56117129361167b565b5001610408565b90565b8161173561123e85611726856102e7565b5001546001600160401b031690565b116117415782016116f0565b611712935061170b91506102e7565b604051631856a49960e21b8152600490fd5b909161177890611770612aa7565b61131e612aa7565b611780612aa7565b6401000000006001600160401b031960005416176000556001600160401b03806117b183516001600160401b031690565b16158015906118d3575b80156118c7575b80156118bb575b80156118af575b80156118a3575b611891576000805260056020526103c79261185590611816847f05b8ccbb9d4d8fb16ea74ce3c29a41f1b461fbdaff4714a0d9a8eb05499746bc611341565b611830846114cd6114b760005463ffffffff9060201c1690565b6006805463ffffffff60a81b191660a89290921b63ffffffff60a81b16919091179055565b611886611861836118f2565b61186a81600155565b61188160e08501519161187c83600255565b600355565b600455565b8042169043166121b0565b6040516350dd03f760e11b8152600490fd5b5060e0820151156117d7565b5060c0820151156117d0565b5060a0820151156117c9565b506080820151156117c2565b506118eb61123e60208401516001600160401b031690565b15156117bb565b60808101519060c060a082015191015160405191602083019384526040830152606082015260608152608081018181106001600160401b038211176103585760405251902090565b801561168a576000190190565b6001600160a01b039081169081156119a257600080516020612b7c83398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b600080516020612b7c833981519152546001600160a01b031633036119dc57565b60405163118cdaa760e01b8152336004820152602490fd5b7f30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000011115611a1d57565b60405162461bcd60e51b815260206004820152601b60248201527f426e3235343a20696e76616c6964207363616c6172206669656c6400000000006044820152606490fd5b60405190611a6f8261035d565b610100368337565b908160209103126101f2575180151581036101f25790565b6000915b60088310611aa057505050565b600190825181526020809101920192019190611a93565b61046090611ad083825160208091805184520151910152565b60208181015180516040860152015160608401526040810151805160808501526020015160a08401526060810151805160c08501526020015160e0840152608081015190611b2e610100928386019060208091805184520151910152565b60a081015191611b4e610140938487019060208091805184520151910152565b60c082015192611b6e610180948588019060208091805184520151910152565b60e083015191611b8e6101c0938489019060208091805184520151910152565b830151611bab610200918289019060208091805184520151910152565b61012084015191611bcc61024093848a019060208091805184520151910152565b84015192611bea61028094858a019060208091805184520151910152565b611c2561016086015196611c0e6102c098898c019060208091805184520151910152565b86015180516103008b0152602001516103208a0152565b6101a08501516103408901528401516103608801526101e08401516103808801528301516103a08701526102208301516103c08701528201516103e08601526102608201516104008601528101516104208501526102a08101516104408501520151910152565b61060090611eb86103c794969593966102a0610a808401988051855260208101516020860152611cce6040820151604087019060208091805184520151910152565b6060810151805160808701526020015160a08601526080810151805160c08701526020015160e086015260a0810151611d17610100918288019060208091805184520151910152565b611e8486611e5560c0850151611d3d610140918285019060208091805184520151910152565b611e2660e087015195611d60610180978887019060208091805184520151910152565b870151611d7d6101c0918287019060208091805184520151910152565b611dba61012089015193611da1610200958689019060208091805184520151910152565b8901516102408097019060208091805184520151910152565b611df78c6102c06101608b015199611de26102809b8c85019060208091805184520151910152565b8b015191019060208091805184520151910152565b6101a088015180516103008e0152602001516103208d015287015180516103408d0152602001516103608c0152565b6101e086015180516103808c0152602001516103a08b015285015180516103c08b0152602001516103e08a0152565b61022084015180516104008a015260200151610420890152830151805161044089015260200151610460880152565b6102608201518051610480880152602001516104a08701528101516104c086015201516104e0840152610500830190611a8f565b0190611ab7565b6040513d6000823e3d90fd5b602090611ed6612424565b6060611ee0611a62565b926002548452611efa61123e82516001600160401b031690565b85850152611f1461123e868301516001600160401b031690565b6040850152604081015182850152015160808301526005611f9d611f4160005463ffffffff9060201c1690565b6003611f5d8263ffffffff166000526005602052604060002090565b015460a08601526004611f808263ffffffff166000526005602052604060002090565b015460c086015263ffffffff166000526005602052604060002090565b015460e0830152611fc260405194859384936350f8d1a760e11b855260048501611c8c565b038173__$5c5c07cf4f55be9472c2b47d897172e765$__5af490811561203357600091612004575b5015611ff257565b6040516309bde33960e01b8152600490fd5b612026915060203d60201161202c575b61201e8183610379565b810190611a77565b38611fea565b503d612014565b611ebf565b6001600160401b03918216908216039190821161168a57565b906120685760028160008093558260018201550155565b634e487b7160e01b600052600060045260246000fd5b6001600160401b0380911690811461168a5760010190565b600854600160401b81101561035857600181018060085581101561032257602060037ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee592600860005202926121a96040857ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee301926121656001600160401b03946121398684511682906001600160401b03166001600160401b0319825416179055565b82870151815467ffffffffffffffff60401b191690871660401b67ffffffffffffffff60401b16179055565b0151918251167ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee48601906001600160401b03166001600160401b0319825416179055565b0151910155565b909161221f6103c7936008548015159081612285575b50612229575b60406121e260208501516001600160401b031690565b9301516121ff6121f06103ba565b6001600160401b039095168552565b602084015261220f6121f06103c9565b6001600160401b03166020840152565b6040820152612096565b6122476122416116b56007546001600160401b031690565b90612051565b61228061226461225f6007546001600160401b031690565b61207e565b6001600160401b03166001600160401b03196007541617600755565b6121cc565b6122c891506122996116b56122aa9261167b565b505460401c6001600160401b031690565b6122c26122996116b56007546001600160401b031690565b90612038565b6001600160401b036122ef6122e660065463ffffffff9060a81c1690565b63ffffffff1690565b91161015386121c6565b908160209103126101f2575190565b6123106103e8565b90600082526000602083015261232461164c565b604083015261233161164c565b606083015261233e61164c565b608083015261234b61164c565b60a083015261235861164c565b60c083015261236561164c565b60e083015261237261164c565b61010083015261238061164c565b61012083015261238e61164c565b61014083015261239c61164c565b6101608301526123aa61164c565b6101808301526123b861164c565b6101a08301526123c661164c565b6101c08301526123d461164c565b6101e08301526123e261164c565b6102008301526123f061164c565b6102208301526123fe61164c565b61024083015261240c61164c565b610260830152600061028083015260006102a0830152565b61242c612308565b906210000082527f2ce6cc664a32147bfe6a0c94a95bf0496679405ccae01648cd4ec021145120d560206008818501527f03a0a9acc3e3815a7ed6cb1379f7d157e6343164729376392a693acbd3ec283c81604086017f20c9403133dfde9a9d382df76fb0523571648725abc0a7c12830bb690ec83b338151525101527f21be232a42246a5663ebf483470cca666ffe9d4f0e63b929c596a7658714e97081606086017f2866c18ad1df10ef13542cce6250ce02cb2a6b72ae00a9852e271187e9e4e0db8151525101527f0be0f448839080132d47de17de0099b4cd74ae1e6b71cdda06cdebb868a50c6d81608086017f07d77873b9860074118e75808c79468b83c8ed64ba14db5cb5afa8e534de7b998151525101527f18f95cdda42ce11d9d10a3b335acc214e3807c578c5359405d810c208df600938160a086017f13bd45a023491eadea44cc3f24cfbd1796eade9c0e39ee81d9f63ea0a58066258151525101527f28c2217f7bacf6f8b2b8ee4a90fcf8b5bca04205ea84e8e1eb54b85dd41bde288160c086017f0970d978763461f09e9ec63454073497386e4d282fedc2ac5b967cb9fd3fa8a98151525101527f202c3e390cee7c5c8525da2329a19f4936f6f71ca97dde6c6fa32b382d5acc038160e086017f02fe3d02988db718380052970aba46a3296df5f29b736ba1f2c4ccffc8b596938151525101527f1c8c2b856cdade256ba3237f39afd5e170a9532012f7aecae49d459b29f6f6ad8161010086017f23ac10ae6ca5cacee8744bb939aaa835390954b91ae668a2c8d0edda558a89e78151525101527f29392152723097e07113c3d7786d245ec40c30928015cd50b5668a4f4ea170318161012086017f16ec03d260bd7ac1c50ffa63565d5274b4582ceea52ff40b81cdfe8f444f01e48151525101527f07fea127dae943b8dc148f1408d40cff465c9c4721943669b1e4fd5a39db70368161014086017f2cdbfb3a4053c8489b0c94e74338ac19118df7a06bc56b1eb4d0e0dc4eae72488151525101527f118623e6bc136ee6d3f9907cd4ad04a9418ea03ba99ad753227cdfee598e84158161016086017f031455a79a2e0ce78a6cb53526ec04ac19716a86b08a93df48d178f8b77e56198151525101527f0805e392bcbc12e40a722778632d73fe981e4bc6fa6d1178b70af7be1cb9a3a38161018086017f0861d1997761a852226aac7ba9717bf6ae56451099be774cdf02ef352a58cbc88151525101527f089eb9c727e6cb07082bc3e6f40cf04f439fe48000602b584774dad7efc6607c816101a086017f101d1e3978cb9f1e303d413144ebe67682c9eb0cfe11242959aa6029d78cdbbc8151525101527f18e45d627aadd4df2794ecd9909fac1a753f0c6fa8a9c6654a7a58b0912fffd5816101c086017f2d489f2493263aa873bcd94f21efb45bf257a61d81c0c95c3297916506653b408151525101527f0eaba9f429c5f6fc3103d4cc4056c500ff42425d8e6465c5b8e145219f9c5cd3816101e086017f0e43e3a4b13cb438e2ad924614261ad0240214fa1c83fcda6a0bf779eb39ffc58151525101527f2b7bc74608d7ec7dadd0597d6a4010d8bfc2b31900281901cedc42bdbb0fb8fc8161020086017f29ae351d09dcf41c0a80ab05393738358baab37e6fbc464b3bb13258994a1fa48151525101527f27ec80e811e636f3348267923c8e641bd98a7e37c5216670cbff14ae323f9e0e8161022086017f066802c7ceb9e913d4f65433a20661e097acac1affecbb534a54f76a297822268151525101527f1588579e6c3378ea32cb641205ef762a63cd353a0bd670394528ad2081ee8dd48161024086017f12604d1f87c583f6c9710c73eaf590af9d07aa743d1381d0e9dff0eab261423981515251015261026084017f247d65261d3a4ab042ba937331f6d0c0c5eb9ea78753a92084db1a6939e19e828151525101527fb0838893ec1f237e8b07323b0744599f4e97b598b3b589bcc2bc37b8d5c418016102808301527fc18393c0fa30fe4e8b038e357ad851eae8de9107584effe7c7f1f651b2010e266102a0830152565b90813b15612a8657600080516020612b9c83398151915280546001600160a01b0319166001600160a01b0384169081179091557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b600080a2805115612a6b57612a6891612ad6565b50565b505034612a7457565b60405163b398979f60e01b8152600490fd5b604051634c9c8ce360e01b81526001600160a01b0383166004820152602490fd5b60ff600080516020612bbc8339815191525460401c1615612ac457565b604051631afcd79f60e31b8152600490fd5b60008061171293602081519101845af43d15612b14573d91612af783610a5e565b92612b056040519485610379565b83523d6000602085013e612b18565b6060915b90612b3f5750805115612b2d57805190602001fd5b604051630a12f52160e11b8152600490fd5b81511580612b72575b612b50575090565b604051639996b31560e01b81526001600160a01b039091166004820152602490fd5b50803b15612b4856fe9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbcf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a164736f6c6343000817000a" diff --git a/contract-bindings/src/i_plonk_verifier.rs b/contract-bindings/src/i_plonk_verifier.rs index d326b5c8eb..cb15763c48 100644 --- a/contract-bindings/src/i_plonk_verifier.rs +++ b/contract-bindings/src/i_plonk_verifier.rs @@ -97,6 +97,8 @@ pub mod i_plonk_verifier { ::ethers::core::abi::ethabi::ParamType::Uint(256usize), ::ethers::core::abi::ethabi::ParamType::Uint(256usize), ],), + ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize), + ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize), ],), internal_type: ::core::option::Option::Some( ::std::borrow::ToOwned::to_owned( @@ -106,13 +108,14 @@ pub mod i_plonk_verifier { }, ::ethers::core::abi::ethabi::Param { name: ::std::borrow::ToOwned::to_owned("publicInput"), - kind: ::ethers::core::abi::ethabi::ParamType::Array( + kind: ::ethers::core::abi::ethabi::ParamType::FixedArray( ::std::boxed::Box::new( ::ethers::core::abi::ethabi::ParamType::Uint(256usize), ), + 8usize, ), internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("uint256[]"), + ::std::borrow::ToOwned::to_owned("uint256[8]"), ), }, ::ethers::core::abi::ethabi::Param { @@ -187,13 +190,6 @@ pub mod i_plonk_verifier { ), ), }, - ::ethers::core::abi::ethabi::Param { - name: ::std::borrow::ToOwned::to_owned("extraTranscriptInitMsg",), - kind: ::ethers::core::abi::ethabi::ParamType::Bytes, - internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("bytes"), - ), - }, ], outputs: ::std::vec![::ethers::core::abi::ethabi::Param { name: ::std::string::String::new(), @@ -252,24 +248,15 @@ pub mod i_plonk_verifier { client, )) } - ///Calls the contract's `verify` (0x202a4b1b) function + ///Calls the contract's `verify` (0x64e4c59e) function pub fn verify( &self, verifying_key: VerifyingKey, - public_input: ::std::vec::Vec<::ethers::core::types::U256>, + public_input: [::ethers::core::types::U256; 8], proof: PlonkProof, - extra_transcript_init_msg: ::ethers::core::types::Bytes, ) -> ::ethers::contract::builders::ContractCall { self.0 - .method_hash( - [32, 42, 75, 27], - ( - verifying_key, - public_input, - proof, - extra_transcript_init_msg, - ), - ) + .method_hash([100, 228, 197, 158], (verifying_key, public_input, proof)) .expect("method not found (this should never happen)") } } @@ -280,7 +267,7 @@ pub mod i_plonk_verifier { Self::new(contract.address(), contract.client()) } } - ///Container type for all input parameters for the `verify` function with signature `verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256)),uint256[],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)` and selector `0x202a4b1b` + ///Container type for all input parameters for the `verify` function with signature `verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),bytes32,bytes32),uint256[8],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))` and selector `0x64e4c59e` #[derive( Clone, ::ethers::contract::EthCall, @@ -290,15 +277,14 @@ pub mod i_plonk_verifier { )] #[ethcall( name = "verify", - abi = "verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256)),uint256[],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)" + abi = "verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),bytes32,bytes32),uint256[8],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))" )] pub struct VerifyCall { pub verifying_key: VerifyingKey, - pub public_input: ::std::vec::Vec<::ethers::core::types::U256>, + pub public_input: [::ethers::core::types::U256; 8], pub proof: PlonkProof, - pub extra_transcript_init_msg: ::ethers::core::types::Bytes, } - ///Container type for all return fields from the `verify` function with signature `verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256)),uint256[],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256),bytes)` and selector `0x202a4b1b` + ///Container type for all return fields from the `verify` function with signature `verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),bytes32,bytes32),uint256[8],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))` and selector `0x64e4c59e` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/contract-bindings/src/lib.rs b/contract-bindings/src/lib.rs index 1dc3429611..16b3043216 100644 --- a/contract-bindings/src/lib.rs +++ b/contract-bindings/src/lib.rs @@ -12,4 +12,5 @@ pub mod light_client_mock; pub mod light_client_state_update_vk; pub mod light_client_state_update_vk_mock; pub mod plonk_verifier; +pub mod plonk_verifier_2; pub mod shared_types; diff --git a/contract-bindings/src/plonk_verifier.rs b/contract-bindings/src/plonk_verifier.rs index e4e99b2df6..c8fbe84f4e 100644 --- a/contract-bindings/src/plonk_verifier.rs +++ b/contract-bindings/src/plonk_verifier.rs @@ -97,6 +97,8 @@ pub mod plonk_verifier { ::ethers::core::abi::ethabi::ParamType::Uint(256usize), ::ethers::core::abi::ethabi::ParamType::Uint(256usize), ],), + ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize), + ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize), ],), internal_type: ::core::option::Option::Some( ::std::borrow::ToOwned::to_owned( @@ -106,13 +108,14 @@ pub mod plonk_verifier { }, ::ethers::core::abi::ethabi::Param { name: ::std::borrow::ToOwned::to_owned("publicInput"), - kind: ::ethers::core::abi::ethabi::ParamType::Array( + kind: ::ethers::core::abi::ethabi::ParamType::FixedArray( ::std::boxed::Box::new( ::ethers::core::abi::ethabi::ParamType::Uint(256usize), ), + 8usize, ), internal_type: ::core::option::Option::Some( - ::std::borrow::ToOwned::to_owned("uint256[]"), + ::std::borrow::ToOwned::to_owned("uint256[8]"), ), }, ::ethers::core::abi::ethabi::Param { @@ -208,13 +211,6 @@ pub mod plonk_verifier { inputs: ::std::vec![], },], ), - ( - ::std::borrow::ToOwned::to_owned("InvalidPolyEvalArgs"), - ::std::vec![::ethers::core::abi::ethabi::AbiError { - name: ::std::borrow::ToOwned::to_owned("InvalidPolyEvalArgs",), - inputs: ::std::vec![], - },], - ), ( ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), ::std::vec![::ethers::core::abi::ethabi::AbiError { @@ -238,12 +234,12 @@ pub mod plonk_verifier { pub static PLONKVERIFIER_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = ::ethers::contract::Lazy::new(__abi); #[rustfmt::skip] - const __BYTECODE: &[u8] = b"`\x80\x80`@R4a\0\x1AWa6\x0B\x90\x81a\0 \x8290\x81PP\xF3[`\0\x80\xFD\xFE`\x80`@R`\x046\x10\x15a\0\x12W`\0\x80\xFD[`\0\x805`\xE0\x1Cc1\xD9Qt\x14a\0(W`\0\x80\xFD[6`\x03\x19\x01a\t`\x81\x12a\x01\xABWa\x04\xC0\x13a\x01\xA8Wa\0Fa\x02tV[\x90`\x045\x82R`$5` \x83\x01Ra\0]6a\x02\xEFV[`@\x83\x01Ra\0k6a\x03\x1CV[``\x83\x01Ra\0y6a\x03DV[`\x80\x83\x01Ra\0\x876a\x03lV[`\xA0\x83\x01Ra\0\x956a\x03\x97V[`\xC0\x83\x01Ra\0\xA36a\x03\xC2V[`\xE0\x83\x01Ra\0\xB16a\x03\xEDV[a\x01\0\x83\x01Ra\0\xC06a\x04\x18V[a\x01 \x83\x01Ra\0\xCF6a\x04CV[a\x01@\x83\x01Ra\0\xDE6a\x04nV[a\x01`\x83\x01Ra\0\xED6a\x04\x99V[a\x01\x80\x83\x01Ra\0\xFC6a\x04\xC4V[a\x01\xA0\x83\x01Ra\x01\x0B6a\x04\xEFV[a\x01\xC0\x83\x01Ra\x01\x1A6a\x05\x1AV[a\x01\xE0\x83\x01Ra\x01)6a\x05EV[a\x02\0\x83\x01Ra\x0186a\x05pV[a\x02 \x83\x01Ra\x01G6a\x05\x9BV[a\x02@\x83\x01Ra\x01V6a\x05\xC6V[a\x02`\x83\x01Ra\x04\xC45\x90`\x01`\x01`@\x1B\x03\x82\x11a\x01\xA8Wa\x01\xA4a\x01\x92\x84a\x01\x836`\x04\x87\x01a\x087V[a\x01\x8C6a\x08\x97V[\x91a\x0B\xEFV[`@Q\x90\x15\x15\x81R\x90\x81\x90` \x82\x01\x90V[\x03\x90\xF3[\x80\xFD[P\x80\xFD[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[a\x01\xAFV[a\x01\0\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[`\x80\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[a\x03\xE0\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[``\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[\x90`\x1F\x80\x19\x91\x01\x16\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[`@Q\x90a\x02\x80\x82\x01\x82\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[`@Q\x90a\x02\xE0\x82\x01\x82\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[`@Q\x90a\x02\xC1\x82a\x01\xE5V[V[`@Q\x90a\x02\xC1\x82a\x02\x01V[`@Q\x90`\xA0\x82\x01\x82\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[`@\x90`C\x19\x01\x12a\x03\x17W`@Q\x90a\x03\x08\x82a\x01\xC5V[`D5\x82R`d5` \x83\x01RV[`\0\x80\xFD[`@\x90`\x83\x19\x01\x12a\x03\x17W`@Q\x90a\x035\x82a\x01\xC5V[`\x845\x82R`\xA45` \x83\x01RV[`@\x90`\xC3\x19\x01\x12a\x03\x17W`@Q\x90a\x03]\x82a\x01\xC5V[`\xC45\x82R`\xE45` \x83\x01RV[`@\x90a\x01\x03\x19\x01\x12a\x03\x17W`@Q\x90a\x03\x86\x82a\x01\xC5V[a\x01\x045\x82Ra\x01$5` \x83\x01RV[`@\x90a\x01C\x19\x01\x12a\x03\x17W`@Q\x90a\x03\xB1\x82a\x01\xC5V[a\x01D5\x82Ra\x01d5` \x83\x01RV[`@\x90a\x01\x83\x19\x01\x12a\x03\x17W`@Q\x90a\x03\xDC\x82a\x01\xC5V[a\x01\x845\x82Ra\x01\xA45` \x83\x01RV[`@\x90a\x01\xC3\x19\x01\x12a\x03\x17W`@Q\x90a\x04\x07\x82a\x01\xC5V[a\x01\xC45\x82Ra\x01\xE45` \x83\x01RV[`@\x90a\x02\x03\x19\x01\x12a\x03\x17W`@Q\x90a\x042\x82a\x01\xC5V[a\x02\x045\x82Ra\x02$5` \x83\x01RV[`@\x90a\x02C\x19\x01\x12a\x03\x17W`@Q\x90a\x04]\x82a\x01\xC5V[a\x02D5\x82Ra\x02d5` \x83\x01RV[`@\x90a\x02\x83\x19\x01\x12a\x03\x17W`@Q\x90a\x04\x88\x82a\x01\xC5V[a\x02\x845\x82Ra\x02\xA45` \x83\x01RV[`@\x90a\x02\xC3\x19\x01\x12a\x03\x17W`@Q\x90a\x04\xB3\x82a\x01\xC5V[a\x02\xC45\x82Ra\x02\xE45` \x83\x01RV[`@\x90a\x03\x03\x19\x01\x12a\x03\x17W`@Q\x90a\x04\xDE\x82a\x01\xC5V[a\x03\x045\x82Ra\x03$5` \x83\x01RV[`@\x90a\x03C\x19\x01\x12a\x03\x17W`@Q\x90a\x05\t\x82a\x01\xC5V[a\x03D5\x82Ra\x03d5` \x83\x01RV[`@\x90a\x03\x83\x19\x01\x12a\x03\x17W`@Q\x90a\x054\x82a\x01\xC5V[a\x03\x845\x82Ra\x03\xA45` \x83\x01RV[`@\x90a\x03\xC3\x19\x01\x12a\x03\x17W`@Q\x90a\x05_\x82a\x01\xC5V[a\x03\xC45\x82Ra\x03\xE45` \x83\x01RV[`@\x90a\x04\x03\x19\x01\x12a\x03\x17W`@Q\x90a\x05\x8A\x82a\x01\xC5V[a\x04\x045\x82Ra\x04$5` \x83\x01RV[`@\x90a\x04C\x19\x01\x12a\x03\x17W`@Q\x90a\x05\xB5\x82a\x01\xC5V[a\x04D5\x82Ra\x04d5` \x83\x01RV[`@\x90a\x04\x83\x19\x01\x12a\x03\x17W`@Q\x90a\x05\xE0\x82a\x01\xC5V[a\x04\x845\x82Ra\x04\xA45` \x83\x01RV[`@\x90a\x04\xE3\x19\x01\x12a\x03\x17W`@Q\x90a\x06\x0B\x82a\x01\xC5V[a\x04\xE45\x82Ra\x05\x045` \x83\x01RV[`@\x90a\x05#\x19\x01\x12a\x03\x17W`@Q\x90a\x066\x82a\x01\xC5V[a\x05$5\x82Ra\x05D5` \x83\x01RV[`@\x90a\x05c\x19\x01\x12a\x03\x17W`@Q\x90a\x06a\x82a\x01\xC5V[a\x05d5\x82Ra\x05\x845` \x83\x01RV[`@\x90a\x05\xA3\x19\x01\x12a\x03\x17W`@Q\x90a\x06\x8C\x82a\x01\xC5V[a\x05\xA45\x82Ra\x05\xC45` \x83\x01RV[`@\x90a\x05\xE3\x19\x01\x12a\x03\x17W`@Q\x90a\x06\xB7\x82a\x01\xC5V[a\x05\xE45\x82Ra\x06\x045` \x83\x01RV[`@\x90a\x06#\x19\x01\x12a\x03\x17W`@Q\x90a\x06\xE2\x82a\x01\xC5V[a\x06$5\x82Ra\x06D5` \x83\x01RV[`@\x90a\x06c\x19\x01\x12a\x03\x17W`@Q\x90a\x07\r\x82a\x01\xC5V[a\x06d5\x82Ra\x06\x845` \x83\x01RV[`@\x90a\x06\xA3\x19\x01\x12a\x03\x17W`@Q\x90a\x078\x82a\x01\xC5V[a\x06\xA45\x82Ra\x06\xC45` \x83\x01RV[`@\x90a\x06\xE3\x19\x01\x12a\x03\x17W`@Q\x90a\x07c\x82a\x01\xC5V[a\x06\xE45\x82Ra\x07\x045` \x83\x01RV[`@\x90a\x07#\x19\x01\x12a\x03\x17W`@Q\x90a\x07\x8E\x82a\x01\xC5V[a\x07$5\x82Ra\x07D5` \x83\x01RV[`@\x90a\x07c\x19\x01\x12a\x03\x17W`@Q\x90a\x07\xB9\x82a\x01\xC5V[a\x07d5\x82Ra\x07\x845` \x83\x01RV[`@\x90a\x07\xA3\x19\x01\x12a\x03\x17W`@Q\x90a\x07\xE4\x82a\x01\xC5V[a\x07\xA45\x82Ra\x07\xC45` \x83\x01RV[`@\x90a\x07\xE3\x19\x01\x12a\x03\x17W`@Q\x90a\x08\x0F\x82a\x01\xC5V[a\x07\xE45\x82Ra\x08\x045` \x83\x01RV[`\x01`\x01`@\x1B\x03\x81\x11a\x01\xE0W`\x05\x1B` \x01\x90V[\x90\x80`\x1F\x83\x01\x12\x15a\x03\x17W` \x90\x825a\x08Q\x81a\x08 V[\x93a\x08_`@Q\x95\x86a\x02SV[\x81\x85R` \x80\x86\x01\x92`\x05\x1B\x82\x01\x01\x92\x83\x11a\x03\x17W` \x01\x90[\x82\x82\x10a\x08\x88WPPPP\x90V[\x815\x81R\x90\x83\x01\x90\x83\x01a\x08zV[\x90a\x04\x80a\x04\xE3\x19\x83\x01\x12a\x03\x17Wa\t`a\x08\xB1a\x02\x94V[\x92a\x08\xBB\x81a\x05\xF1V[\x84Ra\x08\xC6\x81a\x06\x1CV[` \x85\x01Ra\x08\xD4\x81a\x06GV[`@\x85\x01Ra\x08\xE2\x81a\x06rV[``\x85\x01Ra\x08\xF0\x81a\x06\x9DV[`\x80\x85\x01Ra\x08\xFE\x81a\x06\xC8V[`\xA0\x85\x01Ra\t\x0C\x81a\x06\xF3V[`\xC0\x85\x01Ra\t\x1A\x81a\x07\x1EV[`\xE0\x85\x01Ra\t(\x81a\x07IV[a\x01\0\x85\x01Ra\t7\x81a\x07tV[a\x01 \x85\x01Ra\tF\x81a\x07\x9FV[a\x01@\x85\x01Ra\tU\x81a\x07\xCAV[a\x01`\x85\x01Ra\x07\xF5V[a\x01\x80\x83\x01Ra\x08$5a\x01\xA0\x83\x01Ra\x08D5a\x01\xC0\x83\x01Ra\x08d5a\x01\xE0\x83\x01Ra\x08\x845a\x02\0\x83\x01Ra\x08\xA45a\x02 \x83\x01Ra\x08\xC45a\x02@\x83\x01Ra\x08\xE45a\x02`\x83\x01Ra\t\x045a\x02\x80\x83\x01Ra\t$5a\x02\xA0\x83\x01Ra\tD5a\x02\xC0\x83\x01RV[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[\x80Q\x15a\t\xEFW` \x01\x90V[a\t\xCCV[\x80Q`\x01\x10\x15a\t\xEFW`@\x01\x90V[\x80Q`\x02\x10\x15a\t\xEFW``\x01\x90V[\x80Q`\x03\x10\x15a\t\xEFW`\x80\x01\x90V[\x80Q`\x04\x10\x15a\t\xEFW`\xA0\x01\x90V[\x80Q`\x05\x10\x15a\t\xEFW`\xC0\x01\x90V[\x80Q`\x06\x10\x15a\t\xEFW`\xE0\x01\x90V[\x80Q`\x07\x10\x15a\t\xEFWa\x01\0\x01\x90V[\x80Q`\x14\x10\x15a\t\xEFWa\x02\xA0\x01\x90V[\x80Q`\x15\x10\x15a\t\xEFWa\x02\xC0\x01\x90V[\x80Q`\x16\x10\x15a\t\xEFWa\x02\xE0\x01\x90V[\x80Q`\x17\x10\x15a\t\xEFWa\x03\0\x01\x90V[\x80Q`\x18\x10\x15a\t\xEFWa\x03 \x01\x90V[\x80Q`\x19\x10\x15a\t\xEFWa\x03@\x01\x90V[\x80Q`\x1A\x10\x15a\t\xEFWa\x03`\x01\x90V[\x80Q`\x1B\x10\x15a\t\xEFWa\x03\x80\x01\x90V[\x80Q`\x1C\x10\x15a\t\xEFWa\x03\xA0\x01\x90V[\x80Q`\x1D\x10\x15a\t\xEFWa\x03\xC0\x01\x90V[\x80Q`\x08\x10\x15a\t\xEFWa\x01 \x01\x90V[\x80Q`\t\x10\x15a\t\xEFWa\x01@\x01\x90V[\x80Q`\n\x10\x15a\t\xEFWa\x01`\x01\x90V[\x80Q`\x0B\x10\x15a\t\xEFWa\x01\x80\x01\x90V[\x80Q`\x0C\x10\x15a\t\xEFWa\x01\xA0\x01\x90V[\x80Q`\r\x10\x15a\t\xEFWa\x01\xC0\x01\x90V[\x80Q`\x0E\x10\x15a\t\xEFWa\x01\xE0\x01\x90V[\x80Q`\x0F\x10\x15a\t\xEFWa\x02\0\x01\x90V[\x80Q`\x10\x10\x15a\t\xEFWa\x02 \x01\x90V[\x80Q`\x11\x10\x15a\t\xEFWa\x02@\x01\x90V[\x80Q`\x12\x10\x15a\t\xEFWa\x02`\x01\x90V[\x80Q`\x13\x10\x15a\t\xEFWa\x02\x80\x01\x90V[\x80Q\x82\x10\x15a\t\xEFW` \x91`\x05\x1B\x01\x01\x90V[\x91a\r\x9A\x91a\r\x9F\x93a\x0C\x02\x83Qa\x13\x13V[a\x0C\x0F` \x84\x01Qa\x13\x13V[a\x0C\x1C`@\x84\x01Qa\x13\x13V[a\x0C)``\x84\x01Qa\x13\x13V[a\x0C6`\x80\x84\x01Qa\x13\x13V[a\x0CC`\xA0\x84\x01Qa\x13\x13V[a\x0CP`\xC0\x84\x01Qa\x13\x13V[a\x0C]`\xE0\x84\x01Qa\x13\x13V[a\x0Cka\x01\0\x84\x01Qa\x13\x13V[a\x0Cya\x01 \x84\x01Qa\x13\x13V[a\x0C\x87a\x01@\x84\x01Qa\x13\x13V[a\x0C\x95a\x01`\x84\x01Qa\x13\x13V[a\x0C\xA3a\x01\x80\x84\x01Qa\x13\x13V[a\x0C\xB1a\x01\xA0\x84\x01Qa\r\xA2V[a\x0C\xBFa\x01\xC0\x84\x01Qa\r\xA2V[a\x0C\xCDa\x01\xE0\x84\x01Qa\r\xA2V[a\x0C\xDBa\x02\0\x84\x01Qa\r\xA2V[a\x0C\xE9a\x02 \x84\x01Qa\r\xA2V[a\x0C\xF7a\x02@\x84\x01Qa\r\xA2V[a\r\x05a\x02`\x84\x01Qa\r\xA2V[a\r\x13a\x02\x80\x84\x01Qa\r\xA2V[a\r!a\x02\xA0\x84\x01Qa\r\xA2V[a\r/a\x02\xC0\x84\x01Qa\r\xA2V[a\rAa\r;\x83a\t\xE2V[Qa\r\xA2V[a\rMa\r;\x83a\t\xF4V[a\rYa\r;\x83a\n\x04V[a\rea\r;\x83a\n\x14V[a\rqa\r;\x83a\n$V[a\r}a\r;\x83a\n4V[a\r\x89a\r;\x83a\nDV[a\r\x95a\r;\x83a\nTV[a\x0FzV[a\x10\x98V[\x90V[`\0\x80Q` a5\xDF\x839\x81Q\x91R\x11\x15a\r\xB9WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x90\xFD[`@Q\x90a\x0E\x0B\x82a\x01\xC5V[`\0` \x83\x82\x81R\x01RV[`@Q\x90a\x0E$\x82a\x01\xE5V[\x81`\0\x81R`\0` \x82\x01R`\0`@\x82\x01R`\0``\x82\x01R```\x80\x82\x01R```\xA0\x82\x01Ra\x0ETa\r\xFEV[`\xC0\x82\x01R`\xE0a\x0Eca\r\xFEV[\x91\x01RV[`@Q\x90a\x0Eu\x82a\x02\x1CV[`\x1E\x82Ra\x03\xC06` \x84\x017V[\x90a\x0E\x8E\x82a\x08 V[a\x0E\x9B`@Q\x91\x82a\x02SV[\x82\x81R\x80\x92a\x0E\xAC`\x1F\x19\x91a\x08 V[\x01\x90` 6\x91\x017V[`@Q\x90a\x0E\xC3\x82a\x02\x1CV[`\x1E\x82R\x81`\0[a\x03\xC0\x81\x10a\x0E\xD8WPPV[` \x90a\x0E\xE3a\r\xFEV[\x82\x82\x85\x01\x01R\x01a\x0E\xCBV[`@\x90`@Q\x91a\x0E\xFF\x83a\x028V[`\x02\x83R\x82`\0[\x82\x81\x10a\x0F\x13WPPPV[` \x90a\x0F\x1Ea\r\xFEV[\x82\x82\x85\x01\x01R\x01a\x0F\x07V[\x90a\x0F4\x82a\x08 V[a\x0FA`@Q\x91\x82a\x02SV[\x82\x81R\x80\x92a\x0FR`\x1F\x19\x91a\x08 V[\x01\x90`\0[\x82\x81\x10a\x0FcWPPPV[` \x90a\x0Fna\r\xFEV[\x82\x82\x85\x01\x01R\x01a\x0FWV[\x90\x91a\x0F\x84a\x0E\x17V[P\x82Q` \x83\x01Q\x03a\x104Wa\x0F\x9C\x81\x84\x84a\x15\x0FV[\x92a\x0F\xA7\x83Qa\x17\xF4V[\x92a\x0F\xB8`\xA0\x86\x01\x92\x83Q\x86a\x1BrV[\x91`\xE0`\0\x80Q` a5\xDF\x839\x81Q\x91R``a\x0F\xEBa\x0F\xD7a\x0EhV[\x95\x86\x8B\x8Aa\x0F\xE3a\x0E\xB6V[\x9A\x8B\x94a\x1C9V[\x93Q\x97\x01Q\x87\t\x96\x01Q\x95a\x01\x80a\x01`\x86\x01Q\x95\x01Q\x95a\x10\x0Ba\x02\xB4V[\x97\x88R` \x88\x01R`@\x87\x01R``\x86\x01R`\x80\x85\x01R`\xA0\x84\x01R`\xC0\x83\x01R`\xE0\x82\x01R\x90V[`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x90\xFD[`@Q\x90a\x10S\x82a\x028V[`\x02\x82R`@6` \x84\x017V[cNH{q`\xE0\x1B`\0R`\x11`\x04R`$`\0\xFD[`\x02\x01\x90\x81`\x02\x11a\x10\x85WV[a\x10aV[\x90`\x01\x82\x01\x80\x92\x11a\x10\x85WV[a\x10\xA0a\r\xFEV[Pa\x10\xA9a\r\xFEV[Pa\x10\xB2a\x10FV[a\x10\xBAa\x0E\xEFV[\x91`\x01\x90`\x01a\x10\xC9\x84a\t\xE2V[Ra\x11\x14`\xC0\x82\x01\x93\x84Qa\x10\xDD\x87a\t\xE2V[Ra\x10\xE7\x86a\t\xE2V[P\x82Qa\x10\xF3\x82a\t\xF4V[R`\xE0\x83\x01\x95\x86Qa\x11\x04\x82a\t\xF4V[Ra\x11\x0E\x81a\t\xF4V[Pa\x1D\tV[\x93`\x80\x82\x01a\x11,a\x11'\x82QQa\x10wV[a\x10\x8AV[\x94a\x11?a\x119\x87a\x0E\x84V[\x96a\x0F*V[\x94\x80`\0\x93\x84\x92[a\x12\xB4W[PPP\x83a\x11\xE0a\r\x9F\x98\x97\x94``a\x11\xD5a\x11\x99a\x12\t\x9A\x97a\x11\x0E\x97` a\x12\x04\x9C\x01Qa\x11|\x83\x8Da\x0B\xDBV[RQa\x11\x88\x82\x8Ba\x0B\xDBV[Ra\x11\x93\x81\x8Aa\x0B\xDBV[Pa\x10\x8AV[\x85Q\x93`\0\x80Q` a5\xDF\x839\x81Q\x91R\x80\x95`@\x89\x01Q\x90\ta\x11\xBE\x83\x8Ca\x0B\xDBV[RQa\x11\xCA\x82\x8Aa\x0B\xDBV[Ra\x11\x93\x81\x89a\x0B\xDBV[\x93\x01Q`\0\x08a\x1D\xEEV[a\x11\xEA\x82\x86a\x0B\xDBV[Ra\x11\xF3a\x1E\x0CV[a\x11\xFD\x82\x85a\x0B\xDBV[R\x82a\x0B\xDBV[a\x1E/V[a\x12\x11a\x02\xC3V[\x7F\x01\x18\xC4\xD5\xB87\xBC\xC2\xBC\x89\xB5\xB3\x98\xB5\x97N\x9FYD\x07;2\x07\x8B~#\x1F\xEC\x93\x88\x83\xB0\x81R\x7F&\x0E\x01\xB2Q\xF6\xF1\xC7\xE7\xFFNX\x07\x91\xDE\xE8\xEAQ\xD8z5\x8E\x03\x8BN\xFE0\xFA\xC0\x93\x83\xC1` \x82\x01R\x7F\"\xFE\xBD\xA3\xC0\xC0c*VG[B\x14\xE5a^\x11\xE6\xDD?\x96\xE6\xCE\xA2\x85J\x87\xD4\xDA\xCC^U`@\x82\x01R\x7F\x04\xFCci\xF7\x11\x0F\xE3\xD2QV\xC1\xBB\x9Ar\x85\x9C\xF2\xA0FA\xF9\x9B\xA4\xEEA<\x80\xDAj_\xE4``\x82\x01Ra\x12\xAEa\x1E\x93V[\x92a\x1F\xA4V[\x90\x91\x93\x81Q\x80Q\x86\x10\x15a\x13\x0CWa\x13\x04\x82\x8Ba\x12\xDF\x87\x96\x95a\x12\xD8\x8B\x89\x97a\x0B\xDBV[Q\x92a\x0B\xDBV[Ra\x12\xEE\x88`\xA0\x8C\x01Qa\x0B\xDBV[Qa\x12\xF9\x82\x8Da\x0B\xDBV[Ra\x11\x93\x81\x8Ca\x0B\xDBV[\x95\x01\x92a\x11GV[P\x93a\x11LV[\x80Q` \x82\x01Q\x15\x90\x15\x16a\x13\xAEW` \x81Q\x91\x01Q\x90\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG\x80\x80`\x03\x81\x80\x86\x80\t\x86\t\x08\x81\x85\x80\t\x14\x93\x10\x91\x10\x16\x16\x15a\x13iWV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7FBn254: invalid G1 point\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x90\xFD[PV[`@Q\x90a\x13\xBE\x82a\x01\xE5V[\x81`\xE0`\0\x91\x82\x81R\x82` \x82\x01R\x82`@\x82\x01R\x82``\x82\x01R\x82`\x80\x82\x01R\x82`\xA0\x82\x01R\x82`\xC0\x82\x01R\x01RV[`@Q\x90a\x13\xFC\x82a\x01\xC5V[`\0` \x83``\x81R\x01RV[\x90\x81Q\x91`\0[\x83\x81\x10a\x14!WPP\x01`\0\x81R\x90V[\x80` \x80\x92\x84\x01\x01Q\x81\x85\x01R\x01a\x14\x10V[a\x14@\x90`\xA0\x92a\x14\tV[`\x01`\xF8\x1B\x81R\x7FJ\x1D0\xB1{\xFB\xA4]\x83\x85?\x81\x94l\xCAsL@\x10\xE1D*\xE1\xC4B\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01`@\x82\x01R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0``\x82\x01R\x7F'$q6\x03\xBF\xBDy\n\xEA\xF3\xE7\xDF%\xD8\xE7\xEF\x8F1\x134\x90[M\x8C\x99\x98\x0C\xF2\x10\x97\x9D`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x90\xFD[a\x1A\xF3a\x02\xD0V[\x90`\x14\x82R` \x82\x01R\x7F0dKl\x9CJr\x16\x9EM\xAA1}%\xF0E\x12\xAE\x15\xC5;4\xE8\xF5\xAC\xD8\xE1U\xD0\xA6\xC1\x01`@\x82\x01R\x7F&\x12]\xA1\n\x0E\xD0c'P\x8A\xBA\x06\xD1\xE3\x03\xACaf2\xDB\xED4\x9FSB-\xA9S3xW``\x82\x01R\x7F\x10\x0C3-!\0\x89_\xABds\xBC,Q\xBF\xCAR\x1FE\xCB;\xAC\xA6&\x08R\xA8\xFD\xE2l\x91\xF3`\x80\x82\x01R\x90V[\x91\x92\x90\x92`@Q\x92``\x84\x01\x84\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@R`\0\x84R` \x84\x01\x94`\0\x86R`@\x85\x01\x92`\0\x84R\x85\x83Q\x97\x83`\0\x14a\x1C\x08W\x83\x98`\0\x90[\x80\x82\x10a\x1B\xEAWPPa\x1B\xDDa\x1B\xE6\x96\x97\x98\x99`\0\x19\x01[\x80\x84R\x85\x87a&?V[\x90RQ\x92a&\xA8V[\x90RV[\x90\x99`\0\x80Q` a5\xDF\x839\x81Q\x91R\x81`\x01\x92\t\x9A\x01\x90a\x1B\xBBV[a\x1B\xE6\x95\x96\x97\x98Pa\x1B\xDD\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a\x1B\xD3V[\x90a\r\x9F\x95\x93\x92\x93` \x82\x01Qa\x1C\xFF`@\x84\x01Q\x92\x88\x88``\x89\x01Q\x96`\x80\x8A\x01Q\x99\x82a\x01\xA0\x81\x01Q\x9B\x80`\0\x80Q` a5\xDF\x839\x81Q\x91R\x80\x9E\x81\x9D\x82\x86\x85\x82\x80\x80\x80\x80\x80\x9D\x99\x81\x9D\x82a\x02@\x81\x9D\x01Q\x8C\t\x91\x01\x08`\x01\t\x81a\x01\xC0\x87\x01Q\x86\x82a\x02`\x8A\x01Q\x8C\t\x91\x01\x08\x90\t\x81a\x01\xE0\x86\x01Q\x85\x82a\x02\x80\x89\x01Q\x8B\t\x91\x01\x08\x90\t\x94a\x02\xA0a\x02\0\x85\x01Q\x94\x01Q\x90\t\x91\x01\x08\x90\t\x91\x81a\x02 \x89\x01Q\x91a\x02\xC0\x8A\x01Q\x92\x08\t\x90\t\x98\x81\x83Q\x99` \x85\x01Q\t\x82\x03\x90\x08\x99a'\xD9V[\t\x82\x03\x90\x08a)\xE6V[\x91\x90a\x1D\x13a\r\xFEV[P\x80Q\x83Q\x03a\x1D\x8EWa\x1D:a\x1D)\x84a\t\xE2V[Qa\x1D3\x83a\t\xE2V[Q\x90a*:V[\x92`\x01\x91\x82\x91\x82[a\x1DMW[PPPPV[\x90\x91\x92\x94\x82Q\x86\x10\x15a\x1D\x88W\x90\x83a\x1D\x80\x81\x94\x93a\x1Dza\x1Do\x8A\x86a\x0B\xDBV[Qa\x1D3\x8B\x88a\x0B\xDBV[\x90a*\x7FV[\x96\x01\x93a\x1DBV[\x94a\x1DGV[`d`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R` `$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R\xFD[\x90`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\x82\x03\x91\x82\x11a\x10\x85WV[`\0\x80Q` a5\xDF\x839\x81Q\x91R\x80\x91\x06\x81\x03\x90\x81\x11a\x10\x85W\x90V[a\x1E\x14a\r\xFEV[P`@Qa\x1E!\x81a\x01\xC5V[`\x01\x81R`\x02` \x82\x01R\x90V[a\x1E7a\r\xFEV[P\x80Q` \x82\x01Q\x15\x90\x15\x16a\r\x9FW` \x81Q\x91\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG\x91\x82\x91\x01Q\x06\x81\x03\x90\x81\x11a\x10\x85W`@Q\x91a\x1E\x89\x83a\x01\xC5V[\x82R` \x82\x01R\x90V[`\0```@Qa\x1E\xA3\x81a\x02\x01V[\x82\x81R\x82` \x82\x01R\x82`@\x82\x01R\x01R`@Qa\x1E\xC0\x81a\x02\x01V[\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2` \x82\x01R\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA`@\x82\x01R\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[``\x82\x01R\x90V[\x15a\x1F_WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x90\xFD[\x91`@a\x01\x80\x92\x94`\0\x94\x82Q\x93\x81Q\x85R\x83` \x98\x89\x80\x94\x01Q\x84\x88\x01R\x83\x81\x01Q\x82\x88\x01R\x80Q``\x88\x01R``\x81\x01Q`\x80\x88\x01R\x01Q`\xA0\x86\x01R\x80Q`\xC0\x86\x01R\x01Q`\xE0\x84\x01R\x85\x81\x01Qa\x01\0\x84\x01R\x80Qa\x01 \x84\x01R``\x81\x01Qa\x01@\x84\x01R\x01Qa\x01`\x82\x01R`\x08Z\xFAa &`\0Q\x91a\x1FXV[\x15\x15\x90V[a A\x90a\x01\0\x9A\x98\x96\x94\x92\x99\x97\x95\x93\x99a\x14\tV[\x97\x88R` \x88\x01R`@\x87\x01R``\x86\x01R`\x80\x85\x01R`\xA0\x84\x01R`\xC0\x83\x01R`\xE0\x82\x01R\x01\x90V[\x90\x81Q`@\x91\x82Q\x92` \x92\x84\x84\x81\x01a \x8D\x90` \x90`\x7F`\xF9\x1B\x81R\x01\x90V[\x03\x94`\x1F\x19\x95\x86\x81\x01\x82Ra \xA2\x90\x82a\x02SV[a \xAB\x90a+\rV[\x90\x83Qa \xB7\x90a%,V[\x83Q\x86\x81\x01\x91\x82R\x90\x81\x90` \x01\x03\x87\x81\x01\x82Ra \xD5\x90\x82a\x02SV[a \xDE\x90a+XV[\x85\x85\x01Qa \xEB\x90a%,V[\x84Q\x87\x81\x01\x91\x82R\x90\x81\x90` \x01\x03\x88\x81\x01\x82Ra!\t\x90\x82a\x02SV[a!\x12\x90a+XV[\x90\x84Q\x93\x84\x93\x88\x85\x01a!$\x91a\x14\tV[a!-\x91a\x14\tV[a!6\x91a\x14\tV[a!?\x91a\x14\tV[\x03\x85\x81\x01\x82Ra!O\x90\x82a\x02SV[\x80\x86R\x81Q\x80\x91\x85\x82\x01\x90a!c\x91a\x144V[\x03\x85\x81\x01\x82Ra!s\x90\x82a\x02SV[\x80\x86R`\xE0\x83\x01Qa!\x84\x90a$UV[\x90a\x01\0\x84\x01Qa!\x94\x90a$UV[a\x01 \x85\x01Qa!\xA3\x90a$UV[a\x01@\x86\x01Qa!\xB2\x90a$UV[a\x01`\x87\x01Qa!\xC1\x90a$UV[\x90a\x01\x80\x88\x01Qa!\xD1\x90a$UV[\x92a\x01\xE0\x89\x01Qa!\xE1\x90a$UV[\x94\x88Q\x97\x88\x97\x8C\x89\x01a!\xF3\x91a\x14\tV[a!\xFC\x91a\x14\tV[a\"\x05\x91a\x14\tV[a\"\x0E\x91a\x14\tV[a\"\x17\x91a\x14\tV[a\" \x91a\x14\tV[a\")\x91a\x14\tV[a\"2\x91a\x14\tV[\x03\x85\x81\x01\x82Ra\"B\x90\x82a\x02SV[\x80\x86Ra\x02\0\x83\x01Qa\"T\x90a$UV[\x90a\x02 \x84\x01Qa\"d\x90a$UV[a\x02@\x85\x01Qa\"s\x90a$UV[a\x01\xA0\x86\x01Qa\"\x82\x90a$UV[a\x01\xC0\x87\x01Qa\"\x91\x90a$UV[\x91a\x02`\x88\x01Qa\"\xA1\x90a$UV[\x93\x87Q\x96\x87\x96\x8B\x88\x01a\"\xB3\x91a\x14\tV[a\"\xBC\x91a\x14\tV[a\"\xC5\x91a\x14\tV[a\"\xCE\x91a\x14\tV[a\"\xD7\x91a\x14\tV[a\"\xE0\x91a\x14\tV[a\"\xE9\x91a\x14\tV[\x03\x85\x81\x01\x82Ra\"\xF9\x90\x82a\x02SV[\x80\x86R\x81\x83\x01Qa#\t\x90a$UV[\x92``\x81\x01Qa#\x18\x90a$UV[\x90`\x80\x81\x01Qa#'\x90a$UV[`\xA0\x82\x01Qa#5\x90a$UV[\x91`\xC0\x01Qa#C\x90a$UV[\x92\x85Q\x96\x87\x95\x89\x87\x01a#U\x91a\x14\tV[a#^\x91a\x14\tV[a#g\x91a\x14\tV[a#p\x91a\x14\tV[a#y\x91a\x14\tV[a#\x82\x91a\x14\tV[\x03\x84\x81\x01\x83Ra#\x92\x90\x83a\x02SV[\x81\x85Ra#\x9E\x86a\t\xE2V[Qa#\xA8\x90a%,V[\x95a#\xB2\x81a\t\xF4V[Qa#\xBC\x90a%,V[a#\xC5\x82a\n\x04V[Qa#\xCF\x90a%,V[a#\xD8\x83a\n\x14V[Qa#\xE2\x90a%,V[a#\xEB\x84a\n$V[Qa#\xF5\x90a%,V[\x91a#\xFF\x85a\n4V[Qa$\t\x90a%,V[\x93a$\x13\x86a\nDV[Qa$\x1D\x90a%,V[\x95a$'\x90a\nTV[Qa$1\x90a%,V[\x96Q\x9B\x8C\x99\x8A\x01\x98a$B\x99a +V[\x03\x90\x81\x01\x83Ra$R\x90\x83a\x02SV[RV[a$\xAA\x90`\0\x90a$n\x81` \x81Q\x91\x01Q\x15\x90\x15\x16\x90V[a$\xCCW[\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG` \x82\x01Q`\x01\x1B\x10\x15a$\xC0W[Q\x17a%,V[`@Q\x90` \x82\x01R` \x81Ra\r\x9F\x81a\x01\xC5V[`\x01`\xFF\x1B\x91Pa$\xA3V[`\x01`\xFE\x1B\x91Pa$sV[\x90` \x91` \x81\x01\x90\x81Q\x90Q\x93\x84Q\x90`@Q\x92\x83R`\0[\x82\x81\x10a%\x19WPP`\0\x80Q` a5\xDF\x839\x81Q\x91R\x93\x94P` \x01\x90 \x80\x91R\x06\x90V[\x86\x81\x01\x82\x01Q\x84\x82\x01\x83\x01R\x81\x01a$\xF2V[\x80`\x08\x1C\x90`\x08\x1B\x90~\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\x7F\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0}\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\x84\x16|\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\x84\x16\x17`\x10\x1B\x93\x16\x91\x16\x17`\x10\x1C\x17{\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\x7F\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\0\0\0\0\x82` \x1B\x16\x91` \x1C\x16\x17w\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x19\x82`@\x1B\x16\x91`@\x1C\x16\x17\x80`\x80\x1B\x90`\x80\x1C\x17\x90V[\x82\x15a&\xA0W`@\x01Q`\0\x80Q` a5\xDF\x839\x81Q\x91R\x92\x83\x91\x90\t\x90\x80\x15a&vWa&q\x90`\0\x19\x01a+\xA3V[\x90\t\x90V[Pa&q\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a+\xA3V[PPP`\0\x90V[\x90\x93\x92`\0\x94`\0\x90\x82\x15a'\xD1W\x91\x90\x82\x94\x93\x94Q\x92a&\xCE\x84`@\x88\x01Q\x97a,SV[a&\xD7\x85a\x0E\x84V[\x96`\0\x80Q` a5\xDF\x839\x81Q\x91R\x94\x85\x91\t\x91`\x01\x96`\x01\x90\x85[\x88\x81\x10a'\x9BWPPa'\x06\x90a+\xA3V[\x95\x84\x98[\x81\x8A\x10a'\x1DWPPPPPPPPPPV[\x90\x91\x92\x93\x94\x95\x96\x97\x87\x8A\x9C\x8B\x82\x8C\x85\x9E`\x05\x1B\x91\x82\x91\x81\x8D\x8D` \x96\x87\x91\x01\x01Q\x90\t\t\x92\x8C\x90[\x89\x82\x10a'gWPP\x88\x01\x01Q\x83\x91\t\x90\x08\x9B\x01\x98\x97\x96\x95\x94\x93\x92\x91\x90a'\nV[\x90\x80\x92\x94\x96\x91\x97\x93\x95\x97\x03a'\x87W[P\x01\x91\x8F\x91\x8E\x95\x93\x8D\x95\x93a'EV[\x90\x94\x84\x86`\x05\x1B\x89\x01\x01Q\x90\t\x93\x8Ca'wV[\x98\x89\x81\x9B\x9A`\x05\x9A\x95\x96\x97\x98\x99\x9A\x1B\x93` \x8B\x80\x86\x83\x89\x8D\x01\x01Q\x82\x03\x08\x80\x93\t\x95\x8D\x01\x01R\x01\x99\x98\x99\x97\x96\x95\x94\x93\x92\x97a&\xF4V[P\x94PPPPV[\x90\x91\x84\x86\x85a'\xEC\x93\x97\x96\x97\x86\x86a,\xD6V[`\xC0\x82\x01Q\x80a'\xFB\x85a\neV[R\x84Qa(\x07\x87a\neV[Ra(\x11\x86a\neV[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x81\x80\t\x80a(.\x86a\nvV[R` \x86\x01Qa(=\x88a\nvV[R\x81a(H\x88a\nvV[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x80a(d\x86a\n\x87V[R`@\x86\x01Qa(s\x88a\n\x87V[R\x81a(~\x88a\n\x87V[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x80a(\x9A\x86a\n\x98V[R``\x86\x01Qa(\xA9\x88a\n\x98V[R\x81a(\xB4\x88a\n\x98V[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x80a(\xD0\x86a\n\xA9V[R`\x80\x86\x01Qa(\xDF\x88a\n\xA9V[R\x81a(\xEA\x88a\n\xA9V[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x80a)\x06\x86a\n\xBAV[R`@\x83\x01Qa)\x15\x88a\n\xBAV[R\x81a) \x88a\n\xBAV[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x80a)<\x86a\n\xCBV[R``\x83\x01Qa)K\x88a\n\xCBV[R\x81a)V\x88a\n\xCBV[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x90\x81a)s\x86a\n\xDCV[R`\x80\x83\x01Qa)\x82\x88a\n\xDCV[Ra)\x8C\x87a\n\xDCV[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\ta)\xA7\x84a\n\xEDV[R`\xA0\x01Qa)\xB5\x85a\n\xEDV[Ra)\xBF\x84a\n\xEDV[P`\xE0\x01Q\x90a)\xCE\x90a\n\xFEV[R`\xA0\x01Qa)\xDC\x82a\n\xFEV[Ra\x13\xAE\x90a\n\xFEV[\x92\x91\x90`\0\x80Q` a5\xDF\x839\x81Q\x91R\x93\x84\x03\x93`\0\x92[`\n\x84\x10a*\x0EWPPPPV[\x90\x91\x92\x94\x82`\x01\x91\x81`\x05a\x01\xA0\x8A`\x15\x81\x01\x83\x1B\x88\x01Q\x92\x1B\x89\x01\x01Q\x90\t\x90\x08\x95\x01\x92\x91\x90a*\0V[\x91\x90``\x90`\x80a*Ia\r\xFEV[\x94\x85\x92` `@Q\x92a*[\x84a\x028V[\x866\x857\x80Q\x84R\x01Q` \x83\x01R`@\x82\x01R`\x07a\x07\xCF\x19Z\x01\xFA\x15a\x03\x17WV[` \x92\x91`\xC0``\x92a*\x90a\r\xFEV[\x95\x86\x93\x81`@Q\x93a*\xA1\x85a\x02\x01V[`\x806\x867\x80Q\x85R\x01Q\x82\x84\x01R\x80Q`@\x84\x01R\x01Q\x84\x82\x01R`\x06a\x07\xCF\x19Z\x01\xFA\x15a\x03\x17WV[\x15a*\xD4WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x11`$\x82\x01Rpslice_outOfBounds`x\x1B`D\x82\x01R`d\x90\xFD[a+\x1B`\x04\x82Q\x10\x15a*\xCDV[`@Q\x90`\x04\x80\x83\x01\x91\x01`\x08\x83\x01[\x80\x83\x10a+EWPP`\x04\x82R`\x1F\x01`\x1F\x19\x16`@R\x90V[\x90\x91\x82Q\x81R` \x80\x91\x01\x92\x01\x90a++V[a+f`\x08\x82Q\x10\x15a*\xCDV[`@Q\x90`\x08\x80\x83\x01\x91\x01`\x10\x83\x01[\x80\x83\x10a+\x90WPP`\x08\x82R`\x1F\x01`\x1F\x19\x16`@R\x90V[\x90\x91\x82Q\x81R` \x80\x91\x01\x92\x01\x90a+vV[\x90`@Q\x91`\0`\xC0` \x94\x85\x93\x84\x82R\x84\x80\x83\x01R\x84`@\x83\x01R``\x82\x01R\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xEF\xFF\xFF\xFF`\x80\x82\x01R`\0\x80Q` a5\xDF\x839\x81Q\x91R`\xA0\x82\x01R`\x05Z\xFA\x91`\0Q\x92\x15a,\x0FWPV[`d\x90`@Q\x90bF\x1B\xCD`\xE5\x1B\x82R`\x04\x82\x01R`\x1D`$\x82\x01R\x7FBn254: pow precompile failed!\0\0\0`D\x82\x01R\xFD[\x91\x90\x91` \x90` \x81\x01Q\x84\x11a,\xC4W``\x01Q\x92`\x01\x93a,u\x82a\x0E\x84V[\x94\x82\x15\x19a,\x83WPPPPV[`\x01` \x80\x88\x01\x94`\x05\x1B\x88\x01\x01\x93R`@\x86\x01\x90[\x83\x82\x10a,\xA6WPa\x1DGV[`\0\x80Q` a5\xDF\x839\x81Q\x91R\x83\x86\x92\t\x91\x82\x81R\x01\x90a,\x99V[`@Qc\x8C^\x11\xF1`\xE0\x1B\x81R`\x04\x90\xFD[\x94\x92\x93\x94\x91\x90\x91` \x82\x01Q` \x84\x01Q\x90`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x83Q`\xA0\x85\x01Q``\x86\x01Q\x90`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x90a\x01\xA0\x88\x01Q`\0\x80Q` a5\xDF\x839\x81Q\x91R\x90\x83\x08\x90`\x80\x87\x01Q\x91\x82`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x81a\x01\xC0\x8A\x01Q`\0\x80Q` a5\xDF\x839\x81Q\x91R\x7F/\x8D\xD1\xF1\xA7Xa\x01\xE3V[\x90a\x03\x045\x82Ra\x03$5` \x83\x01RV[`@\x90a\x03C\x19\x01\x12a\x01\xA2Wa\x04ea\x01\xE3V[\x90a\x03D5\x82Ra\x03d5` \x83\x01RV[`@\x90a\x03\x83\x19\x01\x12a\x01\xA2Wa\x04\x8Ca\x01\xE3V[\x90a\x03\x845\x82Ra\x03\xA45` \x83\x01RV[`@\x90a\x03\xC3\x19\x01\x12a\x01\xA2Wa\x04\xB3a\x01\xE3V[\x90a\x03\xC45\x82Ra\x03\xE45` \x83\x01RV[`@\x90a\x04\x03\x19\x01\x12a\x01\xA2Wa\x04\xDAa\x01\xE3V[\x90a\x04\x045\x82Ra\x04$5` \x83\x01RV[`@\x90a\x04C\x19\x01\x12a\x01\xA2Wa\x05\x01a\x01\xE3V[\x90a\x04D5\x82Ra\x04d5` \x83\x01RV[`@\x90a\x04\x83\x19\x01\x12a\x01\xA2Wa\x05(a\x01\xE3V[\x90a\x04\x845\x82Ra\x04\xA45` \x83\x01RV[`@\x90a\x06\x03\x19\x01\x12a\x01\xA2Wa\x05Oa\x01\xE3V[\x90a\x06\x045\x82Ra\x06$5` \x83\x01RV[`@\x90a\x06C\x19\x01\x12a\x01\xA2Wa\x05va\x01\xE3V[\x90a\x06D5\x82Ra\x06d5` \x83\x01RV[`@\x90a\x06\x83\x19\x01\x12a\x01\xA2Wa\x05\x9Da\x01\xE3V[\x90a\x06\x845\x82Ra\x06\xA45` \x83\x01RV[`@\x90a\x06\xC3\x19\x01\x12a\x01\xA2Wa\x05\xC4a\x01\xE3V[\x90a\x06\xC45\x82Ra\x06\xE45` \x83\x01RV[`@\x90a\x07\x03\x19\x01\x12a\x01\xA2Wa\x05\xEBa\x01\xE3V[\x90a\x07\x045\x82Ra\x07$5` \x83\x01RV[`@\x90a\x07C\x19\x01\x12a\x01\xA2Wa\x06\x12a\x01\xE3V[\x90a\x07D5\x82Ra\x07d5` \x83\x01RV[`@\x90a\x07\x83\x19\x01\x12a\x01\xA2Wa\x069a\x01\xE3V[\x90a\x07\x845\x82Ra\x07\xA45` \x83\x01RV[`@\x90a\x07\xC3\x19\x01\x12a\x01\xA2Wa\x06`a\x01\xE3V[\x90a\x07\xC45\x82Ra\x07\xE45` \x83\x01RV[`@\x90a\x08\x03\x19\x01\x12a\x01\xA2Wa\x06\x87a\x01\xE3V[\x90a\x08\x045\x82Ra\x08$5` \x83\x01RV[`@\x90a\x08C\x19\x01\x12a\x01\xA2Wa\x06\xAEa\x01\xE3V[\x90a\x08D5\x82Ra\x08d5` \x83\x01RV[`@\x90a\x08\x83\x19\x01\x12a\x01\xA2Wa\x06\xD5a\x01\xE3V[\x90a\x08\x845\x82Ra\x08\xA45` \x83\x01RV[`@\x90a\x08\xC3\x19\x01\x12a\x01\xA2Wa\x06\xFCa\x01\xE3V[\x90a\x08\xC45\x82Ra\x08\xE45` \x83\x01RV[`@\x90a\t\x03\x19\x01\x12a\x01\xA2Wa\x07#a\x01\xE3V[\x90a\t\x045\x82Ra\t$5` \x83\x01RV[\x80a\x05#\x12\x15a\x01\xA2Wa\x07Ga\x02dV[\x90\x81a\x06\x04\x91\x82\x11a\x01\xA2Wa\x05\x04\x90[\x82\x82\x10a\x07eWPPP\x90V[\x815\x81R` \x91\x82\x01\x91\x01a\x07XV[\x90a\x04\x80a\x06\x03\x19\x83\x01\x12a\x01\xA2Wa\x08>a\x07\x8Fa\x02\x03V[\x92a\x07\x99\x81a\x05:V[\x84Ra\x07\xA4\x81a\x05aV[` \x85\x01Ra\x07\xB2\x81a\x05\x88V[`@\x85\x01Ra\x07\xC0\x81a\x05\xAFV[``\x85\x01Ra\x07\xCE\x81a\x05\xD6V[`\x80\x85\x01Ra\x07\xDC\x81a\x05\xFDV[`\xA0\x85\x01Ra\x07\xEA\x81a\x06$V[`\xC0\x85\x01Ra\x07\xF8\x81a\x06KV[`\xE0\x85\x01Ra\x08\x06\x81a\x06rV[a\x01\0\x85\x01Ra\x08\x15\x81a\x06\x99V[a\x01 \x85\x01Ra\x08$\x81a\x06\xC0V[a\x01@\x85\x01Ra\x083\x81a\x06\xE7V[a\x01`\x85\x01Ra\x07\x0EV[a\x01\x80\x83\x01Ra\tD5a\x01\xA0\x83\x01Ra\td5a\x01\xC0\x83\x01Ra\t\x845a\x01\xE0\x83\x01Ra\t\xA45a\x02\0\x83\x01Ra\t\xC45a\x02 \x83\x01Ra\t\xE45a\x02@\x83\x01Ra\n\x045a\x02`\x83\x01Ra\n$5a\x02\x80\x83\x01Ra\nD5a\x02\xA0\x83\x01Ra\nd5a\x02\xC0\x83\x01RV[\x90`\x08\x81\x10\x15a\x08\xBBW`\x05\x1B\x01\x90V[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[\x90a\nx\x92\x91a\x08\xE1\x83Qa\x0C\x97V[a\x08\xEE` \x84\x01Qa\x0C\x97V[a\x08\xFB`@\x84\x01Qa\x0C\x97V[a\t\x08``\x84\x01Qa\x0C\x97V[a\t\x15`\x80\x84\x01Qa\x0C\x97V[a\t\"`\xA0\x84\x01Qa\x0C\x97V[a\t/`\xC0\x84\x01Qa\x0C\x97V[a\t<`\xE0\x84\x01Qa\x0C\x97V[a\tJa\x01\0\x84\x01Qa\x0C\x97V[a\tXa\x01 \x84\x01Qa\x0C\x97V[a\tfa\x01@\x84\x01Qa\x0C\x97V[a\tta\x01`\x84\x01Qa\x0C\x97V[a\t\x82a\x01\x80\x84\x01Qa\x0C\x97V[a\t\x90a\x01\xA0\x84\x01Qa\n{V[a\t\x9Ea\x01\xC0\x84\x01Qa\n{V[a\t\xACa\x01\xE0\x84\x01Qa\n{V[a\t\xBAa\x02\0\x84\x01Qa\n{V[a\t\xC8a\x02 \x84\x01Qa\n{V[a\t\xD6a\x02@\x84\x01Qa\n{V[a\t\xE4a\x02`\x84\x01Qa\n{V[a\t\xF2a\x02\x80\x84\x01Qa\n{V[a\n\0a\x02\xA0\x84\x01Qa\n{V[a\n\x0Ea\x02\xC0\x84\x01Qa\n{V[a\n\x18\x82Qa\n{V[a\n%` \x83\x01Qa\n{V[a\n2`@\x83\x01Qa\n{V[a\n?``\x83\x01Qa\n{V[a\nL`\x80\x83\x01Qa\n{V[a\nY`\xA0\x83\x01Qa\n{V[a\nf`\xC0\x83\x01Qa\n{V[a\ns`\xE0\x83\x01Qa\n{V[a\n\xEDV[\x90V[`\0\x80Q` a)\x96\x839\x81Q\x91R\x11\x15a\n\x92WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x90\xFD[a\n\xDFa\x01\xE3V[\x90`\0\x82R`\0` \x83\x01RV[`\x08` \x82\x01Q\x03a\x0C\x85Wa\x0B\x04\x83\x83\x83a\r\x85V[\x92\x81Qa\x0B\x10\x90a\x12rV[\x90`\xA0\x85\x01\x93\x84Q\x90a\x0B#\x91\x84a\x16\x9BV[\x92a\x0B,a\n\xD7V[Pa\x0B5a\n\xD7V[Pa\x01`\x82\x01\x90\x81Q\x92a\x01\x80\x81\x01\x95\x86Q\x94`\xE0\x8A\x01\x95\x86Qa\x0BX\x91a\x17NV[a\x0Ba\x91a\x17\x9BV[\x98a\x0Bk\x93a\x18#V[\x90a\x0Bu\x90a\x1B\xF7V[a\x0B~\x91a\x17\x9BV[\x90Q\x85Qa\x0B\x8B\x91a\x17NV[a\x0B\x94\x91a\x17\x9BV[\x93Q\x91`\0\x80Q` a)\x96\x839\x81Q\x91R\x92`@\x84\x92\x01Q` \x01Q\x90\t\x90Q\x90\t\x90Q\x90a\x0B\xC3\x91a\x17NV[a\x0B\xCC\x91a\x17\x9BV[a\x0B\xD4a\x02$V[\x7F\x01\x18\xC4\xD5\xB87\xBC\xC2\xBC\x89\xB5\xB3\x98\xB5\x97N\x9FYD\x07;2\x07\x8B~#\x1F\xEC\x93\x88\x83\xB0\x81R\x7F&\x0E\x01\xB2Q\xF6\xF1\xC7\xE7\xFFNX\x07\x91\xDE\xE8\xEAQ\xD8z5\x8E\x03\x8BN\xFE0\xFA\xC0\x93\x83\xC1` \x82\x01R\x7F\"\xFE\xBD\xA3\xC0\xC0c*VG[B\x14\xE5a^\x11\xE6\xDD?\x96\xE6\xCE\xA2\x85J\x87\xD4\xDA\xCC^U`@\x82\x01R\x7F\x04\xFCci\xF7\x11\x0F\xE3\xD2QV\xC1\xBB\x9Ar\x85\x9C\xF2\xA0FA\xF9\x9B\xA4\xEEA<\x80\xDAj_\xE4``\x82\x01R\x90a\x0Cs\x90a\x1B\xF7V[a\x0C{a\x1C_V[\x91a\nx\x93a\x1DhV[`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x90\xFD[\x80Q` \x82\x01Q\x15\x90\x15\x16a\r2W` \x81Q\x91\x01Q\x90\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG\x80\x80`\x03\x81\x80\x86\x80\t\x86\t\x08\x81\x85\x80\t\x14\x93\x10\x91\x10\x16\x16\x15a\x0C\xEDWV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7FBn254: invalid G1 point\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x90\xFD[PV[`@Q\x90a\x01\0\x82\x01\x82\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x01\xDEW`@R\x81`\xE0`\0\x91\x82\x81R\x82` \x82\x01R\x82`@\x82\x01R\x82``\x82\x01R\x82`\x80\x82\x01R\x82`\xA0\x82\x01R\x82`\xC0\x82\x01R\x01RV[`\xA0\x90` a\x01\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x94\x96\x95`\xE0a\r\xA9a\r5V[\x98\x84`\xC0`@Q\x97`\x7F`\xE1\x1B\x83\x8A\x01R\x80Q\x82\x1B`$\x8A\x01R\x82\x81\x01Q\x82\x1B`,\x8A\x01Ra\x02\x80\x81\x01Q`@\x8A\x01Ra\x02\xA0\x81\x01Q``\x8A\x01R`\x01`\x80\x8A\x01R\x7F/\x8D\xD1\xF1\xA7X\xA8\x01f\x9Cd\x01q \xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85`\x80\x82\x01R\x7F\x12YzV\xC2\xE48b\x0B\x90A\xB9\x89\x92\xAE\rNp[x\0W\xBFwf\xA2v|\xEC\xE1n\x1D`\xA0\x82\x01R\x7F\x02\xD9A\x17\xCD\x17\xBC\xF1)\x0F\xD6|\x01\x15]\xD4\x08\x07\x85}\xFFJZ\x0BM\xC6{\xEF\xA8\xAA4\xFD`\xC0\x82\x01R\x7F\x15\xEE$u\xBE\xE5\x17\xC4\xEE\x05\xE5\x1F\xA1\xEEs\x12\xA87:\x0B\x13\xDB\x8CQ\xBA\xF0L\xB2\xE9\x9B\xD2\xBD`\xE0\x82\x01Ra\x13\xA3a\x02DV[\x90`\x10\x82R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01` \x83\x01R`@\x82\x01R\x90V[b\x10\0\0\x81\x14a\x15IW` \x03a\x157Wa\x13\xEFa\x02dV[`\x01\x81R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0` \x82\x01R\x7F!\x08,\xA2\x16\xCB\xBFN\x1CnOE\x94\xDDP\x8C\x99m\xFB\xE1\x17N\xFB\x98\xB1\x15\t\xC6\xE3\x06F\x0B`@\x82\x01R\x7F\x12w\xAEd\x15\xF0\xEF\x18\xF2\xBA_\xB1b\xC3\x9E\xB71\x1F8n-&\xD6D\x01\xF4\xA2]\xA7|%;``\x82\x01R\x7F+3}\xE1\xC8\xC1O\"\xEC\x9B\x9E/\x96\xAF\xEF6Rbsf\xF8\x17\n\n\x94\x8D\xADJ\xC1\xBD^\x80`\x80\x82\x01R\x7F/\xBDM\xD2\x97k\xE5]\x1A\x16:\xA9\x82\x0F\xB8\x8D\xFA\xC5\xDD\xCEw\xE1\x87.\x90c '2z^\xBE`\xA0\x82\x01R\x7F\x10z\xABI\xE6Zg\xF9\xDA\x9C\xD2\xAB\xF7\x8B\xE3\x8B\xD9\xDC\x1D]\xB3\x9F\x81\xDE6\xBC\xFA[K\x03\x90C`\xC0\x82\x01R~\xE1Kcd\xA4~\x9CB\x84\xA9\xF8\n_\xC4\x1C\xD2\x12\xB0\xD4\xDB\xF8\xA5p7p\xA4\n\x9A49\x90`\xE0\x82\x01Ra\x15\x04a\x02DV[\x90`\x05\x82R\x7F.\xE1+\xFFJ(\x13(j\x8D\xC3\x88\xCDuM\x9A>\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01` \x83\x01R`@\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x90\xFD[Pa\x15Ra\x02dV[`\x01\x81R\x7F&\x12]\xA1\n\x0E\xD0c'P\x8A\xBA\x06\xD1\xE3\x03\xACaf2\xDB\xED4\x9FSB-\xA9S3xW` \x82\x01R\x7F\"`\xE7$\x84K\xCARQ\x82\x93S\x96\x8EI\x150RXA\x83WG:\\\x1DY\x7Fa?l\xBD`@\x82\x01R\x7F \x87\xEA,\xD6d'\x86\x08\xFB\x0E\xBD\xB8 \x90\x7FY\x85\x02\xC8\x1Bf\x90\xC1\x85\xE2\xBF\x15\xCB\x93_B``\x82\x01R\x7F\x19\xDD\xBC\xAF:\x8DF\xC1\\\x01v\xFB\xB5\xB9^M\xC5p\x88\xFF\x13\xF4\xD1\xBD\x84\xC6\xBF\xA5}\xCD\xC0\xE0`\x80\x82\x01R\x7F\x05\xA2\xC8\\\xFCY\x17\x89`\\\xAE\x81\x8E7\xDDAa\xEE\xF9\xAAfk\xECo\xE4(\x8D\t\xE6\xD24\x18`\xA0\x82\x01R\x7F\x11\xF7\x0ESc%\x8F\xF4\xF0\xD7\x16\xA6S\xE1\xDCA\xF1\xC6D\x84\xD7\xF4\xB6\xE2\x19\xD67v\x14\xA3\x90\\`\xC0\x82\x01R\x7F)\xE8AC\xF5\x87\rGv\xA9-\xF8\xDA\x8Cl\x93\x03\xD5\x90\x88\xF3{\xA8_@\xCFo\xD1Be\xB4\xBC`\xE0\x82\x01Ra\x16ha\x02DV[\x90`\x14\x82R\x7F0dKl\x9CJr\x16\x9EM\xAA1}%\xF0E\x12\xAE\x15\xC5;4\xE8\xF5\xAC\xD8\xE1U\xD0\xA6\xC1\x01` \x83\x01R`@\x82\x01R\x90V[\x91\x92\x90\x92a\x16\xA7a\x02DV[\x92`\0\x84R` \x84\x01\x94`\0\x86R`@\x85\x01\x92`\0\x84R\x85\x83Q\x97\x83`\0\x14a\x17\x1DW\x83\x98`\0\x90[\x80\x82\x10a\x16\xFFWPPa\x16\xF2a\x16\xFB\x96\x97\x98\x99`\0\x19\x01[\x80\x84R\x85\x87a\x1D\xEFV[\x90RQ\x92a\x1EhV[\x90RV[\x90\x99`\0\x80Q` a)\x96\x839\x81Q\x91R\x81`\x01\x92\t\x9A\x01\x90a\x16\xD0V[a\x16\xFB\x95\x96\x97\x98Pa\x16\xF2\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a\x16\xE8V[``\x90\x92\x91\x92`\x80a\x17^a\x01\xE3V[\x91`\0\x83R`\0` \x84\x01R\x82\x95` a\x17va\x02DV[\x92\x866\x857\x80Q\x84R\x01Q` \x83\x01R`@\x82\x01R`\x07a\x07\xCF\x19Z\x01\xFA\x15a\x01\xA2WV[``\x90\x92\x91\x92`\xC0a\x17\xABa\x01\xE3V[\x91`\0\x83R`\0` \x84\x01R` \x83\x96\x81a\x17\xC4a\x02$V[\x93`\x806\x867\x80Q\x85R\x01Q\x82\x84\x01R\x80Q`@\x84\x01R\x01Q\x84\x82\x01R`\x06a\x07\xCF\x19Z\x01\xFA\x15a\x01\xA2WV[\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x82\x03\x91\x82\x11a\x18\rWV[cNH{q`\xE0\x1B`\0R`\x11`\x04R`$`\0\xFD[\x90\x91a\x18-a\n\xD7V[Pa\x186a\n\xD7V[Pa\x18C\x84\x82\x85\x85a\x1F\xD6V[\x90a\x18O\x90\x85\x85a'\xE2V[a\x18X\x90a\x17\xF1V[`\xC0\x84\x01Q\x80\x80\x80\x80\x95\x81\x95a\x01\xA0\x8B\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x84\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90\x82\x8BQ\x90a\x18\x9B\x91a\x17NV[a\x18\xA4\x91a\x17\x9BV[\x90a\x01\xC0\x8B\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x84\x80\t\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x83\x80\t` \x8C\x01Q\x90a\x19\x02\x91a\x17NV[a\x19\x0B\x91a\x17\x9BV[\x90\x82`\0\x80Q` a)\x96\x839\x81Q\x91R\x81\x80\t\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x01\xE0\x8C\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x91\x81`@\x8D\x01Q\x90a\x19l\x91a\x17NV[a\x19u\x91a\x17\x9BV[\x92`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02\0\x8B\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x91\x81``\x8C\x01Q\x90a\x19\xC2\x91a\x17NV[a\x19\xCB\x91a\x17\x9BV[\x93`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02 \x8A\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x92\x81`\x80\x8B\x01Q\x90a\x1A\x18\x91a\x17NV[a\x1A!\x91a\x17\x9BV[\x92a\x02@\x8A\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x84\x84\t\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x92`\0\x80Q` a)\x96\x839\x81Q\x91R\x83\x83\t`@\x89\x01Q\x90a\x1A\x7F\x91a\x17NV[a\x1A\x88\x91a\x17\x9BV[\x93`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02`\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x91\x81``\x87\x01Q\x90a\x1A\xE7\x91a\x17NV[a\x1A\xF0\x91a\x17\x9BV[\x92`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02\x80\x87\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x91\x81`\x80\x86\x01Q\x90a\x1B=\x91a\x17NV[a\x1BF\x91a\x17\x9BV[\x92`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02\xA0\x86\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x92`\xA0\x01Q\x90a\x1B\x91\x91a\x17NV[a\x1B\x9A\x91a\x17\x9BV[\x91`\xE0\x01Q\x90a\x02\xC0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x92`\xA0\x01Q\x90a\x1B\xD8\x91a\x17NV[a\x1B\xE1\x91a\x17\x9BV[\x90a\x1B\xEAa(\xA0V[\x90a\x1B\xF4\x91a\x17NV[\x91V[`\0` a\x1C\x03a\x01\xE3V[\x82\x81R\x01R\x80Q` \x82\x01Q\x15\x90\x15\x16a\nxW` \x81Q\x91\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG\x91\x82\x91\x01Q\x06\x81\x03\x90\x81\x11a\x18\rWa\x1CTa\x01\xE3V[\x91\x82R` \x82\x01R\x90V[`\0``a\x1Cka\x02$V[\x82\x81R\x82` \x82\x01R\x82`@\x82\x01R\x01Ra\x1C\x84a\x02$V[\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2` \x82\x01R\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA`@\x82\x01R\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[``\x82\x01R\x90V[\x15a\x1D#WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x90\xFD[\x91`@a\x01\x80\x92\x94`\0\x94\x82Q\x93\x81Q\x85R\x83` \x98\x89\x80\x94\x01Q\x84\x88\x01R\x83\x81\x01Q\x82\x88\x01R\x80Q``\x88\x01R``\x81\x01Q`\x80\x88\x01R\x01Q`\xA0\x86\x01R\x80Q`\xC0\x86\x01R\x01Q`\xE0\x84\x01R\x85\x81\x01Qa\x01\0\x84\x01R\x80Qa\x01 \x84\x01R``\x81\x01Qa\x01@\x84\x01R\x01Qa\x01`\x82\x01R`\x08Z\xFAa\x1D\xEA`\0Q\x91a\x1D\x1CV[\x15\x15\x90V[`\x01\x82\x14a\x1E`W\x82\x15a\x1EXW` \x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x92\x83\x91\x90\t\x90\x80\x15a\x1E.Wa\x1E)\x90`\0\x19\x01a(\xC7V[\x90\t\x90V[Pa\x1E)\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a(\xC7V[PPP`\0\x90V[PPP`\x01\x90V[\x93\x92\x91\x90\x91\x80\x15a\x1FrWa\x1E~\x92\x91\x92a\x128V[\x91`\xE0\x83\x01\x93`@\x87\x01\x94`\xE0\x86Q\x01\x90`\x01\x90`\x01\x81R`\x01\x90[`\x08\x82\x10a\x1F8WPPPP`\0\x94`\x01\x94\x92\x90Q\x90`\0\x90[`\x08\x82\x10a\x1E\xEDWPPPPP\x93a\x1E\xE3\x91` \x94\x95`\0\x80Q` a)\x96\x839\x81Q\x91R\x95\x86\x94\x85\x93a(\xC7V[\x93\x01Q\x90\t\t\t\x90V[\x90\x91\x92\x93\x95\x96`\x01\x90\x84Q\x98\x89\x87\x8A`\0\x80Q` a)\x96\x839\x81Q\x91R\x94\x85\x80\x94\x81\x80\x94\x81\x8CQ\x91Q\x8A\t\t\t\x90\x08\x9B\x82\x03\x08\x90\t\x96` \x80\x80\x92\x01\x93\x01\x94\x01\x92\x01\x90\x93\x92a\x1E\xB4V[`\x01\x90`\x1F\x99\x95\x96\x99\x19\x80\x91\x01\x93`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x81\x89\x88Q\x82\x03\x08\x90\t\x94\x85\x85R\x01\x91\x01\x90\x92\x91\x97\x94\x93\x97a\x1E\x9AV[P\x91\x92`\x01\x92\x91`\0\x91\x90\x84[`\x08\x84\x10a\x1F\x92WPPPPPP`\0\x90V[\x80\x85\x14a\x1F\xC3W`\0\x80Q` a)\x96\x839\x81Q\x91R\x86\x91a\x1F\xB8`@\x86\x01Q` \x01\x90V[Q\x90\t\x93\x01\x92a\x1F\x7FV[P\x91\x92PPa\x1F\xD2\x92Pa\x08\xAAV[Q\x90V[\x92\x91\x92a\x1F\xE1a\n\xD7V[P`\x80\x82\x01Q` \x85\x01Q` \x84\x01Q\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90\x83Q\x90`\xA0\x85\x01Q``\x86\x01Q\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x91\x81a\x01\xA0\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x85\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x81a\x01\xC0\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x7F/\x8D\xD1\xF1\xA7X\x91a\x17NV[\x82Q``\x84\x01Q\x90\x81`\x80\x86\x01Q\x91a\x02\xC0\x88\x01Q\x91`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x81a\x02@\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x85\ta\x01\xA0\x89\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x81a\x02`\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x85\ta\x01\xC0\x89\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x81a\x02\x80\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x85\ta\x01\xE0\x89\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x91a\x02\xA0\x87\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02\0\x87\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\xC0\x83\x01Q\x90a#\xD1\x90a\x17\xF1V[a#\xDA\x91a\x17NV[a#\xE3\x91a\x17\x9BV[`\xE0\x82\x01Qa\x01\xA0\x85\x01Qa#\xF7\x91a\x17NV[a$\0\x91a\x17\x9BV[a\x01\0\x82\x01Qa\x01\xC0\x85\x01Qa$\x15\x91a\x17NV[a$\x1E\x91a\x17\x9BV[a\x01 \x82\x01Qa\x01\xE0\x85\x01Qa$3\x91a\x17NV[a$<\x91a\x17\x9BV[a\x01@\x82\x01Qa\x02\0\x85\x01Qa$Q\x91a\x17NV[a$Z\x91a\x17\x9BV[a\x01\xC0\x84\x01Qa\x01\xA0\x85\x01Q\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x01`\x83\x01Q\x90a$\x88\x91a\x17NV[a$\x91\x91a\x17\x9BV[a\x02\0\x84\x01Qa\x01\xE0\x85\x01Q\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x01\x80\x83\x01Q\x90a$\xBF\x91a\x17NV[a$\xC8\x91a\x17\x9BV[a\x01\xA0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x81\x80\t\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x01\xE0\x83\x01Q\x90a%\x13\x91a\x17NV[a%\x1C\x91a\x17\x9BV[a\x01\xC0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x81\x80\t\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02\0\x83\x01Q\x90a%g\x91a\x17NV[a%p\x91a\x17\x9BV[a\x01\xE0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x81\x80\t\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02 \x83\x01Q\x90a%\xBB\x91a\x17NV[a%\xC4\x91a\x17\x9BV[a\x02\0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x81\x80\t\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02@\x83\x01Q\x90a&\x0F\x91a\x17NV[a&\x18\x91a\x17\x9BV[a\x01\xA0\x82\x01Qa\x02 \x85\x01Qa&-\x90a)wV[a&6\x91a\x17NV[a&?\x91a\x17\x9BV[a\x01\xC0\x82\x01Qa&N\x91a\x17\x9BV[\x90a\x01\xC0\x84\x01Qa\x01\xA0\x85\x01Q\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x01\xE0\x85\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02\0\x85\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02 \x85\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02`\x01Q\x90a&\xC2\x91a\x17NV[a&\xCB\x91a\x17\x9BV[\x90\x83Qa&\xD7\x90a)wV[\x91\x82`\xC0\x85\x01Q\x90a&\xE8\x91a\x17NV[a&\xF1\x91a\x17\x9BV[\x93Q`\x01`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\xA0\x01Q\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x80\x93`\0\x80Q` a)\x96\x839\x81Q\x91R\x82\x80\x94\t\x90\x81`\xE0\x86\x01Q\x90a'T\x91a\x17NV[a']\x91a\x17\x9BV[\x91`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90\x81a\x01\0\x85\x01Q\x90a'\x81\x91a\x17NV[a'\x8A\x91a\x17\x9BV[\x91`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90\x81a\x01 \x84\x01Q\x90a'\xAE\x91a\x17NV[a'\xB7\x91a\x17\x9BV[\x92`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x01@\x01Q\x90a'\xD9\x91a\x17NV[a\nx\x91a\x17\x9BV[\x90`@` \x84\x01Q\x93\x01Q\x92``\x83\x01Q`\x80\x84\x01Q\x94a\x01\xA0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x87\x81\x87\x81\x80\x80\x9C\x98\x81\x80\x80\x80\x9E\x81\x80\x9E\x9C\x81\x80\x9E\x81a\x02@\x81\x96\x01Q\x8A\t\x92\x08\x08`\x01\t\x81a\x01\xC0\x89\x01Q\x81\x8C\x81a\x02`\x8D\x01Q\x8A\t\x92\x08\x08\x90\t\x81a\x01\xE0\x88\x01Q\x81\x8B\x81a\x02\x80\x8C\x01Q\x89\t\x92\x08\x08\x90\t\x91\x81\x88\x81a\x02\0\x89\x01Q\x93a\x02\xA0\x8A\x01Q\x90\t\x92\x08\x08\x90\t\x93a\x02\xC0a\x02 \x84\x01Q\x93\x01Q\x92\x08\t\x90\t\x93` \x87Q\x97\x01Q\t\x82\x03\x90\x08\x92\t\x82\x03\x90\x08\x90V[`\0` a(\xACa\x01\xE3V[\x82\x81R\x01Ra(\xB9a\x01\xE3V[`\x01\x81R`\x02` \x82\x01R\x90V[\x90`@Q\x91`\0`\xC0` \x94\x85\x93\x84\x82R\x84\x80\x83\x01R\x84`@\x83\x01R``\x82\x01R\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xEF\xFF\xFF\xFF`\x80\x82\x01R`\0\x80Q` a)\x96\x839\x81Q\x91R`\xA0\x82\x01R`\x05Z\xFA\x91`\0Q\x92\x15a)3WPV[`d\x90`@Q\x90bF\x1B\xCD`\xE5\x1B\x82R`\x04\x82\x01R`\x1D`$\x82\x01R\x7FBn254: pow precompile failed!\0\0\0`D\x82\x01R\xFD[`\0\x80Q` a)\x96\x839\x81Q\x91R\x80\x91\x06\x81\x03\x90\x81\x11a\x18\rW\x90V\xFE0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\x01\xA1dsolcC\0\x08\x17\0\n"; /// The bytecode of the contract. pub static PLONKVERIFIER_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__BYTECODE); #[rustfmt::skip] - const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R`\x046\x10\x15a\0\x12W`\0\x80\xFD[`\0\x805`\xE0\x1Cc1\xD9Qt\x14a\0(W`\0\x80\xFD[6`\x03\x19\x01a\t`\x81\x12a\x01\xABWa\x04\xC0\x13a\x01\xA8Wa\0Fa\x02tV[\x90`\x045\x82R`$5` \x83\x01Ra\0]6a\x02\xEFV[`@\x83\x01Ra\0k6a\x03\x1CV[``\x83\x01Ra\0y6a\x03DV[`\x80\x83\x01Ra\0\x876a\x03lV[`\xA0\x83\x01Ra\0\x956a\x03\x97V[`\xC0\x83\x01Ra\0\xA36a\x03\xC2V[`\xE0\x83\x01Ra\0\xB16a\x03\xEDV[a\x01\0\x83\x01Ra\0\xC06a\x04\x18V[a\x01 \x83\x01Ra\0\xCF6a\x04CV[a\x01@\x83\x01Ra\0\xDE6a\x04nV[a\x01`\x83\x01Ra\0\xED6a\x04\x99V[a\x01\x80\x83\x01Ra\0\xFC6a\x04\xC4V[a\x01\xA0\x83\x01Ra\x01\x0B6a\x04\xEFV[a\x01\xC0\x83\x01Ra\x01\x1A6a\x05\x1AV[a\x01\xE0\x83\x01Ra\x01)6a\x05EV[a\x02\0\x83\x01Ra\x0186a\x05pV[a\x02 \x83\x01Ra\x01G6a\x05\x9BV[a\x02@\x83\x01Ra\x01V6a\x05\xC6V[a\x02`\x83\x01Ra\x04\xC45\x90`\x01`\x01`@\x1B\x03\x82\x11a\x01\xA8Wa\x01\xA4a\x01\x92\x84a\x01\x836`\x04\x87\x01a\x087V[a\x01\x8C6a\x08\x97V[\x91a\x0B\xEFV[`@Q\x90\x15\x15\x81R\x90\x81\x90` \x82\x01\x90V[\x03\x90\xF3[\x80\xFD[P\x80\xFD[cNH{q`\xE0\x1B`\0R`A`\x04R`$`\0\xFD[`@\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[a\x01\xAFV[a\x01\0\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[`\x80\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[a\x03\xE0\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[``\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[\x90`\x1F\x80\x19\x91\x01\x16\x81\x01\x90\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[`@Q\x90a\x02\x80\x82\x01\x82\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[`@Q\x90a\x02\xE0\x82\x01\x82\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[`@Q\x90a\x02\xC1\x82a\x01\xE5V[V[`@Q\x90a\x02\xC1\x82a\x02\x01V[`@Q\x90`\xA0\x82\x01\x82\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@RV[`@\x90`C\x19\x01\x12a\x03\x17W`@Q\x90a\x03\x08\x82a\x01\xC5V[`D5\x82R`d5` \x83\x01RV[`\0\x80\xFD[`@\x90`\x83\x19\x01\x12a\x03\x17W`@Q\x90a\x035\x82a\x01\xC5V[`\x845\x82R`\xA45` \x83\x01RV[`@\x90`\xC3\x19\x01\x12a\x03\x17W`@Q\x90a\x03]\x82a\x01\xC5V[`\xC45\x82R`\xE45` \x83\x01RV[`@\x90a\x01\x03\x19\x01\x12a\x03\x17W`@Q\x90a\x03\x86\x82a\x01\xC5V[a\x01\x045\x82Ra\x01$5` \x83\x01RV[`@\x90a\x01C\x19\x01\x12a\x03\x17W`@Q\x90a\x03\xB1\x82a\x01\xC5V[a\x01D5\x82Ra\x01d5` \x83\x01RV[`@\x90a\x01\x83\x19\x01\x12a\x03\x17W`@Q\x90a\x03\xDC\x82a\x01\xC5V[a\x01\x845\x82Ra\x01\xA45` \x83\x01RV[`@\x90a\x01\xC3\x19\x01\x12a\x03\x17W`@Q\x90a\x04\x07\x82a\x01\xC5V[a\x01\xC45\x82Ra\x01\xE45` \x83\x01RV[`@\x90a\x02\x03\x19\x01\x12a\x03\x17W`@Q\x90a\x042\x82a\x01\xC5V[a\x02\x045\x82Ra\x02$5` \x83\x01RV[`@\x90a\x02C\x19\x01\x12a\x03\x17W`@Q\x90a\x04]\x82a\x01\xC5V[a\x02D5\x82Ra\x02d5` \x83\x01RV[`@\x90a\x02\x83\x19\x01\x12a\x03\x17W`@Q\x90a\x04\x88\x82a\x01\xC5V[a\x02\x845\x82Ra\x02\xA45` \x83\x01RV[`@\x90a\x02\xC3\x19\x01\x12a\x03\x17W`@Q\x90a\x04\xB3\x82a\x01\xC5V[a\x02\xC45\x82Ra\x02\xE45` \x83\x01RV[`@\x90a\x03\x03\x19\x01\x12a\x03\x17W`@Q\x90a\x04\xDE\x82a\x01\xC5V[a\x03\x045\x82Ra\x03$5` \x83\x01RV[`@\x90a\x03C\x19\x01\x12a\x03\x17W`@Q\x90a\x05\t\x82a\x01\xC5V[a\x03D5\x82Ra\x03d5` \x83\x01RV[`@\x90a\x03\x83\x19\x01\x12a\x03\x17W`@Q\x90a\x054\x82a\x01\xC5V[a\x03\x845\x82Ra\x03\xA45` \x83\x01RV[`@\x90a\x03\xC3\x19\x01\x12a\x03\x17W`@Q\x90a\x05_\x82a\x01\xC5V[a\x03\xC45\x82Ra\x03\xE45` \x83\x01RV[`@\x90a\x04\x03\x19\x01\x12a\x03\x17W`@Q\x90a\x05\x8A\x82a\x01\xC5V[a\x04\x045\x82Ra\x04$5` \x83\x01RV[`@\x90a\x04C\x19\x01\x12a\x03\x17W`@Q\x90a\x05\xB5\x82a\x01\xC5V[a\x04D5\x82Ra\x04d5` \x83\x01RV[`@\x90a\x04\x83\x19\x01\x12a\x03\x17W`@Q\x90a\x05\xE0\x82a\x01\xC5V[a\x04\x845\x82Ra\x04\xA45` \x83\x01RV[`@\x90a\x04\xE3\x19\x01\x12a\x03\x17W`@Q\x90a\x06\x0B\x82a\x01\xC5V[a\x04\xE45\x82Ra\x05\x045` \x83\x01RV[`@\x90a\x05#\x19\x01\x12a\x03\x17W`@Q\x90a\x066\x82a\x01\xC5V[a\x05$5\x82Ra\x05D5` \x83\x01RV[`@\x90a\x05c\x19\x01\x12a\x03\x17W`@Q\x90a\x06a\x82a\x01\xC5V[a\x05d5\x82Ra\x05\x845` \x83\x01RV[`@\x90a\x05\xA3\x19\x01\x12a\x03\x17W`@Q\x90a\x06\x8C\x82a\x01\xC5V[a\x05\xA45\x82Ra\x05\xC45` \x83\x01RV[`@\x90a\x05\xE3\x19\x01\x12a\x03\x17W`@Q\x90a\x06\xB7\x82a\x01\xC5V[a\x05\xE45\x82Ra\x06\x045` \x83\x01RV[`@\x90a\x06#\x19\x01\x12a\x03\x17W`@Q\x90a\x06\xE2\x82a\x01\xC5V[a\x06$5\x82Ra\x06D5` \x83\x01RV[`@\x90a\x06c\x19\x01\x12a\x03\x17W`@Q\x90a\x07\r\x82a\x01\xC5V[a\x06d5\x82Ra\x06\x845` \x83\x01RV[`@\x90a\x06\xA3\x19\x01\x12a\x03\x17W`@Q\x90a\x078\x82a\x01\xC5V[a\x06\xA45\x82Ra\x06\xC45` \x83\x01RV[`@\x90a\x06\xE3\x19\x01\x12a\x03\x17W`@Q\x90a\x07c\x82a\x01\xC5V[a\x06\xE45\x82Ra\x07\x045` \x83\x01RV[`@\x90a\x07#\x19\x01\x12a\x03\x17W`@Q\x90a\x07\x8E\x82a\x01\xC5V[a\x07$5\x82Ra\x07D5` \x83\x01RV[`@\x90a\x07c\x19\x01\x12a\x03\x17W`@Q\x90a\x07\xB9\x82a\x01\xC5V[a\x07d5\x82Ra\x07\x845` \x83\x01RV[`@\x90a\x07\xA3\x19\x01\x12a\x03\x17W`@Q\x90a\x07\xE4\x82a\x01\xC5V[a\x07\xA45\x82Ra\x07\xC45` \x83\x01RV[`@\x90a\x07\xE3\x19\x01\x12a\x03\x17W`@Q\x90a\x08\x0F\x82a\x01\xC5V[a\x07\xE45\x82Ra\x08\x045` \x83\x01RV[`\x01`\x01`@\x1B\x03\x81\x11a\x01\xE0W`\x05\x1B` \x01\x90V[\x90\x80`\x1F\x83\x01\x12\x15a\x03\x17W` \x90\x825a\x08Q\x81a\x08 V[\x93a\x08_`@Q\x95\x86a\x02SV[\x81\x85R` \x80\x86\x01\x92`\x05\x1B\x82\x01\x01\x92\x83\x11a\x03\x17W` \x01\x90[\x82\x82\x10a\x08\x88WPPPP\x90V[\x815\x81R\x90\x83\x01\x90\x83\x01a\x08zV[\x90a\x04\x80a\x04\xE3\x19\x83\x01\x12a\x03\x17Wa\t`a\x08\xB1a\x02\x94V[\x92a\x08\xBB\x81a\x05\xF1V[\x84Ra\x08\xC6\x81a\x06\x1CV[` \x85\x01Ra\x08\xD4\x81a\x06GV[`@\x85\x01Ra\x08\xE2\x81a\x06rV[``\x85\x01Ra\x08\xF0\x81a\x06\x9DV[`\x80\x85\x01Ra\x08\xFE\x81a\x06\xC8V[`\xA0\x85\x01Ra\t\x0C\x81a\x06\xF3V[`\xC0\x85\x01Ra\t\x1A\x81a\x07\x1EV[`\xE0\x85\x01Ra\t(\x81a\x07IV[a\x01\0\x85\x01Ra\t7\x81a\x07tV[a\x01 \x85\x01Ra\tF\x81a\x07\x9FV[a\x01@\x85\x01Ra\tU\x81a\x07\xCAV[a\x01`\x85\x01Ra\x07\xF5V[a\x01\x80\x83\x01Ra\x08$5a\x01\xA0\x83\x01Ra\x08D5a\x01\xC0\x83\x01Ra\x08d5a\x01\xE0\x83\x01Ra\x08\x845a\x02\0\x83\x01Ra\x08\xA45a\x02 \x83\x01Ra\x08\xC45a\x02@\x83\x01Ra\x08\xE45a\x02`\x83\x01Ra\t\x045a\x02\x80\x83\x01Ra\t$5a\x02\xA0\x83\x01Ra\tD5a\x02\xC0\x83\x01RV[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[\x80Q\x15a\t\xEFW` \x01\x90V[a\t\xCCV[\x80Q`\x01\x10\x15a\t\xEFW`@\x01\x90V[\x80Q`\x02\x10\x15a\t\xEFW``\x01\x90V[\x80Q`\x03\x10\x15a\t\xEFW`\x80\x01\x90V[\x80Q`\x04\x10\x15a\t\xEFW`\xA0\x01\x90V[\x80Q`\x05\x10\x15a\t\xEFW`\xC0\x01\x90V[\x80Q`\x06\x10\x15a\t\xEFW`\xE0\x01\x90V[\x80Q`\x07\x10\x15a\t\xEFWa\x01\0\x01\x90V[\x80Q`\x14\x10\x15a\t\xEFWa\x02\xA0\x01\x90V[\x80Q`\x15\x10\x15a\t\xEFWa\x02\xC0\x01\x90V[\x80Q`\x16\x10\x15a\t\xEFWa\x02\xE0\x01\x90V[\x80Q`\x17\x10\x15a\t\xEFWa\x03\0\x01\x90V[\x80Q`\x18\x10\x15a\t\xEFWa\x03 \x01\x90V[\x80Q`\x19\x10\x15a\t\xEFWa\x03@\x01\x90V[\x80Q`\x1A\x10\x15a\t\xEFWa\x03`\x01\x90V[\x80Q`\x1B\x10\x15a\t\xEFWa\x03\x80\x01\x90V[\x80Q`\x1C\x10\x15a\t\xEFWa\x03\xA0\x01\x90V[\x80Q`\x1D\x10\x15a\t\xEFWa\x03\xC0\x01\x90V[\x80Q`\x08\x10\x15a\t\xEFWa\x01 \x01\x90V[\x80Q`\t\x10\x15a\t\xEFWa\x01@\x01\x90V[\x80Q`\n\x10\x15a\t\xEFWa\x01`\x01\x90V[\x80Q`\x0B\x10\x15a\t\xEFWa\x01\x80\x01\x90V[\x80Q`\x0C\x10\x15a\t\xEFWa\x01\xA0\x01\x90V[\x80Q`\r\x10\x15a\t\xEFWa\x01\xC0\x01\x90V[\x80Q`\x0E\x10\x15a\t\xEFWa\x01\xE0\x01\x90V[\x80Q`\x0F\x10\x15a\t\xEFWa\x02\0\x01\x90V[\x80Q`\x10\x10\x15a\t\xEFWa\x02 \x01\x90V[\x80Q`\x11\x10\x15a\t\xEFWa\x02@\x01\x90V[\x80Q`\x12\x10\x15a\t\xEFWa\x02`\x01\x90V[\x80Q`\x13\x10\x15a\t\xEFWa\x02\x80\x01\x90V[\x80Q\x82\x10\x15a\t\xEFW` \x91`\x05\x1B\x01\x01\x90V[\x91a\r\x9A\x91a\r\x9F\x93a\x0C\x02\x83Qa\x13\x13V[a\x0C\x0F` \x84\x01Qa\x13\x13V[a\x0C\x1C`@\x84\x01Qa\x13\x13V[a\x0C)``\x84\x01Qa\x13\x13V[a\x0C6`\x80\x84\x01Qa\x13\x13V[a\x0CC`\xA0\x84\x01Qa\x13\x13V[a\x0CP`\xC0\x84\x01Qa\x13\x13V[a\x0C]`\xE0\x84\x01Qa\x13\x13V[a\x0Cka\x01\0\x84\x01Qa\x13\x13V[a\x0Cya\x01 \x84\x01Qa\x13\x13V[a\x0C\x87a\x01@\x84\x01Qa\x13\x13V[a\x0C\x95a\x01`\x84\x01Qa\x13\x13V[a\x0C\xA3a\x01\x80\x84\x01Qa\x13\x13V[a\x0C\xB1a\x01\xA0\x84\x01Qa\r\xA2V[a\x0C\xBFa\x01\xC0\x84\x01Qa\r\xA2V[a\x0C\xCDa\x01\xE0\x84\x01Qa\r\xA2V[a\x0C\xDBa\x02\0\x84\x01Qa\r\xA2V[a\x0C\xE9a\x02 \x84\x01Qa\r\xA2V[a\x0C\xF7a\x02@\x84\x01Qa\r\xA2V[a\r\x05a\x02`\x84\x01Qa\r\xA2V[a\r\x13a\x02\x80\x84\x01Qa\r\xA2V[a\r!a\x02\xA0\x84\x01Qa\r\xA2V[a\r/a\x02\xC0\x84\x01Qa\r\xA2V[a\rAa\r;\x83a\t\xE2V[Qa\r\xA2V[a\rMa\r;\x83a\t\xF4V[a\rYa\r;\x83a\n\x04V[a\rea\r;\x83a\n\x14V[a\rqa\r;\x83a\n$V[a\r}a\r;\x83a\n4V[a\r\x89a\r;\x83a\nDV[a\r\x95a\r;\x83a\nTV[a\x0FzV[a\x10\x98V[\x90V[`\0\x80Q` a5\xDF\x839\x81Q\x91R\x11\x15a\r\xB9WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x90\xFD[`@Q\x90a\x0E\x0B\x82a\x01\xC5V[`\0` \x83\x82\x81R\x01RV[`@Q\x90a\x0E$\x82a\x01\xE5V[\x81`\0\x81R`\0` \x82\x01R`\0`@\x82\x01R`\0``\x82\x01R```\x80\x82\x01R```\xA0\x82\x01Ra\x0ETa\r\xFEV[`\xC0\x82\x01R`\xE0a\x0Eca\r\xFEV[\x91\x01RV[`@Q\x90a\x0Eu\x82a\x02\x1CV[`\x1E\x82Ra\x03\xC06` \x84\x017V[\x90a\x0E\x8E\x82a\x08 V[a\x0E\x9B`@Q\x91\x82a\x02SV[\x82\x81R\x80\x92a\x0E\xAC`\x1F\x19\x91a\x08 V[\x01\x90` 6\x91\x017V[`@Q\x90a\x0E\xC3\x82a\x02\x1CV[`\x1E\x82R\x81`\0[a\x03\xC0\x81\x10a\x0E\xD8WPPV[` \x90a\x0E\xE3a\r\xFEV[\x82\x82\x85\x01\x01R\x01a\x0E\xCBV[`@\x90`@Q\x91a\x0E\xFF\x83a\x028V[`\x02\x83R\x82`\0[\x82\x81\x10a\x0F\x13WPPPV[` \x90a\x0F\x1Ea\r\xFEV[\x82\x82\x85\x01\x01R\x01a\x0F\x07V[\x90a\x0F4\x82a\x08 V[a\x0FA`@Q\x91\x82a\x02SV[\x82\x81R\x80\x92a\x0FR`\x1F\x19\x91a\x08 V[\x01\x90`\0[\x82\x81\x10a\x0FcWPPPV[` \x90a\x0Fna\r\xFEV[\x82\x82\x85\x01\x01R\x01a\x0FWV[\x90\x91a\x0F\x84a\x0E\x17V[P\x82Q` \x83\x01Q\x03a\x104Wa\x0F\x9C\x81\x84\x84a\x15\x0FV[\x92a\x0F\xA7\x83Qa\x17\xF4V[\x92a\x0F\xB8`\xA0\x86\x01\x92\x83Q\x86a\x1BrV[\x91`\xE0`\0\x80Q` a5\xDF\x839\x81Q\x91R``a\x0F\xEBa\x0F\xD7a\x0EhV[\x95\x86\x8B\x8Aa\x0F\xE3a\x0E\xB6V[\x9A\x8B\x94a\x1C9V[\x93Q\x97\x01Q\x87\t\x96\x01Q\x95a\x01\x80a\x01`\x86\x01Q\x95\x01Q\x95a\x10\x0Ba\x02\xB4V[\x97\x88R` \x88\x01R`@\x87\x01R``\x86\x01R`\x80\x85\x01R`\xA0\x84\x01R`\xC0\x83\x01R`\xE0\x82\x01R\x90V[`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x90\xFD[`@Q\x90a\x10S\x82a\x028V[`\x02\x82R`@6` \x84\x017V[cNH{q`\xE0\x1B`\0R`\x11`\x04R`$`\0\xFD[`\x02\x01\x90\x81`\x02\x11a\x10\x85WV[a\x10aV[\x90`\x01\x82\x01\x80\x92\x11a\x10\x85WV[a\x10\xA0a\r\xFEV[Pa\x10\xA9a\r\xFEV[Pa\x10\xB2a\x10FV[a\x10\xBAa\x0E\xEFV[\x91`\x01\x90`\x01a\x10\xC9\x84a\t\xE2V[Ra\x11\x14`\xC0\x82\x01\x93\x84Qa\x10\xDD\x87a\t\xE2V[Ra\x10\xE7\x86a\t\xE2V[P\x82Qa\x10\xF3\x82a\t\xF4V[R`\xE0\x83\x01\x95\x86Qa\x11\x04\x82a\t\xF4V[Ra\x11\x0E\x81a\t\xF4V[Pa\x1D\tV[\x93`\x80\x82\x01a\x11,a\x11'\x82QQa\x10wV[a\x10\x8AV[\x94a\x11?a\x119\x87a\x0E\x84V[\x96a\x0F*V[\x94\x80`\0\x93\x84\x92[a\x12\xB4W[PPP\x83a\x11\xE0a\r\x9F\x98\x97\x94``a\x11\xD5a\x11\x99a\x12\t\x9A\x97a\x11\x0E\x97` a\x12\x04\x9C\x01Qa\x11|\x83\x8Da\x0B\xDBV[RQa\x11\x88\x82\x8Ba\x0B\xDBV[Ra\x11\x93\x81\x8Aa\x0B\xDBV[Pa\x10\x8AV[\x85Q\x93`\0\x80Q` a5\xDF\x839\x81Q\x91R\x80\x95`@\x89\x01Q\x90\ta\x11\xBE\x83\x8Ca\x0B\xDBV[RQa\x11\xCA\x82\x8Aa\x0B\xDBV[Ra\x11\x93\x81\x89a\x0B\xDBV[\x93\x01Q`\0\x08a\x1D\xEEV[a\x11\xEA\x82\x86a\x0B\xDBV[Ra\x11\xF3a\x1E\x0CV[a\x11\xFD\x82\x85a\x0B\xDBV[R\x82a\x0B\xDBV[a\x1E/V[a\x12\x11a\x02\xC3V[\x7F\x01\x18\xC4\xD5\xB87\xBC\xC2\xBC\x89\xB5\xB3\x98\xB5\x97N\x9FYD\x07;2\x07\x8B~#\x1F\xEC\x93\x88\x83\xB0\x81R\x7F&\x0E\x01\xB2Q\xF6\xF1\xC7\xE7\xFFNX\x07\x91\xDE\xE8\xEAQ\xD8z5\x8E\x03\x8BN\xFE0\xFA\xC0\x93\x83\xC1` \x82\x01R\x7F\"\xFE\xBD\xA3\xC0\xC0c*VG[B\x14\xE5a^\x11\xE6\xDD?\x96\xE6\xCE\xA2\x85J\x87\xD4\xDA\xCC^U`@\x82\x01R\x7F\x04\xFCci\xF7\x11\x0F\xE3\xD2QV\xC1\xBB\x9Ar\x85\x9C\xF2\xA0FA\xF9\x9B\xA4\xEEA<\x80\xDAj_\xE4``\x82\x01Ra\x12\xAEa\x1E\x93V[\x92a\x1F\xA4V[\x90\x91\x93\x81Q\x80Q\x86\x10\x15a\x13\x0CWa\x13\x04\x82\x8Ba\x12\xDF\x87\x96\x95a\x12\xD8\x8B\x89\x97a\x0B\xDBV[Q\x92a\x0B\xDBV[Ra\x12\xEE\x88`\xA0\x8C\x01Qa\x0B\xDBV[Qa\x12\xF9\x82\x8Da\x0B\xDBV[Ra\x11\x93\x81\x8Ca\x0B\xDBV[\x95\x01\x92a\x11GV[P\x93a\x11LV[\x80Q` \x82\x01Q\x15\x90\x15\x16a\x13\xAEW` \x81Q\x91\x01Q\x90\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG\x80\x80`\x03\x81\x80\x86\x80\t\x86\t\x08\x81\x85\x80\t\x14\x93\x10\x91\x10\x16\x16\x15a\x13iWV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7FBn254: invalid G1 point\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x90\xFD[PV[`@Q\x90a\x13\xBE\x82a\x01\xE5V[\x81`\xE0`\0\x91\x82\x81R\x82` \x82\x01R\x82`@\x82\x01R\x82``\x82\x01R\x82`\x80\x82\x01R\x82`\xA0\x82\x01R\x82`\xC0\x82\x01R\x01RV[`@Q\x90a\x13\xFC\x82a\x01\xC5V[`\0` \x83``\x81R\x01RV[\x90\x81Q\x91`\0[\x83\x81\x10a\x14!WPP\x01`\0\x81R\x90V[\x80` \x80\x92\x84\x01\x01Q\x81\x85\x01R\x01a\x14\x10V[a\x14@\x90`\xA0\x92a\x14\tV[`\x01`\xF8\x1B\x81R\x7FJ\x1D0\xB1{\xFB\xA4]\x83\x85?\x81\x94l\xCAsL@\x10\xE1D*\xE1\xC4B\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01`@\x82\x01R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0``\x82\x01R\x7F'$q6\x03\xBF\xBDy\n\xEA\xF3\xE7\xDF%\xD8\xE7\xEF\x8F1\x134\x90[M\x8C\x99\x98\x0C\xF2\x10\x97\x9D`\x80\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x90\xFD[a\x1A\xF3a\x02\xD0V[\x90`\x14\x82R` \x82\x01R\x7F0dKl\x9CJr\x16\x9EM\xAA1}%\xF0E\x12\xAE\x15\xC5;4\xE8\xF5\xAC\xD8\xE1U\xD0\xA6\xC1\x01`@\x82\x01R\x7F&\x12]\xA1\n\x0E\xD0c'P\x8A\xBA\x06\xD1\xE3\x03\xACaf2\xDB\xED4\x9FSB-\xA9S3xW``\x82\x01R\x7F\x10\x0C3-!\0\x89_\xABds\xBC,Q\xBF\xCAR\x1FE\xCB;\xAC\xA6&\x08R\xA8\xFD\xE2l\x91\xF3`\x80\x82\x01R\x90V[\x91\x92\x90\x92`@Q\x92``\x84\x01\x84\x81\x10`\x01`\x01`@\x1B\x03\x82\x11\x17a\x01\xE0W`@R`\0\x84R` \x84\x01\x94`\0\x86R`@\x85\x01\x92`\0\x84R\x85\x83Q\x97\x83`\0\x14a\x1C\x08W\x83\x98`\0\x90[\x80\x82\x10a\x1B\xEAWPPa\x1B\xDDa\x1B\xE6\x96\x97\x98\x99`\0\x19\x01[\x80\x84R\x85\x87a&?V[\x90RQ\x92a&\xA8V[\x90RV[\x90\x99`\0\x80Q` a5\xDF\x839\x81Q\x91R\x81`\x01\x92\t\x9A\x01\x90a\x1B\xBBV[a\x1B\xE6\x95\x96\x97\x98Pa\x1B\xDD\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a\x1B\xD3V[\x90a\r\x9F\x95\x93\x92\x93` \x82\x01Qa\x1C\xFF`@\x84\x01Q\x92\x88\x88``\x89\x01Q\x96`\x80\x8A\x01Q\x99\x82a\x01\xA0\x81\x01Q\x9B\x80`\0\x80Q` a5\xDF\x839\x81Q\x91R\x80\x9E\x81\x9D\x82\x86\x85\x82\x80\x80\x80\x80\x80\x9D\x99\x81\x9D\x82a\x02@\x81\x9D\x01Q\x8C\t\x91\x01\x08`\x01\t\x81a\x01\xC0\x87\x01Q\x86\x82a\x02`\x8A\x01Q\x8C\t\x91\x01\x08\x90\t\x81a\x01\xE0\x86\x01Q\x85\x82a\x02\x80\x89\x01Q\x8B\t\x91\x01\x08\x90\t\x94a\x02\xA0a\x02\0\x85\x01Q\x94\x01Q\x90\t\x91\x01\x08\x90\t\x91\x81a\x02 \x89\x01Q\x91a\x02\xC0\x8A\x01Q\x92\x08\t\x90\t\x98\x81\x83Q\x99` \x85\x01Q\t\x82\x03\x90\x08\x99a'\xD9V[\t\x82\x03\x90\x08a)\xE6V[\x91\x90a\x1D\x13a\r\xFEV[P\x80Q\x83Q\x03a\x1D\x8EWa\x1D:a\x1D)\x84a\t\xE2V[Qa\x1D3\x83a\t\xE2V[Q\x90a*:V[\x92`\x01\x91\x82\x91\x82[a\x1DMW[PPPPV[\x90\x91\x92\x94\x82Q\x86\x10\x15a\x1D\x88W\x90\x83a\x1D\x80\x81\x94\x93a\x1Dza\x1Do\x8A\x86a\x0B\xDBV[Qa\x1D3\x8B\x88a\x0B\xDBV[\x90a*\x7FV[\x96\x01\x93a\x1DBV[\x94a\x1DGV[`d`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R` `$\x82\x01R\x7FMSM error: length does not match`D\x82\x01R\xFD[\x90`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\x82\x03\x91\x82\x11a\x10\x85WV[`\0\x80Q` a5\xDF\x839\x81Q\x91R\x80\x91\x06\x81\x03\x90\x81\x11a\x10\x85W\x90V[a\x1E\x14a\r\xFEV[P`@Qa\x1E!\x81a\x01\xC5V[`\x01\x81R`\x02` \x82\x01R\x90V[a\x1E7a\r\xFEV[P\x80Q` \x82\x01Q\x15\x90\x15\x16a\r\x9FW` \x81Q\x91\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG\x91\x82\x91\x01Q\x06\x81\x03\x90\x81\x11a\x10\x85W`@Q\x91a\x1E\x89\x83a\x01\xC5V[\x82R` \x82\x01R\x90V[`\0```@Qa\x1E\xA3\x81a\x02\x01V[\x82\x81R\x82` \x82\x01R\x82`@\x82\x01R\x01R`@Qa\x1E\xC0\x81a\x02\x01V[\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2` \x82\x01R\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA`@\x82\x01R\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[``\x82\x01R\x90V[\x15a\x1F_WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x90\xFD[\x91`@a\x01\x80\x92\x94`\0\x94\x82Q\x93\x81Q\x85R\x83` \x98\x89\x80\x94\x01Q\x84\x88\x01R\x83\x81\x01Q\x82\x88\x01R\x80Q``\x88\x01R``\x81\x01Q`\x80\x88\x01R\x01Q`\xA0\x86\x01R\x80Q`\xC0\x86\x01R\x01Q`\xE0\x84\x01R\x85\x81\x01Qa\x01\0\x84\x01R\x80Qa\x01 \x84\x01R``\x81\x01Qa\x01@\x84\x01R\x01Qa\x01`\x82\x01R`\x08Z\xFAa &`\0Q\x91a\x1FXV[\x15\x15\x90V[a A\x90a\x01\0\x9A\x98\x96\x94\x92\x99\x97\x95\x93\x99a\x14\tV[\x97\x88R` \x88\x01R`@\x87\x01R``\x86\x01R`\x80\x85\x01R`\xA0\x84\x01R`\xC0\x83\x01R`\xE0\x82\x01R\x01\x90V[\x90\x81Q`@\x91\x82Q\x92` \x92\x84\x84\x81\x01a \x8D\x90` \x90`\x7F`\xF9\x1B\x81R\x01\x90V[\x03\x94`\x1F\x19\x95\x86\x81\x01\x82Ra \xA2\x90\x82a\x02SV[a \xAB\x90a+\rV[\x90\x83Qa \xB7\x90a%,V[\x83Q\x86\x81\x01\x91\x82R\x90\x81\x90` \x01\x03\x87\x81\x01\x82Ra \xD5\x90\x82a\x02SV[a \xDE\x90a+XV[\x85\x85\x01Qa \xEB\x90a%,V[\x84Q\x87\x81\x01\x91\x82R\x90\x81\x90` \x01\x03\x88\x81\x01\x82Ra!\t\x90\x82a\x02SV[a!\x12\x90a+XV[\x90\x84Q\x93\x84\x93\x88\x85\x01a!$\x91a\x14\tV[a!-\x91a\x14\tV[a!6\x91a\x14\tV[a!?\x91a\x14\tV[\x03\x85\x81\x01\x82Ra!O\x90\x82a\x02SV[\x80\x86R\x81Q\x80\x91\x85\x82\x01\x90a!c\x91a\x144V[\x03\x85\x81\x01\x82Ra!s\x90\x82a\x02SV[\x80\x86R`\xE0\x83\x01Qa!\x84\x90a$UV[\x90a\x01\0\x84\x01Qa!\x94\x90a$UV[a\x01 \x85\x01Qa!\xA3\x90a$UV[a\x01@\x86\x01Qa!\xB2\x90a$UV[a\x01`\x87\x01Qa!\xC1\x90a$UV[\x90a\x01\x80\x88\x01Qa!\xD1\x90a$UV[\x92a\x01\xE0\x89\x01Qa!\xE1\x90a$UV[\x94\x88Q\x97\x88\x97\x8C\x89\x01a!\xF3\x91a\x14\tV[a!\xFC\x91a\x14\tV[a\"\x05\x91a\x14\tV[a\"\x0E\x91a\x14\tV[a\"\x17\x91a\x14\tV[a\" \x91a\x14\tV[a\")\x91a\x14\tV[a\"2\x91a\x14\tV[\x03\x85\x81\x01\x82Ra\"B\x90\x82a\x02SV[\x80\x86Ra\x02\0\x83\x01Qa\"T\x90a$UV[\x90a\x02 \x84\x01Qa\"d\x90a$UV[a\x02@\x85\x01Qa\"s\x90a$UV[a\x01\xA0\x86\x01Qa\"\x82\x90a$UV[a\x01\xC0\x87\x01Qa\"\x91\x90a$UV[\x91a\x02`\x88\x01Qa\"\xA1\x90a$UV[\x93\x87Q\x96\x87\x96\x8B\x88\x01a\"\xB3\x91a\x14\tV[a\"\xBC\x91a\x14\tV[a\"\xC5\x91a\x14\tV[a\"\xCE\x91a\x14\tV[a\"\xD7\x91a\x14\tV[a\"\xE0\x91a\x14\tV[a\"\xE9\x91a\x14\tV[\x03\x85\x81\x01\x82Ra\"\xF9\x90\x82a\x02SV[\x80\x86R\x81\x83\x01Qa#\t\x90a$UV[\x92``\x81\x01Qa#\x18\x90a$UV[\x90`\x80\x81\x01Qa#'\x90a$UV[`\xA0\x82\x01Qa#5\x90a$UV[\x91`\xC0\x01Qa#C\x90a$UV[\x92\x85Q\x96\x87\x95\x89\x87\x01a#U\x91a\x14\tV[a#^\x91a\x14\tV[a#g\x91a\x14\tV[a#p\x91a\x14\tV[a#y\x91a\x14\tV[a#\x82\x91a\x14\tV[\x03\x84\x81\x01\x83Ra#\x92\x90\x83a\x02SV[\x81\x85Ra#\x9E\x86a\t\xE2V[Qa#\xA8\x90a%,V[\x95a#\xB2\x81a\t\xF4V[Qa#\xBC\x90a%,V[a#\xC5\x82a\n\x04V[Qa#\xCF\x90a%,V[a#\xD8\x83a\n\x14V[Qa#\xE2\x90a%,V[a#\xEB\x84a\n$V[Qa#\xF5\x90a%,V[\x91a#\xFF\x85a\n4V[Qa$\t\x90a%,V[\x93a$\x13\x86a\nDV[Qa$\x1D\x90a%,V[\x95a$'\x90a\nTV[Qa$1\x90a%,V[\x96Q\x9B\x8C\x99\x8A\x01\x98a$B\x99a +V[\x03\x90\x81\x01\x83Ra$R\x90\x83a\x02SV[RV[a$\xAA\x90`\0\x90a$n\x81` \x81Q\x91\x01Q\x15\x90\x15\x16\x90V[a$\xCCW[\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG` \x82\x01Q`\x01\x1B\x10\x15a$\xC0W[Q\x17a%,V[`@Q\x90` \x82\x01R` \x81Ra\r\x9F\x81a\x01\xC5V[`\x01`\xFF\x1B\x91Pa$\xA3V[`\x01`\xFE\x1B\x91Pa$sV[\x90` \x91` \x81\x01\x90\x81Q\x90Q\x93\x84Q\x90`@Q\x92\x83R`\0[\x82\x81\x10a%\x19WPP`\0\x80Q` a5\xDF\x839\x81Q\x91R\x93\x94P` \x01\x90 \x80\x91R\x06\x90V[\x86\x81\x01\x82\x01Q\x84\x82\x01\x83\x01R\x81\x01a$\xF2V[\x80`\x08\x1C\x90`\x08\x1B\x90~\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\x7F\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0}\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\x84\x16|\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\0\0\0\xFF\x84\x16\x17`\x10\x1B\x93\x16\x91\x16\x17`\x10\x1C\x17{\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\x7F\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\0\0\0\0\xFF\xFF\xFF\xFF\0\0\0\0\x82` \x1B\x16\x91` \x1C\x16\x17w\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\0\0\0\0\0\0\0\0\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x80\x19\x82`@\x1B\x16\x91`@\x1C\x16\x17\x80`\x80\x1B\x90`\x80\x1C\x17\x90V[\x82\x15a&\xA0W`@\x01Q`\0\x80Q` a5\xDF\x839\x81Q\x91R\x92\x83\x91\x90\t\x90\x80\x15a&vWa&q\x90`\0\x19\x01a+\xA3V[\x90\t\x90V[Pa&q\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a+\xA3V[PPP`\0\x90V[\x90\x93\x92`\0\x94`\0\x90\x82\x15a'\xD1W\x91\x90\x82\x94\x93\x94Q\x92a&\xCE\x84`@\x88\x01Q\x97a,SV[a&\xD7\x85a\x0E\x84V[\x96`\0\x80Q` a5\xDF\x839\x81Q\x91R\x94\x85\x91\t\x91`\x01\x96`\x01\x90\x85[\x88\x81\x10a'\x9BWPPa'\x06\x90a+\xA3V[\x95\x84\x98[\x81\x8A\x10a'\x1DWPPPPPPPPPPV[\x90\x91\x92\x93\x94\x95\x96\x97\x87\x8A\x9C\x8B\x82\x8C\x85\x9E`\x05\x1B\x91\x82\x91\x81\x8D\x8D` \x96\x87\x91\x01\x01Q\x90\t\t\x92\x8C\x90[\x89\x82\x10a'gWPP\x88\x01\x01Q\x83\x91\t\x90\x08\x9B\x01\x98\x97\x96\x95\x94\x93\x92\x91\x90a'\nV[\x90\x80\x92\x94\x96\x91\x97\x93\x95\x97\x03a'\x87W[P\x01\x91\x8F\x91\x8E\x95\x93\x8D\x95\x93a'EV[\x90\x94\x84\x86`\x05\x1B\x89\x01\x01Q\x90\t\x93\x8Ca'wV[\x98\x89\x81\x9B\x9A`\x05\x9A\x95\x96\x97\x98\x99\x9A\x1B\x93` \x8B\x80\x86\x83\x89\x8D\x01\x01Q\x82\x03\x08\x80\x93\t\x95\x8D\x01\x01R\x01\x99\x98\x99\x97\x96\x95\x94\x93\x92\x97a&\xF4V[P\x94PPPPV[\x90\x91\x84\x86\x85a'\xEC\x93\x97\x96\x97\x86\x86a,\xD6V[`\xC0\x82\x01Q\x80a'\xFB\x85a\neV[R\x84Qa(\x07\x87a\neV[Ra(\x11\x86a\neV[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x81\x80\t\x80a(.\x86a\nvV[R` \x86\x01Qa(=\x88a\nvV[R\x81a(H\x88a\nvV[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x80a(d\x86a\n\x87V[R`@\x86\x01Qa(s\x88a\n\x87V[R\x81a(~\x88a\n\x87V[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x80a(\x9A\x86a\n\x98V[R``\x86\x01Qa(\xA9\x88a\n\x98V[R\x81a(\xB4\x88a\n\x98V[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x80a(\xD0\x86a\n\xA9V[R`\x80\x86\x01Qa(\xDF\x88a\n\xA9V[R\x81a(\xEA\x88a\n\xA9V[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x80a)\x06\x86a\n\xBAV[R`@\x83\x01Qa)\x15\x88a\n\xBAV[R\x81a) \x88a\n\xBAV[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x80a)<\x86a\n\xCBV[R``\x83\x01Qa)K\x88a\n\xCBV[R\x81a)V\x88a\n\xCBV[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x90\x81a)s\x86a\n\xDCV[R`\x80\x83\x01Qa)\x82\x88a\n\xDCV[Ra)\x8C\x87a\n\xDCV[P`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\ta)\xA7\x84a\n\xEDV[R`\xA0\x01Qa)\xB5\x85a\n\xEDV[Ra)\xBF\x84a\n\xEDV[P`\xE0\x01Q\x90a)\xCE\x90a\n\xFEV[R`\xA0\x01Qa)\xDC\x82a\n\xFEV[Ra\x13\xAE\x90a\n\xFEV[\x92\x91\x90`\0\x80Q` a5\xDF\x839\x81Q\x91R\x93\x84\x03\x93`\0\x92[`\n\x84\x10a*\x0EWPPPPV[\x90\x91\x92\x94\x82`\x01\x91\x81`\x05a\x01\xA0\x8A`\x15\x81\x01\x83\x1B\x88\x01Q\x92\x1B\x89\x01\x01Q\x90\t\x90\x08\x95\x01\x92\x91\x90a*\0V[\x91\x90``\x90`\x80a*Ia\r\xFEV[\x94\x85\x92` `@Q\x92a*[\x84a\x028V[\x866\x857\x80Q\x84R\x01Q` \x83\x01R`@\x82\x01R`\x07a\x07\xCF\x19Z\x01\xFA\x15a\x03\x17WV[` \x92\x91`\xC0``\x92a*\x90a\r\xFEV[\x95\x86\x93\x81`@Q\x93a*\xA1\x85a\x02\x01V[`\x806\x867\x80Q\x85R\x01Q\x82\x84\x01R\x80Q`@\x84\x01R\x01Q\x84\x82\x01R`\x06a\x07\xCF\x19Z\x01\xFA\x15a\x03\x17WV[\x15a*\xD4WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x11`$\x82\x01Rpslice_outOfBounds`x\x1B`D\x82\x01R`d\x90\xFD[a+\x1B`\x04\x82Q\x10\x15a*\xCDV[`@Q\x90`\x04\x80\x83\x01\x91\x01`\x08\x83\x01[\x80\x83\x10a+EWPP`\x04\x82R`\x1F\x01`\x1F\x19\x16`@R\x90V[\x90\x91\x82Q\x81R` \x80\x91\x01\x92\x01\x90a++V[a+f`\x08\x82Q\x10\x15a*\xCDV[`@Q\x90`\x08\x80\x83\x01\x91\x01`\x10\x83\x01[\x80\x83\x10a+\x90WPP`\x08\x82R`\x1F\x01`\x1F\x19\x16`@R\x90V[\x90\x91\x82Q\x81R` \x80\x91\x01\x92\x01\x90a+vV[\x90`@Q\x91`\0`\xC0` \x94\x85\x93\x84\x82R\x84\x80\x83\x01R\x84`@\x83\x01R``\x82\x01R\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xEF\xFF\xFF\xFF`\x80\x82\x01R`\0\x80Q` a5\xDF\x839\x81Q\x91R`\xA0\x82\x01R`\x05Z\xFA\x91`\0Q\x92\x15a,\x0FWPV[`d\x90`@Q\x90bF\x1B\xCD`\xE5\x1B\x82R`\x04\x82\x01R`\x1D`$\x82\x01R\x7FBn254: pow precompile failed!\0\0\0`D\x82\x01R\xFD[\x91\x90\x91` \x90` \x81\x01Q\x84\x11a,\xC4W``\x01Q\x92`\x01\x93a,u\x82a\x0E\x84V[\x94\x82\x15\x19a,\x83WPPPPV[`\x01` \x80\x88\x01\x94`\x05\x1B\x88\x01\x01\x93R`@\x86\x01\x90[\x83\x82\x10a,\xA6WPa\x1DGV[`\0\x80Q` a5\xDF\x839\x81Q\x91R\x83\x86\x92\t\x91\x82\x81R\x01\x90a,\x99V[`@Qc\x8C^\x11\xF1`\xE0\x1B\x81R`\x04\x90\xFD[\x94\x92\x93\x94\x91\x90\x91` \x82\x01Q` \x84\x01Q\x90`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x83Q`\xA0\x85\x01Q``\x86\x01Q\x90`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x90a\x01\xA0\x88\x01Q`\0\x80Q` a5\xDF\x839\x81Q\x91R\x90\x83\x08\x90`\x80\x87\x01Q\x91\x82`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a5\xDF\x839\x81Q\x91R\x91\t\x81a\x01\xC0\x8A\x01Q`\0\x80Q` a5\xDF\x839\x81Q\x91R\x7F/\x8D\xD1\xF1\xA7Xa\x01\xE3V[\x90a\x03\x045\x82Ra\x03$5` \x83\x01RV[`@\x90a\x03C\x19\x01\x12a\x01\xA2Wa\x04ea\x01\xE3V[\x90a\x03D5\x82Ra\x03d5` \x83\x01RV[`@\x90a\x03\x83\x19\x01\x12a\x01\xA2Wa\x04\x8Ca\x01\xE3V[\x90a\x03\x845\x82Ra\x03\xA45` \x83\x01RV[`@\x90a\x03\xC3\x19\x01\x12a\x01\xA2Wa\x04\xB3a\x01\xE3V[\x90a\x03\xC45\x82Ra\x03\xE45` \x83\x01RV[`@\x90a\x04\x03\x19\x01\x12a\x01\xA2Wa\x04\xDAa\x01\xE3V[\x90a\x04\x045\x82Ra\x04$5` \x83\x01RV[`@\x90a\x04C\x19\x01\x12a\x01\xA2Wa\x05\x01a\x01\xE3V[\x90a\x04D5\x82Ra\x04d5` \x83\x01RV[`@\x90a\x04\x83\x19\x01\x12a\x01\xA2Wa\x05(a\x01\xE3V[\x90a\x04\x845\x82Ra\x04\xA45` \x83\x01RV[`@\x90a\x06\x03\x19\x01\x12a\x01\xA2Wa\x05Oa\x01\xE3V[\x90a\x06\x045\x82Ra\x06$5` \x83\x01RV[`@\x90a\x06C\x19\x01\x12a\x01\xA2Wa\x05va\x01\xE3V[\x90a\x06D5\x82Ra\x06d5` \x83\x01RV[`@\x90a\x06\x83\x19\x01\x12a\x01\xA2Wa\x05\x9Da\x01\xE3V[\x90a\x06\x845\x82Ra\x06\xA45` \x83\x01RV[`@\x90a\x06\xC3\x19\x01\x12a\x01\xA2Wa\x05\xC4a\x01\xE3V[\x90a\x06\xC45\x82Ra\x06\xE45` \x83\x01RV[`@\x90a\x07\x03\x19\x01\x12a\x01\xA2Wa\x05\xEBa\x01\xE3V[\x90a\x07\x045\x82Ra\x07$5` \x83\x01RV[`@\x90a\x07C\x19\x01\x12a\x01\xA2Wa\x06\x12a\x01\xE3V[\x90a\x07D5\x82Ra\x07d5` \x83\x01RV[`@\x90a\x07\x83\x19\x01\x12a\x01\xA2Wa\x069a\x01\xE3V[\x90a\x07\x845\x82Ra\x07\xA45` \x83\x01RV[`@\x90a\x07\xC3\x19\x01\x12a\x01\xA2Wa\x06`a\x01\xE3V[\x90a\x07\xC45\x82Ra\x07\xE45` \x83\x01RV[`@\x90a\x08\x03\x19\x01\x12a\x01\xA2Wa\x06\x87a\x01\xE3V[\x90a\x08\x045\x82Ra\x08$5` \x83\x01RV[`@\x90a\x08C\x19\x01\x12a\x01\xA2Wa\x06\xAEa\x01\xE3V[\x90a\x08D5\x82Ra\x08d5` \x83\x01RV[`@\x90a\x08\x83\x19\x01\x12a\x01\xA2Wa\x06\xD5a\x01\xE3V[\x90a\x08\x845\x82Ra\x08\xA45` \x83\x01RV[`@\x90a\x08\xC3\x19\x01\x12a\x01\xA2Wa\x06\xFCa\x01\xE3V[\x90a\x08\xC45\x82Ra\x08\xE45` \x83\x01RV[`@\x90a\t\x03\x19\x01\x12a\x01\xA2Wa\x07#a\x01\xE3V[\x90a\t\x045\x82Ra\t$5` \x83\x01RV[\x80a\x05#\x12\x15a\x01\xA2Wa\x07Ga\x02dV[\x90\x81a\x06\x04\x91\x82\x11a\x01\xA2Wa\x05\x04\x90[\x82\x82\x10a\x07eWPPP\x90V[\x815\x81R` \x91\x82\x01\x91\x01a\x07XV[\x90a\x04\x80a\x06\x03\x19\x83\x01\x12a\x01\xA2Wa\x08>a\x07\x8Fa\x02\x03V[\x92a\x07\x99\x81a\x05:V[\x84Ra\x07\xA4\x81a\x05aV[` \x85\x01Ra\x07\xB2\x81a\x05\x88V[`@\x85\x01Ra\x07\xC0\x81a\x05\xAFV[``\x85\x01Ra\x07\xCE\x81a\x05\xD6V[`\x80\x85\x01Ra\x07\xDC\x81a\x05\xFDV[`\xA0\x85\x01Ra\x07\xEA\x81a\x06$V[`\xC0\x85\x01Ra\x07\xF8\x81a\x06KV[`\xE0\x85\x01Ra\x08\x06\x81a\x06rV[a\x01\0\x85\x01Ra\x08\x15\x81a\x06\x99V[a\x01 \x85\x01Ra\x08$\x81a\x06\xC0V[a\x01@\x85\x01Ra\x083\x81a\x06\xE7V[a\x01`\x85\x01Ra\x07\x0EV[a\x01\x80\x83\x01Ra\tD5a\x01\xA0\x83\x01Ra\td5a\x01\xC0\x83\x01Ra\t\x845a\x01\xE0\x83\x01Ra\t\xA45a\x02\0\x83\x01Ra\t\xC45a\x02 \x83\x01Ra\t\xE45a\x02@\x83\x01Ra\n\x045a\x02`\x83\x01Ra\n$5a\x02\x80\x83\x01Ra\nD5a\x02\xA0\x83\x01Ra\nd5a\x02\xC0\x83\x01RV[\x90`\x08\x81\x10\x15a\x08\xBBW`\x05\x1B\x01\x90V[cNH{q`\xE0\x1B`\0R`2`\x04R`$`\0\xFD[\x90a\nx\x92\x91a\x08\xE1\x83Qa\x0C\x97V[a\x08\xEE` \x84\x01Qa\x0C\x97V[a\x08\xFB`@\x84\x01Qa\x0C\x97V[a\t\x08``\x84\x01Qa\x0C\x97V[a\t\x15`\x80\x84\x01Qa\x0C\x97V[a\t\"`\xA0\x84\x01Qa\x0C\x97V[a\t/`\xC0\x84\x01Qa\x0C\x97V[a\t<`\xE0\x84\x01Qa\x0C\x97V[a\tJa\x01\0\x84\x01Qa\x0C\x97V[a\tXa\x01 \x84\x01Qa\x0C\x97V[a\tfa\x01@\x84\x01Qa\x0C\x97V[a\tta\x01`\x84\x01Qa\x0C\x97V[a\t\x82a\x01\x80\x84\x01Qa\x0C\x97V[a\t\x90a\x01\xA0\x84\x01Qa\n{V[a\t\x9Ea\x01\xC0\x84\x01Qa\n{V[a\t\xACa\x01\xE0\x84\x01Qa\n{V[a\t\xBAa\x02\0\x84\x01Qa\n{V[a\t\xC8a\x02 \x84\x01Qa\n{V[a\t\xD6a\x02@\x84\x01Qa\n{V[a\t\xE4a\x02`\x84\x01Qa\n{V[a\t\xF2a\x02\x80\x84\x01Qa\n{V[a\n\0a\x02\xA0\x84\x01Qa\n{V[a\n\x0Ea\x02\xC0\x84\x01Qa\n{V[a\n\x18\x82Qa\n{V[a\n%` \x83\x01Qa\n{V[a\n2`@\x83\x01Qa\n{V[a\n?``\x83\x01Qa\n{V[a\nL`\x80\x83\x01Qa\n{V[a\nY`\xA0\x83\x01Qa\n{V[a\nf`\xC0\x83\x01Qa\n{V[a\ns`\xE0\x83\x01Qa\n{V[a\n\xEDV[\x90V[`\0\x80Q` a)\x96\x839\x81Q\x91R\x11\x15a\n\x92WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1B`$\x82\x01R\x7FBn254: invalid scalar field\0\0\0\0\0`D\x82\x01R`d\x90\xFD[a\n\xDFa\x01\xE3V[\x90`\0\x82R`\0` \x83\x01RV[`\x08` \x82\x01Q\x03a\x0C\x85Wa\x0B\x04\x83\x83\x83a\r\x85V[\x92\x81Qa\x0B\x10\x90a\x12rV[\x90`\xA0\x85\x01\x93\x84Q\x90a\x0B#\x91\x84a\x16\x9BV[\x92a\x0B,a\n\xD7V[Pa\x0B5a\n\xD7V[Pa\x01`\x82\x01\x90\x81Q\x92a\x01\x80\x81\x01\x95\x86Q\x94`\xE0\x8A\x01\x95\x86Qa\x0BX\x91a\x17NV[a\x0Ba\x91a\x17\x9BV[\x98a\x0Bk\x93a\x18#V[\x90a\x0Bu\x90a\x1B\xF7V[a\x0B~\x91a\x17\x9BV[\x90Q\x85Qa\x0B\x8B\x91a\x17NV[a\x0B\x94\x91a\x17\x9BV[\x93Q\x91`\0\x80Q` a)\x96\x839\x81Q\x91R\x92`@\x84\x92\x01Q` \x01Q\x90\t\x90Q\x90\t\x90Q\x90a\x0B\xC3\x91a\x17NV[a\x0B\xCC\x91a\x17\x9BV[a\x0B\xD4a\x02$V[\x7F\x01\x18\xC4\xD5\xB87\xBC\xC2\xBC\x89\xB5\xB3\x98\xB5\x97N\x9FYD\x07;2\x07\x8B~#\x1F\xEC\x93\x88\x83\xB0\x81R\x7F&\x0E\x01\xB2Q\xF6\xF1\xC7\xE7\xFFNX\x07\x91\xDE\xE8\xEAQ\xD8z5\x8E\x03\x8BN\xFE0\xFA\xC0\x93\x83\xC1` \x82\x01R\x7F\"\xFE\xBD\xA3\xC0\xC0c*VG[B\x14\xE5a^\x11\xE6\xDD?\x96\xE6\xCE\xA2\x85J\x87\xD4\xDA\xCC^U`@\x82\x01R\x7F\x04\xFCci\xF7\x11\x0F\xE3\xD2QV\xC1\xBB\x9Ar\x85\x9C\xF2\xA0FA\xF9\x9B\xA4\xEEA<\x80\xDAj_\xE4``\x82\x01R\x90a\x0Cs\x90a\x1B\xF7V[a\x0C{a\x1C_V[\x91a\nx\x93a\x1DhV[`@Qc \xFA\x9D\x89`\xE1\x1B\x81R`\x04\x90\xFD[\x80Q` \x82\x01Q\x15\x90\x15\x16a\r2W` \x81Q\x91\x01Q\x90\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG\x80\x80`\x03\x81\x80\x86\x80\t\x86\t\x08\x81\x85\x80\t\x14\x93\x10\x91\x10\x16\x16\x15a\x0C\xEDWV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7FBn254: invalid G1 point\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x90\xFD[PV[`@Q\x90a\x01\0\x82\x01\x82\x81\x10g\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x82\x11\x17a\x01\xDEW`@R\x81`\xE0`\0\x91\x82\x81R\x82` \x82\x01R\x82`@\x82\x01R\x82``\x82\x01R\x82`\x80\x82\x01R\x82`\xA0\x82\x01R\x82`\xC0\x82\x01R\x01RV[`\xA0\x90` a\x01\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x94\x96\x95`\xE0a\r\xA9a\r5V[\x98\x84`\xC0`@Q\x97`\x7F`\xE1\x1B\x83\x8A\x01R\x80Q\x82\x1B`$\x8A\x01R\x82\x81\x01Q\x82\x1B`,\x8A\x01Ra\x02\x80\x81\x01Q`@\x8A\x01Ra\x02\xA0\x81\x01Q``\x8A\x01R`\x01`\x80\x8A\x01R\x7F/\x8D\xD1\xF1\xA7X\xA8\x01f\x9Cd\x01q \xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85`\x80\x82\x01R\x7F\x12YzV\xC2\xE48b\x0B\x90A\xB9\x89\x92\xAE\rNp[x\0W\xBFwf\xA2v|\xEC\xE1n\x1D`\xA0\x82\x01R\x7F\x02\xD9A\x17\xCD\x17\xBC\xF1)\x0F\xD6|\x01\x15]\xD4\x08\x07\x85}\xFFJZ\x0BM\xC6{\xEF\xA8\xAA4\xFD`\xC0\x82\x01R\x7F\x15\xEE$u\xBE\xE5\x17\xC4\xEE\x05\xE5\x1F\xA1\xEEs\x12\xA87:\x0B\x13\xDB\x8CQ\xBA\xF0L\xB2\xE9\x9B\xD2\xBD`\xE0\x82\x01Ra\x13\xA3a\x02DV[\x90`\x10\x82R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01` \x83\x01R`@\x82\x01R\x90V[b\x10\0\0\x81\x14a\x15IW` \x03a\x157Wa\x13\xEFa\x02dV[`\x01\x81R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0` \x82\x01R\x7F!\x08,\xA2\x16\xCB\xBFN\x1CnOE\x94\xDDP\x8C\x99m\xFB\xE1\x17N\xFB\x98\xB1\x15\t\xC6\xE3\x06F\x0B`@\x82\x01R\x7F\x12w\xAEd\x15\xF0\xEF\x18\xF2\xBA_\xB1b\xC3\x9E\xB71\x1F8n-&\xD6D\x01\xF4\xA2]\xA7|%;``\x82\x01R\x7F+3}\xE1\xC8\xC1O\"\xEC\x9B\x9E/\x96\xAF\xEF6Rbsf\xF8\x17\n\n\x94\x8D\xADJ\xC1\xBD^\x80`\x80\x82\x01R\x7F/\xBDM\xD2\x97k\xE5]\x1A\x16:\xA9\x82\x0F\xB8\x8D\xFA\xC5\xDD\xCEw\xE1\x87.\x90c '2z^\xBE`\xA0\x82\x01R\x7F\x10z\xABI\xE6Zg\xF9\xDA\x9C\xD2\xAB\xF7\x8B\xE3\x8B\xD9\xDC\x1D]\xB3\x9F\x81\xDE6\xBC\xFA[K\x03\x90C`\xC0\x82\x01R~\xE1Kcd\xA4~\x9CB\x84\xA9\xF8\n_\xC4\x1C\xD2\x12\xB0\xD4\xDB\xF8\xA5p7p\xA4\n\x9A49\x90`\xE0\x82\x01Ra\x15\x04a\x02DV[\x90`\x05\x82R\x7F.\xE1+\xFFJ(\x13(j\x8D\xC3\x88\xCDuM\x9A>\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01` \x83\x01R`@\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x90\xFD[Pa\x15Ra\x02dV[`\x01\x81R\x7F&\x12]\xA1\n\x0E\xD0c'P\x8A\xBA\x06\xD1\xE3\x03\xACaf2\xDB\xED4\x9FSB-\xA9S3xW` \x82\x01R\x7F\"`\xE7$\x84K\xCARQ\x82\x93S\x96\x8EI\x150RXA\x83WG:\\\x1DY\x7Fa?l\xBD`@\x82\x01R\x7F \x87\xEA,\xD6d'\x86\x08\xFB\x0E\xBD\xB8 \x90\x7FY\x85\x02\xC8\x1Bf\x90\xC1\x85\xE2\xBF\x15\xCB\x93_B``\x82\x01R\x7F\x19\xDD\xBC\xAF:\x8DF\xC1\\\x01v\xFB\xB5\xB9^M\xC5p\x88\xFF\x13\xF4\xD1\xBD\x84\xC6\xBF\xA5}\xCD\xC0\xE0`\x80\x82\x01R\x7F\x05\xA2\xC8\\\xFCY\x17\x89`\\\xAE\x81\x8E7\xDDAa\xEE\xF9\xAAfk\xECo\xE4(\x8D\t\xE6\xD24\x18`\xA0\x82\x01R\x7F\x11\xF7\x0ESc%\x8F\xF4\xF0\xD7\x16\xA6S\xE1\xDCA\xF1\xC6D\x84\xD7\xF4\xB6\xE2\x19\xD67v\x14\xA3\x90\\`\xC0\x82\x01R\x7F)\xE8AC\xF5\x87\rGv\xA9-\xF8\xDA\x8Cl\x93\x03\xD5\x90\x88\xF3{\xA8_@\xCFo\xD1Be\xB4\xBC`\xE0\x82\x01Ra\x16ha\x02DV[\x90`\x14\x82R\x7F0dKl\x9CJr\x16\x9EM\xAA1}%\xF0E\x12\xAE\x15\xC5;4\xE8\xF5\xAC\xD8\xE1U\xD0\xA6\xC1\x01` \x83\x01R`@\x82\x01R\x90V[\x91\x92\x90\x92a\x16\xA7a\x02DV[\x92`\0\x84R` \x84\x01\x94`\0\x86R`@\x85\x01\x92`\0\x84R\x85\x83Q\x97\x83`\0\x14a\x17\x1DW\x83\x98`\0\x90[\x80\x82\x10a\x16\xFFWPPa\x16\xF2a\x16\xFB\x96\x97\x98\x99`\0\x19\x01[\x80\x84R\x85\x87a\x1D\xEFV[\x90RQ\x92a\x1EhV[\x90RV[\x90\x99`\0\x80Q` a)\x96\x839\x81Q\x91R\x81`\x01\x92\t\x9A\x01\x90a\x16\xD0V[a\x16\xFB\x95\x96\x97\x98Pa\x16\xF2\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a\x16\xE8V[``\x90\x92\x91\x92`\x80a\x17^a\x01\xE3V[\x91`\0\x83R`\0` \x84\x01R\x82\x95` a\x17va\x02DV[\x92\x866\x857\x80Q\x84R\x01Q` \x83\x01R`@\x82\x01R`\x07a\x07\xCF\x19Z\x01\xFA\x15a\x01\xA2WV[``\x90\x92\x91\x92`\xC0a\x17\xABa\x01\xE3V[\x91`\0\x83R`\0` \x84\x01R` \x83\x96\x81a\x17\xC4a\x02$V[\x93`\x806\x867\x80Q\x85R\x01Q\x82\x84\x01R\x80Q`@\x84\x01R\x01Q\x84\x82\x01R`\x06a\x07\xCF\x19Z\x01\xFA\x15a\x01\xA2WV[\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x82\x03\x91\x82\x11a\x18\rWV[cNH{q`\xE0\x1B`\0R`\x11`\x04R`$`\0\xFD[\x90\x91a\x18-a\n\xD7V[Pa\x186a\n\xD7V[Pa\x18C\x84\x82\x85\x85a\x1F\xD6V[\x90a\x18O\x90\x85\x85a'\xE2V[a\x18X\x90a\x17\xF1V[`\xC0\x84\x01Q\x80\x80\x80\x80\x95\x81\x95a\x01\xA0\x8B\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x84\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90\x82\x8BQ\x90a\x18\x9B\x91a\x17NV[a\x18\xA4\x91a\x17\x9BV[\x90a\x01\xC0\x8B\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x84\x80\t\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x83\x80\t` \x8C\x01Q\x90a\x19\x02\x91a\x17NV[a\x19\x0B\x91a\x17\x9BV[\x90\x82`\0\x80Q` a)\x96\x839\x81Q\x91R\x81\x80\t\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x01\xE0\x8C\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x91\x81`@\x8D\x01Q\x90a\x19l\x91a\x17NV[a\x19u\x91a\x17\x9BV[\x92`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02\0\x8B\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x91\x81``\x8C\x01Q\x90a\x19\xC2\x91a\x17NV[a\x19\xCB\x91a\x17\x9BV[\x93`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02 \x8A\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x92\x81`\x80\x8B\x01Q\x90a\x1A\x18\x91a\x17NV[a\x1A!\x91a\x17\x9BV[\x92a\x02@\x8A\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x84\x84\t\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x92`\0\x80Q` a)\x96\x839\x81Q\x91R\x83\x83\t`@\x89\x01Q\x90a\x1A\x7F\x91a\x17NV[a\x1A\x88\x91a\x17\x9BV[\x93`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02`\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x91\x81``\x87\x01Q\x90a\x1A\xE7\x91a\x17NV[a\x1A\xF0\x91a\x17\x9BV[\x92`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02\x80\x87\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x91\x81`\x80\x86\x01Q\x90a\x1B=\x91a\x17NV[a\x1BF\x91a\x17\x9BV[\x92`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02\xA0\x86\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x92`\xA0\x01Q\x90a\x1B\x91\x91a\x17NV[a\x1B\x9A\x91a\x17\x9BV[\x91`\xE0\x01Q\x90a\x02\xC0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x83\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x92`\xA0\x01Q\x90a\x1B\xD8\x91a\x17NV[a\x1B\xE1\x91a\x17\x9BV[\x90a\x1B\xEAa(\xA0V[\x90a\x1B\xF4\x91a\x17NV[\x91V[`\0` a\x1C\x03a\x01\xE3V[\x82\x81R\x01R\x80Q` \x82\x01Q\x15\x90\x15\x16a\nxW` \x81Q\x91\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG\x91\x82\x91\x01Q\x06\x81\x03\x90\x81\x11a\x18\rWa\x1CTa\x01\xE3V[\x91\x82R` \x82\x01R\x90V[`\0``a\x1Cka\x02$V[\x82\x81R\x82` \x82\x01R\x82`@\x82\x01R\x01Ra\x1C\x84a\x02$V[\x7F\x18\0\xDE\xEF\x12\x1F\x1EvBj\0f^\\DygC\"\xD4\xF7^\xDA\xDDF\xDE\xBD\\\xD9\x92\xF6\xED\x81R\x7F\x19\x8E\x93\x93\x92\rH:r`\xBF\xB71\xFB]%\xF1\xAAI35\xA9\xE7\x12\x97\xE4\x85\xB7\xAE\xF3\x12\xC2` \x82\x01R\x7F\x12\xC8^\xA5\xDB\x8Cm\xEBJ\xABq\x80\x8D\xCB@\x8F\xE3\xD1\xE7i\x0CC\xD3{L\xE6\xCC\x01f\xFA}\xAA`@\x82\x01R\x7F\t\x06\x89\xD0X_\xF0u\xEC\x9E\x99\xADi\x0C3\x95\xBCK13p\xB3\x8E\xF3U\xAC\xDA\xDC\xD1\"\x97[``\x82\x01R\x90V[\x15a\x1D#WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x1C`$\x82\x01R\x7FBn254: Pairing check failed!\0\0\0\0`D\x82\x01R`d\x90\xFD[\x91`@a\x01\x80\x92\x94`\0\x94\x82Q\x93\x81Q\x85R\x83` \x98\x89\x80\x94\x01Q\x84\x88\x01R\x83\x81\x01Q\x82\x88\x01R\x80Q``\x88\x01R``\x81\x01Q`\x80\x88\x01R\x01Q`\xA0\x86\x01R\x80Q`\xC0\x86\x01R\x01Q`\xE0\x84\x01R\x85\x81\x01Qa\x01\0\x84\x01R\x80Qa\x01 \x84\x01R``\x81\x01Qa\x01@\x84\x01R\x01Qa\x01`\x82\x01R`\x08Z\xFAa\x1D\xEA`\0Q\x91a\x1D\x1CV[\x15\x15\x90V[`\x01\x82\x14a\x1E`W\x82\x15a\x1EXW` \x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x92\x83\x91\x90\t\x90\x80\x15a\x1E.Wa\x1E)\x90`\0\x19\x01a(\xC7V[\x90\t\x90V[Pa\x1E)\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a(\xC7V[PPP`\0\x90V[PPP`\x01\x90V[\x93\x92\x91\x90\x91\x80\x15a\x1FrWa\x1E~\x92\x91\x92a\x128V[\x91`\xE0\x83\x01\x93`@\x87\x01\x94`\xE0\x86Q\x01\x90`\x01\x90`\x01\x81R`\x01\x90[`\x08\x82\x10a\x1F8WPPPP`\0\x94`\x01\x94\x92\x90Q\x90`\0\x90[`\x08\x82\x10a\x1E\xEDWPPPPP\x93a\x1E\xE3\x91` \x94\x95`\0\x80Q` a)\x96\x839\x81Q\x91R\x95\x86\x94\x85\x93a(\xC7V[\x93\x01Q\x90\t\t\t\x90V[\x90\x91\x92\x93\x95\x96`\x01\x90\x84Q\x98\x89\x87\x8A`\0\x80Q` a)\x96\x839\x81Q\x91R\x94\x85\x80\x94\x81\x80\x94\x81\x8CQ\x91Q\x8A\t\t\t\x90\x08\x9B\x82\x03\x08\x90\t\x96` \x80\x80\x92\x01\x93\x01\x94\x01\x92\x01\x90\x93\x92a\x1E\xB4V[`\x01\x90`\x1F\x99\x95\x96\x99\x19\x80\x91\x01\x93`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x81\x89\x88Q\x82\x03\x08\x90\t\x94\x85\x85R\x01\x91\x01\x90\x92\x91\x97\x94\x93\x97a\x1E\x9AV[P\x91\x92`\x01\x92\x91`\0\x91\x90\x84[`\x08\x84\x10a\x1F\x92WPPPPPP`\0\x90V[\x80\x85\x14a\x1F\xC3W`\0\x80Q` a)\x96\x839\x81Q\x91R\x86\x91a\x1F\xB8`@\x86\x01Q` \x01\x90V[Q\x90\t\x93\x01\x92a\x1F\x7FV[P\x91\x92PPa\x1F\xD2\x92Pa\x08\xAAV[Q\x90V[\x92\x91\x92a\x1F\xE1a\n\xD7V[P`\x80\x82\x01Q` \x85\x01Q` \x84\x01Q\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90\x83Q\x90`\xA0\x85\x01Q``\x86\x01Q\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x91\x81a\x01\xA0\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x85\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x81a\x01\xC0\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x7F/\x8D\xD1\xF1\xA7X\x91a\x17NV[\x82Q``\x84\x01Q\x90\x81`\x80\x86\x01Q\x91a\x02\xC0\x88\x01Q\x91`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x81a\x02@\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x85\ta\x01\xA0\x89\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x81a\x02`\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x85\ta\x01\xC0\x89\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x81a\x02\x80\x88\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x90\x85\ta\x01\xE0\x89\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x91a\x02\xA0\x87\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02\0\x87\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\xC0\x83\x01Q\x90a#\xD1\x90a\x17\xF1V[a#\xDA\x91a\x17NV[a#\xE3\x91a\x17\x9BV[`\xE0\x82\x01Qa\x01\xA0\x85\x01Qa#\xF7\x91a\x17NV[a$\0\x91a\x17\x9BV[a\x01\0\x82\x01Qa\x01\xC0\x85\x01Qa$\x15\x91a\x17NV[a$\x1E\x91a\x17\x9BV[a\x01 \x82\x01Qa\x01\xE0\x85\x01Qa$3\x91a\x17NV[a$<\x91a\x17\x9BV[a\x01@\x82\x01Qa\x02\0\x85\x01Qa$Q\x91a\x17NV[a$Z\x91a\x17\x9BV[a\x01\xC0\x84\x01Qa\x01\xA0\x85\x01Q\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x01`\x83\x01Q\x90a$\x88\x91a\x17NV[a$\x91\x91a\x17\x9BV[a\x02\0\x84\x01Qa\x01\xE0\x85\x01Q\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x01\x80\x83\x01Q\x90a$\xBF\x91a\x17NV[a$\xC8\x91a\x17\x9BV[a\x01\xA0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x81\x80\t\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x01\xE0\x83\x01Q\x90a%\x13\x91a\x17NV[a%\x1C\x91a\x17\x9BV[a\x01\xC0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x81\x80\t\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02\0\x83\x01Q\x90a%g\x91a\x17NV[a%p\x91a\x17\x9BV[a\x01\xE0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x81\x80\t\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02 \x83\x01Q\x90a%\xBB\x91a\x17NV[a%\xC4\x91a\x17\x9BV[a\x02\0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x81\x80\t\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02@\x83\x01Q\x90a&\x0F\x91a\x17NV[a&\x18\x91a\x17\x9BV[a\x01\xA0\x82\x01Qa\x02 \x85\x01Qa&-\x90a)wV[a&6\x91a\x17NV[a&?\x91a\x17\x9BV[a\x01\xC0\x82\x01Qa&N\x91a\x17\x9BV[\x90a\x01\xC0\x84\x01Qa\x01\xA0\x85\x01Q\x90`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x01\xE0\x85\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02\0\x85\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\ta\x02 \x85\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x02`\x01Q\x90a&\xC2\x91a\x17NV[a&\xCB\x91a\x17\x9BV[\x90\x83Qa&\xD7\x90a)wV[\x91\x82`\xC0\x85\x01Q\x90a&\xE8\x91a\x17NV[a&\xF1\x91a\x17\x9BV[\x93Q`\x01`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\x08\x90`\xA0\x01Q\x80`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x80\x93`\0\x80Q` a)\x96\x839\x81Q\x91R\x82\x80\x94\t\x90\x81`\xE0\x86\x01Q\x90a'T\x91a\x17NV[a']\x91a\x17\x9BV[\x91`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90\x81a\x01\0\x85\x01Q\x90a'\x81\x91a\x17NV[a'\x8A\x91a\x17\x9BV[\x91`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90\x81a\x01 \x84\x01Q\x90a'\xAE\x91a\x17NV[a'\xB7\x91a\x17\x9BV[\x92`\0\x80Q` a)\x96\x839\x81Q\x91R\x91\t\x90a\x01@\x01Q\x90a'\xD9\x91a\x17NV[a\nx\x91a\x17\x9BV[\x90`@` \x84\x01Q\x93\x01Q\x92``\x83\x01Q`\x80\x84\x01Q\x94a\x01\xA0\x84\x01Q`\0\x80Q` a)\x96\x839\x81Q\x91R\x87\x81\x87\x81\x80\x80\x9C\x98\x81\x80\x80\x80\x9E\x81\x80\x9E\x9C\x81\x80\x9E\x81a\x02@\x81\x96\x01Q\x8A\t\x92\x08\x08`\x01\t\x81a\x01\xC0\x89\x01Q\x81\x8C\x81a\x02`\x8D\x01Q\x8A\t\x92\x08\x08\x90\t\x81a\x01\xE0\x88\x01Q\x81\x8B\x81a\x02\x80\x8C\x01Q\x89\t\x92\x08\x08\x90\t\x91\x81\x88\x81a\x02\0\x89\x01Q\x93a\x02\xA0\x8A\x01Q\x90\t\x92\x08\x08\x90\t\x93a\x02\xC0a\x02 \x84\x01Q\x93\x01Q\x92\x08\t\x90\t\x93` \x87Q\x97\x01Q\t\x82\x03\x90\x08\x92\t\x82\x03\x90\x08\x90V[`\0` a(\xACa\x01\xE3V[\x82\x81R\x01Ra(\xB9a\x01\xE3V[`\x01\x81R`\x02` \x82\x01R\x90V[\x90`@Q\x91`\0`\xC0` \x94\x85\x93\x84\x82R\x84\x80\x83\x01R\x84`@\x83\x01R``\x82\x01R\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xEF\xFF\xFF\xFF`\x80\x82\x01R`\0\x80Q` a)\x96\x839\x81Q\x91R`\xA0\x82\x01R`\x05Z\xFA\x91`\0Q\x92\x15a)3WPV[`d\x90`@Q\x90bF\x1B\xCD`\xE5\x1B\x82R`\x04\x82\x01R`\x1D`$\x82\x01R\x7FBn254: pow precompile failed!\0\0\0`D\x82\x01R\xFD[`\0\x80Q` a)\x96\x839\x81Q\x91R\x80\x91\x06\x81\x03\x90\x81\x11a\x18\rW\x90V\xFE0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\x01\xA1dsolcC\0\x08\x17\0\n"; /// The deployed bytecode of the contract. pub static PLONKVERIFIER_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); @@ -323,15 +319,15 @@ pub mod plonk_verifier { let deployer = ::ethers::contract::ContractDeployer::new(deployer); Ok(deployer) } - ///Calls the contract's `verify` (0x8c266f05) function + ///Calls the contract's `verify` (0x64e4c59e) function pub fn verify( &self, verifying_key: VerifyingKey, - public_input: ::std::vec::Vec<::ethers::core::types::U256>, + public_input: [::ethers::core::types::U256; 8], proof: PlonkProof, ) -> ::ethers::contract::builders::ContractCall { self.0 - .method_hash([140, 38, 111, 5], (verifying_key, public_input, proof)) + .method_hash([100, 228, 197, 158], (verifying_key, public_input, proof)) .expect("method not found (this should never happen)") } } @@ -357,21 +353,6 @@ pub mod plonk_verifier { )] #[etherror(name = "InvalidPlonkArgs", abi = "InvalidPlonkArgs()")] pub struct InvalidPlonkArgs; - ///Custom Error type `InvalidPolyEvalArgs` with signature `InvalidPolyEvalArgs()` and selector `0x8c5e11f1` - #[derive( - Clone, - ::ethers::contract::EthError, - ::ethers::contract::EthDisplay, - serde::Serialize, - serde::Deserialize, - Default, - Debug, - PartialEq, - Eq, - Hash, - )] - #[etherror(name = "InvalidPolyEvalArgs", abi = "InvalidPolyEvalArgs()")] - pub struct InvalidPolyEvalArgs; ///Custom Error type `UnsupportedDegree` with signature `UnsupportedDegree()` and selector `0xe2ef09e5` #[derive( Clone, @@ -415,7 +396,6 @@ pub mod plonk_verifier { )] pub enum PlonkVerifierErrors { InvalidPlonkArgs(InvalidPlonkArgs), - InvalidPolyEvalArgs(InvalidPolyEvalArgs), UnsupportedDegree(UnsupportedDegree), WrongPlonkVK(WrongPlonkVK), /// The standard solidity revert string, with selector @@ -436,11 +416,6 @@ pub mod plonk_verifier { { return Ok(Self::InvalidPlonkArgs(decoded)); } - if let Ok(decoded) = - ::decode(data) - { - return Ok(Self::InvalidPolyEvalArgs(decoded)); - } if let Ok(decoded) = ::decode(data) { return Ok(Self::UnsupportedDegree(decoded)); @@ -455,9 +430,6 @@ pub mod plonk_verifier { fn encode(self) -> ::std::vec::Vec { match self { Self::InvalidPlonkArgs(element) => ::ethers::core::abi::AbiEncode::encode(element), - Self::InvalidPolyEvalArgs(element) => { - ::ethers::core::abi::AbiEncode::encode(element) - } Self::UnsupportedDegree(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::WrongPlonkVK(element) => ::ethers::core::abi::AbiEncode::encode(element), Self::RevertString(s) => ::ethers::core::abi::AbiEncode::encode(s), @@ -471,11 +443,6 @@ pub mod plonk_verifier { _ if selector == ::selector() => { true } - _ if selector - == ::selector() => - { - true - } _ if selector == ::selector() => { @@ -490,7 +457,6 @@ pub mod plonk_verifier { fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { match self { Self::InvalidPlonkArgs(element) => ::core::fmt::Display::fmt(element, f), - Self::InvalidPolyEvalArgs(element) => ::core::fmt::Display::fmt(element, f), Self::UnsupportedDegree(element) => ::core::fmt::Display::fmt(element, f), Self::WrongPlonkVK(element) => ::core::fmt::Display::fmt(element, f), Self::RevertString(s) => ::core::fmt::Display::fmt(s, f), @@ -507,11 +473,6 @@ pub mod plonk_verifier { Self::InvalidPlonkArgs(value) } } - impl ::core::convert::From for PlonkVerifierErrors { - fn from(value: InvalidPolyEvalArgs) -> Self { - Self::InvalidPolyEvalArgs(value) - } - } impl ::core::convert::From for PlonkVerifierErrors { fn from(value: UnsupportedDegree) -> Self { Self::UnsupportedDegree(value) @@ -522,7 +483,7 @@ pub mod plonk_verifier { Self::WrongPlonkVK(value) } } - ///Container type for all input parameters for the `verify` function with signature `verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256)),uint256[],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))` and selector `0x8c266f05` + ///Container type for all input parameters for the `verify` function with signature `verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),bytes32,bytes32),uint256[8],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))` and selector `0x64e4c59e` #[derive( Clone, ::ethers::contract::EthCall, @@ -532,14 +493,14 @@ pub mod plonk_verifier { )] #[ethcall( name = "verify", - abi = "verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256)),uint256[],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))" + abi = "verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),bytes32,bytes32),uint256[8],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))" )] pub struct VerifyCall { pub verifying_key: VerifyingKey, - pub public_input: ::std::vec::Vec<::ethers::core::types::U256>, + pub public_input: [::ethers::core::types::U256; 8], pub proof: PlonkProof, } - ///Container type for all return fields from the `verify` function with signature `verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256)),uint256[],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))` and selector `0x8c266f05` + ///Container type for all return fields from the `verify` function with signature `verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),bytes32,bytes32),uint256[8],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))` and selector `0x64e4c59e` #[derive( Clone, ::ethers::contract::EthAbiType, diff --git a/contract-bindings/src/plonk_verifier_2.rs b/contract-bindings/src/plonk_verifier_2.rs new file mode 100644 index 0000000000..8d9abf362d --- /dev/null +++ b/contract-bindings/src/plonk_verifier_2.rs @@ -0,0 +1,538 @@ +pub use plonk_verifier_2::*; +/// This module was auto-generated with ethers-rs Abigen. +/// More information at: +#[allow( + clippy::enum_variant_names, + clippy::too_many_arguments, + clippy::upper_case_acronyms, + clippy::type_complexity, + dead_code, + non_camel_case_types +)] +pub mod plonk_verifier_2 { + pub use super::super::shared_types::*; + #[allow(deprecated)] + fn __abi() -> ::ethers::core::abi::Abi { + ::ethers::core::abi::ethabi::Contract { + constructor: ::core::option::Option::None, + functions: ::core::convert::From::from([ + ( + ::std::borrow::ToOwned::to_owned("P_MOD"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("P_MOD"), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(256usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("R_MOD"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("R_MOD"), + inputs: ::std::vec![], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::string::String::new(), + kind: ::ethers::core::abi::ethabi::ParamType::Uint(256usize,), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ( + ::std::borrow::ToOwned::to_owned("verify"), + ::std::vec![::ethers::core::abi::ethabi::Function { + name: ::std::borrow::ToOwned::to_owned("verify"), + inputs: ::std::vec![ + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("vk"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize), + ::ethers::core::abi::ethabi::ParamType::FixedBytes(32usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct IPlonkVerifier.VerifyingKey", + ), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("publicInput"), + kind: ::ethers::core::abi::ethabi::ParamType::FixedArray( + ::std::boxed::Box::new( + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ), + 8usize, + ), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("uint256[8]"), + ), + }, + ::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("proof"), + kind: ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Tuple(::std::vec![ + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ::ethers::core::abi::ethabi::ParamType::Uint(256usize), + ],), + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned( + "struct IPlonkVerifier.PlonkProof", + ), + ), + }, + ], + outputs: ::std::vec![::ethers::core::abi::ethabi::Param { + name: ::std::borrow::ToOwned::to_owned("success"), + kind: ::ethers::core::abi::ethabi::ParamType::Bool, + internal_type: ::core::option::Option::Some( + ::std::borrow::ToOwned::to_owned("bool"), + ), + },], + constant: ::core::option::Option::None, + state_mutability: ::ethers::core::abi::ethabi::StateMutability::View, + },], + ), + ]), + events: ::std::collections::BTreeMap::new(), + errors: ::core::convert::From::from([( + ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), + ::std::vec![::ethers::core::abi::ethabi::AbiError { + name: ::std::borrow::ToOwned::to_owned("UnsupportedDegree"), + inputs: ::std::vec![], + },], + )]), + receive: false, + fallback: false, + } + } + ///The parsed JSON ABI of the contract. + pub static PLONKVERIFIER2_ABI: ::ethers::contract::Lazy<::ethers::core::abi::Abi> = + ::ethers::contract::Lazy::new(__abi); + #[rustfmt::skip] + const __BYTECODE: &[u8] = b"`\x80\x80`@R4a\0\x1AWa)\x03\x90\x81a\0 \x8290\x81PP\xF3[`\0\x80\xFD\xFE`\x80`@R`\x046\x10\x15a\0\x12W`\0\x80\xFD[`\0\x805`\xE0\x1C\x90\x81c\x1Dq.'\x14a\x01\xC7W\x81c\xA1\xF1\xA3N\x14a\0EWPc\xDFnl\xB4\x14a\0@W`\0\x80\xFD[a\x08\xE4V[6`\x03\x19\x01a\n\x80\x81\x12a\x01\xC3Wa\x05\0\x13a\x01\xC0Wa\x01\xBCa\x01\xAAa\0ia\x02\x12V[`\x045\x81R`$5` \x82\x01Ra\0\x7F6a\x02\xBAV[`@\x82\x01Ra\0\x8D6a\x02\xE3V[``\x82\x01Ra\0\x9B6a\x03\x07V[`\x80\x82\x01Ra\0\xA96a\x03+V[`\xA0\x82\x01Ra\0\xB76a\x03RV[`\xC0\x82\x01Ra\0\xC56a\x03yV[`\xE0\x82\x01Ra\0\xD36a\x03\xA0V[a\x01\0\x82\x01Ra\0\xE26a\x03\xC7V[a\x01 \x82\x01Ra\0\xF16a\x03\xEEV[a\x01@\x82\x01Ra\x01\x006a\x04\x15V[a\x01`\x82\x01Ra\x01\x0F6a\x04\xA8\x01f\x9Cd\x01q \xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85`\x80\x82\x01R\x7F\x12YzV\xC2\xE48b\x0B\x90A\xB9\x89\x92\xAE\rNp[x\0W\xBFwf\xA2v|\xEC\xE1n\x1D`\xA0\x82\x01R\x7F\x02\xD9A\x17\xCD\x17\xBC\xF1)\x0F\xD6|\x01\x15]\xD4\x08\x07\x85}\xFFJZ\x0BM\xC6{\xEF\xA8\xAA4\xFD`\xC0\x82\x01R\x7F\x15\xEE$u\xBE\xE5\x17\xC4\xEE\x05\xE5\x1F\xA1\xEEs\x12\xA87:\x0B\x13\xDB\x8CQ\xBA\xF0L\xB2\xE9\x9B\xD2\xBD`\xE0\x82\x01Ra!=a\x02yV[\x90`\x10\x82R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01` \x83\x01R`@\x82\x01R\x90V[b\x10\0\0\x81\x14a\"\xE3W` \x03a\"\xD1Wa!\x89a\x02\x99V[`\x01\x81R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0` \x82\x01R\x7F!\x08,\xA2\x16\xCB\xBFN\x1CnOE\x94\xDDP\x8C\x99m\xFB\xE1\x17N\xFB\x98\xB1\x15\t\xC6\xE3\x06F\x0B`@\x82\x01R\x7F\x12w\xAEd\x15\xF0\xEF\x18\xF2\xBA_\xB1b\xC3\x9E\xB71\x1F8n-&\xD6D\x01\xF4\xA2]\xA7|%;``\x82\x01R\x7F+3}\xE1\xC8\xC1O\"\xEC\x9B\x9E/\x96\xAF\xEF6Rbsf\xF8\x17\n\n\x94\x8D\xADJ\xC1\xBD^\x80`\x80\x82\x01R\x7F/\xBDM\xD2\x97k\xE5]\x1A\x16:\xA9\x82\x0F\xB8\x8D\xFA\xC5\xDD\xCEw\xE1\x87.\x90c '2z^\xBE`\xA0\x82\x01R\x7F\x10z\xABI\xE6Zg\xF9\xDA\x9C\xD2\xAB\xF7\x8B\xE3\x8B\xD9\xDC\x1D]\xB3\x9F\x81\xDE6\xBC\xFA[K\x03\x90C`\xC0\x82\x01R~\xE1Kcd\xA4~\x9CB\x84\xA9\xF8\n_\xC4\x1C\xD2\x12\xB0\xD4\xDB\xF8\xA5p7p\xA4\n\x9A49\x90`\xE0\x82\x01Ra\"\x9Ea\x02yV[\x90`\x05\x82R\x7F.\xE1+\xFFJ(\x13(j\x8D\xC3\x88\xCDuM\x9A>\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01` \x83\x01R`@\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x90\xFD[Pa\"\xECa\x02\x99V[`\x01\x81R\x7F&\x12]\xA1\n\x0E\xD0c'P\x8A\xBA\x06\xD1\xE3\x03\xACaf2\xDB\xED4\x9FSB-\xA9S3xW` \x82\x01R\x7F\"`\xE7$\x84K\xCARQ\x82\x93S\x96\x8EI\x150RXA\x83WG:\\\x1DY\x7Fa?l\xBD`@\x82\x01R\x7F \x87\xEA,\xD6d'\x86\x08\xFB\x0E\xBD\xB8 \x90\x7FY\x85\x02\xC8\x1Bf\x90\xC1\x85\xE2\xBF\x15\xCB\x93_B``\x82\x01R\x7F\x19\xDD\xBC\xAF:\x8DF\xC1\\\x01v\xFB\xB5\xB9^M\xC5p\x88\xFF\x13\xF4\xD1\xBD\x84\xC6\xBF\xA5}\xCD\xC0\xE0`\x80\x82\x01R\x7F\x05\xA2\xC8\\\xFCY\x17\x89`\\\xAE\x81\x8E7\xDDAa\xEE\xF9\xAAfk\xECo\xE4(\x8D\t\xE6\xD24\x18`\xA0\x82\x01R\x7F\x11\xF7\x0ESc%\x8F\xF4\xF0\xD7\x16\xA6S\xE1\xDCA\xF1\xC6D\x84\xD7\xF4\xB6\xE2\x19\xD67v\x14\xA3\x90\\`\xC0\x82\x01R\x7F)\xE8AC\xF5\x87\rGv\xA9-\xF8\xDA\x8Cl\x93\x03\xD5\x90\x88\xF3{\xA8_@\xCFo\xD1Be\xB4\xBC`\xE0\x82\x01Ra$\x02a\x02yV[\x90`\x14\x82R\x7F0dKl\x9CJr\x16\x9EM\xAA1}%\xF0E\x12\xAE\x15\xC5;4\xE8\xF5\xAC\xD8\xE1U\xD0\xA6\xC1\x01` \x83\x01R`@\x82\x01R\x90V[\x91\x92\x90\x92a$Aa\x02yV[\x92`\0\x84R` \x84\x01\x94`\0\x86R`@\x85\x01\x92`\0\x84R\x85\x83Q\x97\x83`\0\x14a$\xB7W\x83\x98`\0\x90[\x80\x82\x10a$\x99WPPa$\x8Ca$\x95\x96\x97\x98\x99`\0\x19\x01[\x80\x84R\x85\x87a&?V[\x90RQ\x92a&\xB8V[\x90RV[\x90\x99`\0\x80Q` a(\xD7\x839\x81Q\x91R\x81`\x01\x92\t\x9A\x01\x90a$jV[a$\x95\x95\x96\x97\x98Pa$\x8C\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a$\x82V[\x90`@` \x84\x01Q\x93\x01Q\x92``\x83\x01Q`\x80\x84\x01Q\x94a\x01\xA0\x84\x01Q`\0\x80Q` a(\xD7\x839\x81Q\x91R\x87\x81\x87\x81\x80\x80\x9C\x98\x81\x80\x80\x80\x9E\x81\x80\x9E\x9C\x81\x80\x9E\x81a\x02@\x81\x96\x01Q\x8A\t\x92\x08\x08`\x01\t\x81a\x01\xC0\x89\x01Q\x81\x8C\x81a\x02`\x8D\x01Q\x8A\t\x92\x08\x08\x90\t\x81a\x01\xE0\x88\x01Q\x81\x8B\x81a\x02\x80\x8C\x01Q\x89\t\x92\x08\x08\x90\t\x91\x81\x88\x81a\x02\0\x89\x01Q\x93a\x02\xA0\x8A\x01Q\x90\t\x92\x08\x08\x90\t\x93a\x02\xC0a\x02 \x84\x01Q\x93\x01Q\x92\x08\t\x90\t\x93` \x87Q\x97\x01Q\t\x82\x03\x90\x08\x92\t\x82\x03\x90\x08\x90V[` \x81Q\x91\x01Q\x90\x81\x15\x81\x15\x16a&;W\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG\x80\x80`\x03\x81\x80\x86\x80\t\x86\t\x08\x81\x85\x80\t\x14\x93\x10\x91\x10\x16\x16\x15a%\xF6WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7FBn254: invalid G1 point\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x90\xFD[PPV[`\x01\x82\x14a&\xB0W\x82\x15a&\xA8W` \x01Q`\0\x80Q` a(\xD7\x839\x81Q\x91R\x92\x83\x91\x90\t\x90\x80\x15a&~Wa&y\x90`\0\x19\x01a(&V[\x90\t\x90V[Pa&y\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a(&V[PPP`\0\x90V[PPP`\x01\x90V[\x93\x92\x91\x90\x91\x80\x15a'\xC2Wa&\xCE\x92\x91\x92a\x1F\xD2V[\x91`\xE0\x83\x01\x93`@\x87\x01\x94`\xE0\x86Q\x01\x90`\x01\x90`\x01\x81R`\x01\x90[`\x08\x82\x10a'\x88WPPPP`\0\x94`\x01\x94\x92\x90Q\x90`\0\x90[`\x08\x82\x10a'=WPPPPP\x93a'3\x91` \x94\x95`\0\x80Q` a(\xD7\x839\x81Q\x91R\x95\x86\x94\x85\x93a(&V[\x93\x01Q\x90\t\t\t\x90V[\x90\x91\x92\x93\x95\x96`\x01\x90\x84Q\x98\x89\x87\x8A`\0\x80Q` a(\xD7\x839\x81Q\x91R\x94\x85\x80\x94\x81\x80\x94\x81\x8CQ\x91Q\x8A\t\t\t\x90\x08\x9B\x82\x03\x08\x90\t\x96` \x80\x80\x92\x01\x93\x01\x94\x01\x92\x01\x90\x93\x92a'\x04V[`\x01\x90`\x1F\x99\x95\x96\x99\x19\x80\x91\x01\x93`\0\x80Q` a(\xD7\x839\x81Q\x91R\x90\x81\x89\x88Q\x82\x03\x08\x90\t\x94\x85\x85R\x01\x91\x01\x90\x92\x91\x97\x94\x93\x97a&\xEAV[P\x91\x92`\x01\x92\x91`\0\x91\x90\x84[`\x08\x84\x10a'\xE2WPPPPPP`\0\x90V[\x80\x85\x14a(\x13W`\0\x80Q` a(\xD7\x839\x81Q\x91R\x86\x91a(\x08`@\x86\x01Q` \x01\x90V[Q\x90\t\x93\x01\x92a'\xCFV[P\x91\x92PPa(\"\x92Pa\t\x08V[Q\x90V[\x90`@Q\x91`\0`\xC0` \x94\x85\x93\x84\x82R\x84\x80\x83\x01R\x84`@\x83\x01R``\x82\x01R\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xEF\xFF\xFF\xFF`\x80\x82\x01R`\0\x80Q` a(\xD7\x839\x81Q\x91R`\xA0\x82\x01R`\x05Z\xFA\x91`\0Q\x92\x15a(\x92WPV[`d\x90`@Q\x90bF\x1B\xCD`\xE5\x1B\x82R`\x04\x82\x01R`\x1D`$\x82\x01R\x7FBn254: pow precompile failed!\0\0\0`D\x82\x01R\xFD\xFE0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\x01\xA1dsolcC\0\x08\x17\0\n"; + /// The bytecode of the contract. + pub static PLONKVERIFIER2_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__BYTECODE); + #[rustfmt::skip] + const __DEPLOYED_BYTECODE: &[u8] = b"`\x80`@R`\x046\x10\x15a\0\x12W`\0\x80\xFD[`\0\x805`\xE0\x1C\x90\x81c\x1Dq.'\x14a\x01\xC7W\x81c\xA1\xF1\xA3N\x14a\0EWPc\xDFnl\xB4\x14a\0@W`\0\x80\xFD[a\x08\xE4V[6`\x03\x19\x01a\n\x80\x81\x12a\x01\xC3Wa\x05\0\x13a\x01\xC0Wa\x01\xBCa\x01\xAAa\0ia\x02\x12V[`\x045\x81R`$5` \x82\x01Ra\0\x7F6a\x02\xBAV[`@\x82\x01Ra\0\x8D6a\x02\xE3V[``\x82\x01Ra\0\x9B6a\x03\x07V[`\x80\x82\x01Ra\0\xA96a\x03+V[`\xA0\x82\x01Ra\0\xB76a\x03RV[`\xC0\x82\x01Ra\0\xC56a\x03yV[`\xE0\x82\x01Ra\0\xD36a\x03\xA0V[a\x01\0\x82\x01Ra\0\xE26a\x03\xC7V[a\x01 \x82\x01Ra\0\xF16a\x03\xEEV[a\x01@\x82\x01Ra\x01\x006a\x04\x15V[a\x01`\x82\x01Ra\x01\x0F6a\x04\xA8\x01f\x9Cd\x01q \xE1t \xAA\xE6\xAD\xAA\x01\xC2a|n\x85`\x80\x82\x01R\x7F\x12YzV\xC2\xE48b\x0B\x90A\xB9\x89\x92\xAE\rNp[x\0W\xBFwf\xA2v|\xEC\xE1n\x1D`\xA0\x82\x01R\x7F\x02\xD9A\x17\xCD\x17\xBC\xF1)\x0F\xD6|\x01\x15]\xD4\x08\x07\x85}\xFFJZ\x0BM\xC6{\xEF\xA8\xAA4\xFD`\xC0\x82\x01R\x7F\x15\xEE$u\xBE\xE5\x17\xC4\xEE\x05\xE5\x1F\xA1\xEEs\x12\xA87:\x0B\x13\xDB\x8CQ\xBA\xF0L\xB2\xE9\x9B\xD2\xBD`\xE0\x82\x01Ra!=a\x02yV[\x90`\x10\x82R\x7F0d\x1E\x0E\x92\xBE\xBE\xF8\x18&\x8Df;\xCA\xD6\xDB\xCF\xD6\xC0\x14\x91p\xF6\xD7\xD3P\xB1\xB1\xFAl\x10\x01` \x83\x01R`@\x82\x01R\x90V[b\x10\0\0\x81\x14a\"\xE3W` \x03a\"\xD1Wa!\x89a\x02\x99V[`\x01\x81R\x7F\t\xC52\xC60k\x93\xD2\x96x \rG\xC0\xB2\xA9\x9C\x18\xD5\x1B\x83\x8E\xEB\x1D>\xEDLS;\xB5\x12\xD0` \x82\x01R\x7F!\x08,\xA2\x16\xCB\xBFN\x1CnOE\x94\xDDP\x8C\x99m\xFB\xE1\x17N\xFB\x98\xB1\x15\t\xC6\xE3\x06F\x0B`@\x82\x01R\x7F\x12w\xAEd\x15\xF0\xEF\x18\xF2\xBA_\xB1b\xC3\x9E\xB71\x1F8n-&\xD6D\x01\xF4\xA2]\xA7|%;``\x82\x01R\x7F+3}\xE1\xC8\xC1O\"\xEC\x9B\x9E/\x96\xAF\xEF6Rbsf\xF8\x17\n\n\x94\x8D\xADJ\xC1\xBD^\x80`\x80\x82\x01R\x7F/\xBDM\xD2\x97k\xE5]\x1A\x16:\xA9\x82\x0F\xB8\x8D\xFA\xC5\xDD\xCEw\xE1\x87.\x90c '2z^\xBE`\xA0\x82\x01R\x7F\x10z\xABI\xE6Zg\xF9\xDA\x9C\xD2\xAB\xF7\x8B\xE3\x8B\xD9\xDC\x1D]\xB3\x9F\x81\xDE6\xBC\xFA[K\x03\x90C`\xC0\x82\x01R~\xE1Kcd\xA4~\x9CB\x84\xA9\xF8\n_\xC4\x1C\xD2\x12\xB0\xD4\xDB\xF8\xA5p7p\xA4\n\x9A49\x90`\xE0\x82\x01Ra\"\x9Ea\x02yV[\x90`\x05\x82R\x7F.\xE1+\xFFJ(\x13(j\x8D\xC3\x88\xCDuM\x9A>\xF2I\x065\xEB\xA5\x0C\xB9\xC2\xE5\xE7P\x80\0\x01` \x83\x01R`@\x82\x01R\x90V[`@Qc\xE2\xEF\t\xE5`\xE0\x1B\x81R`\x04\x90\xFD[Pa\"\xECa\x02\x99V[`\x01\x81R\x7F&\x12]\xA1\n\x0E\xD0c'P\x8A\xBA\x06\xD1\xE3\x03\xACaf2\xDB\xED4\x9FSB-\xA9S3xW` \x82\x01R\x7F\"`\xE7$\x84K\xCARQ\x82\x93S\x96\x8EI\x150RXA\x83WG:\\\x1DY\x7Fa?l\xBD`@\x82\x01R\x7F \x87\xEA,\xD6d'\x86\x08\xFB\x0E\xBD\xB8 \x90\x7FY\x85\x02\xC8\x1Bf\x90\xC1\x85\xE2\xBF\x15\xCB\x93_B``\x82\x01R\x7F\x19\xDD\xBC\xAF:\x8DF\xC1\\\x01v\xFB\xB5\xB9^M\xC5p\x88\xFF\x13\xF4\xD1\xBD\x84\xC6\xBF\xA5}\xCD\xC0\xE0`\x80\x82\x01R\x7F\x05\xA2\xC8\\\xFCY\x17\x89`\\\xAE\x81\x8E7\xDDAa\xEE\xF9\xAAfk\xECo\xE4(\x8D\t\xE6\xD24\x18`\xA0\x82\x01R\x7F\x11\xF7\x0ESc%\x8F\xF4\xF0\xD7\x16\xA6S\xE1\xDCA\xF1\xC6D\x84\xD7\xF4\xB6\xE2\x19\xD67v\x14\xA3\x90\\`\xC0\x82\x01R\x7F)\xE8AC\xF5\x87\rGv\xA9-\xF8\xDA\x8Cl\x93\x03\xD5\x90\x88\xF3{\xA8_@\xCFo\xD1Be\xB4\xBC`\xE0\x82\x01Ra$\x02a\x02yV[\x90`\x14\x82R\x7F0dKl\x9CJr\x16\x9EM\xAA1}%\xF0E\x12\xAE\x15\xC5;4\xE8\xF5\xAC\xD8\xE1U\xD0\xA6\xC1\x01` \x83\x01R`@\x82\x01R\x90V[\x91\x92\x90\x92a$Aa\x02yV[\x92`\0\x84R` \x84\x01\x94`\0\x86R`@\x85\x01\x92`\0\x84R\x85\x83Q\x97\x83`\0\x14a$\xB7W\x83\x98`\0\x90[\x80\x82\x10a$\x99WPPa$\x8Ca$\x95\x96\x97\x98\x99`\0\x19\x01[\x80\x84R\x85\x87a&?V[\x90RQ\x92a&\xB8V[\x90RV[\x90\x99`\0\x80Q` a(\xD7\x839\x81Q\x91R\x81`\x01\x92\t\x9A\x01\x90a$jV[a$\x95\x95\x96\x97\x98Pa$\x8C\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a$\x82V[\x90`@` \x84\x01Q\x93\x01Q\x92``\x83\x01Q`\x80\x84\x01Q\x94a\x01\xA0\x84\x01Q`\0\x80Q` a(\xD7\x839\x81Q\x91R\x87\x81\x87\x81\x80\x80\x9C\x98\x81\x80\x80\x80\x9E\x81\x80\x9E\x9C\x81\x80\x9E\x81a\x02@\x81\x96\x01Q\x8A\t\x92\x08\x08`\x01\t\x81a\x01\xC0\x89\x01Q\x81\x8C\x81a\x02`\x8D\x01Q\x8A\t\x92\x08\x08\x90\t\x81a\x01\xE0\x88\x01Q\x81\x8B\x81a\x02\x80\x8C\x01Q\x89\t\x92\x08\x08\x90\t\x91\x81\x88\x81a\x02\0\x89\x01Q\x93a\x02\xA0\x8A\x01Q\x90\t\x92\x08\x08\x90\t\x93a\x02\xC0a\x02 \x84\x01Q\x93\x01Q\x92\x08\t\x90\t\x93` \x87Q\x97\x01Q\t\x82\x03\x90\x08\x92\t\x82\x03\x90\x08\x90V[` \x81Q\x91\x01Q\x90\x81\x15\x81\x15\x16a&;W\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X]\x97\x81j\x91hq\xCA\x8D< \x8C\x16\xD8|\xFDG\x80\x80`\x03\x81\x80\x86\x80\t\x86\t\x08\x81\x85\x80\t\x14\x93\x10\x91\x10\x16\x16\x15a%\xF6WV[`@QbF\x1B\xCD`\xE5\x1B\x81R` `\x04\x82\x01R`\x17`$\x82\x01R\x7FBn254: invalid G1 point\0\0\0\0\0\0\0\0\0`D\x82\x01R`d\x90\xFD[PPV[`\x01\x82\x14a&\xB0W\x82\x15a&\xA8W` \x01Q`\0\x80Q` a(\xD7\x839\x81Q\x91R\x92\x83\x91\x90\t\x90\x80\x15a&~Wa&y\x90`\0\x19\x01a(&V[\x90\t\x90V[Pa&y\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\0a(&V[PPP`\0\x90V[PPP`\x01\x90V[\x93\x92\x91\x90\x91\x80\x15a'\xC2Wa&\xCE\x92\x91\x92a\x1F\xD2V[\x91`\xE0\x83\x01\x93`@\x87\x01\x94`\xE0\x86Q\x01\x90`\x01\x90`\x01\x81R`\x01\x90[`\x08\x82\x10a'\x88WPPPP`\0\x94`\x01\x94\x92\x90Q\x90`\0\x90[`\x08\x82\x10a'=WPPPPP\x93a'3\x91` \x94\x95`\0\x80Q` a(\xD7\x839\x81Q\x91R\x95\x86\x94\x85\x93a(&V[\x93\x01Q\x90\t\t\t\x90V[\x90\x91\x92\x93\x95\x96`\x01\x90\x84Q\x98\x89\x87\x8A`\0\x80Q` a(\xD7\x839\x81Q\x91R\x94\x85\x80\x94\x81\x80\x94\x81\x8CQ\x91Q\x8A\t\t\t\x90\x08\x9B\x82\x03\x08\x90\t\x96` \x80\x80\x92\x01\x93\x01\x94\x01\x92\x01\x90\x93\x92a'\x04V[`\x01\x90`\x1F\x99\x95\x96\x99\x19\x80\x91\x01\x93`\0\x80Q` a(\xD7\x839\x81Q\x91R\x90\x81\x89\x88Q\x82\x03\x08\x90\t\x94\x85\x85R\x01\x91\x01\x90\x92\x91\x97\x94\x93\x97a&\xEAV[P\x91\x92`\x01\x92\x91`\0\x91\x90\x84[`\x08\x84\x10a'\xE2WPPPPPP`\0\x90V[\x80\x85\x14a(\x13W`\0\x80Q` a(\xD7\x839\x81Q\x91R\x86\x91a(\x08`@\x86\x01Q` \x01\x90V[Q\x90\t\x93\x01\x92a'\xCFV[P\x91\x92PPa(\"\x92Pa\t\x08V[Q\x90V[\x90`@Q\x91`\0`\xC0` \x94\x85\x93\x84\x82R\x84\x80\x83\x01R\x84`@\x83\x01R``\x82\x01R\x7F0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xEF\xFF\xFF\xFF`\x80\x82\x01R`\0\x80Q` a(\xD7\x839\x81Q\x91R`\xA0\x82\x01R`\x05Z\xFA\x91`\0Q\x92\x15a(\x92WPV[`d\x90`@Q\x90bF\x1B\xCD`\xE5\x1B\x82R`\x04\x82\x01R`\x1D`$\x82\x01R\x7FBn254: pow precompile failed!\0\0\0`D\x82\x01R\xFD\xFE0dNr\xE11\xA0)\xB8PE\xB6\x81\x81X](3\xE8Hy\xB9p\x91C\xE1\xF5\x93\xF0\0\0\x01\xA1dsolcC\0\x08\x17\0\n"; + /// The deployed bytecode of the contract. + pub static PLONKVERIFIER2_DEPLOYED_BYTECODE: ::ethers::core::types::Bytes = + ::ethers::core::types::Bytes::from_static(__DEPLOYED_BYTECODE); + pub struct PlonkVerifier2(::ethers::contract::Contract); + impl ::core::clone::Clone for PlonkVerifier2 { + fn clone(&self) -> Self { + Self(::core::clone::Clone::clone(&self.0)) + } + } + impl ::core::ops::Deref for PlonkVerifier2 { + type Target = ::ethers::contract::Contract; + fn deref(&self) -> &Self::Target { + &self.0 + } + } + impl ::core::ops::DerefMut for PlonkVerifier2 { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + impl ::core::fmt::Debug for PlonkVerifier2 { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_tuple(::core::stringify!(PlonkVerifier2)) + .field(&self.address()) + .finish() + } + } + impl PlonkVerifier2 { + /// Creates a new contract instance with the specified `ethers` client at + /// `address`. The contract derefs to a `ethers::Contract` object. + pub fn new>( + address: T, + client: ::std::sync::Arc, + ) -> Self { + Self(::ethers::contract::Contract::new( + address.into(), + PLONKVERIFIER2_ABI.clone(), + client, + )) + } + /// Constructs the general purpose `Deployer` instance based on the provided constructor arguments and sends it. + /// Returns a new instance of a deployer that returns an instance of this contract after sending the transaction + /// + /// Notes: + /// - If there are no constructor arguments, you should pass `()` as the argument. + /// - The default poll duration is 7 seconds. + /// - The default number of confirmations is 1 block. + /// + /// + /// # Example + /// + /// Generate contract bindings with `abigen!` and deploy a new contract instance. + /// + /// *Note*: this requires a `bytecode` and `abi` object in the `greeter.json` artifact. + /// + /// ```ignore + /// # async fn deploy(client: ::std::sync::Arc) { + /// abigen!(Greeter, "../greeter.json"); + /// + /// let greeter_contract = Greeter::deploy(client, "Hello world!".to_string()).unwrap().send().await.unwrap(); + /// let msg = greeter_contract.greet().call().await.unwrap(); + /// # } + /// ``` + pub fn deploy( + client: ::std::sync::Arc, + constructor_args: T, + ) -> ::core::result::Result< + ::ethers::contract::builders::ContractDeployer, + ::ethers::contract::ContractError, + > { + let factory = ::ethers::contract::ContractFactory::new( + PLONKVERIFIER2_ABI.clone(), + PLONKVERIFIER2_BYTECODE.clone().into(), + client, + ); + let deployer = factory.deploy(constructor_args)?; + let deployer = ::ethers::contract::ContractDeployer::new(deployer); + Ok(deployer) + } + ///Calls the contract's `P_MOD` (0x1d712e27) function + pub fn p_mod( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([29, 113, 46, 39], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `R_MOD` (0xdf6e6cb4) function + pub fn r_mod( + &self, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([223, 110, 108, 180], ()) + .expect("method not found (this should never happen)") + } + ///Calls the contract's `verify` (0x64e4c59e) function + pub fn verify( + &self, + vk: VerifyingKey, + public_input: [::ethers::core::types::U256; 8], + proof: PlonkProof, + ) -> ::ethers::contract::builders::ContractCall { + self.0 + .method_hash([100, 228, 197, 158], (vk, public_input, proof)) + .expect("method not found (this should never happen)") + } + } + impl From<::ethers::contract::Contract> + for PlonkVerifier2 + { + fn from(contract: ::ethers::contract::Contract) -> Self { + Self::new(contract.address(), contract.client()) + } + } + ///Custom Error type `UnsupportedDegree` with signature `UnsupportedDegree()` and selector `0xe2ef09e5` + #[derive( + Clone, + ::ethers::contract::EthError, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[etherror(name = "UnsupportedDegree", abi = "UnsupportedDegree()")] + pub struct UnsupportedDegree; + ///Container type for all input parameters for the `P_MOD` function with signature `P_MOD()` and selector `0x1d712e27` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "P_MOD", abi = "P_MOD()")] + pub struct PModCall; + ///Container type for all input parameters for the `R_MOD` function with signature `R_MOD()` and selector `0xdf6e6cb4` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + #[ethcall(name = "R_MOD", abi = "R_MOD()")] + pub struct RModCall; + ///Container type for all input parameters for the `verify` function with signature `verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),bytes32,bytes32),uint256[8],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))` and selector `0x64e4c59e` + #[derive( + Clone, + ::ethers::contract::EthCall, + ::ethers::contract::EthDisplay, + serde::Serialize, + serde::Deserialize, + )] + #[ethcall( + name = "verify", + abi = "verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),bytes32,bytes32),uint256[8],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))" + )] + pub struct VerifyCall { + pub vk: VerifyingKey, + pub public_input: [::ethers::core::types::U256; 8], + pub proof: PlonkProof, + } + ///Container type for all of the contract's call + #[derive(Clone, ::ethers::contract::EthAbiType, serde::Serialize, serde::Deserialize)] + pub enum PlonkVerifier2Calls { + PMod(PModCall), + RMod(RModCall), + Verify(VerifyCall), + } + impl ::ethers::core::abi::AbiDecode for PlonkVerifier2Calls { + fn decode( + data: impl AsRef<[u8]>, + ) -> ::core::result::Result { + let data = data.as_ref(); + if let Ok(decoded) = ::decode(data) { + return Ok(Self::PMod(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::RMod(decoded)); + } + if let Ok(decoded) = ::decode(data) { + return Ok(Self::Verify(decoded)); + } + Err(::ethers::core::abi::Error::InvalidData.into()) + } + } + impl ::ethers::core::abi::AbiEncode for PlonkVerifier2Calls { + fn encode(self) -> Vec { + match self { + Self::PMod(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::RMod(element) => ::ethers::core::abi::AbiEncode::encode(element), + Self::Verify(element) => ::ethers::core::abi::AbiEncode::encode(element), + } + } + } + impl ::core::fmt::Display for PlonkVerifier2Calls { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + match self { + Self::PMod(element) => ::core::fmt::Display::fmt(element, f), + Self::RMod(element) => ::core::fmt::Display::fmt(element, f), + Self::Verify(element) => ::core::fmt::Display::fmt(element, f), + } + } + } + impl ::core::convert::From for PlonkVerifier2Calls { + fn from(value: PModCall) -> Self { + Self::PMod(value) + } + } + impl ::core::convert::From for PlonkVerifier2Calls { + fn from(value: RModCall) -> Self { + Self::RMod(value) + } + } + impl ::core::convert::From for PlonkVerifier2Calls { + fn from(value: VerifyCall) -> Self { + Self::Verify(value) + } + } + ///Container type for all return fields from the `P_MOD` function with signature `P_MOD()` and selector `0x1d712e27` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct PModReturn(pub ::ethers::core::types::U256); + ///Container type for all return fields from the `R_MOD` function with signature `R_MOD()` and selector `0xdf6e6cb4` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct RModReturn(pub ::ethers::core::types::U256); + ///Container type for all return fields from the `verify` function with signature `verify((uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),bytes32,bytes32),uint256[8],((uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256,uint256))` and selector `0x64e4c59e` + #[derive( + Clone, + ::ethers::contract::EthAbiType, + ::ethers::contract::EthAbiCodec, + serde::Serialize, + serde::Deserialize, + Default, + Debug, + PartialEq, + Eq, + Hash, + )] + pub struct VerifyReturn { + pub success: bool, + } +} diff --git a/contract-bindings/src/shared_types.rs b/contract-bindings/src/shared_types.rs index 11200e7b1c..99775566a9 100644 --- a/contract-bindings/src/shared_types.rs +++ b/contract-bindings/src/shared_types.rs @@ -53,7 +53,7 @@ pub struct PlonkProof { pub sigma_eval_3: ::ethers::core::types::U256, pub prod_perm_zeta_omega_eval: ::ethers::core::types::U256, } -///`VerifyingKey(uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256))` +///`VerifyingKey(uint256,uint256,(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),(uint256,uint256),bytes32,bytes32)` #[derive( Clone, ::ethers::contract::EthAbiType, @@ -87,6 +87,8 @@ pub struct VerifyingKey { pub q_h3: G1Point, pub q_h4: G1Point, pub q_ecc: G1Point, + pub g_2lsb: [u8; 32], + pub g_2msb: [u8; 32], } ///`HotShotCommitment(uint64,uint256)` #[derive( diff --git a/contracts/rust/adapter/Cargo.toml b/contracts/rust/adapter/Cargo.toml index 4de7b90d8d..d242940fc4 100644 --- a/contracts/rust/adapter/Cargo.toml +++ b/contracts/rust/adapter/Cargo.toml @@ -8,8 +8,11 @@ edition = { workspace = true } [dependencies] anyhow = { workspace = true } ark-bn254 = { workspace = true } +ark-ec = { workspace = true } +ark-ed-on-bn254 = { workspace = true } ark-ff = { workspace = true } ark-poly = { workspace = true } +ark-serialize = { workspace = true } ark-std = { workspace = true } contract-bindings = { path = "../../../contract-bindings" } diff-test-bn254 = { git = "https://github.com/EspressoSystems/solidity-bn254.git" } diff --git a/contracts/rust/adapter/src/bin/eval_domain.rs b/contracts/rust/adapter/src/bin/eval_domain.rs index 40e4a1f654..cce85cc9ad 100644 --- a/contracts/rust/adapter/src/bin/eval_domain.rs +++ b/contracts/rust/adapter/src/bin/eval_domain.rs @@ -5,7 +5,7 @@ use ark_ff::{Field, PrimeField}; use ark_poly::{EvaluationDomain, Radix2EvaluationDomain}; fn main() { - let domain = Radix2EvaluationDomain::::new(2u32.pow(20) as usize).unwrap(); + let domain = Radix2EvaluationDomain::::new(2u32.pow(5) as usize).unwrap(); let size_inv = <::BasePrimeField as PrimeField>::into_bigint(domain.size_inv); let size_inv_str = format!("0x{:X}", size_inv).to_lowercase(); @@ -23,4 +23,17 @@ fn main() { "groupGen: {}, groupGenInv: {}", group_gen_str, group_gen_inv_str, ); + + let mut domain_elements_str = "".to_owned(); + + // Generates the domain elements for 8 inputs: 1, g, g^2,...,g^7 + for i in 0..8 { + let mut element_fr = domain.group_gen; + element_fr = element_fr.pow([i]); + + let element_bigint = element_fr.into_bigint(); + let new_element_str = format!("0x{:X} ", element_bigint.clone()).to_lowercase(); + domain_elements_str = domain_elements_str.to_owned() + &new_element_str; + } + println!("domain elements: {}", &domain_elements_str); } diff --git a/contracts/rust/adapter/src/jellyfish.rs b/contracts/rust/adapter/src/jellyfish.rs index cd8b0cad16..85ef13fa63 100644 --- a/contracts/rust/adapter/src/jellyfish.rs +++ b/contracts/rust/adapter/src/jellyfish.rs @@ -10,14 +10,14 @@ use ethers::{ abi::AbiDecode, prelude::{AbiError, EthAbiCodec, EthAbiType}, types::{Bytes, H256, U256}, + utils::hex::ToHex, }; use jf_pcs::prelude::Commitment; -use jf_plonk::{ - constants::KECCAK256_STATE_SIZE, - proof_system::structs::{OpenKey, Proof, ProofEvaluations, VerifyingKey}, - testing_apis::Challenges, - transcript::SolidityTranscript, -}; +use jf_plonk::constants::KECCAK256_STATE_SIZE; +use jf_plonk::proof_system::structs::{OpenKey, Proof, ProofEvaluations, VerifyingKey}; +use jf_plonk::testing_apis::Challenges; +use jf_plonk::transcript::SolidityTranscript; +use jf_utils::to_bytes; use num_bigint::BigUint; use num_traits::Num; @@ -96,8 +96,8 @@ pub fn open_key() -> OpenKey { /// an intermediate representation of the transcript parsed from abi.encode(transcript) from Solidity. #[derive(Clone, EthAbiType, EthAbiCodec)] pub struct ParsedTranscript { - pub(crate) transcript: Bytes, pub(crate) state: H256, + pub(crate) transcript: Bytes, } impl FromStr for ParsedTranscript { @@ -110,10 +110,10 @@ impl FromStr for ParsedTranscript { impl From for ParsedTranscript { fn from(t: SolidityTranscript) -> Self { - let (transcript, state) = t.internal(); + let (state, transcript) = t.internal(); Self { - transcript: transcript.into(), state: H256::from_slice(&state), + transcript: transcript.into(), } } } @@ -122,7 +122,7 @@ impl From for SolidityTranscript { fn from(t: ParsedTranscript) -> Self { let mut state = [0u8; KECCAK256_STATE_SIZE]; state.copy_from_slice(&t.state.to_fixed_bytes()); - Self::from_internal(t.transcript.to_vec(), state) + Self::from_internal(state, t.transcript.to_vec()) } } @@ -149,6 +149,8 @@ pub struct ParsedVerifyingKey { pub q_h_3: ParsedG1Point, pub q_h_4: ParsedG1Point, pub q_ecc: ParsedG1Point, + pub g2_lsb: H256, + pub g2_msb: H256, } impl FromStr for ParsedVerifyingKey { @@ -161,6 +163,29 @@ impl FromStr for ParsedVerifyingKey { impl From> for ParsedVerifyingKey { fn from(vk: VerifyingKey) -> Self { + let g2_bytes = to_bytes!(&vk.open_key.powers_of_h[1]).unwrap(); + assert!(g2_bytes.len() == 64); + let mut g2_lsb = [0u8; 32]; + let mut g2_msb = [0u8; 32]; + g2_lsb.copy_from_slice(&g2_bytes[..32]); + g2_msb.copy_from_slice(&g2_bytes[32..]); + + // since G2 point from the Aztec's SRS we use is fixed + // remove these sanity check if using other SRS + // generated via: + // ```rust + // let srs = ark_srs::kzg10::aztec20::setup(2u64.pow(6) as usize + 2).expect("Aztec SRS fail to load"); + // println!("{}", hex::encode(jf_utils::to_bytes!(&srs.beta_h).unwrap())); + // ```` + assert_eq!( + g2_lsb.encode_hex::(), + String::from("b0838893ec1f237e8b07323b0744599f4e97b598b3b589bcc2bc37b8d5c41801") + ); + assert_eq!( + g2_msb.encode_hex::(), + String::from("c18393c0fa30fe4e8b038e357ad851eae8de9107584effe7c7f1f651b2010e26") + ); + Self { domain_size: U256::from(vk.domain_size), num_inputs: U256::from(vk.num_inputs), @@ -182,6 +207,8 @@ impl From> for ParsedVerifyingKey { q_o: vk.selector_comms[10].0.into(), q_c: vk.selector_comms[11].0.into(), q_ecc: vk.selector_comms[12].0.into(), + g2_lsb: g2_lsb.into(), + g2_msb: g2_msb.into(), } } } @@ -467,7 +494,7 @@ impl From> for ParsedChallenges { impl From for Challenges { fn from(c: ParsedChallenges) -> Self { Self { - tau: Fr::from(0u32), + tau: None, alpha: u256_to_field(c.alpha), beta: u256_to_field(c.beta), gamma: u256_to_field(c.gamma), diff --git a/contracts/rust/diff-test/src/main.rs b/contracts/rust/diff-test/src/main.rs index e92cfd3ce3..bfee9075d6 100644 --- a/contracts/rust/diff-test/src/main.rs +++ b/contracts/rust/diff-test/src/main.rs @@ -2,10 +2,12 @@ use ark_bn254::{Bn254, Fq, Fr, G1Affine, G2Affine}; use ark_ec::{AffineRepr, CurveGroup}; use ark_ed_on_bn254::{EdwardsConfig as EdOnBn254Config, Fq as FqEd254}; use ark_ff::field_hashers::{DefaultFieldHasher, HashToField}; -use ark_poly::{domain::radix2::Radix2EvaluationDomain, EvaluationDomain}; +use ark_poly::domain::radix2::Radix2EvaluationDomain; +use ark_poly::EvaluationDomain; use ark_std::rand::{rngs::StdRng, Rng, SeedableRng}; use clap::{Parser, ValueEnum}; use diff_test_bn254::ParsedG2Point; + use ethers::{ abi::{AbiDecode, AbiEncode, Address}, types::{Bytes, U256}, @@ -14,21 +16,16 @@ use hotshot_contract_adapter::{jellyfish::*, light_client::ParsedLightClientStat use hotshot_state_prover::mock_ledger::{ gen_plonk_proof_for_test, MockLedger, MockSystemParam, BLOCKS_PER_EPOCH, STAKE_TABLE_CAPACITY, }; -use itertools::multiunzip; use jf_pcs::prelude::Commitment; +use jf_plonk::proof_system::structs::{Proof, VerifyingKey}; +use jf_plonk::proof_system::PlonkKzgSnark; use jf_plonk::{ - proof_system::{ - structs::{Proof, VerifyingKey}, - PlonkKzgSnark, - }, testing_apis::Verifier, transcript::{PlonkTranscript, SolidityTranscript}, }; -use jf_signature::{ - bls_over_bn254::{hash_to_curve, KeyPair as BLSKeyPair, Signature}, - constants::CS_ID_BLS_BN254, - schnorr::KeyPair as SchnorrKeyPair, -}; +use jf_signature::bls_over_bn254::{hash_to_curve, KeyPair as BLSKeyPair, Signature}; +use jf_signature::constants::CS_ID_BLS_BN254; +use jf_signature::schnorr::KeyPair as SchnorrKeyPair; use sha3::Keccak256; #[derive(Parser)] @@ -66,12 +63,8 @@ enum Action { PlonkConstants, /// Get jf_plonk::Verifier::compute_challenges() PlonkComputeChal, - /// Get jf_plonk::Verifier::aggregate_evaluations() - PlonkPrepareEval, - /// Get jf_plonk::Verifier::prepare_pcs_info() - PlonkPreparePcsInfo, /// Get jf_plonk::Verifier::batch_verify() - PlonkBatchVerify, + PlonkVerify, /// Get a random, dummy proof with correct format DummyProof, /// Test only logic @@ -111,7 +104,6 @@ fn main() { let res = ( field_to_u256(domain.size_inv), field_to_u256(domain.group_gen), - field_to_u256(domain.group_gen_inv), ); println!("{}", res.encode_hex()); } @@ -137,7 +129,7 @@ fn main() { let log_size = cli.args[0].parse::().unwrap(); let zeta = u256_to_field::(cli.args[1].parse::().unwrap()); - let pi_u256: Vec = AbiDecode::decode_hex(&cli.args[2]).unwrap(); + let pi_u256: [U256; 8] = AbiDecode::decode_hex(&cli.args[2]).unwrap(); let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); let verifier = Verifier::::new(2u32.pow(log_size) as usize).unwrap(); @@ -174,7 +166,7 @@ fn main() { let field = u256_to_field::(cli.args[1].parse::().unwrap()); let mut t: SolidityTranscript = t_parsed.into(); - t.append_challenge::(&[], &field).unwrap(); + t.append_field_elem::(&[], &field).unwrap(); let res: ParsedTranscript = t.into(); println!("{}", (res,).encode_hex()); } @@ -200,7 +192,7 @@ fn main() { let t_parsed = cli.args[0].parse::().unwrap(); let mut t: SolidityTranscript = t_parsed.into(); - let chal = t.get_and_append_challenge::(&[]).unwrap(); + let chal = t.get_challenge::(&[]).unwrap(); let updated_t: ParsedTranscript = t.into(); let res = (updated_t, field_to_u256(chal)); @@ -235,7 +227,7 @@ fn main() { let proof: Proof = proof_parsed.clone().into(); let mut t: SolidityTranscript = t_parsed.into(); - >::append_proof_evaluations::( + >::append_proof_evaluations::( &mut t, &proof.poly_evals, ) @@ -269,7 +261,7 @@ fn main() { } let vk = cli.args[0].parse::().unwrap().into(); - let pi_u256: Vec = AbiDecode::decode_hex(&cli.args[1]).unwrap(); + let pi_u256: [U256; 8] = AbiDecode::decode_hex(&cli.args[1]).unwrap(); let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); let proof: Proof = cli.args[2].parse::().unwrap().into(); let msg = { @@ -288,110 +280,33 @@ fn main() { .into(); println!("{}", (chal,).encode_hex()); } - Action::PlonkPrepareEval => { - if cli.args.len() != 3 { - panic!("Should provide arg1=proof, arg2=linPolyConstant, arg3=commScalars"); - } - - let proof: Proof = cli.args[0].parse::().unwrap().into(); - let lin_poly_constant = u256_to_field::(cli.args[1].parse::().unwrap()); - let comm_scalars_u256: Vec = AbiDecode::decode_hex(&cli.args[2]).unwrap(); - // NOTE: only take the last 10 scalars, the first 20 are linearization scalars - let comm_scalars: Vec = comm_scalars_u256 - .into_iter() - .skip(20) - .map(u256_to_field) - .collect(); - - let eval = Verifier::::aggregate_evaluations( - &lin_poly_constant, - &[proof.poly_evals], - &[None], - &comm_scalars, - ) - .unwrap(); - let res = field_to_u256(eval); - println!("{}", (res,).encode_hex()); - } - Action::PlonkPreparePcsInfo => { - if cli.args.len() != 3 { - panic!("Should provide arg1=verifyingKey, arg2=publicInput, arg3=proof"); - } - - let vk: VerifyingKey = cli.args[0].parse::().unwrap().into(); - let pi_u256: Vec = AbiDecode::decode_hex(&cli.args[1]).unwrap(); - let pi: Vec = pi_u256.into_iter().map(u256_to_field).collect(); - let proof: Proof = cli.args[2].parse::().unwrap().into(); - - let verifier = Verifier::::new(vk.domain_size).unwrap(); - let pcs_info = verifier - .prepare_pcs_info::( - &[&vk], - &[&pi], - &proof.into(), - &Some(vec![]), - ) - .unwrap(); - - let scalars_and_bases_prod: ParsedG1Point = pcs_info - .comm_scalars_and_bases - .multi_scalar_mul() - .into_affine() - .into(); - let opening_proof: ParsedG1Point = pcs_info.opening_proof.0.into(); - let shifted_opening_proof: ParsedG1Point = pcs_info.shifted_opening_proof.0.into(); - let res = ( - field_to_u256(pcs_info.u), - field_to_u256(pcs_info.eval_point), - field_to_u256(pcs_info.next_eval_point), - field_to_u256(pcs_info.eval), - scalars_and_bases_prod, - opening_proof, - shifted_opening_proof, - ); - println!("{}", res.encode_hex()); - } - Action::PlonkBatchVerify => { - if cli.args.len() != 1 { - panic!("Should provide arg1=numProof"); - } - - let num_proof = cli.args[0].parse::().unwrap(); - let (proofs, vks, public_inputs, extra_msgs, _): ( - Vec>, - Vec>, - Vec>, - Vec>>, - Vec, - ) = multiunzip(gen_plonk_proof_for_test(num_proof as usize)); + Action::PlonkVerify => { + let (proof, vk, public_input, _, _): ( + Proof, + VerifyingKey, + Vec, + Option>, // won't use extraTranscriptMsg + usize, // won't use circuit size + ) = gen_plonk_proof_for_test(1)[0].clone(); // ensure they are correct params - let proofs_refs: Vec<&Proof> = proofs.iter().collect(); - let vks_refs: Vec<&VerifyingKey> = vks.iter().collect(); - let pi_refs: Vec<&[Fr]> = public_inputs - .iter() - .map(|pub_input| &pub_input[..]) - .collect(); assert!(PlonkKzgSnark::batch_verify::( - &vks_refs, - &pi_refs, - &proofs_refs, - &extra_msgs + &[&vk], + &[&public_input], + &[&proof], + &[None] ) .is_ok()); - let vks_parsed: Vec = vks.into_iter().map(Into::into).collect(); - let pis_parsed: Vec> = public_inputs - .into_iter() - .map(|pi| pi.into_iter().map(field_to_u256).collect()) - .collect(); - let proofs_parsed: Vec = proofs.into_iter().map(Into::into).collect(); - let msgs_parsed: Vec = extra_msgs - .into_iter() - .map(|msg| msg.unwrap().into()) - .collect(); - - let res = (vks_parsed, pis_parsed, proofs_parsed, msgs_parsed); + let vk_parsed: ParsedVerifyingKey = vk.into(); + let mut pi_parsed = [U256::default(); 8]; + assert_eq!(public_input.len(), 8); + for (i, pi) in public_input.into_iter().enumerate() { + pi_parsed[i] = field_to_u256(pi); + } + let proof_parsed: ParsedPlonkProof = proof.into(); + + let res = (vk_parsed, pi_parsed, proof_parsed); println!("{}", res.encode_hex()); } Action::DummyProof => { diff --git a/contracts/rust/gen-vk-contract/Cargo.toml b/contracts/rust/gen-vk-contract/Cargo.toml index dc4920fc7a..45d245871f 100644 --- a/contracts/rust/gen-vk-contract/Cargo.toml +++ b/contracts/rust/gen-vk-contract/Cargo.toml @@ -7,6 +7,7 @@ edition = { workspace = true } [dependencies] ark-srs = { workspace = true } +ethers = { version = "2.0.4" } hotshot-contract-adapter = { path = "../adapter" } hotshot-stake-table = { workspace = true } hotshot-state-prover = { path = "../../../hotshot-state-prover" } diff --git a/contracts/rust/gen-vk-contract/src/main.rs b/contracts/rust/gen-vk-contract/src/main.rs index 24530124c4..20090d1906 100644 --- a/contracts/rust/gen-vk-contract/src/main.rs +++ b/contracts/rust/gen-vk-contract/src/main.rs @@ -4,6 +4,7 @@ use std::{fs::OpenOptions, io::Write, path::PathBuf, process::Command}; +use ethers::core::abi::AbiEncode; use hotshot_contract_adapter::jellyfish::ParsedVerifyingKey; use hotshot_stake_table::config::STAKE_TABLE_CAPACITY; use jf_pcs::prelude::UnivariateUniversalParams; @@ -127,6 +128,10 @@ fn main() { // qEcc mstore(mload(add(vk, 0x260)), {}) mstore(add(mload(add(vk, 0x260)), 0x20), {}) + // g2LSB + mstore(add(vk, 0x280), {}) + // g2MSB + mstore(add(vk, 0x2A0), {}) }} }} }}", @@ -169,6 +174,8 @@ fn main() { vk.q_h_4.y, vk.q_ecc.x, vk.q_ecc.y, + vk.g2_lsb.encode_hex(), + vk.g2_msb.encode_hex(), ) .into_bytes(); diff --git a/contracts/src/LightClient.sol b/contracts/src/LightClient.sol index 751e03dc91..b11c4be19f 100644 --- a/contracts/src/LightClient.sol +++ b/contracts/src/LightClient.sol @@ -19,6 +19,8 @@ import { LightClientStateUpdateVK as VkLib } from "./libraries/LightClientStateU /// Rollup contracts on L1 (Ethereum). /// This state is submitted by any state-prover with evidence which is /// a SNARK proof that proves consensus. +/// This contract also keeps track of the current epoch. +/// For this version, the epoch is not used.
/// The light client state primarily consists of:
/// - the merkle root of finalized block commitments,
/// - the fee ledger commitment and
@@ -299,7 +301,7 @@ contract LightClient is Initializable, OwnableUpgradeable, UUPSUpgradeable { IPlonkVerifier.VerifyingKey memory vk = VkLib.getVk(); // Prepare the public input - uint256[] memory publicInput = new uint256[](8); + uint256[8] memory publicInput; publicInput[0] = votingThreshold; publicInput[1] = uint256(state.viewNum); publicInput[2] = uint256(state.blockHeight); diff --git a/contracts/src/interfaces/IPlonkVerifier.sol b/contracts/src/interfaces/IPlonkVerifier.sol index 6ec8893eca..23077b3426 100644 --- a/contracts/src/interfaces/IPlonkVerifier.sol +++ b/contracts/src/interfaces/IPlonkVerifier.sol @@ -82,18 +82,21 @@ interface IPlonkVerifier { BN254.G1Point qH4; // 0x240 // elliptic curve selector BN254.G1Point qEcc; // 0x260 + // serialized G2 point in SRS (compressed, little-endian, 64 bytes) + // we store the 64 bytes as 2 * bytes32 (first 32 bytes as `g2LSB`) + // (G1 points in SRS are implicited committed via poly commitments) + bytes32 g2LSB; // 0x280 + bytes32 g2MSB; // 0x2A0 } /// @dev Verify a single TurboPlonk proofs. /// @param verifyingKey The Plonk verification key /// @param publicInput The public input fields /// @param proof The TurboPlonk proof - /// @param extraTranscriptInitMsg Optional bytes for transcript init message /// @return _ A boolean indicating successful verification, false otherwise function verify( VerifyingKey memory verifyingKey, - uint256[] memory publicInput, - PlonkProof memory proof, - bytes memory extraTranscriptInitMsg + uint256[8] memory publicInput, + PlonkProof memory proof ) external view returns (bool); } diff --git a/contracts/src/legacy/Transcript.sol b/contracts/src/legacy/Transcript.sol new file mode 100644 index 0000000000..32baf5f45d --- /dev/null +++ b/contracts/src/legacy/Transcript.sol @@ -0,0 +1,213 @@ +// SPDX-License-Identifier: Unlicensed + +pragma solidity ^0.8.0; + +import { BN254 } from "bn254/BN254.sol"; +import { IPlonkVerifier } from "../interfaces/IPlonkVerifier.sol"; + +library Transcript { + struct TranscriptData { + bytes32 state; + bytes transcript; + } + + // ================================ + // Primitive functions + // ================================ + function appendMessage(TranscriptData memory self, bytes memory message) internal pure { + self.transcript = abi.encodePacked(self.transcript, message); + } + + // ================================ + // Transcript APIs + // ================================ + function appendChallenge(TranscriptData memory self, uint256 challenge) internal pure { + self.transcript = abi.encodePacked(self.transcript, challenge); + } + + function appendCommitments(TranscriptData memory self, BN254.G1Point[] memory comms) + internal + pure + { + for (uint256 i = 0; i < comms.length; i++) { + appendCommitment(self, comms[i]); + } + } + + function appendCommitment(TranscriptData memory self, BN254.G1Point memory comm) + internal + pure + { + self.transcript = abi.encodePacked(self.transcript, comm.x, comm.y); + } + + // 1. state = hash(state | transcript) + // 2. transcript = Vec::new() + // 3. challenge = bytes_to_field(state) + // + // Note: every challenge generation is implicitly domain-separated, thus it's safe + // to call it multiple times in a row (e.g. multiple challenges in a single round) + // to get multiple different challenges. + function getChallenge(TranscriptData memory self) internal pure returns (uint256 ret) { + // memory layout: + // offset 0x00: state + // offset 0x20: pointer to transcript (e.g. point to 0x1a0) + // (e.g.0x1a0): length of transcript + // 0x1c0 : transcript bytes + uint256 p = BN254.R_MOD; + + // Instead of using free memory for scratch pad, we do the following trick: + // 1. overwrite offset 0x40 with current state + // 2. compute keccak of "state | transcript" (continuous in memory) + // 3. store the hash to offset 0x00 and update the length of transcript to 0 + // 4. compute challenge from current state + assembly { + let lenPtr := mload(add(self, 0x20)) + // step 1 + let len := mload(lenPtr) + mstore(lenPtr, mload(self)) + + // step 2 + let hash := keccak256(lenPtr, add(len, 0x20)) + // step 3 + mstore(self, hash) + mstore(lenPtr, 0) + // step 4 + ret := mod(hash, p) + } + } + + /// @dev Append the verifying key and the public inputs to the transcript. + /// @param verifyingKey verifying key + /// @param publicInput a list of field elements + function appendVkAndPubInput( + TranscriptData memory self, + IPlonkVerifier.VerifyingKey memory verifyingKey, + uint256[] memory publicInput + ) internal pure { + uint32 sizeInBits = 254; + + self.transcript = abi.encodePacked( + self.transcript, + uint32(sizeInBits), + uint64(verifyingKey.domainSize), + uint64(verifyingKey.numInputs), + bytes12(0) // padding to align with word size + ); + + // G2 point from KZG SRS + self.transcript = abi.encodePacked(self.transcript, verifyingKey.g2LSB, verifyingKey.g2MSB); + + // ===================== + // k: coset representatives + // ===================== + // Currently, K is hardcoded, and there are 5 of them since + // # wire types == 5 + + self.transcript = abi.encodePacked( + self.transcript, + uint256(0x1), // k0 = 1 + uint256(0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a), // k1 + uint256(0x1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025), // k2 + uint256(0x2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a), // k3 + uint256(0x2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881) // k4 + ); + + // selectors + self.transcript = abi.encodePacked( + self.transcript, + verifyingKey.q1.x, + verifyingKey.q1.y, + verifyingKey.q2.x, + verifyingKey.q2.y, + verifyingKey.q3.x, + verifyingKey.q3.y, + verifyingKey.q4.x, + verifyingKey.q4.y + ); + self.transcript = abi.encodePacked( + self.transcript, + verifyingKey.qM12.x, + verifyingKey.qM12.y, + verifyingKey.qM34.x, + verifyingKey.qM34.y + ); + self.transcript = abi.encodePacked( + self.transcript, + verifyingKey.qH1.x, + verifyingKey.qH1.y, + verifyingKey.qH2.x, + verifyingKey.qH2.y, + verifyingKey.qH3.x, + verifyingKey.qH3.y, + verifyingKey.qH4.x, + verifyingKey.qH4.y + ); + self.transcript = abi.encodePacked( + self.transcript, + verifyingKey.qO.x, + verifyingKey.qO.y, + verifyingKey.qC.x, + verifyingKey.qC.y, + verifyingKey.qEcc.x, + verifyingKey.qEcc.y + ); + + // sigmas + self.transcript = abi.encodePacked( + self.transcript, + verifyingKey.sigma0.x, + verifyingKey.sigma0.y, + verifyingKey.sigma1.x, + verifyingKey.sigma1.y, + verifyingKey.sigma2.x, + verifyingKey.sigma2.y + ); + self.transcript = abi.encodePacked( + self.transcript, + verifyingKey.sigma3.x, + verifyingKey.sigma3.y, + verifyingKey.sigma4.x, + verifyingKey.sigma4.y + ); + + // public inputs + self.transcript = abi.encodePacked( + self.transcript, + publicInput[0], + publicInput[1], + publicInput[2], + publicInput[3], + publicInput[4], + publicInput[5], + publicInput[6], + publicInput[7] + ); + } + + /// @dev Append the proof to the transcript. Only used for test purposes. + function appendProofEvaluations( + TranscriptData memory self, + IPlonkVerifier.PlonkProof memory proof + ) internal pure { + self.transcript = abi.encodePacked(self.transcript, proof.wireEval0); + + self.transcript = abi.encodePacked(self.transcript, proof.wireEval1); + + self.transcript = abi.encodePacked(self.transcript, proof.wireEval2); + + self.transcript = abi.encodePacked(self.transcript, proof.wireEval3); + + self.transcript = abi.encodePacked(self.transcript, proof.wireEval4); + + self.transcript = abi.encodePacked(self.transcript, proof.sigmaEval0); + + self.transcript = abi.encodePacked(self.transcript, proof.sigmaEval1); + + self.transcript = abi.encodePacked(self.transcript, proof.sigmaEval2); + + self.transcript = abi.encodePacked(self.transcript, proof.sigmaEval3); + + self.transcript = abi.encodePacked(self.transcript, proof.prodPermZetaOmegaEval); + } +} diff --git a/contracts/src/libraries/LightClientStateUpdateVK.sol b/contracts/src/libraries/LightClientStateUpdateVK.sol index 8188c54093..edd3eeefb4 100644 --- a/contracts/src/libraries/LightClientStateUpdateVK.sol +++ b/contracts/src/libraries/LightClientStateUpdateVK.sol @@ -192,6 +192,14 @@ library LightClientStateUpdateVK { add(mload(add(vk, 0x260)), 0x20), 20309550876545766116130682111350015544103338784776768395329281357767924326613 ) + // g2LSB + mstore( + add(vk, 0x280), 0xb0838893ec1f237e8b07323b0744599f4e97b598b3b589bcc2bc37b8d5c41801 + ) + // g2MSB + mstore( + add(vk, 0x2A0), 0xc18393c0fa30fe4e8b038e357ad851eae8de9107584effe7c7f1f651b2010e26 + ) } } } diff --git a/contracts/src/libraries/PlonkVerifier.sol b/contracts/src/libraries/PlonkVerifier.sol index a76430ca7d..f6b23a8f5e 100644 --- a/contracts/src/libraries/PlonkVerifier.sol +++ b/contracts/src/libraries/PlonkVerifier.sol @@ -2,10 +2,9 @@ pragma solidity ^0.8.0; -import { BN254, Utils } from "bn254/BN254.sol"; +import { BN254 } from "bn254/BN254.sol"; import { PolynomialEval as Poly } from "./PolynomialEval.sol"; import { IPlonkVerifier } from "../interfaces/IPlonkVerifier.sol"; -import { Transcript } from "./Transcript.sol"; /* solhint-disable no-inline-assembly */ @@ -22,8 +21,6 @@ library PlonkVerifier { /// Plonk: wrong verification key used. error WrongPlonkVK(); - using Transcript for Transcript.TranscriptData; - // _COSET_K0 = 1, has no effect during multiplication, thus avoid declaring it here. uint256 internal constant COSET_K1 = 0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a; @@ -51,26 +48,6 @@ library PlonkVerifier { /// The number of wire types of the circuit, TurboPlonk has 5. uint256 internal constant NUM_WIRE_TYPES = 5; - /// @dev polynomial commitment evaluation info. - struct PcsInfo { - // a random combiner that was used to combine evaluations at point - uint256 u; // 0x00 - // the point to be evaluated at - uint256 evalPoint; // 0x20 - // the shifted point to be evaluated at - uint256 nextEvalPoint; // 0x40 - // the polynomial evaluation value - uint256 eval; // 0x60 - // scalars of poly comm for MSM - uint256[] commScalars; // 0x80 - // bases of poly comm for MSM - BN254.G1Point[] commBases; // 0xa0 - // proof of evaluations at point `eval_point` - BN254.G1Point openingProof; // 0xc0 - // proof of evaluations at point `next_eval_point` - BN254.G1Point shiftedOpeningProof; // 0xe0 - } - /// @dev Plonk IOP verifier challenges. struct Challenges { uint256 alpha; // 0x00 @@ -90,7 +67,7 @@ library PlonkVerifier { /// @return _ A boolean indicating successful verification, false otherwise function verify( IPlonkVerifier.VerifyingKey memory verifyingKey, - uint256[] memory publicInput, + uint256[8] memory publicInput, IPlonkVerifier.PlonkProof memory proof ) external view returns (bool) { _validateProof(proof); @@ -104,8 +81,7 @@ library PlonkVerifier { BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[6])); BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[7])); - PcsInfo memory pcsInfo = _preparePcsInfo(verifyingKey, publicInput, proof); - return _verifyOpeningProofs(pcsInfo); + return _verify(verifyingKey, publicInput, proof); } /// @dev Validate all group points and scalar fields. Revert if @@ -137,12 +113,13 @@ library PlonkVerifier { BN254.validateScalarField(proof.prodPermZetaOmegaEval); } - function _preparePcsInfo( + // core verifier logic, assuming all input arguments are validated + function _verify( IPlonkVerifier.VerifyingKey memory verifyingKey, - uint256[] memory publicInput, + uint256[8] memory publicInput, IPlonkVerifier.PlonkProof memory proof - ) internal view returns (PcsInfo memory res) { - if (publicInput.length != verifyingKey.numInputs) revert WrongPlonkVK(); + ) private view returns (bool) { + if (verifyingKey.numInputs != 8) revert WrongPlonkVK(); Challenges memory chal = _computeChallenges(verifyingKey, publicInput, proof); @@ -150,134 +127,259 @@ library PlonkVerifier { // pre-compute evaluation data Poly.EvalData memory evalData = Poly.evalDataGen(domain, chal.zeta, publicInput); - // compute opening proof in poly comm. - uint256[] memory commScalars = new uint256[](30); - BN254.G1Point[] memory commBases = new BN254.G1Point[](30); + // in the final pairing check: e(a, [x]_2) =?= e(b, [1]_2) + BN254.G1Point memory a; + BN254.G1Point memory b; + + // a = openingProof + shiftedOpeningProof^u + // in Plonk paper: "[Wz]1 + u · [Wzω]1" + a = BN254.add(proof.zeta, BN254.scalarMul(proof.zetaOmega, BN254.ScalarField.wrap(chal.u))); - uint256 eval = - _prepareOpeningProof(verifyingKey, evalData, proof, chal, commScalars, commBases); + // computing b in Plonk paper: "z · [Wz]1 + uzω · [Wzω]1 + [F]1 − [E]1" + (BN254.G1Point memory e1, BN254.G1Point memory f1) = + _preparePolyCommitments(verifyingKey, chal, evalData, proof); + b = BN254.add(f1, BN254.negate(e1)); // [F]1 − [E]1 + // b += proof.zeta^chal.zeta or "z · [Wz]1" + b = BN254.add(b, BN254.scalarMul(proof.zeta, BN254.ScalarField.wrap(chal.zeta))); - uint256 zeta = chal.zeta; - uint256 omega = domain.groupGen; uint256 p = BN254.R_MOD; - uint256 zetaOmega; + uint256 scalar; assembly { - zetaOmega := mulmod(zeta, omega, p) + // chal.zeta + scalar := mload(add(chal, 0xa0)) + // chal.zeta * groupGen or nextEvalPoint or zetaOmega + scalar := mulmod(scalar, mload(add(mload(add(domain, 0x40)), 0x20)), p) + // u * zetaOmega or "uzω" + scalar := mulmod(scalar, mload(add(chal, 0xe0)), p) } + // b += proof.zetaOmega^(u * chal.zeta * groupGen) + b = BN254.add(b, BN254.scalarMul(proof.zetaOmega, BN254.ScalarField.wrap(scalar))); - res = PcsInfo( - chal.u, zeta, zetaOmega, eval, commScalars, commBases, proof.zeta, proof.zetaOmega - ); + BN254.G2Point memory betaH = BN254.G2Point({ + x0: BN254.BaseField.wrap(BETA_H_X1), + x1: BN254.BaseField.wrap(BETA_H_X0), + y0: BN254.BaseField.wrap(BETA_H_Y1), + y1: BN254.BaseField.wrap(BETA_H_Y0) + }); + // Check e(A, [x]2) =?= e(B, [1]2) + // Equivalently, e(A, [x]2) * e(-B, [1]2) =?= 1 + return BN254.pairingProd2(a, betaH, BN254.negate(b), BN254.P2()); } function _computeChallenges( - IPlonkVerifier.VerifyingKey memory verifyingKey, - uint256[] memory publicInput, + IPlonkVerifier.VerifyingKey memory vk, + uint256[8] memory pi, IPlonkVerifier.PlonkProof memory proof ) internal pure returns (Challenges memory res) { - Transcript.TranscriptData memory transcript; uint256 p = BN254.R_MOD; - transcript.appendVkAndPubInput(verifyingKey, publicInput); - - transcript.transcript = abi.encodePacked( - transcript.transcript, - BN254.g1Serialize(proof.wire0), - BN254.g1Serialize(proof.wire1), - BN254.g1Serialize(proof.wire2), - BN254.g1Serialize(proof.wire3), - BN254.g1Serialize(proof.wire4) - ); - - // have to compute tau, but not really used anywhere - // slither-disable-next-line unused-return - transcript.getAndAppendChallenge(); - res.beta = transcript.getAndAppendChallenge(); - res.gamma = transcript.getAndAppendChallenge(); - - transcript.transcript = - abi.encodePacked(transcript.transcript, BN254.g1Serialize(proof.prodPerm)); - - res.alpha = transcript.getAndAppendChallenge(); + assembly { + // use free memory space for scratch pad, 0x40: free memory ptr + let statePtr := mload(0x40) + let dataPtr := add(statePtr, 0x20) + + // Start of transcript (unit: bytes) + // sizeInBits (4) | domainSize (8) | numInputs (8) | pad (12) + mstore(dataPtr, 0) // initialize to 0 first + mstore(dataPtr, shl(224, 254)) // sizeInBits + mstore(add(dataPtr, 4), shl(192, mload(vk))) // domainSize + mstore(add(dataPtr, 12), shl(192, mload(add(vk, 0x20)))) // numInputs + + // G2 from SRS + mstore(add(dataPtr, 0x20), mload(add(vk, 0x280))) // g2LSB (32) + mstore(add(dataPtr, 0x40), mload(add(vk, 0x2a0))) // g2MSB (32) + + // k0 ~ k4 + mstore(add(dataPtr, 0x60), 0x1) + mstore(add(dataPtr, 0x80), COSET_K1) + mstore(add(dataPtr, 0xa0), COSET_K2) + mstore(add(dataPtr, 0xc0), COSET_K3) + mstore(add(dataPtr, 0xe0), COSET_K4) + + // selectors + let q1Ptr := mload(add(vk, 0xe0)) + mstore(add(dataPtr, 0x100), mload(q1Ptr)) // q1.x + mstore(add(dataPtr, 0x120), mload(add(q1Ptr, 0x20))) // q1.y + let q2Ptr := mload(add(vk, 0x100)) + mstore(add(dataPtr, 0x140), mload(q2Ptr)) // q2.x + mstore(add(dataPtr, 0x160), mload(add(q2Ptr, 0x20))) // q2.y + let q3Ptr := mload(add(vk, 0x120)) + mstore(add(dataPtr, 0x180), mload(q3Ptr)) // q3.x + mstore(add(dataPtr, 0x1a0), mload(add(q3Ptr, 0x20))) // q3.y + let q4Ptr := mload(add(vk, 0x140)) + mstore(add(dataPtr, 0x1c0), mload(q4Ptr)) // q4.x + mstore(add(dataPtr, 0x1e0), mload(add(q4Ptr, 0x20))) // q4.y + let qM12Ptr := mload(add(vk, 0x160)) + mstore(add(dataPtr, 0x200), mload(qM12Ptr)) // qM12.x + mstore(add(dataPtr, 0x220), mload(add(qM12Ptr, 0x20))) // qM12.y + let qM34Ptr := mload(add(vk, 0x180)) + mstore(add(dataPtr, 0x240), mload(qM34Ptr)) // qM34.x + mstore(add(dataPtr, 0x260), mload(add(qM34Ptr, 0x20))) // qM34.y + let qH1Ptr := mload(add(vk, 0x1e0)) + mstore(add(dataPtr, 0x280), mload(qH1Ptr)) // qH1.x + mstore(add(dataPtr, 0x2a0), mload(add(qH1Ptr, 0x20))) // qH1.y + let qH2Ptr := mload(add(vk, 0x200)) + mstore(add(dataPtr, 0x2c0), mload(qH2Ptr)) // qH2.x + mstore(add(dataPtr, 0x2e0), mload(add(qH2Ptr, 0x20))) // qH2.y + let qH3Ptr := mload(add(vk, 0x220)) + mstore(add(dataPtr, 0x300), mload(qH3Ptr)) // qH3.x + mstore(add(dataPtr, 0x320), mload(add(qH3Ptr, 0x20))) // qH3.y + let qH4Ptr := mload(add(vk, 0x240)) + mstore(add(dataPtr, 0x340), mload(qH4Ptr)) // qH4.x + mstore(add(dataPtr, 0x360), mload(add(qH4Ptr, 0x20))) // qH4.y + let qOPtr := mload(add(vk, 0x1a0)) + mstore(add(dataPtr, 0x380), mload(qOPtr)) // qO.x + mstore(add(dataPtr, 0x3a0), mload(add(qOPtr, 0x20))) // qO.y + let qCPtr := mload(add(vk, 0x1c0)) + mstore(add(dataPtr, 0x3c0), mload(qCPtr)) // qC.x + mstore(add(dataPtr, 0x3e0), mload(add(qCPtr, 0x20))) // qC.y + let qECCPtr := mload(add(vk, 0x260)) + mstore(add(dataPtr, 0x400), mload(qECCPtr)) // qECC.x + mstore(add(dataPtr, 0x420), mload(add(qECCPtr, 0x20))) // qECC.y + + // sigmas + let sigma0Ptr := mload(add(vk, 0x40)) + mstore(add(dataPtr, 0x440), mload(sigma0Ptr)) // sigma0.x + mstore(add(dataPtr, 0x460), mload(add(sigma0Ptr, 0x20))) // sigma0.y + let sigma1Ptr := mload(add(vk, 0x60)) + mstore(add(dataPtr, 0x480), mload(sigma1Ptr)) // sigma1.x + mstore(add(dataPtr, 0x4a0), mload(add(sigma1Ptr, 0x20))) // sigma1.y + let sigma2Ptr := mload(add(vk, 0x80)) + mstore(add(dataPtr, 0x4c0), mload(sigma2Ptr)) // sigma2.x + mstore(add(dataPtr, 0x4e0), mload(add(sigma2Ptr, 0x20))) // sigma2.y + let sigma3Ptr := mload(add(vk, 0xa0)) + mstore(add(dataPtr, 0x500), mload(sigma3Ptr)) // sigma3.x + mstore(add(dataPtr, 0x520), mload(add(sigma3Ptr, 0x20))) // sigma3.y + let sigma4Ptr := mload(add(vk, 0xc0)) + mstore(add(dataPtr, 0x540), mload(sigma4Ptr)) // sigma4.x + mstore(add(dataPtr, 0x560), mload(add(sigma4Ptr, 0x20))) // sigma4.y + + // public inputs + mstore(add(dataPtr, 0x580), mload(pi)) // PI[0] + mstore(add(dataPtr, 0x5a0), mload(add(pi, 0x20))) // PI[1] + mstore(add(dataPtr, 0x5c0), mload(add(pi, 0x40))) // PI[2] + mstore(add(dataPtr, 0x5e0), mload(add(pi, 0x60))) // PI[3] + mstore(add(dataPtr, 0x600), mload(add(pi, 0x80))) // PI[4] + mstore(add(dataPtr, 0x620), mload(add(pi, 0xa0))) // PI[5] + mstore(add(dataPtr, 0x640), mload(add(pi, 0xc0))) // PI[6] + mstore(add(dataPtr, 0x660), mload(add(pi, 0xe0))) // PI[7] + + // proof + let wire0Ptr := mload(proof) + mstore(add(dataPtr, 0x680), mload(wire0Ptr)) // wire0.x + mstore(add(dataPtr, 0x6a0), mload(add(wire0Ptr, 0x20))) // wire0.y + let wire1Ptr := mload(add(proof, 0x20)) + mstore(add(dataPtr, 0x6c0), mload(wire1Ptr)) // wire1.x + mstore(add(dataPtr, 0x6e0), mload(add(wire1Ptr, 0x20))) // wire1.y + let wire2Ptr := mload(add(proof, 0x40)) + mstore(add(dataPtr, 0x700), mload(wire2Ptr)) // wire2.x + mstore(add(dataPtr, 0x720), mload(add(wire2Ptr, 0x20))) // wire2.y + let wire3Ptr := mload(add(proof, 0x60)) + mstore(add(dataPtr, 0x740), mload(wire3Ptr)) // wire3.x + mstore(add(dataPtr, 0x760), mload(add(wire3Ptr, 0x20))) // wire3.y + let wire4Ptr := mload(add(proof, 0x80)) + mstore(add(dataPtr, 0x780), mload(wire4Ptr)) // wire4.x + mstore(add(dataPtr, 0x7a0), mload(add(wire4Ptr, 0x20))) // wire4.y + + // challenge: beta + { + mstore(statePtr, 0x0) // init state + // preimage len: state(0x20) + transcript(0x7c0) + // overwrite previous state at freePtr + mstore(statePtr, keccak256(statePtr, 0x7e0)) + // (mod p) to get beta + mstore(add(res, 0x60), mod(mload(statePtr), p)) + } - transcript.transcript = abi.encodePacked( - transcript.transcript, - BN254.g1Serialize(proof.split0), - BN254.g1Serialize(proof.split1), - BN254.g1Serialize(proof.split2), - BN254.g1Serialize(proof.split3), - BN254.g1Serialize(proof.split4) - ); + // challenge: gamma + { + // preimage len: state(0x20) + transcript(0x0) + // overwrite previous state at freePtr + mstore(statePtr, keccak256(statePtr, 0x20)) + // (mod p) to get gamma + mstore(add(res, 0x80), mod(mload(statePtr), p)) + } - res.zeta = transcript.getAndAppendChallenge(); + let prodPermPtr := mload(add(proof, 0xa0)) + mstore(dataPtr, mload(prodPermPtr)) // prodPerm.x + mstore(add(dataPtr, 0x20), mload(add(prodPermPtr, 0x20))) // prodPerm.y - // Append proof evaluations - transcript.transcript = abi.encodePacked( - transcript.transcript, - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.wireEval0)), - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.wireEval1)), - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.wireEval2)), - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.wireEval3)), - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.wireEval4)) - ); - - transcript.transcript = abi.encodePacked( - transcript.transcript, - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.sigmaEval0)), - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.sigmaEval1)), - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.sigmaEval2)), - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.sigmaEval3)), - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.prodPermZetaOmegaEval)) - ); + // challenge: alpha, alpha2, alpha3 + { + // preimage len: state(0x20) + transcript(0x40) + let alpha := keccak256(statePtr, 0x60) + mstore(statePtr, alpha) + // (mod p) to get challenge + mstore(res, mod(alpha, p)) + + let alpha2 := mulmod(alpha, alpha, p) + let alpha3 := mulmod(alpha2, alpha, p) + mstore(add(res, 0x20), alpha2) + mstore(add(res, 0x40), alpha3) + } - res.v = transcript.getAndAppendChallenge(); + let split0Ptr := mload(add(proof, 0xc0)) + mstore(dataPtr, mload(split0Ptr)) // split0.x + mstore(add(dataPtr, 0x20), mload(add(split0Ptr, 0x20))) // split0.y + let split1Ptr := mload(add(proof, 0xe0)) + mstore(add(dataPtr, 0x40), mload(split1Ptr)) // split1.x + mstore(add(dataPtr, 0x60), mload(add(split1Ptr, 0x20))) // split1.y + let split2Ptr := mload(add(proof, 0x100)) + mstore(add(dataPtr, 0x80), mload(split2Ptr)) // split2.x + mstore(add(dataPtr, 0xa0), mload(add(split2Ptr, 0x20))) // split2.y + let split3Ptr := mload(add(proof, 0x120)) + mstore(add(dataPtr, 0xc0), mload(split3Ptr)) // split3.x + mstore(add(dataPtr, 0xe0), mload(add(split3Ptr, 0x20))) // split3.y + let split4Ptr := mload(add(proof, 0x140)) + mstore(add(dataPtr, 0x100), mload(split4Ptr)) // split4.x + mstore(add(dataPtr, 0x120), mload(add(split4Ptr, 0x20))) // split4.y + + // challenge: zeta + { + // preimage len: state(0x20) + transcript(0x140) + // overwrite previous state at freePtr + mstore(statePtr, keccak256(statePtr, 0x160)) + // (mod p) to get challenge + mstore(add(res, 0xa0), mod(mload(statePtr), p)) + } - transcript.transcript = abi.encodePacked( - transcript.transcript, BN254.g1Serialize(proof.zeta), BN254.g1Serialize(proof.zetaOmega) - ); + mstore(dataPtr, mload(add(proof, 0x1a0))) // wireEval0 + mstore(add(dataPtr, 0x20), mload(add(proof, 0x1c0))) // wireEval1 + mstore(add(dataPtr, 0x40), mload(add(proof, 0x1e0))) // wireEval2 + mstore(add(dataPtr, 0x60), mload(add(proof, 0x200))) // wireEval3 + mstore(add(dataPtr, 0x80), mload(add(proof, 0x220))) // wireEval4 + mstore(add(dataPtr, 0xa0), mload(add(proof, 0x240))) // sigmaEval0 + mstore(add(dataPtr, 0xc0), mload(add(proof, 0x260))) // sigmaEval1 + mstore(add(dataPtr, 0xe0), mload(add(proof, 0x280))) // sigmaEval2 + mstore(add(dataPtr, 0x100), mload(add(proof, 0x2a0))) // sigmaEval3 + mstore(add(dataPtr, 0x120), mload(add(proof, 0x2c0))) // prodPermZetaOmegaEval + + // challenge: v + { + // preimage len: state(0x20) + transcript(0x140) + // overwrite previous state at freePtr + mstore(statePtr, keccak256(statePtr, 0x160)) + // (mod p) to get challenge + mstore(add(res, 0xc0), mod(mload(statePtr), p)) + } - res.u = transcript.getAndAppendChallenge(); + let zetaPtr := mload(add(proof, 0x160)) + mstore(dataPtr, mload(zetaPtr)) // zeta.x + mstore(add(dataPtr, 0x20), mload(add(zetaPtr, 0x20))) // zeta.y + let zetaOmegaPtr := mload(add(proof, 0x180)) + mstore(add(dataPtr, 0x40), mload(zetaOmegaPtr)) // zetaOmega.x + mstore(add(dataPtr, 0x60), mload(add(zetaOmegaPtr, 0x20))) // zetaOmega.y - assembly { - let alpha := mload(res) - let alpha2 := mulmod(alpha, alpha, p) - let alpha3 := mulmod(alpha2, alpha, p) - mstore(add(res, 0x20), alpha2) - mstore(add(res, 0x40), alpha3) + // challenge: u + { + // preimage len: state(0x20) + transcript(0x80) + let hash := keccak256(statePtr, 0xa0) + // (mod p) to get challenge + mstore(add(res, 0xe0), mod(hash, p)) + } } } - /// @dev Compute components in [E]1 and [F]1 used for PolyComm opening verification - /// equivalent of JF's - /// https://github.com/EspressoSystems/jellyfish/blob/main/plonk/src/proof_system/verifier.rs#L154-L170 - /// caller allocates the memory fr commScalars and commBases - /// requires Arrays of size 30. - /// @param verifyingKey A verifier key - /// @param evalData A polynomial evaluation - /// @param proof A Plonk proof - /// @param chal A set of challenges - /// @param commScalars Common scalars - /// @param commBases Common bases - // The returned commitment is a generalization of - // `[F]1` described in Sec 8.4, step 10 of https://eprint.iacr.org/2019/953.pdf - // Returned evaluation is the scalar in `[E]1` described in Sec 8.4, step 11 of - // https://eprint.iacr.org/2019/953.pdf - function _prepareOpeningProof( - IPlonkVerifier.VerifyingKey memory verifyingKey, - Poly.EvalData memory evalData, - IPlonkVerifier.PlonkProof memory proof, - Challenges memory chal, - uint256[] memory commScalars, - BN254.G1Point[] memory commBases - ) internal pure returns (uint256 eval) { - // compute the constant term of the linearization polynomial - uint256 linPolyConstant = _computeLinPolyConstantTerm(chal, proof, evalData); - - _preparePolyCommitments(verifyingKey, chal, evalData, proof, commScalars, commBases); - - eval = _prepareEvaluations(linPolyConstant, proof, commScalars); - } - /// @dev Compute the constant term of the linearization polynomial. /// ``` /// r_plonk = PI - L1(x) * alpha^2 - alpha * \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) * @@ -302,22 +404,22 @@ library PlonkVerifier { { let w0 := mload(add(proof, 0x1a0)) let sigma0 := mload(add(proof, 0x240)) - perm := mulmod(perm, addmod(add(w0, gamma), mulmod(beta, sigma0, p), p), p) + perm := mulmod(perm, addmod(addmod(w0, gamma, p), mulmod(beta, sigma0, p), p), p) } { let w1 := mload(add(proof, 0x1c0)) let sigma1 := mload(add(proof, 0x260)) - perm := mulmod(perm, addmod(add(w1, gamma), mulmod(beta, sigma1, p), p), p) + perm := mulmod(perm, addmod(addmod(w1, gamma, p), mulmod(beta, sigma1, p), p), p) } { let w2 := mload(add(proof, 0x1e0)) let sigma2 := mload(add(proof, 0x280)) - perm := mulmod(perm, addmod(add(w2, gamma), mulmod(beta, sigma2, p), p), p) + perm := mulmod(perm, addmod(addmod(w2, gamma, p), mulmod(beta, sigma2, p), p), p) } { let w3 := mload(add(proof, 0x200)) let sigma3 := mload(add(proof, 0x2a0)) - perm := mulmod(perm, addmod(add(w3, gamma), mulmod(beta, sigma3, p), p), p) + perm := mulmod(perm, addmod(addmod(w3, gamma, p), mulmod(beta, sigma3, p), p), p) } // \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) * (w_m + gamma) * z(xw) @@ -336,354 +438,126 @@ library PlonkVerifier { } } - /// @dev Similar to `aggregate_poly_commitments()` in Jellyfish, but we are not aggregating - /// multiple, - /// but rather preparing for `[F]1` from a single proof. - /// The caller allocates the memory fr commScalars and commBases. - /// Requires Arrays of size 30. + /// @return e1 The [E]1 in Sec 8.4, step 11 of Plonk + /// @return f1 The [F]1 in Sec 8.4, step 10 of Plonk function _preparePolyCommitments( IPlonkVerifier.VerifyingKey memory verifyingKey, Challenges memory chal, Poly.EvalData memory evalData, - IPlonkVerifier.PlonkProof memory proof, - uint256[] memory commScalars, - BN254.G1Point[] memory commBases - ) internal pure { - _linearizationScalarsAndBases(verifyingKey, chal, evalData, proof, commBases, commScalars); + IPlonkVerifier.PlonkProof memory proof + ) internal view returns (BN254.G1Point memory e1, BN254.G1Point memory f1) { + // Compute first part of batched polynomial commitment [D]1 + BN254.G1Point memory d1 = _linearizationPolyComm(verifyingKey, chal, evalData, proof); + // ============================================ + // Add wire witness poly commitments + // Meanwhile, _prepareEvaluation (`[E]1` in Sec 8.4, step 11 of Plonk) + // ============================================ uint256 p = BN254.R_MOD; + + // r0 in step 8 of Plonk + uint256 eval = _computeLinPolyConstantTerm(chal, proof, evalData); + eval = p - eval; // -r0 + uint256 v = chal.v; - uint256 vBase = v; + uint256 vPow = v; - // Add wire witness polynomial commitments. - commScalars[20] = vBase; - commBases[20] = proof.wire0; assembly { - vBase := mulmod(vBase, v, p) + // eval += v * proof.wireEval0 + eval := addmod(eval, mulmod(vPow, mload(add(proof, 0x1a0)), p), p) } + f1 = BN254.add(d1, BN254.scalarMul(proof.wire0, BN254.ScalarField.wrap(vPow))); - commScalars[21] = vBase; - commBases[21] = proof.wire1; assembly { - vBase := mulmod(vBase, v, p) + // vPow = v^2 + vPow := mulmod(vPow, v, p) + // eval += v^2 * proof.wireEval1 + eval := addmod(eval, mulmod(vPow, mload(add(proof, 0x1c0)), p), p) } + f1 = BN254.add(f1, BN254.scalarMul(proof.wire1, BN254.ScalarField.wrap(vPow))); - commScalars[22] = vBase; - commBases[22] = proof.wire2; assembly { - vBase := mulmod(vBase, v, p) + // vPow = v^3 + vPow := mulmod(vPow, v, p) + // eval += v^3 * proof.wireEval2 + eval := addmod(eval, mulmod(vPow, mload(add(proof, 0x1e0)), p), p) } + f1 = BN254.add(f1, BN254.scalarMul(proof.wire2, BN254.ScalarField.wrap(vPow))); - commScalars[23] = vBase; - commBases[23] = proof.wire3; assembly { - vBase := mulmod(vBase, v, p) + // vPow = v^4 + vPow := mulmod(vPow, v, p) + // eval += v^4 * proof.wireEval3 + eval := addmod(eval, mulmod(vPow, mload(add(proof, 0x200)), p), p) } + f1 = BN254.add(f1, BN254.scalarMul(proof.wire3, BN254.ScalarField.wrap(vPow))); - commScalars[24] = vBase; - commBases[24] = proof.wire4; assembly { - vBase := mulmod(vBase, v, p) + // vPow = v^5 + vPow := mulmod(vPow, v, p) + // eval += v^5 * proof.wireEval4 + eval := addmod(eval, mulmod(vPow, mload(add(proof, 0x220)), p), p) } + f1 = BN254.add(f1, BN254.scalarMul(proof.wire4, BN254.ScalarField.wrap(vPow))); // Add wire sigma polynomial commitments. The last sigma commitment is excluded. - commScalars[25] = vBase; - commBases[25] = verifyingKey.sigma0; assembly { - vBase := mulmod(vBase, v, p) + // vPow = v^6 + vPow := mulmod(vPow, v, p) + // eval += v^6 * proof.sigmaEval0 + eval := addmod(eval, mulmod(vPow, mload(add(proof, 0x240)), p), p) } + f1 = BN254.add(f1, BN254.scalarMul(verifyingKey.sigma0, BN254.ScalarField.wrap(vPow))); - commScalars[26] = vBase; - commBases[26] = verifyingKey.sigma1; assembly { - vBase := mulmod(vBase, v, p) + // vPow = v^7 + vPow := mulmod(vPow, v, p) + // eval += v^7 * proof.sigmaEval1 + eval := addmod(eval, mulmod(vPow, mload(add(proof, 0x260)), p), p) } + f1 = BN254.add(f1, BN254.scalarMul(verifyingKey.sigma1, BN254.ScalarField.wrap(vPow))); - commScalars[27] = vBase; - commBases[27] = verifyingKey.sigma2; assembly { - vBase := mulmod(vBase, v, p) + // vPow = v^8 + vPow := mulmod(vPow, v, p) + // eval += v^8 * proof.sigmaEval2 + eval := addmod(eval, mulmod(vPow, mload(add(proof, 0x280)), p), p) } + f1 = BN254.add(f1, BN254.scalarMul(verifyingKey.sigma2, BN254.ScalarField.wrap(vPow))); - commScalars[28] = vBase; - commBases[28] = verifyingKey.sigma3; assembly { - vBase := mulmod(vBase, v, p) + // vPow = v^9 + vPow := mulmod(vPow, v, p) + // eval += v^9 * proof.sigmaEval3 + eval := addmod(eval, mulmod(vPow, mload(add(proof, 0x2a0)), p), p) } + f1 = BN254.add(f1, BN254.scalarMul(verifyingKey.sigma3, BN254.ScalarField.wrap(vPow))); // Add poly commitments to be evaluated at point `zeta * g`. - commScalars[29] = chal.u; - commBases[29] = proof.prodPerm; - } - - /// @dev `aggregate_evaluations()` in Jellyfish, but since we are not aggregating multiple, but - /// rather preparing `[E]1` from a single proof. - /// @dev caller allocates the memory fr commScalars - /// requires Arrays of size 30. - /// @param linPolyConstant A linear polynomial constant - /// @param proof A Plonk proof - /// @param commScalars An array of common scalars - /// The returned value is the scalar in `[E]1` described in Sec 8.4, step 11 of - /// https://eprint.iacr.org/2019/953.pdf - function _prepareEvaluations( - uint256 linPolyConstant, - IPlonkVerifier.PlonkProof memory proof, - uint256[] memory commScalars - ) internal pure returns (uint256 eval) { - uint256 p = BN254.R_MOD; + uint256 u = chal.u; assembly { - eval := sub(p, linPolyConstant) - for { let i := 0 } lt(i, 10) { i := add(i, 1) } { - // the first u256 stores the length of this array; - // the next 20 elements are used to store the linearization of the scalars - // the first free space starts from 21 - let combiner := mload(add(commScalars, mul(add(i, 21), 0x20))) - let termEval := mload(add(proof, add(0x1a0, mul(i, 0x20)))) - eval := addmod(eval, mulmod(combiner, termEval, p), p) - } - } - } - - /// @dev Verify opening proof - /// `open_key` has been assembled from BN254.P1(), BN254.P2() and contract variable _betaH - /// @param pcsInfo A single PcsInfo - /// @dev Returns true if the pc opening verifies - function _verifyOpeningProofs(PcsInfo memory pcsInfo) internal view returns (bool) { - uint256 p = BN254.R_MOD; - // Compute a pseudorandom challenge from the instances - - BN254.G1Point memory a1; - BN254.G1Point memory b1; - - // Compute A - { - BN254.ScalarField[] memory scalars = new BN254.ScalarField[](2); - BN254.G1Point[] memory bases = new BN254.G1Point[](2); - uint256 rBase = 1; - - scalars[0] = BN254.ScalarField.wrap(rBase); - bases[0] = pcsInfo.openingProof; - - scalars[1] = BN254.ScalarField.wrap(pcsInfo.u); - - bases[1] = pcsInfo.shiftedOpeningProof; - - a1 = BN254.multiScalarMul(bases, scalars); - } - - // Compute B - { - BN254.ScalarField[] memory scalars; - BN254.G1Point[] memory bases; - { - // variable scoping to avoid "Stack too deep" - uint256 scalarsLenPerInfo = pcsInfo.commScalars.length; - uint256 totalScalarsLen = (2 + scalarsLenPerInfo) + 1; - scalars = new BN254.ScalarField[](totalScalarsLen); - bases = new BN254.G1Point[](totalScalarsLen); - } - uint256 sumEvals = 0; - uint256 idx = 0; - - for (uint256 j = 0; j < pcsInfo.commScalars.length; j++) { - scalars[idx] = BN254.ScalarField.wrap(pcsInfo.commScalars[j]); - - bases[idx] = pcsInfo.commBases[j]; - idx += 1; - } - - scalars[idx] = BN254.ScalarField.wrap(pcsInfo.evalPoint); - - bases[idx] = pcsInfo.openingProof; - idx += 1; - - { - uint256 u = pcsInfo.u; - uint256 nextEvalPoint = pcsInfo.nextEvalPoint; - uint256 tmp; - assembly { - // slither-disable-next-line variable-scope - tmp := mulmod(u, nextEvalPoint, p) - } - scalars[idx] = BN254.ScalarField.wrap(tmp); - } - bases[idx] = pcsInfo.shiftedOpeningProof; - idx += 1; - - { - uint256 eval = pcsInfo.eval; - assembly { - sumEvals := addmod(sumEvals, eval, p) - } - } - - scalars[idx] = BN254.negate(BN254.ScalarField.wrap(sumEvals)); - bases[idx] = BN254.P1(); - b1 = BN254.negate(BN254.multiScalarMul(bases, scalars)); - } - - // Check e(A, [x]2) ?= e(B, [1]2) - BN254.G2Point memory betaH = BN254.G2Point({ - x0: BN254.BaseField.wrap(BETA_H_X1), - x1: BN254.BaseField.wrap(BETA_H_X0), - y0: BN254.BaseField.wrap(BETA_H_Y1), - y1: BN254.BaseField.wrap(BETA_H_Y0) - }); - - return BN254.pairingProd2(a1, betaH, b1, BN254.P2()); - } - - /// @dev Batchly verify multiple PCS opening proofs. - /// `open_key` has been assembled from BN254.P1(), BN254.P2() and contract variable _betaH - /// @param pcsInfos An array of PcsInfo - /// @dev Returns true if the entire batch verifiies and false otherwise. - function _batchVerifyOpeningProofs(PcsInfo[] memory pcsInfos) internal view returns (bool) { - uint256 pcsLen = pcsInfos.length; - uint256 p = BN254.R_MOD; - // Compute a pseudorandom challenge from the instances - uint256 r = 1; // for a single proof, no need to use `r` (`r=1` has no effect) - if (pcsLen > 1) { - Transcript.TranscriptData memory transcript; - for (uint256 i = 0; i < pcsLen; i++) { - transcript.appendChallenge(pcsInfos[i].u); - } - r = transcript.getAndAppendChallenge(); - } - - BN254.G1Point memory a1; - BN254.G1Point memory b1; - - // Compute A := A0 + r * A1 + ... + r^{m-1} * Am - { - BN254.ScalarField[] memory scalars = new BN254.ScalarField[](2 * pcsLen); - BN254.G1Point[] memory bases = new BN254.G1Point[](2 * pcsLen); - uint256 rBase = 1; - for (uint256 i = 0; i < pcsLen; i++) { - scalars[2 * i] = BN254.ScalarField.wrap(rBase); - bases[2 * i] = pcsInfos[i].openingProof; - - { - // slither-disable-next-line write-after-write - uint256 tmp; - uint256 u = pcsInfos[i].u; - assembly { - tmp := mulmod(rBase, u, p) - } - scalars[2 * i + 1] = BN254.ScalarField.wrap(tmp); - } - bases[2 * i + 1] = pcsInfos[i].shiftedOpeningProof; - - assembly { - rBase := mulmod(rBase, r, p) - } - } - a1 = BN254.multiScalarMul(bases, scalars); - } - - // Compute B := B0 + r * B1 + ... + r^{m-1} * Bm - { - BN254.ScalarField[] memory scalars; - BN254.G1Point[] memory bases; - { - // variable scoping to avoid "Stack too deep" - uint256 scalarsLenPerInfo = pcsInfos[0].commScalars.length; - uint256 totalScalarsLen = (2 + scalarsLenPerInfo) * pcsInfos.length + 1; - scalars = new BN254.ScalarField[](totalScalarsLen); - bases = new BN254.G1Point[](totalScalarsLen); - } - uint256 sumEvals = 0; - uint256 idx = 0; - uint256 rBase = 1; - for (uint256 i = 0; i < pcsInfos.length; i++) { - for (uint256 j = 0; j < pcsInfos[0].commScalars.length; j++) { - { - // scalars[idx] = (rBase * pcsInfos[i].commScalars[j]) % BN254.R_MOD; - uint256 s = pcsInfos[i].commScalars[j]; - uint256 tmp; - assembly { - // slither-disable-next-line variable-scope - tmp := mulmod(rBase, s, p) - } - scalars[idx] = BN254.ScalarField.wrap(tmp); - } - bases[idx] = pcsInfos[i].commBases[j]; - idx += 1; - } - - { - // scalars[idx] = (rBase * pcsInfos[i].evalPoint) % BN254.R_MOD; - uint256 evalPoint = pcsInfos[i].evalPoint; - uint256 tmp; - assembly { - // slither-disable-next-line variable-scope - tmp := mulmod(rBase, evalPoint, p) - } - scalars[idx] = BN254.ScalarField.wrap(tmp); - } - bases[idx] = pcsInfos[i].openingProof; - idx += 1; - - { - // scalars[idx] = (rBase * pcsInfos[i].u * pcsInfos[i].nextEvalPoint) % - // BN254.R_MOD; - uint256 u = pcsInfos[i].u; - uint256 nextEvalPoint = pcsInfos[i].nextEvalPoint; - uint256 tmp; - assembly { - // slither-disable-next-line variable-scope - tmp := mulmod(rBase, mulmod(u, nextEvalPoint, p), p) - } - scalars[idx] = BN254.ScalarField.wrap(tmp); - } - bases[idx] = pcsInfos[i].shiftedOpeningProof; - idx += 1; - - { - // sumEvals = (sumEvals + rBase * pcsInfos[i].eval) % BN254.R_MOD; - // rBase = (rBase * r) % BN254.R_MOD; - uint256 eval = pcsInfos[i].eval; - assembly { - sumEvals := addmod(sumEvals, mulmod(rBase, eval, p), p) - rBase := mulmod(rBase, r, p) - } - } - } - scalars[idx] = BN254.negate(BN254.ScalarField.wrap(sumEvals)); - bases[idx] = BN254.P1(); - b1 = BN254.negate(BN254.multiScalarMul(bases, scalars)); + // eval += u * proof.prodPermZetaOmegaEval + eval := addmod(eval, mulmod(u, mload(add(proof, 0x2c0)), p), p) } + f1 = BN254.add(f1, BN254.scalarMul(proof.prodPerm, BN254.ScalarField.wrap(u))); - // Check e(A, [x]2) ?= e(B, [1]2) - // TODO the tests pass but it feels wrong. - BN254.G2Point memory betaH = BN254.G2Point({ - x0: BN254.BaseField.wrap(BETA_H_X1), - x1: BN254.BaseField.wrap(BETA_H_X0), - y0: BN254.BaseField.wrap(BETA_H_Y1), - y1: BN254.BaseField.wrap(BETA_H_Y0) - }); - - return BN254.pairingProd2(a1, betaH, b1, BN254.P2()); + // e1 = eval * [1]1 + e1 = BN254.scalarMul(BN254.P1(), BN254.ScalarField.wrap(eval)); } - /// @dev Compute the linearization of the scalars and bases. - /// The caller allocates the memory from commScalars and commBases. - /// Requires arrays of size 30. + /// @dev Compute the linearization poly commitment /// @param verifyingKey The verifying key /// @param challenge A set of challenges /// @param evalData Polynomial evaluation data /// @param proof A Plonk proof - /// @param bases An array of BN254 G1 points - /// @param scalars An array of scalars - function _linearizationScalarsAndBases( + /// @return d1 The [D]1 in Step 9 of Plonk + function _linearizationPolyComm( IPlonkVerifier.VerifyingKey memory verifyingKey, Challenges memory challenge, Poly.EvalData memory evalData, - IPlonkVerifier.PlonkProof memory proof, - BN254.G1Point[] memory bases, - uint256[] memory scalars - ) internal pure { - uint256 firstScalar; - uint256 secondScalar; + IPlonkVerifier.PlonkProof memory proof + ) private view returns (BN254.G1Point memory d1) { + uint256 tmpScalar; uint256 rhs; uint256 tmp; uint256 tmp2; @@ -704,8 +578,9 @@ library PlonkVerifier { // - proof.prodPerm // - firstScalar assembly { + let gamma := mload(add(challenge, 0x80)) // firstScalar = alpha^2 * L1(zeta) - firstScalar := mulmod(mload(add(challenge, 0x20)), mload(add(evalData, 0x20)), p) + tmpScalar := mulmod(mload(add(challenge, 0x20)), mload(add(evalData, 0x20)), p) // rhs = alpha rhs := mload(challenge) @@ -718,8 +593,7 @@ library PlonkVerifier { // (beta * zeta + wireEval0 + gamma) // ================================= tmp2 := addmod(tmp, mload(add(proof, 0x1A0)), p) - tmp2 := addmod(tmp2, mload(add(challenge, 0x80)), p) - + tmp2 := addmod(tmp2, gamma, p) rhs := mulmod(tmp2, rhs, p) // ================================= @@ -728,8 +602,7 @@ library PlonkVerifier { // ================================= tmp2 := mulmod(tmp, COSET_K1, p) tmp2 := addmod(tmp2, mload(add(proof, 0x1C0)), p) - tmp2 := addmod(tmp2, mload(add(challenge, 0x80)), p) - + tmp2 := addmod(tmp2, gamma, p) rhs := mulmod(tmp2, rhs, p) // ================================= @@ -738,7 +611,7 @@ library PlonkVerifier { // ================================= tmp2 := mulmod(tmp, COSET_K2, p) tmp2 := addmod(tmp2, mload(add(proof, 0x1E0)), p) - tmp2 := addmod(tmp2, mload(add(challenge, 0x80)), p) + tmp2 := addmod(tmp2, gamma, p) rhs := mulmod(tmp2, rhs, p) // ================================= @@ -747,7 +620,7 @@ library PlonkVerifier { // ================================= tmp2 := mulmod(tmp, COSET_K3, p) tmp2 := addmod(tmp2, mload(add(proof, 0x200)), p) - tmp2 := addmod(tmp2, mload(add(challenge, 0x80)), p) + tmp2 := addmod(tmp2, gamma, p) rhs := mulmod(tmp2, rhs, p) // ================================= @@ -756,17 +629,16 @@ library PlonkVerifier { // ================================= tmp2 := mulmod(tmp, COSET_K4, p) tmp2 := addmod(tmp2, mload(add(proof, 0x220)), p) - tmp2 := addmod(tmp2, mload(add(challenge, 0x80)), p) + tmp2 := addmod(tmp2, gamma, p) rhs := mulmod(tmp2, rhs, p) - firstScalar := addmod(firstScalar, rhs, p) + tmpScalar := addmod(tmpScalar, rhs, p) } - bases[0] = proof.prodPerm; - scalars[0] = firstScalar; + d1 = BN254.scalarMul(proof.prodPerm, BN254.ScalarField.wrap(tmpScalar)); // ============================================ // Compute coefficient for the last wire sigma polynomial commitment. - // secondScalar = alpha * beta * z_w * [s_sigma_3]_1 + // secondScalar = - alpha * beta * z_w // * (wireEval0 + gamma + beta * sigmaEval0) // * (wireEval1 + gamma + beta * sigmaEval1) // * ... @@ -775,40 +647,44 @@ library PlonkVerifier { // - verifyingKey.sigma4 // - secondScalar assembly { + let alpha := mload(challenge) + let beta := mload(add(challenge, 0x60)) + let gamma := mload(add(challenge, 0x80)) // secondScalar = alpha * beta * z_w - secondScalar := mulmod(mload(challenge), mload(add(challenge, 0x60)), p) - secondScalar := mulmod(secondScalar, mload(add(proof, 0x2C0)), p) + tmpScalar := mulmod(alpha, beta, p) + tmpScalar := mulmod(tmpScalar, mload(add(proof, 0x2C0)), p) // (wireEval0 + gamma + beta * sigmaEval0) - tmp := mulmod(mload(add(challenge, 0x60)), mload(add(proof, 0x240)), p) + tmp := mulmod(beta, mload(add(proof, 0x240)), p) tmp := addmod(tmp, mload(add(proof, 0x1A0)), p) - tmp := addmod(tmp, mload(add(challenge, 0x80)), p) + tmp := addmod(tmp, gamma, p) - secondScalar := mulmod(secondScalar, tmp, p) + tmpScalar := mulmod(tmpScalar, tmp, p) // (wireEval1 + gamma + beta * sigmaEval1) - tmp := mulmod(mload(add(challenge, 0x60)), mload(add(proof, 0x260)), p) + tmp := mulmod(beta, mload(add(proof, 0x260)), p) tmp := addmod(tmp, mload(add(proof, 0x1C0)), p) - tmp := addmod(tmp, mload(add(challenge, 0x80)), p) + tmp := addmod(tmp, gamma, p) - secondScalar := mulmod(secondScalar, tmp, p) + tmpScalar := mulmod(tmpScalar, tmp, p) // (wireEval2 + gamma + beta * sigmaEval2) - tmp := mulmod(mload(add(challenge, 0x60)), mload(add(proof, 0x280)), p) + tmp := mulmod(beta, mload(add(proof, 0x280)), p) tmp := addmod(tmp, mload(add(proof, 0x1E0)), p) - tmp := addmod(tmp, mload(add(challenge, 0x80)), p) + tmp := addmod(tmp, gamma, p) - secondScalar := mulmod(secondScalar, tmp, p) + tmpScalar := mulmod(tmpScalar, tmp, p) // (wireEval3 + gamma + beta * sigmaEval3) - tmp := mulmod(mload(add(challenge, 0x60)), mload(add(proof, 0x2A0)), p) + tmp := mulmod(beta, mload(add(proof, 0x2A0)), p) tmp := addmod(tmp, mload(add(proof, 0x200)), p) - tmp := addmod(tmp, mload(add(challenge, 0x80)), p) + tmp := addmod(tmp, gamma, p) - secondScalar := mulmod(secondScalar, tmp, p) + tmpScalar := mulmod(tmpScalar, tmp, p) } - bases[1] = verifyingKey.sigma4; - scalars[1] = p - secondScalar; + d1 = BN254.add( + d1, BN254.scalarMul(verifyingKey.sigma4, BN254.ScalarField.wrap(p - tmpScalar)) + ); // ============================================ // next 13 are for selectors: @@ -826,14 +702,10 @@ library PlonkVerifier { // q_lc // ============ // q_1...q_4 - scalars[2] = BN254.ScalarField.unwrap(proof.wireEval0); - scalars[3] = BN254.ScalarField.unwrap(proof.wireEval1); - scalars[4] = BN254.ScalarField.unwrap(proof.wireEval2); - scalars[5] = BN254.ScalarField.unwrap(proof.wireEval3); - bases[2] = verifyingKey.q1; - bases[3] = verifyingKey.q2; - bases[4] = verifyingKey.q3; - bases[5] = verifyingKey.q4; + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.q1, proof.wireEval0)); + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.q2, proof.wireEval1)); + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.q3, proof.wireEval2)); + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.q4, proof.wireEval3)); // ============ // q_M @@ -843,14 +715,12 @@ library PlonkVerifier { assembly { tmp := mulmod(mload(add(proof, 0x1A0)), mload(add(proof, 0x1C0)), p) } - scalars[6] = tmp; - bases[6] = verifyingKey.qM12; + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.qM12, BN254.ScalarField.wrap(tmp))); assembly { tmp := mulmod(mload(add(proof, 0x1E0)), mload(add(proof, 0x200)), p) } - scalars[7] = tmp; - bases[7] = verifyingKey.qM34; + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.qM34, BN254.ScalarField.wrap(tmp))); // ============ // q_H @@ -862,8 +732,7 @@ library PlonkVerifier { tmp2 := mulmod(tmp2, tmp2, p) tmp := mulmod(tmp, tmp2, p) } - scalars[8] = tmp; - bases[8] = verifyingKey.qH1; + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.qH1, BN254.ScalarField.wrap(tmp))); // w_evals[1].pow([5]); assembly { @@ -872,8 +741,7 @@ library PlonkVerifier { tmp2 := mulmod(tmp2, tmp2, p) tmp := mulmod(tmp, tmp2, p) } - scalars[9] = tmp; - bases[9] = verifyingKey.qH2; + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.qH2, BN254.ScalarField.wrap(tmp))); // w_evals[2].pow([5]); assembly { @@ -882,8 +750,7 @@ library PlonkVerifier { tmp2 := mulmod(tmp2, tmp2, p) tmp := mulmod(tmp, tmp2, p) } - scalars[10] = tmp; - bases[10] = verifyingKey.qH3; + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.qH3, BN254.ScalarField.wrap(tmp))); // w_evals[3].pow([5]); assembly { @@ -892,18 +759,15 @@ library PlonkVerifier { tmp2 := mulmod(tmp2, tmp2, p) tmp := mulmod(tmp, tmp2, p) } - scalars[11] = tmp; - bases[11] = verifyingKey.qH4; + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.qH4, BN254.ScalarField.wrap(tmp))); // ============ // q_o and q_c // ============ // q_o - scalars[12] = p - BN254.ScalarField.unwrap(proof.wireEval4); - bases[12] = verifyingKey.qO; + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.qO, BN254.negate(proof.wireEval4))); // q_c - scalars[13] = 1; - bases[13] = verifyingKey.qC; + d1 = BN254.add(d1, verifyingKey.qC); // ============ // q_Ecc @@ -915,50 +779,44 @@ library PlonkVerifier { tmp := mulmod(tmp, mload(add(proof, 0x200)), p) tmp := mulmod(tmp, mload(add(proof, 0x220)), p) } - scalars[14] = tmp; - bases[14] = verifyingKey.qEcc; + d1 = BN254.add(d1, BN254.scalarMul(verifyingKey.qEcc, BN254.ScalarField.wrap(tmp))); // ============================================ // the last 5 are for splitting quotient commitments // ============================================ // first one is 1-zeta^n - scalars[15] = p - BN254.ScalarField.unwrap(evalData.vanishEval); - bases[15] = proof.split0; + tmpScalar = BN254.ScalarField.unwrap(BN254.negate(evalData.vanishEval)); // reused next + d1 = BN254.add(d1, BN254.scalarMul(proof.split0, BN254.ScalarField.wrap(tmpScalar))); + + // second one is (1-zeta^n) zeta^(n+2) assembly { - // tmp = zeta^{n+2} + // zeta^n tmp := addmod(mload(evalData), 1, p) // todo: use pre-computed zeta^2 tmp2 := mulmod(mload(add(challenge, 0xA0)), mload(add(challenge, 0xA0)), p) + // tmp = zeta^{n+2} tmp := mulmod(tmp, tmp2, p) + tmpScalar := mulmod(tmpScalar, tmp, p) } - - // second one is (1-zeta^n) zeta^(n+2) - assembly { - tmp2 := mulmod(mload(add(scalars, mul(16, 0x20))), tmp, p) - } - scalars[16] = tmp2; - bases[16] = proof.split1; + d1 = BN254.add(d1, BN254.scalarMul(proof.split1, BN254.ScalarField.wrap(tmpScalar))); // third one is (1-zeta^n) zeta^2(n+2) assembly { - tmp2 := mulmod(mload(add(scalars, mul(17, 0x20))), tmp, p) + tmpScalar := mulmod(tmpScalar, tmp, p) } - scalars[17] = tmp2; - bases[17] = proof.split2; + d1 = BN254.add(d1, BN254.scalarMul(proof.split2, BN254.ScalarField.wrap(tmpScalar))); // forth one is (1-zeta^n) zeta^3(n+2) assembly { - tmp2 := mulmod(mload(add(scalars, mul(18, 0x20))), tmp, p) + tmpScalar := mulmod(tmpScalar, tmp, p) } - scalars[18] = tmp2; - bases[18] = proof.split3; + d1 = BN254.add(d1, BN254.scalarMul(proof.split3, BN254.ScalarField.wrap(tmpScalar))); // fifth one is (1-zeta^n) zeta^4(n+2) assembly { - tmp2 := mulmod(mload(add(scalars, mul(19, 0x20))), tmp, p) + tmpScalar := mulmod(tmpScalar, tmp, p) } - scalars[19] = tmp2; - bases[19] = proof.split4; + d1 = BN254.add(d1, BN254.scalarMul(proof.split4, BN254.ScalarField.wrap(tmpScalar))); } } diff --git a/contracts/src/libraries/PlonkVerifier2.sol b/contracts/src/libraries/PlonkVerifier2.sol new file mode 100644 index 0000000000..2ceed4fc09 --- /dev/null +++ b/contracts/src/libraries/PlonkVerifier2.sol @@ -0,0 +1,930 @@ +// SPDX-License-Identifier: UNLICENSED + +pragma solidity ^0.8.0; + +import { BN254 } from "bn254/BN254.sol"; +import { PolynomialEval as Poly } from "./PolynomialEval.sol"; +import { IPlonkVerifier } from "../interfaces/IPlonkVerifier.sol"; + +library PlonkVerifier2 { + // use notation from https://datatracker.ietf.org/doc/draft-irtf-cfrg-pairing-friendly-curves/ + // + // Elliptic curve is defined over a prime field GF(p), with embedding degree k. + // Short Weierstrass (SW form) is, for a, b \in GF(p^n) for some natural number n > 0: + // E: y^2 = x^3 + a * x + b + // + // Pairing is defined over cyclic subgroups G1, G2, both of which are of order r. + // G1 is a subgroup of E(GF(p)), G2 is a subgroup of E(GF(p^k)). + // + // BN family are parameterized curves with well-chosen t, + // p = 36 * t^4 + 36 * t^3 + 24 * t^2 + 6 * t + 1 + // r = 36 * t^4 + 36 * t^3 + 18 * t^2 + 6 * t + 1 + // for some integer t. + // E has the equation: + // E: y^2 = x^3 + b + // where b is a primitive element of multiplicative group (GF(p))^* of order (p-1). + // A pairing e is defined by taking G1 as a subgroup of E(GF(p)) of order r, + // G2 as a subgroup of E'(GF(p^2)), + // and G_T as a subgroup of a multiplicative group (GF(p^12))^* of order r. + // + // BN254 is defined over a 254-bit prime order p, embedding degree k = 12. + uint256 public constant P_MOD = + 21888242871839275222246405745257275088696311157297823662689037894645226208583; + uint256 public constant R_MOD = + 21888242871839275222246405745257275088548364400416034343698204186575808495617; + + // _COSET_K0 = 1, has no effect during multiplication, thus avoid declaring it here. + uint256 private constant COSET_K1 = + 0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a; + uint256 private constant COSET_K2 = + 0x1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025; + uint256 private constant COSET_K3 = + 0x2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a; + uint256 private constant COSET_K4 = + 0x2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881; + + // Parsed from Aztec's Ignition CRS, + // `beta_h` \in G2 where \beta is the trapdoor, h is G2 generator `BN254.P2()` + // See parsing code: https://github.com/alxiong/crs + uint256 private constant BETA_H_X0 = + 0x260e01b251f6f1c7e7ff4e580791dee8ea51d87a358e038b4efe30fac09383c1; + uint256 private constant BETA_H_X1 = + 0x0118c4d5b837bcc2bc89b5b398b5974e9f5944073b32078b7e231fec938883b0; + uint256 private constant BETA_H_Y0 = + 0x04fc6369f7110fe3d25156c1bb9a72859cf2a04641f99ba4ee413c80da6a5fe4; + uint256 private constant BETA_H_Y1 = + 0x22febda3c0c0632a56475b4214e5615e11e6dd3f96e6cea2854a87d4dacc5e55; + + // BN254.P2 + uint256 private constant H_X0 = + 0x198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2; + uint256 private constant H_X1 = + 0x1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed; + uint256 private constant H_Y0 = + 0x090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b; + uint256 private constant H_Y1 = + 0x12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa; + + /// The number of wire types of the circuit, TurboPlonk has 5. + uint256 private constant NUM_WIRE_TYPES = 5; + + uint256 private constant ERROR_STRING_ID = + 0x08c379a000000000000000000000000000000000000000000000000000000000; // selector for function + // Error(string) + + /// @dev Plonk IOP verifier challenges. + struct Challenges { + uint256 alpha; // 0x00 + uint256 alpha2; // 0x20 + uint256 alpha3; // 0x40 + uint256 beta; // 0x60 + uint256 gamma; // 0x80 + uint256 zeta; // 0xA0 + uint256 v; // 0xC0 + uint256 u; // 0xE0 + } + /// @dev Validate all group points and scalar fields. Revert if + /// any are invalid. + /// @param proof A Plonk proof + + function _validateProof(IPlonkVerifier.PlonkProof memory proof) internal pure { + BN254.validateG1Point(proof.wire0); + BN254.validateG1Point(proof.wire1); + BN254.validateG1Point(proof.wire2); + BN254.validateG1Point(proof.wire3); + BN254.validateG1Point(proof.wire4); + BN254.validateG1Point(proof.prodPerm); + BN254.validateG1Point(proof.split0); + BN254.validateG1Point(proof.split1); + BN254.validateG1Point(proof.split2); + BN254.validateG1Point(proof.split3); + BN254.validateG1Point(proof.split4); + BN254.validateG1Point(proof.zeta); + BN254.validateG1Point(proof.zetaOmega); + BN254.validateScalarField(proof.wireEval0); + BN254.validateScalarField(proof.wireEval1); + BN254.validateScalarField(proof.wireEval2); + BN254.validateScalarField(proof.wireEval3); + BN254.validateScalarField(proof.wireEval4); + BN254.validateScalarField(proof.sigmaEval0); + BN254.validateScalarField(proof.sigmaEval1); + BN254.validateScalarField(proof.sigmaEval2); + BN254.validateScalarField(proof.sigmaEval3); + BN254.validateScalarField(proof.prodPermZetaOmegaEval); + } + + /// @dev Compute the constant term of the linearization polynomial. + /// ``` + /// r_plonk = PI - L1(x) * alpha^2 - alpha * \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) * + /// (w_m + gamma) * z(xw) + /// ``` + /// where m is the number of wire types. + function _computeLinPolyConstantTerm( + Challenges memory chal, + IPlonkVerifier.PlonkProof memory proof, + Poly.EvalData memory evalData + ) internal pure returns (uint256 res) { + uint256 lagrangeOneEval = BN254.ScalarField.unwrap(evalData.lagrangeOne); + uint256 piEval = BN254.ScalarField.unwrap(evalData.piEval); + uint256 perm = 1; + + assembly { + let beta := mload(add(chal, 0x60)) + let gamma := mload(add(chal, 0x80)) + + // \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) + { + let w0 := mload(add(proof, 0x1a0)) + let sigma0 := mload(add(proof, 0x240)) + perm := + mulmod( + perm, + addmod(addmod(w0, gamma, R_MOD), mulmod(beta, sigma0, R_MOD), R_MOD), + R_MOD + ) + } + { + let w1 := mload(add(proof, 0x1c0)) + let sigma1 := mload(add(proof, 0x260)) + perm := + mulmod( + perm, + addmod(addmod(w1, gamma, R_MOD), mulmod(beta, sigma1, R_MOD), R_MOD), + R_MOD + ) + } + { + let w2 := mload(add(proof, 0x1e0)) + let sigma2 := mload(add(proof, 0x280)) + perm := + mulmod( + perm, + addmod(addmod(w2, gamma, R_MOD), mulmod(beta, sigma2, R_MOD), R_MOD), + R_MOD + ) + } + { + let w3 := mload(add(proof, 0x200)) + let sigma3 := mload(add(proof, 0x2a0)) + perm := + mulmod( + perm, + addmod(addmod(w3, gamma, R_MOD), mulmod(beta, sigma3, R_MOD), R_MOD), + R_MOD + ) + } + + // \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) * (w_m + gamma) * z(xw) + { + let w4 := mload(add(proof, 0x220)) + let permNextEval := mload(add(proof, 0x2c0)) + perm := mulmod(perm, mulmod(addmod(w4, gamma, R_MOD), permNextEval, R_MOD), R_MOD) + } + + let alpha := mload(chal) + let alpha2 := mload(add(chal, 0x20)) + // PI - L1(x) * alpha^2 - alpha * \prod_i=1..m-1 (w_i + beta * sigma_i + gamma) * (w_m + + // gamma) * z(xw) + res := addmod(piEval, sub(R_MOD, mulmod(alpha2, lagrangeOneEval, R_MOD)), R_MOD) + res := addmod(res, sub(R_MOD, mulmod(alpha, perm, R_MOD)), R_MOD) + } + } + + function _computeChallenges( + IPlonkVerifier.VerifyingKey memory vk, + uint256[8] memory pi, + IPlonkVerifier.PlonkProof memory proof + ) internal pure returns (Challenges memory res) { + assembly { + // use free memory space for scratch pad, 0x40: free memory ptr + let statePtr := mload(0x40) + let dataPtr := add(statePtr, 0x20) + + // Start of transcript (unit: bytes) + // sizeInBits (4) | domainSize (8) | numInputs (8) | pad (12) + mstore(dataPtr, 0) // initialize to 0 first + mstore(dataPtr, shl(224, 254)) // sizeInBits + mstore(add(dataPtr, 4), shl(192, mload(vk))) // domainSize + mstore(add(dataPtr, 12), shl(192, mload(add(vk, 0x20)))) // numInputs + + // G2 from SRS + mstore(add(dataPtr, 0x20), mload(add(vk, 0x280))) // g2LSB (32) + mstore(add(dataPtr, 0x40), mload(add(vk, 0x2a0))) // g2MSB (32) + + // k0 ~ k4 + mstore(add(dataPtr, 0x60), 0x1) + mstore( + add(dataPtr, 0x80), + 0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a + ) + mstore( + add(dataPtr, 0xa0), + 0x1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025 + ) + mstore( + add(dataPtr, 0xc0), + 0x2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a + ) + mstore( + add(dataPtr, 0xe0), + 0x2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881 + ) + + // selectors + let q1Ptr := mload(add(vk, 0xe0)) + mstore(add(dataPtr, 0x100), mload(q1Ptr)) // q1.x + mstore(add(dataPtr, 0x120), mload(add(q1Ptr, 0x20))) // q1.y + let q2Ptr := mload(add(vk, 0x100)) + mstore(add(dataPtr, 0x140), mload(q2Ptr)) // q2.x + mstore(add(dataPtr, 0x160), mload(add(q2Ptr, 0x20))) // q2.y + let q3Ptr := mload(add(vk, 0x120)) + mstore(add(dataPtr, 0x180), mload(q3Ptr)) // q3.x + mstore(add(dataPtr, 0x1a0), mload(add(q3Ptr, 0x20))) // q3.y + let q4Ptr := mload(add(vk, 0x140)) + mstore(add(dataPtr, 0x1c0), mload(q4Ptr)) // q4.x + mstore(add(dataPtr, 0x1e0), mload(add(q4Ptr, 0x20))) // q4.y + let qM12Ptr := mload(add(vk, 0x160)) + mstore(add(dataPtr, 0x200), mload(qM12Ptr)) // qM12.x + mstore(add(dataPtr, 0x220), mload(add(qM12Ptr, 0x20))) // qM12.y + let qM34Ptr := mload(add(vk, 0x180)) + mstore(add(dataPtr, 0x240), mload(qM34Ptr)) // qM34.x + mstore(add(dataPtr, 0x260), mload(add(qM34Ptr, 0x20))) // qM34.y + let qH1Ptr := mload(add(vk, 0x1e0)) + mstore(add(dataPtr, 0x280), mload(qH1Ptr)) // qH1.x + mstore(add(dataPtr, 0x2a0), mload(add(qH1Ptr, 0x20))) // qH1.y + let qH2Ptr := mload(add(vk, 0x200)) + mstore(add(dataPtr, 0x2c0), mload(qH2Ptr)) // qH2.x + mstore(add(dataPtr, 0x2e0), mload(add(qH2Ptr, 0x20))) // qH2.y + let qH3Ptr := mload(add(vk, 0x220)) + mstore(add(dataPtr, 0x300), mload(qH3Ptr)) // qH3.x + mstore(add(dataPtr, 0x320), mload(add(qH3Ptr, 0x20))) // qH3.y + let qH4Ptr := mload(add(vk, 0x240)) + mstore(add(dataPtr, 0x340), mload(qH4Ptr)) // qH4.x + mstore(add(dataPtr, 0x360), mload(add(qH4Ptr, 0x20))) // qH4.y + let qOPtr := mload(add(vk, 0x1a0)) + mstore(add(dataPtr, 0x380), mload(qOPtr)) // qO.x + mstore(add(dataPtr, 0x3a0), mload(add(qOPtr, 0x20))) // qO.y + let qCPtr := mload(add(vk, 0x1c0)) + mstore(add(dataPtr, 0x3c0), mload(qCPtr)) // qC.x + mstore(add(dataPtr, 0x3e0), mload(add(qCPtr, 0x20))) // qC.y + let qECCPtr := mload(add(vk, 0x260)) + mstore(add(dataPtr, 0x400), mload(qECCPtr)) // qECC.x + mstore(add(dataPtr, 0x420), mload(add(qECCPtr, 0x20))) // qECC.y + + // sigmas + let sigma0Ptr := mload(add(vk, 0x40)) + mstore(add(dataPtr, 0x440), mload(sigma0Ptr)) // sigma0.x + mstore(add(dataPtr, 0x460), mload(add(sigma0Ptr, 0x20))) // sigma0.y + let sigma1Ptr := mload(add(vk, 0x60)) + mstore(add(dataPtr, 0x480), mload(sigma1Ptr)) // sigma1.x + mstore(add(dataPtr, 0x4a0), mload(add(sigma1Ptr, 0x20))) // sigma1.y + let sigma2Ptr := mload(add(vk, 0x80)) + mstore(add(dataPtr, 0x4c0), mload(sigma2Ptr)) // sigma2.x + mstore(add(dataPtr, 0x4e0), mload(add(sigma2Ptr, 0x20))) // sigma2.y + let sigma3Ptr := mload(add(vk, 0xa0)) + mstore(add(dataPtr, 0x500), mload(sigma3Ptr)) // sigma3.x + mstore(add(dataPtr, 0x520), mload(add(sigma3Ptr, 0x20))) // sigma3.y + let sigma4Ptr := mload(add(vk, 0xc0)) + mstore(add(dataPtr, 0x540), mload(sigma4Ptr)) // sigma4.x + mstore(add(dataPtr, 0x560), mload(add(sigma4Ptr, 0x20))) // sigma4.y + + // public inputs + mstore(add(dataPtr, 0x580), mload(pi)) // PI[0] + mstore(add(dataPtr, 0x5a0), mload(add(pi, 0x20))) // PI[1] + mstore(add(dataPtr, 0x5c0), mload(add(pi, 0x40))) // PI[2] + mstore(add(dataPtr, 0x5e0), mload(add(pi, 0x60))) // PI[3] + mstore(add(dataPtr, 0x600), mload(add(pi, 0x80))) // PI[4] + mstore(add(dataPtr, 0x620), mload(add(pi, 0xa0))) // PI[5] + mstore(add(dataPtr, 0x640), mload(add(pi, 0xc0))) // PI[6] + mstore(add(dataPtr, 0x660), mload(add(pi, 0xe0))) // PI[7] + + // proof + let wire0Ptr := mload(proof) + mstore(add(dataPtr, 0x680), mload(wire0Ptr)) // wire0.x + mstore(add(dataPtr, 0x6a0), mload(add(wire0Ptr, 0x20))) // wire0.y + let wire1Ptr := mload(add(proof, 0x20)) + mstore(add(dataPtr, 0x6c0), mload(wire1Ptr)) // wire1.x + mstore(add(dataPtr, 0x6e0), mload(add(wire1Ptr, 0x20))) // wire1.y + let wire2Ptr := mload(add(proof, 0x40)) + mstore(add(dataPtr, 0x700), mload(wire2Ptr)) // wire2.x + mstore(add(dataPtr, 0x720), mload(add(wire2Ptr, 0x20))) // wire2.y + let wire3Ptr := mload(add(proof, 0x60)) + mstore(add(dataPtr, 0x740), mload(wire3Ptr)) // wire3.x + mstore(add(dataPtr, 0x760), mload(add(wire3Ptr, 0x20))) // wire3.y + let wire4Ptr := mload(add(proof, 0x80)) + mstore(add(dataPtr, 0x780), mload(wire4Ptr)) // wire4.x + mstore(add(dataPtr, 0x7a0), mload(add(wire4Ptr, 0x20))) // wire4.y + + // challenge: beta + { + mstore(statePtr, 0x0) // init state + // preimage len: state(0x20) + transcript(0x7c0) + mstore(add(dataPtr, 0x7c0), keccak256(statePtr, 0x7e0)) + // update new state (by updating state pointer) + statePtr := add(dataPtr, 0x7c0) + // empty transcript + dataPtr := add(statePtr, 0x20) + // (mod R_MOD) to get beta + mstore(add(res, 0x60), mod(mload(statePtr), R_MOD)) + } + + // challenge: gamma + { + // preimage len: state(0x20) + transcript(0x0) + mstore(dataPtr, keccak256(statePtr, 0x20)) + // update new state (by updating state pointer) + statePtr := dataPtr + // empty transcript + dataPtr := add(statePtr, 0x20) + // (mod R_MOD) to get gamma + mstore(add(res, 0x80), mod(mload(statePtr), R_MOD)) + } + + let prodPermPtr := mload(add(proof, 0xa0)) + mstore(dataPtr, mload(prodPermPtr)) // prodPerm.x + mstore(add(dataPtr, 0x20), mload(add(prodPermPtr, 0x20))) // prodPerm.y + + // challenge: alpha, alpha2, alpha3 + { + // preimage len: state(0x20) + transcript(0x40) + let alpha := keccak256(statePtr, 0x60) + // update new state (by updating state pointer) + statePtr := add(dataPtr, 0x40) + mstore(statePtr, alpha) + // empty transcript + dataPtr := add(statePtr, 0x20) + // (mod R_MOD) to get challenge + mstore(res, mod(alpha, R_MOD)) + + let alpha2 := mulmod(alpha, alpha, R_MOD) + let alpha3 := mulmod(alpha2, alpha, R_MOD) + mstore(add(res, 0x20), alpha2) + mstore(add(res, 0x40), alpha3) + } + + let split0Ptr := mload(add(proof, 0xc0)) + mstore(dataPtr, mload(split0Ptr)) // split0.x + mstore(add(dataPtr, 0x20), mload(add(split0Ptr, 0x20))) // split0.y + let split1Ptr := mload(add(proof, 0xe0)) + mstore(add(dataPtr, 0x40), mload(split1Ptr)) // split1.x + mstore(add(dataPtr, 0x60), mload(add(split1Ptr, 0x20))) // split1.y + let split2Ptr := mload(add(proof, 0x100)) + mstore(add(dataPtr, 0x80), mload(split2Ptr)) // split2.x + mstore(add(dataPtr, 0xa0), mload(add(split2Ptr, 0x20))) // split2.y + let split3Ptr := mload(add(proof, 0x120)) + mstore(add(dataPtr, 0xc0), mload(split3Ptr)) // split3.x + mstore(add(dataPtr, 0xe0), mload(add(split3Ptr, 0x20))) // split3.y + let split4Ptr := mload(add(proof, 0x140)) + mstore(add(dataPtr, 0x100), mload(split4Ptr)) // split4.x + mstore(add(dataPtr, 0x120), mload(add(split4Ptr, 0x20))) // split4.y + + // challenge: zeta + { + // preimage len: state(0x20) + transcript(0x140) + mstore(add(dataPtr, 0x140), keccak256(statePtr, 0x160)) + // update new state (by updating state pointer) + statePtr := add(dataPtr, 0x140) + // empty transcript + dataPtr := add(statePtr, 0x20) + // (mod R_MOD) to get challenge + mstore(add(res, 0xa0), mod(mload(statePtr), R_MOD)) + } + + mstore(dataPtr, mload(add(proof, 0x1a0))) // wireEval0 + mstore(add(dataPtr, 0x20), mload(add(proof, 0x1c0))) // wireEval1 + mstore(add(dataPtr, 0x40), mload(add(proof, 0x1e0))) // wireEval2 + mstore(add(dataPtr, 0x60), mload(add(proof, 0x200))) // wireEval3 + mstore(add(dataPtr, 0x80), mload(add(proof, 0x220))) // wireEval4 + mstore(add(dataPtr, 0xa0), mload(add(proof, 0x240))) // sigmaEval0 + mstore(add(dataPtr, 0xc0), mload(add(proof, 0x260))) // sigmaEval1 + mstore(add(dataPtr, 0xe0), mload(add(proof, 0x280))) // sigmaEval2 + mstore(add(dataPtr, 0x100), mload(add(proof, 0x2a0))) // sigmaEval3 + mstore(add(dataPtr, 0x120), mload(add(proof, 0x2c0))) // prodPermZetaOmegaEval + + // challenge: v + { + // preimage len: state(0x20) + transcript(0x140) + mstore(add(dataPtr, 0x140), keccak256(statePtr, 0x160)) + // update new state (by updating state pointer) + statePtr := add(dataPtr, 0x140) + // empty transcript + dataPtr := add(statePtr, 0x20) + // (mod R_MOD) to get challenge + mstore(add(res, 0xc0), mod(mload(statePtr), R_MOD)) + } + + let zetaPtr := mload(add(proof, 0x160)) + mstore(dataPtr, mload(zetaPtr)) // zeta.x + mstore(add(dataPtr, 0x20), mload(add(zetaPtr, 0x20))) // zeta.y + let zetaOmegaPtr := mload(add(proof, 0x180)) + mstore(add(dataPtr, 0x40), mload(zetaOmegaPtr)) // zetaOmega.x + mstore(add(dataPtr, 0x60), mload(add(zetaOmegaPtr, 0x20))) // zetaOmega.y + + // challenge: u + { + // preimage len: state(0x20) + transcript(0x80) + let hash := keccak256(statePtr, 0xa0) + // (mod R_MOD) to get challenge + mstore(add(res, 0xe0), mod(hash, R_MOD)) + } + } + } + + function verify( + IPlonkVerifier.VerifyingKey memory vk, + uint256[8] memory publicInput, + IPlonkVerifier.PlonkProof memory proof + ) external view returns (bool success) { + _validateProof(proof); + + BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[0])); + BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[1])); + BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[2])); + BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[3])); + BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[4])); + BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[5])); + BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[6])); + BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[7])); + + Challenges memory chal = _computeChallenges(vk, publicInput, proof); + Poly.EvalDomain memory domain = Poly.newEvalDomain(vk.domainSize); + Poly.EvalData memory evalData = Poly.evalDataGen(domain, chal.zeta, publicInput); + + uint256 linPolyConstant = _computeLinPolyConstantTerm(chal, proof, evalData); + + assembly { + // credit: error function from Succinct's SP1 code + function error_verify() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0xc) + mstore(add(ptError, 0x44), "error verify") + revert(ptError, 0x64) + } + function error_pairing() { + let ptError := mload(0x40) + mstore(ptError, ERROR_STRING_ID) // selector for function Error(string) + mstore(add(ptError, 0x4), 0x20) + mstore(add(ptError, 0x24), 0xd) + mstore(add(ptError, 0x44), "error pairing") + revert(ptError, 0x64) + } + // allocate 64 bytes in memory to store a G1 point + function mallocG1() -> ptr { + ptr := mload(0x40) + mstore(0x40, add(ptr, 0x40)) + } + + // base: &uint256[2], scalar: uint256 + // result will be written to 0x00 (as there are 64 bytes of scratch space) + function scalarMul(base, scalar) { + let ptr := mload(0x40) // free memory pointer + // layout: + // 0x00: base.x + // 0x20: base.y + // 0x40: scalar + mstore(ptr, mload(base)) + mstore(add(ptr, 0x20), mload(add(base, 0x20))) + mstore(add(ptr, 0x40), scalar) + let l_success := staticcall(gas(), 7, ptr, 0x60, 0x00, 0x40) + if iszero(l_success) { error_verify() } + } + + // self: &uint256[2], rhs: &uint256[2] placed at 0x0 + // self += rhs (G1 point addition) + function g1AddAssign(self) { + let ptr := mload(0x40) // free memory pointer + // layout: + // 0x00: self.x + // 0x20: self.y + // 0x40: rhs.x + // 0x60: rhs.y + mstore(ptr, mload(self)) + mstore(add(ptr, 0x20), mload(add(self, 0x20))) + mstore(add(ptr, 0x40), mload(0x0)) + mstore(add(ptr, 0x60), mload(add(0x0, 0x20))) + let l_success := staticcall(gas(), 6, ptr, 0x80, self, 0x40) + if iszero(l_success) { error_verify() } + } + + /// @dev self: &uint256[2] + /// self = -self + function g1NegateAssign(self) { + let y := mload(add(self, 0x20)) + mstore(add(self, 0x20), sub(P_MOD, y)) + } + + // layout for final pairing check (total memory size: 0x180): + // e(a, [x]_2) =?= e(b, [1]_2) + // Definitions: + // - x \in Fp2 = c0 + c1 * X + // 0x00: a.x + // 0x20: a.y + // 0x40: [x]_2.x.c0 + // 0x60: [x]_2.x.c1 + // 0x80: [x]_2.y.c0 + // 0xa0: [x]_2.y.c1 + // 0xc0: b.x + // 0xe0: b.y + // 0x100: [1]_2.x.c1 + // 0x120: [1]_2.x.c0 + // 0x140: [1]_2.y.c1 + // 0x160: [1]_2.y.c0 + + let aPtr := mload(0x40) // free memory ptr + let bPtr := add(aPtr, 0xc0) + // load beta_h (i.e. [x]_2) from SRS + mstore(add(aPtr, 0x40), BETA_H_X0) + mstore(add(aPtr, 0x60), BETA_H_X1) + mstore(add(aPtr, 0x80), BETA_H_Y0) + mstore(add(aPtr, 0xa0), BETA_H_Y1) + // load BN254.P2 (i.e. [1]_2) from SRS + mstore(add(aPtr, 0x100), H_X0) + mstore(add(aPtr, 0x120), H_X1) + mstore(add(aPtr, 0x140), H_Y0) + mstore(add(aPtr, 0x160), H_Y1) + // reserve space for inputs to the pairing check + mstore(0x40, add(aPtr, 0x180)) + + let base := 0x00 + let scalar := 0 + let tmp := 0 + let tmp2 := 0 + + let gamma := mload(add(chal, 0x80)) + + // ============================================ + // Compute coefficient for the permutation product polynomial commitment. + // firstScalar = + // L1(zeta) * alpha^2 + // + alpha + // * (beta * zeta + wireEval0 + gamma) + // * (beta * k1 * zeta + wireEval1 + gamma) + // * (beta * k2 * zeta + wireEval2 + gamma) + // * ... + // where wireEval0, wireEval1, wireEval2, ... are in w_evals + // ============================================ + { + // firstScalar = alpha^2 * L1(zeta) + scalar := mulmod(mload(add(chal, 0x20)), mload(add(evalData, 0x20)), R_MOD) + // rhs = alpha + let rhs := mload(chal) + // tmp = beta * zeta + tmp := mulmod(mload(add(chal, 0x60)), mload(add(chal, 0xA0)), R_MOD) + // ================================= + // k0 (which is 1) component + // (beta * zeta + wireEval0 + gamma) + // ================================= + tmp2 := addmod(tmp, mload(add(proof, 0x1A0)), R_MOD) + tmp2 := addmod(tmp2, gamma, R_MOD) + rhs := mulmod(tmp2, rhs, R_MOD) + + // ================================= + // k1 component + // (beta * zeta * k1 + wireEval1 + gamma) + // ================================= + tmp2 := mulmod(tmp, COSET_K1, R_MOD) + tmp2 := addmod(tmp2, mload(add(proof, 0x1C0)), R_MOD) + tmp2 := addmod(tmp2, gamma, R_MOD) + rhs := mulmod(tmp2, rhs, R_MOD) + + // ================================= + // k2 component + // (beta * zeta * k2 + wireEval2 + gamma) + // ================================= + tmp2 := mulmod(tmp, COSET_K2, R_MOD) + tmp2 := addmod(tmp2, mload(add(proof, 0x1E0)), R_MOD) + tmp2 := addmod(tmp2, gamma, R_MOD) + rhs := mulmod(tmp2, rhs, R_MOD) + + // ================================= + // k3 component + // (beta * zeta * k3 + wireEval3 + gamma) + // ================================= + tmp2 := mulmod(tmp, COSET_K3, R_MOD) + tmp2 := addmod(tmp2, mload(add(proof, 0x200)), R_MOD) + tmp2 := addmod(tmp2, gamma, R_MOD) + rhs := mulmod(tmp2, rhs, R_MOD) + + // ================================= + // k4 component + // (beta * zeta * k4 + wireEval4 + gamma) + // ================================= + tmp2 := mulmod(tmp, COSET_K4, R_MOD) + tmp2 := addmod(tmp2, mload(add(proof, 0x220)), R_MOD) + tmp2 := addmod(tmp2, gamma, R_MOD) + rhs := mulmod(tmp2, rhs, R_MOD) + + scalar := addmod(scalar, rhs, R_MOD) // firstScalar + } + base := mload(add(proof, 0xa0)) // proof.prodPerm + scalarMul(base, scalar) + // update G1 point `b` with result from scalarMul in scratch pad + mstore(bPtr, mload(0x00)) + mstore(add(bPtr, 0x20), mload(0x20)) + + // ============================================ + // Compute coefficient for the last wire sigma polynomial commitment. + // secondScalar = - alpha * beta * z_w + // * (wireEval0 + gamma + beta * sigmaEval0) + // * (wireEval1 + gamma + beta * sigmaEval1) + // * ... + // ============================================ + // secondScalar = alpha * beta * z_w + scalar := mulmod(mload(chal), mload(add(chal, 0x60)), R_MOD) + scalar := mulmod(scalar, mload(add(proof, 0x2C0)), R_MOD) + + // (wireEval0 + gamma + beta * sigmaEval0) + tmp := mulmod(mload(add(chal, 0x60)), mload(add(proof, 0x240)), R_MOD) + tmp := addmod(tmp, mload(add(proof, 0x1A0)), R_MOD) + tmp := addmod(tmp, gamma, R_MOD) + scalar := mulmod(scalar, tmp, R_MOD) + + // (wireEval1 + gamma + beta * sigmaEval1) + tmp := mulmod(mload(add(chal, 0x60)), mload(add(proof, 0x260)), R_MOD) + tmp := addmod(tmp, mload(add(proof, 0x1C0)), R_MOD) + tmp := addmod(tmp, gamma, R_MOD) + scalar := mulmod(scalar, tmp, R_MOD) + + // (wireEval2 + gamma + beta * sigmaEval2) + tmp := mulmod(mload(add(chal, 0x60)), mload(add(proof, 0x280)), R_MOD) + tmp := addmod(tmp, mload(add(proof, 0x1E0)), R_MOD) + tmp := addmod(tmp, gamma, R_MOD) + scalar := mulmod(scalar, tmp, R_MOD) + + // (wireEval3 + gamma + beta * sigmaEval3) + tmp := mulmod(mload(add(chal, 0x60)), mload(add(proof, 0x2A0)), R_MOD) + tmp := addmod(tmp, mload(add(proof, 0x200)), R_MOD) + tmp := addmod(tmp, gamma, R_MOD) + + scalar := sub(R_MOD, mulmod(scalar, tmp, R_MOD)) // secondScalar + base := mload(add(vk, 0xc0)) // vk.sigma4 + scalarMul(base, scalar) // base^scalar (res stored at 0x00) + g1AddAssign(bPtr) // b += base^scalar + + // ============ + // q_lc: linear combination selectors + // ============ + scalar := mload(add(proof, 0x1a0)) // proof.wireEval0 + base := mload(add(vk, 0xe0)) // vk.q1 + scalarMul(base, scalar) // q1^wireEval0 (result stored at 0x00) + g1AddAssign(bPtr) // b += q1^wireEval0 + + scalar := mload(add(proof, 0x1c0)) // proof.wireEval1 + base := mload(add(vk, 0x100)) // vk.q2 + scalarMul(base, scalar) // q2^wireEval1 (result stored at 0x00) + g1AddAssign(bPtr) // b += q2^wireEval1 + + scalar := mload(add(proof, 0x1e0)) // proof.wireEval2 + base := mload(add(vk, 0x120)) // vk.q3 + scalarMul(base, scalar) // q3^wireEval2 (result stored at 0x00) + g1AddAssign(bPtr) // b += q3^wireEval2 + + scalar := mload(add(proof, 0x200)) // proof.wireEval3 + base := mload(add(vk, 0x140)) // vk.q4 + scalarMul(base, scalar) // q4^wireEval3 (result stored at 0x00) + g1AddAssign(bPtr) // b += q4^wireEval3 + + // ============ + // q_M: multiplication selectors + // ============ + // w_evals[0] * w_evals[1] + scalar := mulmod(mload(add(proof, 0x1a0)), mload(add(proof, 0x1c0)), R_MOD) + base := mload(add(vk, 0x160)) // vk.qM12 + scalarMul(base, scalar) // qM12^(wireEval0 * wireEval1) + g1AddAssign(bPtr) // b += qM12^(wireEval0 * wireEval1) + + // w_evals[2] * w_evals[3] + scalar := mulmod(mload(add(proof, 0x1e0)), mload(add(proof, 0x200)), R_MOD) + base := mload(add(vk, 0x180)) // vk.qM34 + scalarMul(base, scalar) // qM34^(wireEval2 * wireEval3) + g1AddAssign(bPtr) // b += qM34^(wireEval2 * wireEval3) + + // ============ + // q_H: hash (rescue-friendly) selectors + // ============ + // w_evals[0].pow(5); + tmp := mload(add(proof, 0x1a0)) // proof.wireEval0 + tmp2 := mulmod(tmp, tmp, R_MOD) + tmp2 := mulmod(tmp2, tmp2, R_MOD) + scalar := mulmod(tmp, tmp2, R_MOD) + base := mload(add(vk, 0x1e0)) // vk.qH1 + scalarMul(base, scalar) // qH1^(wireEval0.pow(5)) + g1AddAssign(bPtr) // b += qH1^(wireEval0.pow(5)) + + // w_evals[1].pow(5); + tmp := mload(add(proof, 0x1c0)) // proof.wireEval1 + tmp2 := mulmod(tmp, tmp, R_MOD) + tmp2 := mulmod(tmp2, tmp2, R_MOD) + scalar := mulmod(tmp, tmp2, R_MOD) + base := mload(add(vk, 0x200)) // vk.qH2 + scalarMul(base, scalar) // qH2^(wireEval2.pow(5)) + g1AddAssign(bPtr) // b += qH2^(wireEval1.pow(5)) + + // w_evals[2].pow(5); + tmp := mload(add(proof, 0x1e0)) // proof.wireEval2 + tmp2 := mulmod(tmp, tmp, R_MOD) + tmp2 := mulmod(tmp2, tmp2, R_MOD) + scalar := mulmod(tmp, tmp2, R_MOD) + base := mload(add(vk, 0x220)) // vk.qH3 + scalarMul(base, scalar) // qH3^(wireEval2.pow(5)) + g1AddAssign(bPtr) // b += qH3^(wireEval2.pow(5)) + + // w_evals[3].pow(5); + tmp := mload(add(proof, 0x200)) // proof.wireEval3 + tmp2 := mulmod(tmp, tmp, R_MOD) + tmp2 := mulmod(tmp2, tmp2, R_MOD) + scalar := mulmod(tmp, tmp2, R_MOD) + base := mload(add(vk, 0x240)) // vk.qH4 + scalarMul(base, scalar) // qH4^(wireEval3.pow(5)) + g1AddAssign(bPtr) // b += qH4^(wireEval3.pow(5)) + + // ============ + // q_o and q_c: output and constant selectors + // ============ + scalar := sub(R_MOD, mload(add(proof, 0x220))) // - proof.wireEval4 + base := mload(add(vk, 0x1a0)) // vk.qO + scalarMul(base, scalar) // qO^(-w_evals[4]) + g1AddAssign(bPtr) // b += qO^(-w_evals[4]) + + scalar := 1 + base := mload(add(vk, 0x1c0)) // vk.qC + scalarMul(base, scalar) // qC + g1AddAssign(bPtr) // b += qC + + // ============ + // q_Ecc: Elliptic Curve Operation selector + // ============ + // q_Ecc = w_evals[0] * w_evals[1] * w_evals[2] * w_evals[3] * w_evals[4]; + tmp := mulmod(mload(add(proof, 0x1a0)), mload(add(proof, 0x1c0)), R_MOD) + tmp := mulmod(tmp, mload(add(proof, 0x1E0)), R_MOD) + tmp := mulmod(tmp, mload(add(proof, 0x200)), R_MOD) + scalar := mulmod(tmp, mload(add(proof, 0x220)), R_MOD) + base := mload(add(vk, 0x260)) // vk.qEcc + scalarMul(base, scalar) // qEcc^(\prod{w_evals}) + g1AddAssign(bPtr) // b += qEcc^(\prod{w_evals}) + + // ============================================ + // splitting quotient commitments + // ============================================ + // 1 - zeta^n = - (zeta^n - 1) + scalar := sub(R_MOD, mload(evalData)) // - vanishEval + base := mload(add(proof, 0xc0)) // proof.split0 + scalarMul(base, scalar) // split0^(-vanishEval) + g1AddAssign(bPtr) // b += split0^(-vanishEval) + + // (1-zeta^n) * zeta^(n+2) + tmp := addmod(mload(evalData), 1, R_MOD) // zeta^n + tmp2 := mload(add(chal, 0xa0)) // zeta + tmp2 := mulmod(tmp2, tmp2, R_MOD) // zeta^2 + tmp := mulmod(tmp, tmp2, R_MOD) // zeta^(n+2) + scalar := mulmod(scalar, tmp, R_MOD) + base := mload(add(proof, 0xe0)) // proof.split1 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += split1^[(1-zeta^n) * zeta^(n+2)] + + // (1-zeta^n) * zeta^2(n+2) + scalar := mulmod(scalar, tmp, R_MOD) + base := mload(add(proof, 0x100)) // proof.split2 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += split2^[(1-zeta^n) * zeta^2(n+2)] + + // (1-zeta^n) * zeta^3(n+2) + scalar := mulmod(scalar, tmp, R_MOD) + base := mload(add(proof, 0x120)) // proof.split3 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += split3^[(1-zeta^n) * zeta^3(n+2)] + + // (1-zeta^n) * zeta^4(n+2) + scalar := mulmod(scalar, tmp, R_MOD) + base := mload(add(proof, 0x140)) // proof.split4 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += split4^[(1-zeta^n) * zeta^4(n+2)] + + // ============================================ + // Add wire witness poly commitments + // Meanwhile, _prepareEvaluation (`[E]1` in Sec 8.4, step 11 of Plonk) + // ============================================ + let eval := sub(R_MOD, linPolyConstant) // - r0 + tmp := mload(add(chal, 0xc0)) // chal.v + + scalar := tmp // chal.v + base := mload(proof) // proof.wire0 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += wire0^v + // eval += v * proof.wireEval0 + eval := addmod(eval, mulmod(scalar, mload(add(proof, 0x1a0)), R_MOD), R_MOD) + + scalar := mulmod(scalar, tmp, R_MOD) // v^2 + base := mload(add(proof, 0x20)) // proof.wire1 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += wire1^(v^2) + // eval += v^2 * proof.wireEval1 + eval := addmod(eval, mulmod(scalar, mload(add(proof, 0x1c0)), R_MOD), R_MOD) + + scalar := mulmod(scalar, tmp, R_MOD) // v^3 + base := mload(add(proof, 0x40)) // proof.wire2 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += wire2^(v^3) + // eval += v^3 * proof.wireEval2 + eval := addmod(eval, mulmod(scalar, mload(add(proof, 0x1e0)), R_MOD), R_MOD) + + scalar := mulmod(scalar, tmp, R_MOD) // v^4 + base := mload(add(proof, 0x60)) // proof.wire3 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += wire3^(v^4) + // eval += v^4 * proof.wireEval3 + eval := addmod(eval, mulmod(scalar, mload(add(proof, 0x200)), R_MOD), R_MOD) + + scalar := mulmod(scalar, tmp, R_MOD) // v^5 + base := mload(add(proof, 0x80)) // proof.wire4 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += wire4^(v^5) + // eval += v^5 * proof.wireEval4 + eval := addmod(eval, mulmod(scalar, mload(add(proof, 0x220)), R_MOD), R_MOD) + + // ============================================ + // Add sigma poly commitments + // The last sigma commitment is excluded. + // ============================================ + scalar := mulmod(scalar, tmp, R_MOD) // v^6 + base := mload(add(vk, 0x40)) // vk.sigma0 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += sigma0^(v^6) + // eval += v^6 * proof.sigmaEval0 + eval := addmod(eval, mulmod(scalar, mload(add(proof, 0x240)), R_MOD), R_MOD) + + scalar := mulmod(scalar, tmp, R_MOD) // v^7 + base := mload(add(vk, 0x60)) // vk.sigma1 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += sigma1^(v^7) + // eval += v^7 * proof.sigmaEval1 + eval := addmod(eval, mulmod(scalar, mload(add(proof, 0x260)), R_MOD), R_MOD) + + scalar := mulmod(scalar, tmp, R_MOD) // v^8 + base := mload(add(vk, 0x80)) // vk.sigma2 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += sigma2^(v^8) + // eval += v^8 * proof.sigmaEval2 + eval := addmod(eval, mulmod(scalar, mload(add(proof, 0x280)), R_MOD), R_MOD) + + scalar := mulmod(scalar, tmp, R_MOD) // v^9 + base := mload(add(vk, 0xa0)) // vk.sigma3 + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += sigma3^(v^9) + // eval += v^9 * proof.sigmaEval3 + eval := addmod(eval, mulmod(scalar, mload(add(proof, 0x2a0)), R_MOD), R_MOD) + + // ============================================ + // Add poly comm evaluated at point `zeta * g` + // ============================================ + scalar := mload(add(chal, 0xe0)) // chal.u + base := mload(add(proof, 0xa0)) // proof.prodPerm + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += prodPerm^u + // eval += u * proof.prodPermZetaOmegaEval + eval := addmod(eval, mulmod(scalar, mload(add(proof, 0x2c0)), R_MOD), R_MOD) + + scalar := mload(add(chal, 0xa0)) // chal.zeta or evalPoint + base := mload(add(proof, 0x160)) // proof.zeta or openingProof + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += proof.zeta^chal.zeta + + // chal.zeta * groupGen or nextEvalPoint + tmp := mulmod(scalar, mload(add(mload(add(domain, 0x40)), 0x20)), R_MOD) + scalar := mulmod(tmp, mload(add(chal, 0xe0)), R_MOD) // u * nextEvalPoint + base := mload(add(proof, 0x180)) // shiftedOpeningProof or proof.zetaOmega + scalarMul(base, scalar) + g1AddAssign(bPtr) // b += proof.zetaOmega^(u * chal.zeta * groupGen) + + base := mallocG1() + mstore(base, 1) // BN254.P1.x + mstore(add(base, 0x20), 2) // BN254.P1.y + scalarMul(base, sub(R_MOD, eval)) // P1^-eval or [E]1 in paper + g1AddAssign(bPtr) // b += P1^-eval + + // b = -b + g1NegateAssign(bPtr) + + // a = openingProof + shiftedOpeningProof^u + // first store openingProof to aPtr + tmp := mload(add(proof, 0x160)) // ptr to proof.zeta + mstore(aPtr, mload(tmp)) + mstore(add(aPtr, 0x20), mload(add(tmp, 0x20))) + + scalar := mload(add(chal, 0xe0)) // chal.u + base := mload(add(proof, 0x180)) // shiftedOpeningProof or proof.zetaOmega + scalarMul(base, scalar) + g1AddAssign(aPtr) // a += shiftedOpeningProof^u + + // ============================================ + // Final pairing check + // ============================================ + let l_success := staticcall(gas(), 8, aPtr, 0x180, 0x00, 0x20) + if iszero(l_success) { error_pairing() } + + success := mload(0x00) + } + } +} diff --git a/contracts/src/libraries/PolynomialEval.sol b/contracts/src/libraries/PolynomialEval.sol index 60138c7f79..e971f67515 100644 --- a/contracts/src/libraries/PolynomialEval.sol +++ b/contracts/src/libraries/PolynomialEval.sol @@ -9,16 +9,12 @@ import { BN254 } from "bn254/BN254.sol"; library PolynomialEval { /// Unsupported polynomial degree, currently size must in 2^{14~17}. error UnsupportedDegree(); - /// Unexpected input arguments, some precondition assumptions violated. - error InvalidPolyEvalArgs(); /// @dev a Radix 2 Evaluation Domain struct EvalDomain { uint256 logSize; // log_2(self.size) - uint256 size; // Size of the domain as a field element uint256 sizeInv; // Inverse of the size in the field - uint256 groupGen; // A generator of the subgroup - uint256 groupGenInv; // Inverse of the generator of the subgroup + uint256[8] elements; // 1, g, g^2, ..., g^7 } /// @dev stores vanishing poly, lagrange at 1, and Public input poly @@ -29,57 +25,56 @@ library PolynomialEval { } /// @dev Create a new Radix2EvalDomain with `domainSize` which should be power of 2. - /// @dev Will revert if domainSize is not among {2^5, 2^16, 2^17, 2^18, 2^19, 2^20} + /// @dev Will revert if domainSize is not among {2^5, 2^16, 2^20} + /// @dev The hardcoded values are generated by the rust script `eval-domain`. function newEvalDomain(uint256 domainSize) internal pure returns (EvalDomain memory) { if (domainSize == 65536) { + // For testing purposes return EvalDomain( 16, - domainSize, 0x30641e0e92bebef818268d663bcad6dbcfd6c0149170f6d7d350b1b1fa6c1001, - 0x00eeb2cb5981ed45649abebde081dcff16c8601de4347e7dd1628ba2daac43b7, - 0x0b5d56b77fe704e8e92338c0082f37e091126414c830e4c6922d5ac802d842d4 - ); - } else if (domainSize == 131072) { - return EvalDomain( - 17, - domainSize, - 0x30643640b9f82f90e83b698e5ea6179c7c05542e859533b48b9953a2f5360801, - 0x1bf82deba7d74902c3708cc6e70e61f30512eca95655210e276e5858ce8f58e5, - 0x244cf010c43ca87237d8b00bf9dd50c4c01c7f086bd4e8c920e75251d96f0d22 - ); - } else if (domainSize == 262144) { - return EvalDomain( - 18, - domainSize, - 0x30644259cd94e7dd5045d7a27013b7fcd21c9e3b7fa75222e7bda49b729b0401, - 0x19ddbcaf3a8d46c15c0176fbb5b95e4dc57088ff13f4d1bd84c6bfa57dcdc0e0, - 0x36853f083780e87f8d7c71d111119c57dbe118c22d5ad707a82317466c5174c - ); - } else if (domainSize == 524288) { - return EvalDomain( - 19, - domainSize, - 0x3064486657634403844b0eac78ca882cfd284341fcb0615a15cfcd17b14d8201, - 0x2260e724844bca5251829353968e4915305258418357473a5c1d597f613f6cbd, - 0x6e402c0a314fb67a15cf806664ae1b722dbc0efe66e6c81d98f9924ca535321 + [ + 0x1, + 0xeeb2cb5981ed45649abebde081dcff16c8601de4347e7dd1628ba2daac43b7, + 0x2d1ba66f5941dc91017171fa69ec2bd0022a2a2d4115a009a93458fd4e26ecfb, + 0x86812a00ac43ea801669c640171203c41a496671bfbc065ac8db24d52cf31e5, + 0x2d965651cdd9e4811f4e51b80ddca8a8b4a93ee17420aae6adaa01c2617c6e85, + 0x12597a56c2e438620b9041b98992ae0d4e705b780057bf7766a2767cece16e1d, + 0x2d94117cd17bcf1290fd67c01155dd40807857dff4a5a0b4dc67befa8aa34fd, + 0x15ee2475bee517c4ee05e51fa1ee7312a8373a0b13db8c51baf04cb2e99bd2bd + ] ); } else if (domainSize == 1048576) { return EvalDomain( 20, - domainSize, 0x30644b6c9c4a72169e4daa317d25f04512ae15c53b34e8f5acd8e155d0a6c101, - 0x26125da10a0ed06327508aba06d1e303ac616632dbed349f53422da953337857, - 0x100c332d2100895fab6473bc2c51bfca521f45cb3baca6260852a8fde26c91f3 + [ + 0x1, + 0x26125da10a0ed06327508aba06d1e303ac616632dbed349f53422da953337857, + 0x2260e724844bca5251829353968e4915305258418357473a5c1d597f613f6cbd, + 0x2087ea2cd664278608fb0ebdb820907f598502c81b6690c185e2bf15cb935f42, + 0x19ddbcaf3a8d46c15c0176fbb5b95e4dc57088ff13f4d1bd84c6bfa57dcdc0e0, + 0x5a2c85cfc591789605cae818e37dd4161eef9aa666bec6fe4288d09e6d23418, + 0x11f70e5363258ff4f0d716a653e1dc41f1c64484d7f4b6e219d6377614a3905c, + 0x29e84143f5870d4776a92df8da8c6c9303d59088f37ba85f40cf6fd14265b4bc + ] ); } if (domainSize == 32) { // useful for small-size test, in practice unlikely to be used. return EvalDomain( 5, - domainSize, 0x2ee12bff4a2813286a8dc388cd754d9a3ef2490635eba50cb9c2e5e750800001, - 0x9c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d0, - 0x2724713603bfbd790aeaf3e7df25d8e7ef8f311334905b4d8c99980cf210979d + [ + 0x1, + 0x9c532c6306b93d29678200d47c0b2a99c18d51b838eeb1d3eed4c533bb512d0, + 0x21082ca216cbbf4e1c6e4f4594dd508c996dfbe1174efb98b11509c6e306460b, + 0x1277ae6415f0ef18f2ba5fb162c39eb7311f386e2d26d64401f4a25da77c253b, + 0x2b337de1c8c14f22ec9b9e2f96afef3652627366f8170a0a948dad4ac1bd5e80, + 0x2fbd4dd2976be55d1a163aa9820fb88dfac5ddce77e1872e90632027327a5ebe, + 0x107aab49e65a67f9da9cd2abf78be38bd9dc1d5db39f81de36bcfa5b4b039043, + 0xe14b6364a47e9c4284a9f80a5fc41cd212b0d4dbf8a5703770a40a9a343990 + ] ); } else { revert UnsupportedDegree(); @@ -117,7 +112,12 @@ library PolynomialEval { BN254.ScalarField zeta, BN254.ScalarField vanishEval ) internal view returns (BN254.ScalarField res) { + if (BN254.ScalarField.unwrap(zeta) == 1) { + // when zeta is first element in the eval domain + return BN254.ScalarField.wrap(1); + } if (BN254.ScalarField.unwrap(vanishEval) == 0) { + // else, if zeta is other elements in the eval domain return BN254.ScalarField.wrap(0); } @@ -144,121 +144,138 @@ library PolynomialEval { /// @dev Evaluate public input polynomial at point `zeta`. function evaluatePiPoly( EvalDomain memory self, - uint256[] memory pi, + uint256[8] memory pi, uint256 zeta, - uint256 vanishEval + uint256 vanishingPolyEval ) internal view returns (uint256 res) { - if (vanishEval == 0) { + uint256 p = BN254.R_MOD; + + if (vanishingPolyEval == 0) { + uint256 group = 1; + for (uint256 i = 0; i < 8; i++) { + if (zeta == group) { + return pi[i]; + } + group = mulmod(group, self.elements[1], p); + } return 0; } - uint256 p = BN254.R_MOD; - uint256 length = pi.length; - uint256 ithLagrange; - uint256 ithDivisor; - uint256 tmp; - uint256 vanishEvalDivN = self.sizeInv; - uint256 divisorProd; - uint256[] memory localDomainElements = domainElements(self, length); - uint256[] memory divisors = new uint256[](length); + // In order to compute PiPoly(zeta) in an efficient way, we can do the following derivation: + + // PiPoly(zeta) = \sum_{i=0}^{length} pi[i] * L_i(zeta) where + // L_i(zeta) = (Z_H(zeta) * g^i) / (n * (zeta - g^i)) + // PiPoly(zeta) = (Z_H(zeta) / n) * \sum_{i=0}^{length} pi[i] * g^i * (\prod_{i neq j} + // (zeta - g^j)) / (\prod_{j=0}^{length} (zeta - g^j)) + + // Since the denominator (\prod_{j=0}^{length} (zeta - g^j)) is the total product and + // doesn't depend on i, we can take it out of the sum and compute it once. + + // PiPoly(zeta) = vanishingPolyEval / (n * fullProduct) * \sum_{i=0}^{length} pi[i] * g^i * + // (\prod_{i != j} (zeta - g^j)) + + // where fullProduct = \prod_{j=0}^{length} (zeta - g^j) + + // Another optimization we can do is instead of computing the product where i != j, we can + // precompute the prefix and suffix products and just calculate prefix[i] * suffix[i] to get + // the product (\prod_{i != j} (zeta - g^j)). + // The prefix array doesn't need to be kept in memory, it can be computed on the fly when + // computing the sum. + // We keep currentElementPrefix = \prod_{j=0}^{i} (zeta - g^j) and update it at each i. + + // compute suffix product array as described in the function _computeSuffixProduct + // this helps optimize the PiPoly computation by using the following formula: + // PiPoly(zeta) = vanishingPolyEval / (n * fullProduct) * \sum_{i=0}^{length} + // (currentElementPrefix * suffix[i] * pi[i] * g^i) + // Compute suffix product + // This optimization keeps the 1 inversion but reduces the number of multiplications from + // n(n - 1) to 3n + // + // credit: @shresthagrawal and @jakovmitrovski from CommonPrefix + uint256[8] memory suffix; + + // Assume we have [a, b, c, d] where a = zeta - g^0, b = zeta - g^1, ... + // + // suffix[length - i - 1] = suffix[length - i] * (zeta - g^(length - i)) and + // suffix[length - 1] = 1 + // suffix = [dcb, dc, d, 1] assembly { - // vanish_eval_div_n = (zeta^n-1)/n - vanishEvalDivN := mulmod(vanishEvalDivN, vanishEval, p) - - // Now we need to compute - // \sum_{i=0..l} L_{i,H}(zeta) * pub_input[i] - // where - // - L_{i,H}(zeta) - // = Z_H(zeta) * v_i / (zeta - g^i) - // = vanish_eval_div_n * g^i / (zeta - g^i) - // - v_i = g^i / n - // - // we want to use batch inversion method where we compute - // - // divisorProd = 1 / \prod (zeta - g^i) - // - // and then each 1 / (zeta - g^i) can be computed via (length - 1) - // multiplications: - // - // 1 / (zeta - g^i) = divisorProd * \prod_{j!=i} (zeta - g^j) - // - // In total this takes n(n-1) multiplications and 1 inversion, - // instead of doing n inversions. - divisorProd := 1 - - for { let i := 0 } lt(i, length) { i := add(i, 1) } { - // tmp points to g^i - // first 32 bytes of reference is the length of an array - tmp := mload(add(add(localDomainElements, 0x20), mul(i, 0x20))) - // compute (zeta - g^i) - ithDivisor := addmod(sub(p, tmp), zeta, p) - // accumulate (zeta - g^i) to the divisorProd - divisorProd := mulmod(divisorProd, ithDivisor, p) - // store ithDivisor in the array - mstore(add(add(divisors, 0x20), mul(i, 0x20)), ithDivisor) + let suffixPtr := add(suffix, mul(7, 0x20)) + let localDomainElementsPtr := add(mload(add(self, 0x40)), mul(7, 0x20)) + let currentElementSuffix := 1 + + // Last element of suffix is set to 1 + mstore(suffixPtr, currentElementSuffix) + + // Calculate prefix and suffix products + for { let i := 1 } lt(i, 8) { i := add(i, 1) } { + // move suffix pointer + suffixPtr := sub(suffixPtr, 0x20) + + // suffix[length - i - 1] = suffix[length - i] * (zeta - g^(length - i)) + currentElementSuffix := + mulmod( + currentElementSuffix, addmod(sub(p, mload(localDomainElementsPtr)), zeta, p), p + ) + mstore(suffixPtr, currentElementSuffix) + + localDomainElementsPtr := sub(localDomainElementsPtr, 0x20) } } - // compute 1 / \prod_{i=0}^length (zeta - g^i) - divisorProd = BN254.ScalarField.unwrap(BN254.invert(BN254.ScalarField.wrap(divisorProd))); + uint256 fullProduct; + uint256 sum = 0; assembly { - for { let i := 0 } lt(i, length) { i := add(i, 1) } { - // tmp points to g^i - // first 32 bytes of reference is the length of an array - tmp := mload(add(add(localDomainElements, 0x20), mul(i, 0x20))) - // vanish_eval_div_n * g^i - ithLagrange := mulmod(vanishEvalDivN, tmp, p) - - // now we compute vanish_eval_div_n * g^i / (zeta - g^i) via - // vanish_eval_div_n * g^i * divisorProd * \prod_{j!=i} (zeta - g^j) - ithLagrange := mulmod(ithLagrange, divisorProd, p) - for { let j := 0 } lt(j, length) { j := add(j, 1) } { - if iszero(eq(i, j)) { - ithDivisor := mload(add(add(divisors, 0x20), mul(j, 0x20))) - ithLagrange := mulmod(ithLagrange, ithDivisor, p) - } - } + let currentElementPrefix := 1 + let suffixPtr := suffix + let piPtr := pi + let localDomainElementsPtr := mload(add(self, 0x40)) + + // Compute the sum term \sum_{i=0}^{length} currentElementPrefix * suffix[i] * pi[i] * + // g^i + for { let i := 0 } lt(i, 8) { i := add(i, 1) } { + // sum += currentElementPrefix * suffix[i] * pi[i] * g^i + let currentTerm := + mulmod( + mulmod(mulmod(currentElementPrefix, mload(suffixPtr), p), mload(piPtr), p), + mload(localDomainElementsPtr), + p + ) + sum := addmod(sum, currentTerm, p) - // multiply by pub_input[i] and update res - // tmp points to public input - tmp := mload(add(add(pi, 0x20), mul(i, 0x20))) - ithLagrange := mulmod(ithLagrange, tmp, p) - res := addmod(res, ithLagrange, p) + // currentElementPrefix holds \prod_{j=0}^{i} (zeta - g^j) and is updated at each i. + currentElementPrefix := + mulmod( + currentElementPrefix, addmod(sub(p, mload(localDomainElementsPtr)), zeta, p), p + ) + + // move the pointers + suffixPtr := add(suffixPtr, 0x20) + piPtr := add(piPtr, 0x20) + localDomainElementsPtr := add(localDomainElementsPtr, 0x20) } + + fullProduct := currentElementPrefix } - } - /// @dev Generate the domain elements for indexes 0..length - /// which are essentially g^0, g^1, ..., g^{length-1} - function domainElements(EvalDomain memory self, uint256 length) - internal - pure - returns (uint256[] memory elements) - { - if (length > self.size) revert InvalidPolyEvalArgs(); - uint256 groupGen = self.groupGen; - uint256 tmp = 1; - uint256 p = BN254.R_MOD; - elements = new uint256[](length); + // 1 / fullProduct + uint256 invertedProduct = + BN254.ScalarField.unwrap(BN254.invert(BN254.ScalarField.wrap(fullProduct))); + assembly { - if not(iszero(length)) { - let ptr := add(elements, 0x20) - let end := add(ptr, mul(0x20, length)) - mstore(ptr, 1) - ptr := add(ptr, 0x20) - // for (; ptr < end; ptr += 32) loop through the memory of `elements` - for { } lt(ptr, end) { ptr := add(ptr, 0x20) } { - tmp := mulmod(tmp, groupGen, p) - mstore(ptr, tmp) - } - } + // Final computation + let nInverted := mload(add(self, 0x20)) // 1/n + // (vanishingPolyEval / ( n * fullProduct )) * sum + res := mulmod(vanishingPolyEval, nInverted, p) + res := mulmod(res, invertedProduct, p) + res := mulmod(res, sum, p) } } /// @dev compute the EvalData for a given domain and a challenge zeta - function evalDataGen(EvalDomain memory self, uint256 zeta, uint256[] memory publicInput) + function evalDataGen(EvalDomain memory self, uint256 zeta, uint256[8] memory publicInput) internal view returns (EvalData memory evalData) diff --git a/contracts/src/libraries/Transcript.sol b/contracts/src/libraries/Transcript.sol deleted file mode 100644 index 9b9054dc35..0000000000 --- a/contracts/src/libraries/Transcript.sol +++ /dev/null @@ -1,212 +0,0 @@ -// SPDX-License-Identifier: Unlicensed - -pragma solidity ^0.8.0; - -import { BN254, Utils } from "bn254/BN254.sol"; -import { BytesLib } from "solidity-bytes-utils/BytesLib.sol"; -import { IPlonkVerifier } from "../interfaces/IPlonkVerifier.sol"; - -library Transcript { - struct TranscriptData { - bytes transcript; - bytes32 state; - } - - // ================================ - // Primitive functions - // ================================ - function appendMessage(TranscriptData memory self, bytes memory message) internal pure { - self.transcript = abi.encodePacked(self.transcript, message); - } - - // ================================ - // Transcript APIs - // ================================ - function appendChallenge(TranscriptData memory self, uint256 challenge) internal pure { - self.transcript = abi.encodePacked(self.transcript, Utils.reverseEndianness(challenge)); - } - - function appendCommitments(TranscriptData memory self, BN254.G1Point[] memory comms) - internal - pure - { - for (uint256 i = 0; i < comms.length; i++) { - appendCommitment(self, comms[i]); - } - } - - function appendCommitment(TranscriptData memory self, BN254.G1Point memory comm) - internal - pure - { - self.transcript = abi.encodePacked(self.transcript, BN254.g1Serialize(comm)); - } - - function getAndAppendChallenge(TranscriptData memory self) internal pure returns (uint256) { - bytes32 hash; - - bytes32 a = self.state; - bytes memory b = self.transcript; - - // Computes keccak256(bytes32 a, bytes b) - assembly { - // Load the length of 'b' - let bLength := mload(b) - - // Allocate memory for 'a' + 'b' - let data := mload(0x40) // Load free memory pointer - - // Store 'a' in memory - mstore(data, a) - - // Copy 'self.transcript' to memory after 'self.state' - let dataOffset := add(data, 32) // Start right after 'self.state' - for { let i := 0 } lt(i, bLength) { i := add(i, 0x20) } { - mstore(add(dataOffset, i), mload(add(add(b, i), 0x20))) - } - - // Compute the keccak256 hash of the data - hash := keccak256(data, add(32, bLength)) - } - - self.state = hash; - - uint256 ret = uint256(hash) % BN254.R_MOD; - return ret; - } - - /// @dev Append the verifying key and the public inputs to the transcript. - /// @param verifyingKey verifying key - /// @param publicInput a list of field elements - function appendVkAndPubInput( - TranscriptData memory self, - IPlonkVerifier.VerifyingKey memory verifyingKey, - uint256[] memory publicInput - ) internal pure { - uint32 sizeInBits = 254; - - self.transcript = abi.encodePacked( - self.transcript, - BytesLib.slice(abi.encodePacked(Utils.reverseEndianness(sizeInBits)), 0, 4), // Fr field - // size in bits - BytesLib.slice(abi.encodePacked(Utils.reverseEndianness(verifyingKey.domainSize)), 0, 8), // domain - // size - BytesLib.slice(abi.encodePacked(Utils.reverseEndianness(verifyingKey.numInputs)), 0, 8) // number - // of inputs - ); - - // ===================== - // k: coset representatives - // ===================== - // Currently, K is hardcoded, and there are 5 of them since - // # wire types == 5 - - self.transcript = abi.encodePacked( - self.transcript, - Utils.reverseEndianness(0x1), // k0 = 1 - Utils.reverseEndianness( - 0x2f8dd1f1a7583c42c4e12a44e110404c73ca6c94813f85835da4fb7bb1301d4a - ), // k1 - Utils.reverseEndianness( - 0x1ee678a0470a75a6eaa8fe837060498ba828a3703b311d0f77f010424afeb025 - ), // k2 - Utils.reverseEndianness( - 0x2042a587a90c187b0a087c03e29c968b950b1db26d5c82d666905a6895790c0a - ), // k3 - Utils.reverseEndianness( - 0x2e2b91456103698adf57b799969dea1c8f739da5d8d40dd3eb9222db7c81e881 - ) // k4 - ); - - // selectors - self.transcript = abi.encodePacked( - self.transcript, - BN254.g1Serialize(verifyingKey.q1), - BN254.g1Serialize(verifyingKey.q2), - BN254.g1Serialize(verifyingKey.q3), - BN254.g1Serialize(verifyingKey.q4), - BN254.g1Serialize(verifyingKey.qM12), - BN254.g1Serialize(verifyingKey.qM34), - BN254.g1Serialize(verifyingKey.qH1) - ); - self.transcript = abi.encodePacked( - self.transcript, - BN254.g1Serialize(verifyingKey.qH2), - BN254.g1Serialize(verifyingKey.qH3), - BN254.g1Serialize(verifyingKey.qH4), - BN254.g1Serialize(verifyingKey.qO), - BN254.g1Serialize(verifyingKey.qC), - BN254.g1Serialize(verifyingKey.qEcc) - ); - - // sigmas - self.transcript = abi.encodePacked( - self.transcript, - BN254.g1Serialize(verifyingKey.sigma0), - BN254.g1Serialize(verifyingKey.sigma1), - BN254.g1Serialize(verifyingKey.sigma2), - BN254.g1Serialize(verifyingKey.sigma3), - BN254.g1Serialize(verifyingKey.sigma4) - ); - - // public inputs - self.transcript = abi.encodePacked( - self.transcript, - Utils.reverseEndianness(publicInput[0]), - Utils.reverseEndianness(publicInput[1]), - Utils.reverseEndianness(publicInput[2]), - Utils.reverseEndianness(publicInput[3]), - Utils.reverseEndianness(publicInput[4]), - Utils.reverseEndianness(publicInput[5]), - Utils.reverseEndianness(publicInput[6]), - Utils.reverseEndianness(publicInput[7]) - ); - } - - /// @dev Append the proof to the transcript. Only used for test purposes. - function appendProofEvaluations( - TranscriptData memory self, - IPlonkVerifier.PlonkProof memory proof - ) internal pure { - self.transcript = abi.encodePacked( - self.transcript, Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.wireEval0)) - ); - - self.transcript = abi.encodePacked( - self.transcript, Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.wireEval1)) - ); - - self.transcript = abi.encodePacked( - self.transcript, Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.wireEval2)) - ); - - self.transcript = abi.encodePacked( - self.transcript, Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.wireEval3)) - ); - - self.transcript = abi.encodePacked( - self.transcript, Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.wireEval4)) - ); - - self.transcript = abi.encodePacked( - self.transcript, Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.sigmaEval0)) - ); - - self.transcript = abi.encodePacked( - self.transcript, Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.sigmaEval1)) - ); - - self.transcript = abi.encodePacked( - self.transcript, Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.sigmaEval2)) - ); - - self.transcript = abi.encodePacked( - self.transcript, Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.sigmaEval3)) - ); - - self.transcript = abi.encodePacked( - self.transcript, - Utils.reverseEndianness(BN254.ScalarField.unwrap(proof.prodPermZetaOmegaEval)) - ); - } -} diff --git a/contracts/test/LightClientBenchmark.t.sol b/contracts/test/LightClientBenchmark.t.sol index b3305728da..b5fb7aa50f 100644 --- a/contracts/test/LightClientBenchmark.t.sol +++ b/contracts/test/LightClientBenchmark.t.sol @@ -12,14 +12,12 @@ import { IPlonkVerifier as V } from "../src/interfaces/IPlonkVerifier.sol"; import { LightClient as LC } from "../src/LightClient.sol"; import { LightClientCommonTest } from "./LightClient.t.sol"; -contract LightClient_newFinalizedState_Test is LightClientCommonTest { +contract LightClientBench is LightClientCommonTest { + LC.LightClientState state; + V.PlonkProof proof; + function setUp() public { init(); - } - - /// @dev for benchmarking purposes only - function testCorrectUpdateBench() external { - vm.pauseGasMetering(); // Generating a few consecutive states and proofs string[] memory cmds = new string[](5); cmds[0] = "diff-test"; @@ -31,8 +29,18 @@ contract LightClient_newFinalizedState_Test is LightClientCommonTest { bytes memory result = vm.ffi(cmds); (LC.LightClientState[] memory states, V.PlonkProof[] memory proofs) = abi.decode(result, (LC.LightClientState[], V.PlonkProof[])); + + state = states[0]; + proof = proofs[0]; + } + + /// @dev for benchmarking purposes only + function testCorrectUpdateBench() external { + vm.pauseGasMetering(); + LC.LightClientState memory st = state; + V.PlonkProof memory pf = proof; vm.prank(permissionedProver); vm.resumeGasMetering(); - lc.newFinalizedState(states[0], proofs[0]); + lc.newFinalizedState(st, pf); } } diff --git a/contracts/test/PlonkVerifier.t.sol b/contracts/test/PlonkVerifier.t.sol index 299f28c9dd..25e18080df 100644 --- a/contracts/test/PlonkVerifier.t.sol +++ b/contracts/test/PlonkVerifier.t.sol @@ -5,11 +5,11 @@ // NOTE: For developers and auditors: we mainly test the consistency between the outputs between // Solidity and Jellyfish library, with the help of fuzzer-generated inputs from Forge Testing. -// Inside the logic of `batchVerify()`, variables values only need to be consistent and valid +// Inside the logic of `verify()`, variables values only need to be consistent and valid // (i.e. valid group or field elements) and don't need to be from a correct proof/public input. -// Only the last step `_batchVerifyOpeningProof` will test *correctness* of these parameters. +// Only the last step `_verifyOpeningProof` will test *correctness* of these parameters. // Therefore, we employ more randomly generated dummy inputs for most tests for robustness, -// and only rely on Rust-code to generate correct inputs for the `_batchVerifyOpeningProof`. +// and only rely on Rust-code to generate correct inputs for the `_verifyOpeningProof`. pragma solidity ^0.8.0; @@ -34,7 +34,14 @@ contract PlonkVerifierCommonTest is Test { /// @dev Sanitize all values in `a` to be valid scalar fields Bn254::Fr. /// This is helpful to sanitize fuzzer-generated random `uint[]` values. - function sanitizeScalarFields(uint256[] memory a) public pure returns (uint256[] memory) { + function sanitizeScalarFields(uint256[8] memory a) public pure returns (uint256[8] memory) { + for (uint256 i = 0; i < a.length; i++) { + a[i] = sanitizeScalarField(a[i]); + } + return a; + } + + function sanitizeScalarFields(uint256[30] memory a) public pure returns (uint256[30] memory) { for (uint256 i = 0; i < a.length; i++) { a[i] = sanitizeScalarField(a[i]); } @@ -52,16 +59,6 @@ contract PlonkVerifierCommonTest is Test { return vk; } - /// @dev copy a fixed array into a dynamic array, mostly used for converting fuzzer generated - /// array into another accepted by most APIs. - function copyCommScalars(uint256[30] memory a) public pure returns (uint256[] memory) { - uint256[] memory b = new uint256[](a.length); - for (uint256 i = 0; i < a.length; i++) { - b[i] = a[i]; - } - return b; - } - /// @dev Generate a random valid (format-wise) proof from a random seed function dummyProof(uint64 seed) public returns (IPlonkVerifier.PlonkProof memory) { string[] memory cmds = new string[](3); @@ -77,7 +74,7 @@ contract PlonkVerifierCommonTest is Test { /// @dev helper function to generate some dummy but format-valid arguments for /// `prepareOpeningProof` step. The verifyingKey should be fixed/loaded from library, /// proof should be generated via `dummyProof()`, other inputs are from fuzzers. - function dummyArgsForOpeningProof(uint64 seed, uint256[] memory publicInput) + function dummyArgsForOpeningProof(uint64 seed, uint256[8] memory publicInput) public returns ( IPlonkVerifier.VerifyingKey memory, @@ -135,41 +132,33 @@ contract PlonkVerifier_verify_Test is PlonkVerifierCommonTest { /// @dev Test happy path of `verify`. function test_verify_succeeds() external { vm.pauseGasMetering(); - string[] memory cmds = new string[](3); + string[] memory cmds = new string[](2); cmds[0] = "diff-test"; - cmds[1] = "plonk-batch-verify"; - cmds[2] = vm.toString(uint32(1)); + cmds[1] = "plonk-verify"; bytes memory result = vm.ffi(cmds); ( - IPlonkVerifier.VerifyingKey[] memory verifyingKeys, - uint256[][] memory publicInputs, - IPlonkVerifier.PlonkProof[] memory proofs, - ) = abi.decode( - result, - (IPlonkVerifier.VerifyingKey[], uint256[][], IPlonkVerifier.PlonkProof[], bytes[]) - ); + IPlonkVerifier.VerifyingKey memory verifyingKey, + uint256[8] memory publicInput, + IPlonkVerifier.PlonkProof memory proof + ) = abi.decode(result, (IPlonkVerifier.VerifyingKey, uint256[8], IPlonkVerifier.PlonkProof)); vm.resumeGasMetering(); - assert(V.verify(verifyingKeys[0], publicInputs[0], proofs[0])); + assert(V.verify(verifyingKey, publicInput, proof)); } /// @dev Test when bad verifying key is supplied, the verification should fail function testFuzz_badVerifyingKey_fails(uint256 nthPoint) external { - string[] memory cmds = new string[](3); + string[] memory cmds = new string[](2); cmds[0] = "diff-test"; - cmds[1] = "plonk-batch-verify"; - cmds[2] = vm.toString(uint32(1)); + cmds[1] = "plonk-verify"; bytes memory result = vm.ffi(cmds); ( - IPlonkVerifier.VerifyingKey[] memory verifyingKeys, - uint256[][] memory publicInputs, - IPlonkVerifier.PlonkProof[] memory proofs, - ) = abi.decode( - result, - (IPlonkVerifier.VerifyingKey[], uint256[][], IPlonkVerifier.PlonkProof[], bytes[]) - ); + IPlonkVerifier.VerifyingKey memory verifyingKey, + uint256[8] memory publicInput, + IPlonkVerifier.PlonkProof memory proof + ) = abi.decode(result, (IPlonkVerifier.VerifyingKey, uint256[8], IPlonkVerifier.PlonkProof)); // there are 18 points in verifying key // randomly choose one to mutate @@ -177,10 +166,8 @@ contract PlonkVerifier_verify_Test is PlonkVerifierCommonTest { BN254.G1Point memory badPoint; assembly { - // the first 32 bytes is array length - let firstVkRef := add(verifyingKeys, 0x20) // the first point offset is 0x40 - let badPointRef := add(mload(firstVkRef), add(mul(nthPoint, 0x20), 0x40)) + let badPointRef := add(verifyingKey, add(mul(nthPoint, 0x20), 0x40)) badPoint := mload(badPointRef) } @@ -188,58 +175,46 @@ contract PlonkVerifier_verify_Test is PlonkVerifierCommonTest { badPoint = BN254.add(badPoint, BN254.P1()); assembly { - let firstVkRef := add(verifyingKeys, 0x20) - let badPointRef := add(mload(firstVkRef), add(mul(nthPoint, 0x20), 0x40)) + let badPointRef := add(verifyingKey, add(mul(nthPoint, 0x20), 0x40)) mstore(badPointRef, badPoint) } - assert(!V.verify(verifyingKeys[0], publicInputs[0], proofs[0])); + assert(!V.verify(verifyingKey, publicInput, proof)); } // @dev Test when bad public input is supplied, the verification should fail // We know our `gen_circuit_for_test` in `diff_test.rs` has only 8 public inputs function testFuzz_badPublicInput_fails(uint256[8] calldata randPublicInput) external { - uint256[] memory badPublicInput = new uint256[](8); + uint256[8] memory badPublicInput; for (uint256 i = 0; i < 8; i++) { badPublicInput[i] = randPublicInput[i]; } badPublicInput = sanitizeScalarFields(badPublicInput); - string[] memory cmds = new string[](3); + string[] memory cmds = new string[](2); cmds[0] = "diff-test"; - cmds[1] = "plonk-batch-verify"; - cmds[2] = vm.toString(uint32(1)); + cmds[1] = "plonk-verify"; bytes memory result = vm.ffi(cmds); - ( - IPlonkVerifier.VerifyingKey[] memory verifyingKeys, - , - IPlonkVerifier.PlonkProof[] memory proofs, - ) = abi.decode( - result, - (IPlonkVerifier.VerifyingKey[], uint256[][], IPlonkVerifier.PlonkProof[], bytes[]) - ); + (IPlonkVerifier.VerifyingKey memory verifyingKey,, IPlonkVerifier.PlonkProof memory proof) = + abi.decode(result, (IPlonkVerifier.VerifyingKey, uint256[8], IPlonkVerifier.PlonkProof)); - assert(!V.verify(verifyingKeys[0], badPublicInput, proofs[0])); + assert(!V.verify(verifyingKey, badPublicInput, proof)); } /// @dev Test when bad proof is supplied, the verification should fail function testFuzz_badProof_fails(uint64 seed) external { IPlonkVerifier.PlonkProof memory badProof = dummyProof(seed); - string[] memory cmds = new string[](3); + string[] memory cmds = new string[](2); cmds[0] = "diff-test"; - cmds[1] = "plonk-batch-verify"; - cmds[2] = vm.toString(uint32(1)); + cmds[1] = "plonk-verify"; bytes memory result = vm.ffi(cmds); - (IPlonkVerifier.VerifyingKey[] memory verifyingKeys, uint256[][] memory publicInputs,,) = - abi.decode( - result, - (IPlonkVerifier.VerifyingKey[], uint256[][], IPlonkVerifier.PlonkProof[], bytes[]) - ); + (IPlonkVerifier.VerifyingKey memory verifyingKey, uint256[8] memory publicInput,) = + abi.decode(result, (IPlonkVerifier.VerifyingKey, uint256[8], IPlonkVerifier.PlonkProof)); - assert(!V.verify(verifyingKeys[0], publicInputs[0], badProof)); + assert(!V.verify(verifyingKey, publicInput, badProof)); } } @@ -301,68 +276,12 @@ contract PlonkVerifier_validateProof_Test is PlonkVerifierCommonTest { } } -contract PlonkVerifier_preparePcsInfo_Test is PlonkVerifierCommonTest { - /// @dev Test `preparePcsInfo` matches that of Jellyfish - function testFuzz_preparePcsInfo_matches(uint64 seed, uint256[8] memory _publicInput) - external - { - uint256[] memory publicInput = new uint256[](8); - for (uint256 i = 0; i < 8; i++) { - publicInput[i] = _publicInput[i]; - } - - publicInput = sanitizeScalarFields(publicInput); - IPlonkVerifier.VerifyingKey memory vk = sanitizeVk(VkTest.getVk(), publicInput.length); - IPlonkVerifier.PlonkProof memory proof = dummyProof(seed); - - V.PcsInfo memory info = V._preparePcsInfo(vk, publicInput, proof); - - string[] memory cmds = new string[](5); - cmds[0] = "diff-test"; - cmds[1] = "plonk-prepare-pcs-info"; - cmds[2] = vm.toString(abi.encode(vk)); - cmds[3] = vm.toString(abi.encode(publicInput)); - cmds[4] = vm.toString(abi.encode(proof)); - - bytes memory result = vm.ffi(cmds); - ( - uint256 u, - uint256 evalPoint, - uint256 nextEvalPoint, - uint256 eval, - BN254.G1Point memory scalarsAndBasesProd, - BN254.G1Point memory openingProof, - BN254.G1Point memory shiftedOpeningProof - ) = abi.decode( - result, - (uint256, uint256, uint256, uint256, BN254.G1Point, BN254.G1Point, BN254.G1Point) - ); - - assertEq(info.u, u); - assertEq(info.evalPoint, evalPoint); - assertEq(info.nextEvalPoint, nextEvalPoint); - assertEq(info.eval, eval); - // NOTE: since we cannot directly compare `struct ScalarsAndBases`, we compare their MSM - uint256 l = info.commScalars.length; - BN254.ScalarField[] memory infoCommScalars = new BN254.ScalarField[](l); - for (uint256 i = 0; i < l; i++) { - infoCommScalars[i] = BN254.ScalarField.wrap(info.commScalars[i]); - } - assertEq( - abi.encode(BN254.multiScalarMul(info.commBases, infoCommScalars)), - abi.encode(scalarsAndBasesProd) - ); - assertEq(abi.encode(info.openingProof), abi.encode(openingProof)); - assertEq(abi.encode(info.shiftedOpeningProof), abi.encode(shiftedOpeningProof)); - } -} - contract PlonkVerifier_computeChallenges_Test is PlonkVerifierCommonTest { /// @dev Test `computeChallenges` matches that of Jellyfish function testFuzz_computeChallenges_matches(uint64 seed, uint256[8] memory _publicInput) external { - uint256[] memory publicInput = new uint256[](8); + uint256[8] memory publicInput; for (uint256 i = 0; i < 8; i++) { publicInput[i] = _publicInput[i]; } @@ -393,33 +312,3 @@ contract PlonkVerifier_computeChallenges_Test is PlonkVerifierCommonTest { assertEq(chal.u, c.u); } } - -contract PlonkVerifier_prepareEvaluations_Test is PlonkVerifierCommonTest { - /// @dev Test if combining the polynomial evaluations into a single evaluation is done correctly - /// is done correctly - function testFuzz_prepareEvaluations_matches( - uint64 seed, - uint256 linPolyConstant, - uint256[30] memory scalars - ) external { - IPlonkVerifier.PlonkProof memory proof = dummyProof(seed); - linPolyConstant = sanitizeScalarField(linPolyConstant); - uint256[] memory commScalars = sanitizeScalarFields(copyCommScalars(scalars)); - - string[] memory cmds = new string[](5); - cmds[0] = "diff-test"; - cmds[1] = "plonk-prepare-eval"; - cmds[2] = vm.toString(abi.encode(proof)); - cmds[3] = vm.toString(bytes32(linPolyConstant)); - cmds[4] = vm.toString(abi.encode(commScalars)); - - bytes memory result = vm.ffi(cmds); - (uint256 eval) = abi.decode(result, (uint256)); - - assertEq(eval, V._prepareEvaluations(linPolyConstant, proof, commScalars)); - } -} - -// NOTE: it's troublesome to convert `ScalarsAndBases` field of a proper `PcsInfo` from Jellyfish to -// Solidity due to the different data structure (vector v.s. map). Thus, we skip diff-test for -// `batchVerifyOpeningProofs()` for now, and only test the outer `batchVerify()` directly diff --git a/contracts/test/PlonkVerifier2.t.sol b/contracts/test/PlonkVerifier2.t.sol new file mode 100644 index 0000000000..232257b5c3 --- /dev/null +++ b/contracts/test/PlonkVerifier2.t.sol @@ -0,0 +1,144 @@ +// SPDX-License-Identifier: Unlicensed + +/* solhint-disable contract-name-camelcase, func-name-mixedcase, one-contract-per-file */ +/* solhint-disable no-inline-assembly */ + +// NOTE: For developers and auditors: we mainly test the consistency between the outputs between +// Solidity and Jellyfish library, with the help of fuzzer-generated inputs from Forge Testing. +// Inside the logic of `verify()`, variables values only need to be consistent and valid +// (i.e. valid group or field elements) and don't need to be from a correct proof/public input. +// Only the last step `_verifyOpeningProof` will test *correctness* of these parameters. +// Therefore, we employ more randomly generated dummy inputs for most tests for robustness, +// and only rely on Rust-code to generate correct inputs for the `_verifyOpeningProof`. + +pragma solidity ^0.8.0; + +// Libraries +import "forge-std/Test.sol"; +import { BN254 } from "bn254/BN254.sol"; +import { IPlonkVerifier } from "../src/interfaces/IPlonkVerifier.sol"; +import { LightClientStateUpdateVKMock as VkTest } from "./mocks/LightClientStateUpdateVKMock.sol"; + +// Target contract +import { PlonkVerifier2 as V } from "../src/libraries/PlonkVerifier2.sol"; + +/// @dev Common helpers/utils for PlonkVerifier tests +contract PlonkVerifierCommonTest is Test { + /// @dev Sanitize a single value to be valid scalar field Bn254::Fr. + function sanitizeScalarField(uint256 a) public pure returns (uint256) { + a = bound(a, 0, BN254.R_MOD - 1); + BN254.validateScalarField(BN254.ScalarField.wrap(a)); + return a; + } + + /// @dev Sanitize all values in `a` to be valid scalar fields Bn254::Fr. + /// This is helpful to sanitize fuzzer-generated random `uint[]` values. + function sanitizeScalarFields(uint256[8] memory a) public pure returns (uint256[8] memory) { + for (uint256 i = 0; i < a.length; i++) { + a[i] = sanitizeScalarField(a[i]); + } + return a; + } + + /// @dev Generate a random valid (format-wise) proof from a random seed + function dummyProof(uint64 seed) public returns (IPlonkVerifier.PlonkProof memory) { + string[] memory cmds = new string[](3); + cmds[0] = "diff-test"; + cmds[1] = "dummy-proof"; + cmds[2] = vm.toString(seed); + + bytes memory result = vm.ffi(cmds); + (IPlonkVerifier.PlonkProof memory proof) = abi.decode(result, (IPlonkVerifier.PlonkProof)); + return proof; + } +} + +contract PlonkVerifier2_verify_Test is PlonkVerifierCommonTest { + /// @dev Test happy path of `verify`. + function test_verify_succeeds() external { + vm.pauseGasMetering(); + string[] memory cmds = new string[](2); + cmds[0] = "diff-test"; + cmds[1] = "plonk-verify"; + + bytes memory result = vm.ffi(cmds); + ( + IPlonkVerifier.VerifyingKey memory verifyingKey, + uint256[8] memory publicInput, + IPlonkVerifier.PlonkProof memory proof + ) = abi.decode(result, (IPlonkVerifier.VerifyingKey, uint256[8], IPlonkVerifier.PlonkProof)); + + vm.resumeGasMetering(); + assert(V.verify(verifyingKey, publicInput, proof)); + } + + /// @dev Test when bad verifying key is supplied, the verification should fail + function testFuzz_badVerifyingKey_fails(uint256 nthPoint) external { + string[] memory cmds = new string[](2); + cmds[0] = "diff-test"; + cmds[1] = "plonk-verify"; + + bytes memory result = vm.ffi(cmds); + ( + IPlonkVerifier.VerifyingKey memory verifyingKey, + uint256[8] memory publicInput, + IPlonkVerifier.PlonkProof memory proof + ) = abi.decode(result, (IPlonkVerifier.VerifyingKey, uint256[8], IPlonkVerifier.PlonkProof)); + + // there are 18 points in verifying key + // randomly choose one to mutate + nthPoint = bound(nthPoint, 0, 17); + + BN254.G1Point memory badPoint; + assembly { + // the first point offset is 0x40 + let badPointRef := add(verifyingKey, add(mul(nthPoint, 0x20), 0x40)) + badPoint := mload(badPointRef) + } + + // modify the point to be invalid + badPoint = BN254.add(badPoint, BN254.P1()); + + assembly { + let badPointRef := add(verifyingKey, add(mul(nthPoint, 0x20), 0x40)) + mstore(badPointRef, badPoint) + } + + assert(!V.verify(verifyingKey, publicInput, proof)); + } + + // @dev Test when bad public input is supplied, the verification should fail + // We know our `gen_circuit_for_test` in `diff_test.rs` has only 8 public inputs + function testFuzz_badPublicInput_fails(uint256[8] calldata randPublicInput) external { + uint256[8] memory badPublicInput; + for (uint256 i = 0; i < 8; i++) { + badPublicInput[i] = randPublicInput[i]; + } + badPublicInput = sanitizeScalarFields(badPublicInput); + + string[] memory cmds = new string[](2); + cmds[0] = "diff-test"; + cmds[1] = "plonk-verify"; + + bytes memory result = vm.ffi(cmds); + (IPlonkVerifier.VerifyingKey memory verifyingKey,, IPlonkVerifier.PlonkProof memory proof) = + abi.decode(result, (IPlonkVerifier.VerifyingKey, uint256[8], IPlonkVerifier.PlonkProof)); + + assert(!V.verify(verifyingKey, badPublicInput, proof)); + } + + /// @dev Test when bad proof is supplied, the verification should fail + function testFuzz_badProof_fails(uint64 seed) external { + IPlonkVerifier.PlonkProof memory badProof = dummyProof(seed); + + string[] memory cmds = new string[](2); + cmds[0] = "diff-test"; + cmds[1] = "plonk-verify"; + + bytes memory result = vm.ffi(cmds); + (IPlonkVerifier.VerifyingKey memory verifyingKey, uint256[8] memory publicInput,) = + abi.decode(result, (IPlonkVerifier.VerifyingKey, uint256[8], IPlonkVerifier.PlonkProof)); + + assert(!V.verify(verifyingKey, publicInput, badProof)); + } +} diff --git a/contracts/test/PolynomialEval.t.sol b/contracts/test/PolynomialEval.t.sol index 98366ba060..fd41013a40 100644 --- a/contracts/test/PolynomialEval.t.sol +++ b/contracts/test/PolynomialEval.t.sol @@ -14,21 +14,19 @@ import { PolynomialEval as Poly } from "../src/libraries/PolynomialEval.sol"; contract PolynomialEval_newEvalDomain_Test is Test { /// @dev diff-test with Rust when `domainSize` is in {2^16 ~ 2^20, 2^5} function test_supportedDomainSize_matches() external { - uint256[6] memory logSizes = [uint256(5), 16, 17, 18, 19, 20]; - for (uint256 i = 0; i < 6; i++) { + uint256[3] memory logSizes = [uint256(5), 16, 20]; + for (uint256 i = 0; i < 3; i++) { string[] memory cmds = new string[](3); cmds[0] = "diff-test"; cmds[1] = "new-poly-eval-domain"; cmds[2] = vm.toString(logSizes[i]); bytes memory result = vm.ffi(cmds); - (uint256 sizeInv, uint256 groupGen, uint256 groupGenInv) = - abi.decode(result, (uint256, uint256, uint256)); + (uint256 sizeInv, uint256 groupGen) = abi.decode(result, (uint256, uint256)); Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSizes[i]); assertEq(sizeInv, domain.sizeInv); - assertEq(groupGen, domain.groupGen); - assertEq(groupGenInv, domain.groupGenInv); + assertEq(groupGen, domain.elements[1]); } } @@ -44,54 +42,69 @@ contract PolynomialEval_newEvalDomain_Test is Test { } } -contract PolynomialEval_domainElements_Test is Test { +/// @dev Come with some helper function +contract PolynomialEvalTest is Test { + /// @dev Generate the domain elements for indexes 0..length + /// which are essentially g^0, g^1, ..., g^{length-1} + function domainElements(Poly.EvalDomain memory self, uint256 length) + internal + pure + returns (uint256[] memory elements) + { + uint256 groupGen = self.elements[1]; + uint256 tmp = 1; + uint256 p = BN254.R_MOD; + elements = new uint256[](length); + assembly { + if not(iszero(length)) { + let ptr := add(elements, 0x20) + let end := add(ptr, mul(0x20, length)) + mstore(ptr, 1) + ptr := add(ptr, 0x20) + // for (; ptr < end; ptr += 32) loop through the memory of `elements` + for { } lt(ptr, end) { ptr := add(ptr, 0x20) } { + tmp := mulmod(tmp, groupGen, p) + mstore(ptr, tmp) + } + } + } + } + /// @dev Test if the domain elements are generated correctly - function testFuzz_domainElements_matches(uint256 logSize, uint256 length) external { - logSize = bound(logSize, 16, 20); - length = bound(length, 0, 10000); + function test_domainElements_matches() external { + uint256 logSize = 20; Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); - if (length > domain.size) { - vm.expectRevert(Poly.InvalidPolyEvalArgs.selector); - Poly.domainElements(domain, length); - } else { - string[] memory cmds = new string[](4); - cmds[0] = "diff-test"; - cmds[1] = "eval-domain-elements"; - cmds[2] = vm.toString(logSize); - cmds[3] = vm.toString(length); + string[] memory cmds = new string[](4); + cmds[0] = "diff-test"; + cmds[1] = "eval-domain-elements"; + cmds[2] = vm.toString(logSize); + cmds[3] = vm.toString(uint256(8)); - bytes memory result = vm.ffi(cmds); - (uint256[] memory elems) = abi.decode(result, (uint256[])); + bytes memory result = vm.ffi(cmds); + (uint256[] memory elems) = abi.decode(result, (uint256[])); - assertEq(elems, Poly.domainElements(domain, length)); + for (uint256 i = 0; i < 8; i++) { + assertEq(elems[i], domain.elements[i]); } } } -contract PolynomialEval_evalDataGen_Test is Test { +contract PolynomialEval_evalDataGen_Test is PolynomialEvalTest { /// @dev Test if evaluations on the vanishing poly, the lagrange one poly, and the public input /// poly are correct. - function testFuzz_evalDataGen_matches( - uint256 logSize, - uint256 zeta, - uint256[] memory publicInput - ) external { - logSize = bound(logSize, 16, 20); + function testFuzz_evalDataGen_matches(uint256 zeta, uint256[8] memory publicInput) external { + uint256 logSize = 20; zeta = bound(zeta, 0, BN254.R_MOD - 1); BN254.validateScalarField(BN254.ScalarField.wrap(zeta)); // Since these user-provided `publicInputs` were checked outside before passing in via // `BN254.validateScalarField()`, it suffices to assume they are proper for our test here. - for (uint256 i = 0; i < publicInput.length; i++) { + for (uint256 i = 0; i < 8; i++) { publicInput[i] = bound(publicInput[i], 0, BN254.R_MOD - 1); BN254.validateScalarField(BN254.ScalarField.wrap(publicInput[i])); } Poly.EvalDomain memory domain = Poly.newEvalDomain(2 ** logSize); - // NOTE: since zeta comes from CRH via `computeChallenges`, we can assume it's hard to - // be specifically preimage attacked, or accidentally collide with these values. - vm.assume(zeta != 1); // otherwise divisor of lagrange_1_poly would be zero - vm.assume(zeta != domain.groupGenInv); // otherwise divisor of lagrange_n_poly would be zero string[] memory cmds = new string[](5); cmds[0] = "diff-test"; @@ -109,4 +122,66 @@ contract PolynomialEval_evalDataGen_Test is Test { assertEq(lagrangeOne, BN254.ScalarField.unwrap(evalData.lagrangeOne)); assertEq(piEval, BN254.ScalarField.unwrap(evalData.piEval)); } + + /// @dev Test edge cases when zeta is one of the elements in the evaluation domain. + /// The random evaluation point case (most likely outside evalDomain) is already + /// tested in `testFuzz_evalDataGen_matches()` + function test_lagrangeOneCoeffForDomainElements() external view { + uint256 size = 2 ** 5; + Poly.EvalDomain memory domain = Poly.newEvalDomain(size); + + uint256[] memory elements = domainElements(domain, size); + uint256 vanishEval = Poly.evaluateVanishingPoly(domain, elements[0]); + + // L_0(g^0) = 1 + assertEq( + BN254.ScalarField.unwrap( + Poly.evaluateLagrangeOne( + domain, BN254.ScalarField.wrap(elements[0]), BN254.ScalarField.wrap(vanishEval) + ) + ), + 1 + ); + + // L_i(g^0) = 0 for i \in [size] + for (uint256 i = 1; i < size; i++) { + vanishEval = Poly.evaluateVanishingPoly(domain, elements[i]); + assertEq( + BN254.ScalarField.unwrap( + Poly.evaluateLagrangeOne( + domain, + BN254.ScalarField.wrap(elements[i]), + BN254.ScalarField.wrap(vanishEval) + ) + ), + 0 + ); + } + } + + /// @dev Test edge cases when zeta is one of the elements in the evaluation domain. + function test_evaluatePiPolyForDomainElements() external view { + uint256 size = 2 ** 5; + Poly.EvalDomain memory domain = Poly.newEvalDomain(size); + + uint256[] memory elements = domainElements(domain, size); + uint256[8] memory publicInputs; + // arbitrarily pick public input length = 10, and fill in arbitrary values + for (uint256 i = 0; i < 8; i++) { + publicInputs[i] = 2 ** i; + } + + for (uint256 i = 0; i < size; i++) { + uint256 zeta = elements[i]; + uint256 vanishEval = Poly.evaluateVanishingPoly(domain, zeta); + if (i < 8) { + assertEq(vanishEval, 0); + assertEq( + Poly.evaluatePiPoly(domain, publicInputs, zeta, vanishEval), publicInputs[i] + ); + } else { + assertEq(Poly.evaluatePiPoly(domain, publicInputs, zeta, vanishEval), 0); + } + } + } } diff --git a/contracts/test/Transcript.t.sol b/contracts/test/legacy/Transcript.t.sol similarity index 77% rename from contracts/test/Transcript.t.sol rename to contracts/test/legacy/Transcript.t.sol index b1346de042..2cd2701565 100644 --- a/contracts/test/Transcript.t.sol +++ b/contracts/test/legacy/Transcript.t.sol @@ -6,12 +6,12 @@ pragma solidity ^0.8.0; // Libraries import "forge-std/Test.sol"; -import { BN254, Utils } from "bn254/BN254.sol"; -import { IPlonkVerifier } from "../src/interfaces/IPlonkVerifier.sol"; -import { LightClientStateUpdateVKMock as VkTest } from "./mocks/LightClientStateUpdateVKMock.sol"; +import { BN254 } from "bn254/BN254.sol"; +import { IPlonkVerifier } from "../../src/interfaces/IPlonkVerifier.sol"; +import { LightClientStateUpdateVKMock as VkTest } from "../mocks/LightClientStateUpdateVKMock.sol"; // Target contract -import { Transcript as T } from "../src/libraries/Transcript.sol"; +import { Transcript as T } from "../../src/legacy/Transcript.sol"; contract Transcript_appendMessage_Test is Test { using T for T.TranscriptData; @@ -32,8 +32,6 @@ contract Transcript_appendMessage_Test is Test { transcript.appendMessage(message); assertEq(updated.transcript, transcript.transcript); - assertEq(updated.state[0], transcript.state[0]); - assertEq(updated.state[1], transcript.state[1]); } } @@ -57,12 +55,9 @@ contract Transcript_appendFieldElement_Test is Test { bytes memory result = vm.ffi(cmds); (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); - transcript.transcript = - abi.encodePacked(transcript.transcript, Utils.reverseEndianness(fieldElement)); + transcript.transcript = abi.encodePacked(transcript.transcript, fieldElement); assertEq(updated.transcript, transcript.transcript); - assertEq(updated.state[0], transcript.state[0]); - assertEq(updated.state[1], transcript.state[1]); } } @@ -88,12 +83,9 @@ contract Transcript_appendGroupElement_Test is Test { bytes memory result = vm.ffi(cmds); (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); - transcript.transcript = - abi.encodePacked(transcript.transcript, BN254.g1Serialize(randPoint)); + transcript.transcript = abi.encodePacked(transcript.transcript, randPoint.x, randPoint.y); assertEq(updated.transcript, transcript.transcript); - assertEq(updated.state[0], transcript.state[0]); - assertEq(updated.state[1], transcript.state[1]); } /// @dev Test special case where the identity point (or infinity) is appended. @@ -110,18 +102,16 @@ contract Transcript_appendGroupElement_Test is Test { bytes memory result = vm.ffi(cmds); (T.TranscriptData memory updated) = abi.decode(result, (T.TranscriptData)); - transcript.transcript = abi.encodePacked(transcript.transcript, BN254.g1Serialize(infinity)); + transcript.transcript = abi.encodePacked(transcript.transcript, infinity.x, infinity.y); assertEq(updated.transcript, transcript.transcript); - assertEq(updated.state[0], transcript.state[0]); - assertEq(updated.state[1], transcript.state[1]); } } -contract Transcript_getAndAppendChallenge_Test is Test { +contract Transcript_getChallenge_Test is Test { using T for T.TranscriptData; - /// @dev Test if `getAndAppendChallenge` matches that of Jellyfish - function testFuzz_getAndAppendChallenge_matches(T.TranscriptData memory transcript) external { + /// @dev Test if `getChallenge` matches that of Jellyfish + function testFuzz_getChallenge_matches(T.TranscriptData memory transcript) external { string[] memory cmds = new string[](3); cmds[0] = "diff-test"; cmds[1] = "transcript-get-chal"; @@ -131,11 +121,9 @@ contract Transcript_getAndAppendChallenge_Test is Test { (T.TranscriptData memory updated, uint256 chal) = abi.decode(result, (T.TranscriptData, uint256)); - uint256 challenge = transcript.getAndAppendChallenge(); + uint256 challenge = transcript.getChallenge(); assertEq(updated.transcript, transcript.transcript); - assertEq(updated.state[0], transcript.state[0]); - assertEq(updated.state[1], transcript.state[1]); assertEq(chal, challenge); } } @@ -172,8 +160,6 @@ contract Transcript_appendVkAndPubInput_Test is Test { transcript.appendVkAndPubInput(vk, publicInput); assertEq(updated.transcript, transcript.transcript, "transcript field mismatch"); - assertEq(updated.state[0], transcript.state[0], "state[0] field mismatch"); - assertEq(updated.state[1], transcript.state[1], "state[1] field mismatch"); } } @@ -194,7 +180,5 @@ contract Transcript_appendProofEvaluations_Test is Test { transcript.appendProofEvaluations(proof); assertEq(updated.transcript, transcript.transcript, "transcript field mismatch"); - assertEq(updated.state[0], transcript.state[0], "state[0] field mismatch"); - assertEq(updated.state[1], transcript.state[1], "state[1] field mismatch"); } } diff --git a/contracts/test/mocks/LightClientMock.sol b/contracts/test/mocks/LightClientMock.sol index 8a262b9dff..39b81d7af6 100644 --- a/contracts/test/mocks/LightClientMock.sol +++ b/contracts/test/mocks/LightClientMock.sol @@ -31,7 +31,7 @@ contract LightClientMock is LC { IPlonkVerifier.VerifyingKey memory vk = VkLib.getVk(); // Prepare the public input - uint256[] memory publicInput = new uint256[](8); + uint256[8] memory publicInput; publicInput[0] = votingThreshold; publicInput[1] = uint256(state.viewNum); publicInput[2] = uint256(state.blockHeight); diff --git a/contracts/test/mocks/LightClientStateUpdateVKMock.sol b/contracts/test/mocks/LightClientStateUpdateVKMock.sol index e474b7e5b5..472d0802b8 100644 --- a/contracts/test/mocks/LightClientStateUpdateVKMock.sol +++ b/contracts/test/mocks/LightClientStateUpdateVKMock.sol @@ -192,6 +192,14 @@ library LightClientStateUpdateVKMock { add(mload(add(vk, 0x260)), 0x20), 4028482820459137632881945408189551152935873937068798814930695801575907701616 ) + // g2LSB + mstore( + add(vk, 0x280), 0xb0838893ec1f237e8b07323b0744599f4e97b598b3b589bcc2bc37b8d5c41801 + ) + // g2MSB + mstore( + add(vk, 0x2A0), 0xc18393c0fa30fe4e8b038e357ad851eae8de9107584effe7c7f1f651b2010e26 + ) } } } diff --git a/data/chain_config.bin b/data/chain_config.bin new file mode 100644 index 0000000000..1888124061 Binary files /dev/null and b/data/chain_config.bin differ diff --git a/data/chain_config.json b/data/chain_config.json new file mode 100644 index 0000000000..4f0650f18e --- /dev/null +++ b/data/chain_config.json @@ -0,0 +1,7 @@ +{ + "base_fee": "0", + "chain_id": "35353", + "fee_contract": "0x0000000000000000000000000000000000000000", + "fee_recipient": "0x0000000000000000000000000000000000000000", + "max_block_size": "10240" +} diff --git a/data/fee_info.bin b/data/fee_info.bin new file mode 100644 index 0000000000..debddd9d05 Binary files /dev/null and b/data/fee_info.bin differ diff --git a/data/fee_info.json b/data/fee_info.json new file mode 100644 index 0000000000..ae0867bb1a --- /dev/null +++ b/data/fee_info.json @@ -0,0 +1,4 @@ +{ + "account": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266", + "amount": "0" +} diff --git a/data/header.bin b/data/header.bin new file mode 100644 index 0000000000..1c3990498c Binary files /dev/null and b/data/header.bin differ diff --git a/data/l1_block.bin b/data/l1_block.bin new file mode 100644 index 0000000000..ecffa9fdcf Binary files /dev/null and b/data/l1_block.bin differ diff --git a/data/messages.bin b/data/messages.bin new file mode 100644 index 0000000000..a3962ad3d4 Binary files /dev/null and b/data/messages.bin differ diff --git a/data/messages.json b/data/messages.json new file mode 100644 index 0000000000..3a5a376864 --- /dev/null +++ b/data/messages.json @@ -0,0 +1,427 @@ +[ + { + "kind": { + "Consensus": { + "General": { + "Proposal": { + "_pd": null, + "data": { + "block_header": { + "block_merkle_tree_root": "MERKLE_COMM~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAAAAAAAAAAAAAAQA", + "builder_commitment": "BUILDER_COMMITMENT~tEvs0rxqOiMCvfe2R0omNNaphSlUiEDrb2q0IZpRcgA_", + "builder_signature": null, + "chain_config": { + "chain_config": { + "Left": { + "base_fee": "0", + "chain_id": "35353", + "fee_contract": null, + "fee_recipient": "0x0000000000000000000000000000000000000000", + "max_block_size": "10240" + } + } + }, + "fee_info": { + "account": "0x0000000000000000000000000000000000000000", + "amount": "0" + }, + "fee_merkle_tree_root": "MERKLE_COMM~AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAUAAAAAAAAAAAAAAAAAAAAKA", + "height": 0, + "l1_finalized": null, + "l1_head": 0, + "ns_table": { + "bytes": "AAAAAA==" + }, + "payload_commitment": "HASH~AazstQer_ho1SqgGT0r10_Gs0BnjfbPBHJdSO3HHbp29", + "timestamp": 0 + }, + "justify_qc": { + "_pd": null, + "data": { + "leaf_commit": "COMMIT~eaBGKF8-lw-t211wxLq7tcXEEqacbvDVcFFR9aCddO3G" + }, + "signatures": null, + "view_number": 0, + "vote_commitment": "COMMIT~0-ZxNgMSsUEPeGDdq5-TZE8PDsYwgI4O2fVGMKooP87D" + }, + "proposal_certificate": { + "Timeout": { + "_pd": null, + "data": { + "view": 0 + }, + "signatures": null, + "view_number": 0, + "vote_commitment": "COMMIT~TZG1F34lxU6Ny9aKQMkjZAxjW9zotdwW75EHEGbyALOi" + } + }, + "upgrade_certificate": { + "_pd": null, + "data": { + "decide_by": 0, + "new_version": { + "major": 1, + "minor": 0 + }, + "new_version_first_view": 0, + "new_version_hash": [], + "old_version": { + "major": 0, + "minor": 1 + }, + "old_version_last_view": 0 + }, + "signatures": null, + "view_number": 0, + "vote_commitment": "COMMIT~roiQgLLeI4uYqYxjz-0jPwtLyNhSlnfriPEVZ-_4RUrW" + }, + "view_number": 0 + }, + "signature": "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "General": { + "Vote": { + "data": { + "leaf_commit": "COMMIT~eaBGKF8-lw-t211wxLq7tcXEEqacbvDVcFFR9aCddO3G" + }, + "signature": [ + "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U", + "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + ], + "view_number": 0 + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "General": { + "ViewSyncPreCommitVote": { + "data": { + "relay": 0, + "round": 0 + }, + "signature": [ + "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U", + "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + ], + "view_number": 0 + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "General": { + "ViewSyncCommitVote": { + "data": { + "relay": 0, + "round": 0 + }, + "signature": [ + "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U", + "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + ], + "view_number": 0 + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "General": { + "ViewSyncFinalizeVote": { + "data": { + "relay": 0, + "round": 0 + }, + "signature": [ + "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U", + "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + ], + "view_number": 0 + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "General": { + "ViewSyncPreCommitCertificate": { + "_pd": null, + "data": { + "relay": 0, + "round": 0 + }, + "signatures": null, + "view_number": 0, + "vote_commitment": "COMMIT~OQecZxfFpuEuPJgkpsQoglnqY0fm6Qi1PUarYCgiFQ0T" + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "General": { + "ViewSyncCommitCertificate": { + "_pd": null, + "data": { + "relay": 0, + "round": 0 + }, + "signatures": null, + "view_number": 0, + "vote_commitment": "COMMIT~POgBCaDjtUV3Il5-FXVr5KN2KzYSgipfKX6Ci0-nxduO" + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "General": { + "ViewSyncFinalizeCertificate": { + "_pd": null, + "data": { + "relay": 0, + "round": 0 + }, + "signatures": null, + "view_number": 0, + "vote_commitment": "COMMIT~s5i9wmQWH7VU90CUiEWRdAG19LI1iXydSMxp9gZ7kHco" + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "General": { + "TimeoutVote": { + "data": { + "view": 0 + }, + "signature": [ + "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U", + "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + ], + "view_number": 0 + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "General": { + "UpgradeProposal": { + "_pd": null, + "data": { + "upgrade_proposal": { + "decide_by": 0, + "new_version": { + "major": 1, + "minor": 0 + }, + "new_version_first_view": 0, + "new_version_hash": [], + "old_version": { + "major": 0, + "minor": 1 + }, + "old_version_last_view": 0 + }, + "view_number": 0 + }, + "signature": "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "General": { + "UpgradeVote": { + "data": { + "decide_by": 0, + "new_version": { + "major": 1, + "minor": 0 + }, + "new_version_first_view": 0, + "new_version_hash": [], + "old_version": { + "major": 0, + "minor": 1 + }, + "old_version_last_view": 0 + }, + "signature": [ + "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U", + "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + ], + "view_number": 0 + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "Da": { + "DaProposal": { + "_pd": null, + "data": { + "encoded_transactions": [ + 1, + 0, + 0, + 0, + 3, + 0, + 0, + 0, + 1, + 2, + 3 + ], + "metadata": { + "bytes": "AQAAAAEAAAALAAAA" + }, + "view_number": 0 + }, + "signature": "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "Da": { + "DaVote": { + "data": { + "payload_commit": "HASH~AazstQer_ho1SqgGT0r10_Gs0BnjfbPBHJdSO3HHbp29" + }, + "signature": [ + "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U", + "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + ], + "view_number": 0 + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "Da": { + "DaCertificate": { + "_pd": null, + "data": { + "payload_commit": "HASH~AazstQer_ho1SqgGT0r10_Gs0BnjfbPBHJdSO3HHbp29" + }, + "signatures": null, + "view_number": 0, + "vote_commitment": "COMMIT~5E3F3rC4E9DBhMBqOTmjZ9tjX4VFaV5gqrZJl0y6V05D" + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Consensus": { + "Da": { + "VidDisperseMsg": { + "_pd": null, + "data": { + "common": { + "all_evals_digest": "FIELD~rF4TMFZMXJCieDeov31aNuDG5nDGR-iQdteEgBjXkErn", + "multiplicity": 1, + "num_storage_nodes": 1, + "payload_byte_len": 11, + "poly_commits": "FIELD~AQAAAAAAAAD2xsICwO-z0CXx_ucl0FV1j-zJ3tgPO-OL8gYLvXkIkNE" + }, + "payload_commitment": "HASH~Z03vXeC1EEaBGf5iacsBEWYiA7PHi3K6uS9gVpmlUx3t", + "recipient_key": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U", + "share": { + "aggregate_proofs": "FIELD~AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQGY", + "evals": "FIELD~AQAAAAAAAAABAAAAAwAAAAECAwAAAAAAAAAAAAAAAAAAAAAAAAAAAMk", + "evals_proof": { + "pos": "FIELD~AAAAAAAAAAD7", + "proof": [ + { + "Leaf": { + "elem": "FIELD~AQAAAAAAAAABAAAAAwAAAAECAwAAAAAAAAAAAAAAAAAAAAAAAAAAAMk", + "pos": "FIELD~AAAAAAAAAAD7", + "value": "FIELD~rF4TMFZMXJCieDeov31aNuDG5nDGR-iQdteEgBjXkErn" + } + } + ] + }, + "index": 0 + }, + "view_number": 0 + }, + "signature": "BLS_SIG~g3CUcLMD7fnDsBhItKvSqXLwEqdWfvusSrgpL1GBAxf-SWFW0t32Agt2jrOiempjjpI7dBwYGgXv-0mvI4sGEEE" + } + } + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + }, + { + "kind": { + "Data": { + "SubmitTransaction": [ + { + "namespace": 1, + "payload": "AQID" + }, + 0 + ] + } + }, + "sender": "BLS_VER_KEY~bQszS-QKYvUij2g20VqS8asttGSb95NrTu2PUj0uMh1CBUxNy1FqyPDjZqB29M7ZbjWqj79QkEOWkpga84AmDYUeTuWmy-0P1AdKHD3ehc-dKvei78BDj5USwXPJiDUlCxvYs_9rWYhagaq-5_LXENr78xel17spftNd5MA1Mw5U" + } +] \ No newline at end of file diff --git a/data/ns_table.bin b/data/ns_table.bin new file mode 100644 index 0000000000..02a363d7cc Binary files /dev/null and b/data/ns_table.bin differ diff --git a/data/payload.bin b/data/payload.bin new file mode 100644 index 0000000000..806d83c2a3 Binary files /dev/null and b/data/payload.bin differ diff --git a/data/payload.json b/data/payload.json new file mode 100644 index 0000000000..2387c7aa4b --- /dev/null +++ b/data/payload.json @@ -0,0 +1,6 @@ +{ + "ns_table": { + "bytes": "AwAAAO7/wAAcBgAAobC5EkAOAABksAWiXBQAAA==" + }, + "raw_payload": "BgAAAAABAAAAAgAAAAMAAAAEAAAABQAAAAYAAF2eIXFMYkyrHrYISOdpUPxLq2dgmfDilwq9z71rSHb2xcbmS2nim/Ak33mSXGqypeXatObNfgf921YXBvra9Z/oPCq6AEfRmM5J+ZKvcX4URjpPP/AvIPcF3PmLmF/kgyq1cPnT/lQPW5Z9Nb4ka3C1IqLMBqqmNxca+jwWrXOXtaj/VTrLdtRleItPSrcC9ShFVqMk4NJrFe9i6LiuDYom7JdoIeitb+le/x4cl3koNvqFcmVY3013dIXijRwffVUQHWATDTBLMJRTtTiA9gTg+Dl4gsboJzOzlKjaqEgNUouP/E/YMHdTVgUvz3TyvPOCxePq9xg0yeNT8BDKA+kPUd5oezPOoFRQum/hkAidqKl453/BTMpijENApkbiy/s0FV7kT2CyBp+kMHNdVO7IK4JyCO4Mj1HBxtcFaNjhXNg7QAXB0c8t/9E4DhvDU1YX9UB8mSqCRrq35BXOFHRDmMFaXj/WWWMZkeUHeAQZF7Y8k4cHnImIhdZg532eg6QcPNwuHgCdLQOnoZteoZWKoMloJvpS1xcRusvh8Y4wV4L1eURLQLq8eva5UTFs6LzRyPQZ6EOlZvrMTlunRwCGBT5lGiyX3wWGY2m2JWfhR+rlccHcUlwb43d40VkXY3oVg4eR4nWS9eBaqkjHXYuQaX0INhMYV+byHlUn7wJkqiHjp3hY0xts2yr/mjCkUeScU9vG7C+x5lg8r+RDFox1OaF7s9/jYcDEXLZzfyrX5iE8x9ot6A+E6W5rp1Ek/ymkRvK3rr7DmTvGrRpgNfSndlb2FsH7Vu1lnYsE/mNEMwwbhjTrRI1qoWRNdkrJYUZsTOw4NM6SfN0wvZ4PVtTlFb97KvWd5b/y5f9WoGEbqunvtky528CtZyn3e44a0Rd9ECWhYifqb9L7R+D8yGm8NePNpyiAx2TdlX4Su4eN/VeHV04moVpH8ygXKKhMNX2KpDqu7sVB4T5/wUZNOCyvdzoQsZ7ot8JVOol4qLvegxsm/VbK4tQKmzeC/2tXleHPHSl8Nxsd+chgyAGJTuAH8EdCO3vJHSf7BqWzcDAeyz7tWe2sDkW0XJAco+uepk6bISMHItKAdO9tsaf+XMOdrg2lPghOYD2baTpvaF9d9jFZL+P5T+2LwRbKkID3WSC2vt7Ipq5KKsrMoGAzZO+AMOIQJQbGhta8YHLaz7hWrrpfzThxipZnBaGmjeKUMP7aJD4pP0uA5VFbtLYuiXFFh86rq0ovBZFMIe1d99EmksRPhFS1TwG2BjBkvMCjNI7eHYU1/yXvB35UfCNr8hEiaMvfOZ4ZUIzoBymPQtTIhaW/vPGR/4cDt0anBEZ8/4tdyaswCW9tTzfecNzzlt37ymGIDDGsH5UAlM4Th5TDYi+G5rHreV6cwIkaKKwTkVmAwG1eG51EYyO9NKdV1ikjdemEonxX9E4h3ZYZziwlNWCigg5eeo96cqMWL562APWSiyp0ARGlKGLUbrTLeQ8vuEbOOZqiOffH7Lnp24hDGhuUiPeARi15iru4e7YMPjpLD3D38jZHh+wo1BcdA2LWsOGCstaPKaQIgdyDD2xt846nIv6g4ozCsPmVXIBjJ46xvZkFbmmKFXQ0ZfopR2CGqAkAqbo/2EklZzo0kPQNlqDb2gDGafEDC4ND+mBTilxklxx354LlwTO/70S/CJrIs2kQgBPwyblcOguKfJpSLE0aYScDmLbqqIXWJTI6cmmKUf+RvYb+dhp9HGXSVkUpilYqkzRNz+NEwVTH9Afqh3PguK1YEXKINBwm0FMEstgeulTBCErnGYB2+XUdT4tKvC3XnQdsFthPW4VJ0Z8Wo1zt3uOlktbdUePvXLkUbWvaWJppmFidgFy1XBfD5mUyHMuaO7OsXMZHgCcAdx0OhqNAGKhLeN14LeiA8LaBJEV6SGqLy0fh5Vj501jGT+Z8PJ7MKZ38o1q+zUY+q/NnbRnRROTZZCSSAjbo+VosW3arhJeNeFHlABDaalv1GxCY3KIq5/nPK6sPBkIRIIumGXMYDJ9N+vF7rlgeCB+VgQgAAAAAAQAAAAIAAAADAAAABAAAAAUAAAAGAAAABwAAAAgAAM9kwJjeoi0EAJ6Ut9v7a/RueDt+T9TdqgR8o/fpx1WCUgOMGSTcPkOnP2NkuC2GLzV+zEIah3u4xPLjQ1lRZHr2yTAf2B3rtETPpqvYr065U/AobcXdWD3vdMivApM/emVjgu7qFboSXYCBPmr2qqCZndfCcilnWV9sAgns2CfpFFNcWxr6O0tvSChdJC0As3r1Edye2ep7erYCjTZlPFaSykV/QY+A60JWHr81x+0l8/sP/AM0X7uZPh8JSfuPPJJ3Shz8E0W0DHyKcJInJkus4JGGOSIF3xU2OtZTH2YDvpZmkhFKVTAiig7YzN5DAv+aRsmOiNVCbu4jDm6nMqkMjyEolLrO7aPLZUtXr6O8BAUCprmDe0o0TdCR+8pWgGLDQyf3z7Yvo4n7+oNS8j+D0R2zBqyToAnMwOkAecJYvUr27OlzXvEcmAGStoz1A+OngS+3gHIwAMQOrDjwiUra5NausPZ7CbfcuY3FBY8pFrBY/4IkTKql55InYmQTFhQHj5YLFbzHbdZOJpYybVk0OkntRe6OEEQVuo8ivUVHr3lmABW4LT+Xpceqie5i6dqh87b+TqqnNcyEUo66TFOPJWRjVeC8v/Hoy05WnM098DsBMjGvmrFe/9JNQowEnh1XzpjiUHGuHpJPlAo+221hkTaXRve2th1mXmFSzy5fVziicoKc0YVOM3qEmyI2u/ZFXYaGCmWeigQ0mq3JJuKGZXrcfxTivGHXoa4VwELGpxero1XnEwO11rggj/wg8N8jh1UHjdevZiHJOZUuGuve11dSqe5KUdG6ty0exPWWdMiohVJ+coEz98GheJDDGjBFOcF/q1rTcNWRVURpeDx8oxkQ3/E8fwxD76lG8snJjNip/CcFDiDI8orkn6cQsnMybACRf0kKzAAnitxWIuzuvVB99tJ/iDUD+U5fplD5w2ER2Q0kRVLYxEjwdNr/5nzJjHoVehLYupVYvT1hMF+8iQQJfyex4ZeSUeD48p7UEy9IG9JolNVKIH+YpGfR5WU/nfWbieWQtUR+DGGv6CQB20Pztd20I4z/+NcWnFOddFRT51GK8T++Ot7h5jKsaEReI5kKChnPUwA0ZB8GGmKfTC1UOUGESv2l+r5pfSp/st+mT0s9iLcIiBqxzazIlcsAFG/RjpS+UXTC0Vn6ut37XtxSGprSYc4zByNOHW40Wl27pErIEmpivjBgTuI1ta02YAlUcN/AMIDxBq9KcsZMCHnBb11fCU7s+EZCgKWPzXnpwbstf+zMOtMiwwJdiEKq//xbmrK3/JFuXfaomDzQJXsq4OIvGuDZuV3TcXn925y4sqvqwhjGzDZNi4JBzc4o3+4GiyrF6Lz6k0A7G6Ivvb4ZawTJ4IKO99+1rgTKrCrnlTU7DbZssIxSnwH2qW48y+FirOUYH9jwn4gfI6KYAbOmjejZsU7X44sHaGEzNjqXZ3Vb57gUW7vK/cSsuKXDnB8q5bCiudg9BuLz1cuPwAQ4d7NRRJujYeAF+H8Upsmer6sgfl5SvWLzxxkpkz4NcMdH5IJ8Ll9UwoD3/14DOz6EX2drBl075iejXBE0ViBty/CSt0FD1+3tvJbObV3dqq4PrGyEDdp1rg8pVrTtCq6BNEEWM/9n1WRPYFBI6nKMIyqXslNNssZJ4Eya1bwXPxVJxTevGKbsbKFAwFiLq0JzQe2BecfHKGpmvZAjJ54vXwaRVEmbuE6Sw47ec0s4jLAqZ8FMWcxCMho6vcINVeJFll0UZLZSTd8u67tBsHCrXsa54fwwTZ/tL2IayrBa2+y4zgDU6mf/PXBDxn5rUHcqK/LUwxdOvVvFst/HImU0ty8Y+F8eHkTocENVRVTNxPJ2UGQX8DXguv33WQ+kNjO7vY8V18BPTWZYC4Jf3GY2FvAGGr6jGbrAD9/Wb7zetKhS6zrbOnz2KOSJabYRpaNj85+5mALigd9unzZd2evLiX9CZCu/cVwZKoQZw6L4tKYwx5tA9M3qcKvZMNpDxURGStPwpiXnFiAa0+kZ+ugMH9IiEWQyCEInXBMUskVu7+rVs6HqFarEcQGhi3VSxl7S2/PG6K7mNzgBZzgWMeXpAixkWd6zjYESBLsFe6GsYHQjYNq4z0Jjv5Rjx3IOgtbNUZehBkcI+zmpbqf3tv1odmHtxpL/hVgBG2NvWdE+q2OtDaz3JOVZ27Pf6kf0glHhnaPpDDfbjfTygd7B4LFli5k+ED2bMc5264Oa+N2yWRLqhorqibx0L2Y/KzjOVh+qCinziGmfIGVMEhiMJB/SaAw4PMVg7dR+N0C4bHHJBQS8MPv6aydBmPYm9j9kh8ee6pFYqvXgwdXebkJS8j1D1vHb9g3ndhsr4J6x+u0GrlHz1J4cyivM4HG1GqixkW2pCiB3Fh4dEIUeJsUemr0hB9dMdbOC0WBn42Xc6v8MP9gnIrHhCueK7CleMPMjS38E5MgVas0GerM4cGLMBxvjL30zdcBAeMZdRaPR8WQbw5B4jwY93C6LKcxO+gWix02aa0i5ZDcHZY3IjZV7fxy3vvtEs/qxXMto8gLK8I7kjDAblmAIV5yleBUgQ8pzw6BkqbK2/AA6cJcAg7gJUVAA6wT9fsrAUgiMcWuf1+DSSVrBK/FXa7AY5X/PGPaWeZdOCLs1ncGLrVmOSNCFfCWT/5UYvh952uFc+/SghFcdEyQ2bznu9S55FpNFVQ29Ia10aeYMffzonMx+eT01BgAAAAABAAAAAgAAAAMAAAAEAAAABQAAAAYAAKLQrjdgptCHUAMU4Epx9OxmKmeD0v9LZ4yGEf3K9lgBYxrATdQAzMHtZ9GmmubMEgpTgWew4elHoHC7Cw9H889c2Z86VqYBGQ+8xlYRQjy9W5IQtu5SddmMIgUzoBx2itmtCyrthgf79qAInSyQwaJrKiuRRq16wwwoa5j3YQr3AOfrjR+kglN/K8prXBIN8YYJxLi+ntqQ2B5mvIY+3yy+mDsrI2BvS9dcfaAPi+x7V1AgwzXpEvA5Hh/rp3e4WfbH5cUjdubwUr8Qx/a7RUb9jMDZvBm2aKuX5p0kVpntV9nVt2p/fKJ4sXqguB2dHhcU3o5OWMyelM/3qFkLAFKWhRA8XRm7jjQAN7B1+ZtmaPqQIsSza0ToJiYzUR3K/5yy52gfFTwa5G4dpFqRFz+GSTBn/ZiMXLHfZcJwa/ILkNRGSqEj6TFBXYJPaMhrTz6JeA43PcD2x8OF6vKgunyd+HPh3Vi1Mm5UY0q8HHoiZpJ5g+kKKT3dAxS2LekFg+fsDdphawltbsoCeIDHKmLIQ0OEHoB4Y13bb96RzZHFKMRUgGSommgmsEA/yoS20e4wWU1uEv7DcM4PQ75QsntW1296s4DBkHAV0JIe/zetUPnMK/pj4DTlluQR74BPvYmCd6PNdwm8Nw9Y+luvmNm63A3BemUg0yOJV+xC6Lp6i8NuBuwpS2ICoQW/aKNgnBrX0msaee9YhzKiV0gBBjCibHdJNFnWDUBwYJQZc4fdJtgE5gIyTi7UMjgQz65QKbIrCv+jtFmkBN89VflXl1616Cn/9AxGXABurhggbm7QajQpBjJtLaFmSJxHc6/39v+bWHfQFs7Xoi3hDFf1Lk6G+x+972g0ThDI1eZVYaRckd6u1Hg/M8f5GC/J9Ib4RTGHIgAbFfs/CRA7LcSiGY9PEZxSUhMMRhiexEw4x0bkeb8lrsy14aBsM45krvzGWBlJMKRGMtuvsBA3dU+GCjU9+savW/QEIjhm7sWfkvKLcqVreKl1HFHdsB/iKMfHU5Lfd917BM9ip0oOe8y4GLDCscgs/6lUTzO0g30OzZVvlsdOk2pSNRbrbrnhy6HCGsxPxAYuyIJ93ZmHaZ+hEiq1KgISHq7bIxV7ffUEZIZ3+RyTWsvJGB82C027X1NXcrLRtmfJ9L9oUask0rqNz7elKvd8FFET54rUaDOx/dorXjMwoWuxHnViT+jYwsSA+73kiOA5H0Q4y0XT6F58/wo7JSR3hS2PQNPtsuLgX4ZIadYn4njN3w7Uocuz48iw/JYLIM+AlrW16RgduDVr0YhVIcMVAeeeizNM/wkfulryWH5LvDqJ6oH6ir9b5NX5f82FPE7o2p7shS1I02wV3zPpoqcOn4C1z9LC1V0twA4xSRyQc0nmcWZMpIR3/IkSIMRdMa/OB2WsJza/u+DOzJ6HcDfLtqNNIpm/ksVqJiQWkl48B2rCv26KDkRwXFoLopuT2KRlB1kRFew7lNRaTQesbiGMrYFd98AHjDJzuA6197J5c7XgRA7EVaFK72Rbzsudh2oHun/ninbEHNDvEtYrBlZszVJ48a+EL8X/r8gMwoi7Wq33dhwFaDmIezr0/A9RjJELXTEtczYQwt3SP/vkSqjqwbC0LNJVsvoqf8QpkTmfBFyEtakDYgSqOqAei92d3d1yBIq+HFQu4wy83N25zw3fSMJXJixQwp7QEIScYLxQP/9Q3NGiV1QtxGUMdu1bGVTvjcvmNx6sezGBjleuHUBYlF9+y8yVWc3dOyQ9EqEMomqZ4fkeBvNgElGjPTH2SA9nl0ZVKM4EgQ1cvRUYwBWtFYkrfcZquK/G6+/REOOB4Q+xIIcxbsrzCI0DYsFLllEVKIfWLbdJH2WwWINsP96rBhh3aLnTeM0srC3IuZfjI+wgpXnEyMqdWJ1rqjrkMBZHvjecJmWaUhFFmBE22RGJ544P1PsMp/pVEFPGMdb+sSuqhuA88XnuYKI8ENxLXXTHE/to1mQ9khDnpntjARASxeSAFmEddAmrfSoh9JV3P49YR8QBlWAyVPt/aw==" +} \ No newline at end of file diff --git a/data/transaction.bin b/data/transaction.bin new file mode 100644 index 0000000000..9f086e3901 Binary files /dev/null and b/data/transaction.bin differ diff --git a/data/tx_index.bin b/data/tx_index.bin new file mode 100644 index 0000000000..efdcb0dd86 Binary files /dev/null and b/data/tx_index.bin differ diff --git a/data/tx_index.json b/data/tx_index.json new file mode 100644 index 0000000000..0c24f617f1 --- /dev/null +++ b/data/tx_index.json @@ -0,0 +1,14 @@ +{ + "ns_index": [ + 2, + 0, + 0, + 0 + ], + "tx_index": [ + 5, + 0, + 0, + 0 + ] +} \ No newline at end of file diff --git a/justfile b/justfile index bd9d75d19e..2c17d6dfd0 100644 --- a/justfile +++ b/justfile @@ -74,7 +74,7 @@ build-docker-images: scripts/build-docker-images # generate rust bindings for contracts -REGEXP := "^LightClient$|^LightClientStateUpdateVK$|^FeeContract$|^HotShot$|PlonkVerifier$|^ERC1967Proxy$|^LightClientMock$|^LightClientStateUpdateVKMock$" +REGEXP := "^LightClient$|^LightClientStateUpdateVK$|^FeeContract$|^HotShot$|PlonkVerifier$|^ERC1967Proxy$|^LightClientMock$|^LightClientStateUpdateVKMock$|^PlonkVerifier2$" gen-bindings: forge bind --contracts ./contracts/src/ --crate-name contract-bindings --bindings-path contract-bindings --select "{{REGEXP}}" --overwrite --force @@ -112,9 +112,10 @@ lc-contract-profiling-sepolia: echo $LC_CONTRACT_ADDRESS forge script contracts/script/LightClientCallNewFinalizedState.s.sol --sig "run(uint32 numInitValidators, address lcContractAddress)" {{NUM_INIT_VALIDATORS}} $LC_CONTRACT_ADDRESS --fork-url ${SEPOLIA_RPC_URL} --broadcast --chain-id sepolia -lc-contract-benchmark: +gas-benchmarks: cargo build --bin diff-test --release - forge test --mt testCorrectUpdateBench | grep testCorrectUpdateBench + forge snapshot --mt "test_verify_succeeds|testCorrectUpdateBench" + @[ -n "$(git diff --name-only .gas-snapshot)" ] && echo "⚠️ Uncommitted gas benchmarks, please stage them before committing." && exit 1 || exit 0 # This is meant for local development and produces HTML output. In CI # the lcov output is pushed to coveralls. @@ -134,4 +135,3 @@ download-srs: dev-download-srs: @echo "Check existence or download SRS for dev/test" @AZTEC_SRS_PATH="$PWD/data/aztec20/kzg10-aztec20-srs-65544.bin" ./scripts/download_srs_aztec.sh - \ No newline at end of file diff --git a/sequencer/src/block/full_payload.rs b/sequencer/src/block/full_payload.rs new file mode 100644 index 0000000000..61247ec87e --- /dev/null +++ b/sequencer/src/block/full_payload.rs @@ -0,0 +1,9 @@ +mod ns_proof; +mod ns_table; +mod payload; + +pub use ns_proof::NsProof; +pub use ns_table::{NsIndex, NsTable, NsTableValidationError}; +pub use payload::{Payload, PayloadByteLen}; + +pub(in crate::block) use ns_table::NsIter; diff --git a/sequencer/src/block/full_payload/ns_proof.rs b/sequencer/src/block/full_payload/ns_proof.rs new file mode 100644 index 0000000000..104ca45f4f --- /dev/null +++ b/sequencer/src/block/full_payload/ns_proof.rs @@ -0,0 +1,172 @@ +use crate::{ + block::{ + full_payload::{NsIndex, NsTable, Payload, PayloadByteLen}, + namespace_payload::NsPayloadOwned, + }, + NamespaceId, Transaction, +}; +use hotshot_types::{ + traits::EncodeBytes, + vid::{vid_scheme, LargeRangeProofType, VidCommitment, VidCommon, VidSchemeType}, +}; +use jf_vid::{ + payload_prover::{PayloadProver, Statement}, + VidScheme, +}; +use serde::{Deserialize, Serialize}; + +/// Proof of correctness for namespace payload bytes in a block. +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct NsProof { + ns_index: NsIndex, + ns_payload: NsPayloadOwned, + ns_proof: Option, // `None` if ns_payload is empty +} + +impl NsProof { + /// Returns the payload bytes for the `index`th namespace, along with a + /// proof of correctness for those bytes. Returns `None` on error. + /// + /// The namespace payload [`NsPayloadOwned`] is included as a hidden field + /// in the returned [`NsProof`]. A conventional API would instead return + /// `(NsPayload, NsProof)` and [`NsProof`] would not contain the namespace + /// payload. + /// ([`TxProof::new`](crate::block::namespace_payload::TxProof::new) + /// conforms to this convention.) In the future we should change this API to + /// conform to convention. But that would require a change to our RPC + /// endpoint API at [`endpoints`](crate::api::endpoints), which is a hassle. + pub fn new(payload: &Payload, index: &NsIndex, common: &VidCommon) -> Option { + let payload_byte_len = payload.byte_len(); + if !payload_byte_len.is_consistent(common) { + tracing::warn!( + "payload byte len {} inconsistent with common {}", + payload_byte_len, + VidSchemeType::get_payload_byte_len(common) + ); + return None; // error: payload byte len inconsistent with common + } + if !payload.ns_table().in_bounds(index) { + tracing::warn!("ns_index {:?} out of bounds", index); + return None; // error: index out of bounds + } + let ns_payload_range = payload.ns_table().ns_range(index, &payload_byte_len); + + // TODO vid_scheme() arg should be u32 to match get_num_storage_nodes + // https://github.com/EspressoSystems/HotShot/issues/3298 + let vid = vid_scheme( + VidSchemeType::get_num_storage_nodes(common) + .try_into() + .ok()?, // error: failure to convert u32 to usize + ); + + let ns_proof = if ns_payload_range.as_block_range().is_empty() { + None + } else { + Some( + vid.payload_proof(payload.encode(), ns_payload_range.as_block_range()) + .ok()?, // error: internal to payload_proof() + ) + }; + + Some(NsProof { + ns_index: index.clone(), + ns_payload: payload.read_ns_payload(&ns_payload_range).to_owned(), + ns_proof, + }) + } + + /// Verify a [`NsProof`] against a payload commitment. Returns `None` on + /// error or if verification fails. + /// + /// There is no [`NsPayload`](crate::block::namespace_payload::NsPayload) + /// arg because this data is already included in the [`NsProof`]. See + /// [`NsProof::new`] for discussion. + /// + /// If verification is successful then return `(Vec, + /// NamespaceId)` obtained by post-processing the underlying + /// [`NsPayload`](crate::block::namespace_payload::NsPayload). Why? This + /// method might be run by a client in a WASM environment who might be + /// running non-Rust code, in which case the client is unable to perform + /// this post-processing himself. + pub fn verify( + &self, + ns_table: &NsTable, + commit: &VidCommitment, + common: &VidCommon, + ) -> Option<(Vec, NamespaceId)> { + VidSchemeType::is_consistent(commit, common).ok()?; + if !ns_table.in_bounds(&self.ns_index) { + return None; // error: index out of bounds + } + + let range = ns_table + .ns_range(&self.ns_index, &PayloadByteLen::from_vid_common(common)) + .as_block_range(); + + match (&self.ns_proof, range.is_empty()) { + (Some(proof), false) => { + // TODO vid_scheme() arg should be u32 to match get_num_storage_nodes + // https://github.com/EspressoSystems/HotShot/issues/3298 + let vid = vid_scheme( + VidSchemeType::get_num_storage_nodes(common) + .try_into() + .ok()?, // error: failure to convert u32 to usize + ); + + vid.payload_verify( + Statement { + payload_subslice: self.ns_payload.as_bytes_slice(), + range, + commit, + common, + }, + proof, + ) + .ok()? // error: internal to payload_verify() + .ok()?; // verification failure + } + (None, true) => {} // 0-length namespace, nothing to verify + (None, false) => { + tracing::error!( + "ns verify: missing proof for nonempty ns payload range {:?}", + range + ); + return None; + } + (Some(_), true) => { + tracing::error!("ns verify: unexpected proof for empty ns payload range"); + return None; + } + } + + // verification succeeded, return some data + let ns_id = ns_table.read_ns_id_unchecked(&self.ns_index); + Some((self.ns_payload.export_all_txs(&ns_id), ns_id)) + } + + /// Return all transactions in the namespace whose payload is proven by + /// `self`. The namespace ID for each returned [`Transaction`] is set to + /// `ns_id`. + /// + /// # Design warning + /// + /// This method relies on a promise that a [`NsProof`] stores the entire + /// namespace payload. If in the future we wish to remove the payload from a + /// [`NsProof`] then this method can no longer be supported. + /// + /// In that case, use the following a workaround: + /// - Given a [`NamespaceId`], get a [`NsIndex`] `i` via + /// [`NsTable::find_ns_id`]. + /// - Use `i` to get a + /// [`NsPayload`](crate::block::namespace_payload::NsPayload) `p` via + /// [`Payload::ns_payload`]. + /// - Use `p` to get the desired [`Vec`] via + /// [`NsPayload::export_all_txs`](crate::block::namespace_payload::NsPayload::export_all_txs). + /// + /// This workaround duplicates the work done in [`NsProof::new`]. If you + /// don't like that then you could instead hack [`NsProof::new`] to return a + /// pair `(NsProof, Vec)`. + pub fn export_all_txs(&self, ns_id: &NamespaceId) -> Vec { + self.ns_payload.export_all_txs(ns_id) + } +} diff --git a/sequencer/src/block/full_payload/ns_table.rs b/sequencer/src/block/full_payload/ns_table.rs new file mode 100644 index 0000000000..d2d2290ef1 --- /dev/null +++ b/sequencer/src/block/full_payload/ns_table.rs @@ -0,0 +1,467 @@ +//! Types related to a namespace table. +//! +//! All code that needs to know the binary format of a namespace table is +//! restricted to this file. +//! +//! See [`NsTable`] for a full specification of the binary format of a namespace +//! table. +use crate::{ + block::{ + full_payload::payload::PayloadByteLen, + namespace_payload::NsPayloadRange, + uint_bytes::{ + bytes_serde_impl, u32_from_bytes, u32_to_bytes, usize_from_bytes, usize_to_bytes, + }, + }, + NamespaceId, +}; +use committable::{Commitment, Committable, RawCommitmentBuilder}; +use derive_more::Display; +use hotshot_types::traits::EncodeBytes; +use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; +use std::{collections::HashSet, ops::Range, sync::Arc}; +use thiserror::Error; + +/// Byte lengths for the different items that could appear in a namespace table. +const NUM_NSS_BYTE_LEN: usize = 4; +const NS_OFFSET_BYTE_LEN: usize = 4; + +// TODO prefer [`NS_ID_BYTE_LEN`] set to `8` because [`NamespaceId`] is a `u64` +// but we need to maintain serialization compatibility. +// https://github.com/EspressoSystems/espresso-sequencer/issues/1574 +const NS_ID_BYTE_LEN: usize = 4; + +/// Raw binary data for a namespace table. +/// +/// Any sequence of bytes is a valid [`NsTable`]. +/// +/// # Binary format of a namespace table +/// +/// Byte lengths for the different items that could appear in a namespace table +/// are specified in local private constants [`NUM_NSS_BYTE_LEN`], +/// [`NS_OFFSET_BYTE_LEN`], [`NS_ID_BYTE_LEN`]. +/// +/// ## Number of entries in the namespace table +/// +/// The first [`NUM_NSS_BYTE_LEN`] bytes of the namespace table indicate the +/// number `n` of entries in the table as a little-endian unsigned integer. If +/// the entire table length is smaller than [`NUM_NSS_BYTE_LEN`] then the +/// missing bytes are zero-padded. +/// +/// The bytes in the namespace table beyond the first [`NUM_NSS_BYTE_LEN`] bytes +/// encode table entries. Each entry consumes exactly [`NS_ID_BYTE_LEN`] `+` +/// [`NS_OFFSET_BYTE_LEN`] bytes. +/// +/// The number `n` could be anything, including a number much larger than the +/// number of entries that could fit in the namespace table. As such, the actual +/// number of entries in the table is defined as the minimum of `n` and the +/// maximum number of whole entries that could fit in the table. +/// +/// See [`Self::in_bounds`] for clarification. +/// +/// ## Namespace table entry +/// +/// ### Namespace ID +/// +/// The first [`NS_ID_BYTE_LEN`] bytes of each table entry indicate the +/// [`NamespaceId`] for this namespace. Any table entry whose [`NamespaceId`] is +/// a duplicate of a previous entry is ignored. A correct count of the number of +/// *unique* (non-ignored) entries is given by `NsTable::iter().count()`. +/// +/// ### Namespace offset +/// +/// The next [`NS_OFFSET_BYTE_LEN`] bytes of each table entry indicate the +/// end-index of a namespace in the block payload bytes +/// [`Payload`](super::payload::Payload). This end-index is a little-endian +/// unsigned integer. +/// +/// # How to deduce a namespace's byte range +/// +/// In order to extract the payload bytes of a single namespace `N` from the +/// block payload one needs both the start- and end-indices for `N`. +/// +/// See [`Self::ns_range`] for clarification. What follows is a description of +/// what's implemented in [`Self::ns_range`]. +/// +/// If `N` occupies the `i`th entry in the namespace table for `i>0` then the +/// start-index for `N` is defined as the end-index of the `(i-1)`th entry in +/// the table. +/// +/// Even if the `(i-1)`the entry would otherwise be ignored (due to a duplicate +/// [`NamespaceId`] or any other reason), that entry's end-index still defines +/// the start-index of `N`. This rule guarantees that both start- and +/// end-indices for any namespace `N` can be read from a constant-size byte +/// range in the namespace table, and it eliminates the need to traverse an +/// unbounded number of previous entries of the namespace table looking for a +/// previous non-ignored entry. +/// +/// The start-index of the 0th entry in the table is implicitly defined to be +/// `0`. +/// +/// The start- and end-indices `(declared_start, declared_end)` declared in the +/// namespace table could be anything. As such, the actual start- and +/// end-indices `(start, end)` are defined so as to ensure that the byte range +/// is well-defined and in-bounds for the block payload: +/// ```ignore +/// end = min(declared_end, block_payload_byte_length) +/// start = min(declared_start, end) +/// ``` +/// +/// In a "honestly-prepared" namespace table the end-index of the final +/// namespace equals the byte length of the block payload. (Otherwise the block +/// payload might have bytes that are not included in any namespace.) +/// +/// It is possible that a namespace table could indicate two distinct namespaces +/// whose byte ranges overlap, though no "honestly-prepared" namespace table +/// would do this. +/// +/// TODO prefer [`NsTable`] to be a newtype like this +/// ```ignore +/// #[repr(transparent)] +/// #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +/// #[serde(transparent)] +/// pub struct NsTable(#[serde(with = "base64_bytes")] Vec); +/// ``` +/// but we need to maintain serialization compatibility. +/// +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +// Boilerplate: `#[serde(remote = "Self")]` needed to check invariants on +// deserialization. See +// https://github.com/serde-rs/serde/issues/1220#issuecomment-382589140 +#[serde(remote = "Self")] +pub struct NsTable { + #[serde(with = "base64_bytes")] + bytes: Vec, +} + +// Boilerplate: `#[serde(remote = "Self")]` allows invariant checking on +// deserialization via re-implementation of `Deserialize` in terms of default +// derivation. See +// https://github.com/serde-rs/serde/issues/1220#issuecomment-382589140 +impl<'de> Deserialize<'de> for NsTable { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + let unchecked = NsTable::deserialize(deserializer)?; + unchecked + .validate_deserialization_invariants() + .map_err(de::Error::custom)?; + Ok(unchecked) + } +} + +// Boilerplate: use of `#[serde(remote = "Self")]` must include a trivial +// `Serialize` impl. See +// https://github.com/serde-rs/serde/issues/1220#issuecomment-382589140 +impl Serialize for NsTable { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + NsTable::serialize(self, serializer) + } +} + +impl NsTable { + /// Search the namespace table for the ns_index belonging to `ns_id`. + pub fn find_ns_id(&self, ns_id: &NamespaceId) -> Option { + self.iter() + .find(|index| self.read_ns_id_unchecked(index) == *ns_id) + } + + /// Number of entries in the namespace table. + /// + /// Defined as the maximum number of entries that could fit in the namespace + /// table, ignoring what's declared in the table header. + pub fn len(&self) -> NumNss { + NumNss( + self.bytes.len().saturating_sub(NUM_NSS_BYTE_LEN) + / NS_ID_BYTE_LEN.saturating_add(NS_OFFSET_BYTE_LEN), + ) + } + + /// Iterator over all unique namespaces in the namespace table. + pub fn iter(&self) -> impl Iterator + '_ { + NsIter::new(&self.len()) + } + + /// Read the namespace id from the `index`th entry from the namespace table. + /// Returns `None` if `index` is out of bounds. + /// + /// TODO I want to restrict visibility to `pub(crate)` or lower but this + /// method is currently used in `nasty-client`. + pub fn read_ns_id(&self, index: &NsIndex) -> Option { + if !self.in_bounds(index) { + None + } else { + Some(self.read_ns_id_unchecked(index)) + } + } + + /// Like [`Self::read_ns_id`] except `index` is not checked. Use [`Self::in_bounds`] as needed. + pub fn read_ns_id_unchecked(&self, index: &NsIndex) -> NamespaceId { + let start = index.0 * (NS_ID_BYTE_LEN + NS_OFFSET_BYTE_LEN) + NUM_NSS_BYTE_LEN; + + // TODO hack to deserialize `NamespaceId` from `NS_ID_BYTE_LEN` bytes + // https://github.com/EspressoSystems/espresso-sequencer/issues/1574 + NamespaceId::from(u32_from_bytes::( + &self.bytes[start..start + NS_ID_BYTE_LEN], + )) + } + + /// Does the `index`th entry exist in the namespace table? + pub fn in_bounds(&self, index: &NsIndex) -> bool { + self.len().in_bounds(index) + } + + /// Are the bytes of this [`NsTable`] uncorrupted? + /// + /// # Checks + /// 1. Byte length must hold a whole number of entries. + /// 2. All offsets must increase monotonically. Offsets + /// must be nonzero. Namespace IDs must be unique. + /// 3. Header consistent with byte length. (Obsolete after + /// .) + /// 4. Final offset must equal `payload_byte_len`. (Obsolete after + /// .) + /// If the namespace table is empty then `payload_byte_len` must be 0. + pub fn validate( + &self, + payload_byte_len: &PayloadByteLen, + ) -> Result<(), NsTableValidationError> { + use NsTableValidationError::*; + + // conditions 1-3 + self.validate_deserialization_invariants()?; + + // condition 4 + let len = self.len().0; + if len > 0 { + let final_ns_index = NsIndex(len - 1); + let final_offset = self.read_ns_offset_unchecked(&final_ns_index); + if final_offset != payload_byte_len.as_usize() { + return Err(InvalidFinalOffset); + } + } else if payload_byte_len.as_usize() != 0 { + return Err(ExpectNonemptyNsTable); + } + + Ok(()) + } + + // CRATE-VISIBLE HELPERS START HERE + + /// Read subslice range for the `index`th namespace from the namespace + /// table. + pub(in crate::block) fn ns_range( + &self, + index: &NsIndex, + payload_byte_len: &PayloadByteLen, + ) -> NsPayloadRange { + let end = self + .read_ns_offset_unchecked(index) + .min(payload_byte_len.as_usize()); + let start = if index.0 == 0 { + 0 + } else { + self.read_ns_offset_unchecked(&NsIndex(index.0 - 1)) + } + .min(end); + NsPayloadRange::new(start, end) + } + + // PRIVATE HELPERS START HERE + + /// Read the number of namespaces declared in the namespace table. THIS + /// QUANTITY IS NEVER USED. Instead use [`NsTable::len`]. + /// + /// TODO Delete this method after + /// + fn read_num_nss(&self) -> usize { + let num_nss_byte_len = NUM_NSS_BYTE_LEN.min(self.bytes.len()); + usize_from_bytes::(&self.bytes[..num_nss_byte_len]) + } + + /// Read the namespace offset from the `index`th entry from the namespace table. + fn read_ns_offset_unchecked(&self, index: &NsIndex) -> usize { + let start = + index.0 * (NS_ID_BYTE_LEN + NS_OFFSET_BYTE_LEN) + NUM_NSS_BYTE_LEN + NS_ID_BYTE_LEN; + usize_from_bytes::(&self.bytes[start..start + NS_OFFSET_BYTE_LEN]) + } + + /// Helper for [`NsTable::validate`], used in our custom [`serde`] + /// implementation. + /// + /// Checks conditions 1-3 of [`NsTable::validate`]. Those conditions can be + /// checked by looking only at the contents of the [`NsTable`]. + fn validate_deserialization_invariants(&self) -> Result<(), NsTableValidationError> { + use NsTableValidationError::*; + + // Byte length for a table with `x` entries must be exactly `x * + // NsTableBuilder::entry_byte_len() + + // NsTableBuilder::header_byte_len()`. + // + // Explanation for the following `if` condition: + // + // The above condition is equivalent to `[byte length] - + // header_byte_len` equals 0 modulo `entry_byte_len`. In order to + // compute `[byte length] - header_byte_len` we must first check that + // `[byte length]` is not exceeded by `header_byte_len` + if self.bytes.len() < NsTableBuilder::header_byte_len() + || (self.bytes.len() - NsTableBuilder::header_byte_len()) + % NsTableBuilder::entry_byte_len() + != 0 + { + return Err(InvalidByteLen); + } + + // Header must declare the correct number of namespaces + // + // TODO this check obsolete after + // https://github.com/EspressoSystems/espresso-sequencer/issues/1604 + if self.len().0 != self.read_num_nss() { + return Err(InvalidHeader); + } + + // Offsets must increase monotonically. Offsets must + // be nonzero. Namespace IDs must be unique + { + let mut prev_offset = 0; + let mut repeat_ns_ids = HashSet::::new(); + for (ns_id, offset) in self.iter().map(|i| { + ( + self.read_ns_id_unchecked(&i), + self.read_ns_offset_unchecked(&i), + ) + }) { + if !repeat_ns_ids.insert(ns_id) { + return Err(DuplicateNamespaceId); + } + if offset <= prev_offset { + return Err(NonIncreasingEntries); + } + prev_offset = offset; + } + } + + Ok(()) + } +} + +impl EncodeBytes for NsTable { + fn encode(&self) -> Arc<[u8]> { + Arc::from(self.bytes.as_ref()) + } +} + +impl Committable for NsTable { + fn commit(&self) -> Commitment { + RawCommitmentBuilder::new(&Self::tag()) + .var_size_bytes(&self.bytes) + .finalize() + } + + fn tag() -> String { + "NSTABLE".into() + } +} + +/// Return type for [`NsTable::validate`]. +#[derive(Error, Debug, Display, Eq, PartialEq)] +pub enum NsTableValidationError { + InvalidByteLen, + NonIncreasingEntries, + DuplicateNamespaceId, + InvalidHeader, // TODO this variant obsolete after https://github.com/EspressoSystems/espresso-sequencer/issues/1604 + InvalidFinalOffset, // TODO this variant obsolete after https://github.com/EspressoSystems/espresso-sequencer/issues/1604 + ExpectNonemptyNsTable, +} + +pub struct NsTableBuilder { + bytes: Vec, + num_entries: usize, +} + +impl NsTableBuilder { + pub fn new() -> Self { + // pre-allocate space for the ns table header + Self { + bytes: Vec::from([0; NUM_NSS_BYTE_LEN]), + num_entries: 0, + } + } + + /// Add an entry to the namespace table. + pub fn append_entry(&mut self, ns_id: NamespaceId, offset: usize) { + // hack to serialize `NamespaceId` to `NS_ID_BYTE_LEN` bytes + self.bytes + .extend(u32_to_bytes::(u32::from(ns_id))); + self.bytes + .extend(usize_to_bytes::(offset)); + self.num_entries += 1; + } + + /// Serialize to bytes and consume self. + pub fn into_ns_table(self) -> NsTable { + let mut bytes = self.bytes; + // write the number of entries to the ns table header + bytes[..NUM_NSS_BYTE_LEN] + .copy_from_slice(&usize_to_bytes::(self.num_entries)); + NsTable { bytes } + } + + /// Byte length of a namespace table header. + pub const fn header_byte_len() -> usize { + NUM_NSS_BYTE_LEN + } + + /// Byte length of a single namespace table entry. + pub const fn entry_byte_len() -> usize { + NS_ID_BYTE_LEN + NS_OFFSET_BYTE_LEN + } +} + +/// Index for an entry in a ns table. +#[derive(Clone, Debug, Display, Eq, Hash, PartialEq)] +pub struct NsIndex(usize); +bytes_serde_impl!(NsIndex, to_bytes, [u8; NUM_NSS_BYTE_LEN], from_bytes); + +impl NsIndex { + pub fn to_bytes(&self) -> [u8; NUM_NSS_BYTE_LEN] { + usize_to_bytes::(self.0) + } + fn from_bytes(bytes: &[u8]) -> Self { + Self(usize_from_bytes::(bytes)) + } +} + +/// Number of entries in a namespace table. +pub struct NumNss(usize); + +impl NumNss { + pub fn in_bounds(&self, index: &NsIndex) -> bool { + index.0 < self.0 + } +} + +/// Return type for [`Payload::ns_iter`]. +pub(in crate::block) struct NsIter(Range); + +impl NsIter { + pub fn new(num_nss: &NumNss) -> Self { + Self(0..num_nss.0) + } +} + +// Simple `impl Iterator` delegates to `Range`. +impl Iterator for NsIter { + type Item = NsIndex; + + fn next(&mut self) -> Option { + self.0.next().map(NsIndex) + } +} + +#[cfg(test)] +mod test; diff --git a/sequencer/src/block/full_payload/ns_table/test.rs b/sequencer/src/block/full_payload/ns_table/test.rs new file mode 100644 index 0000000000..6f02b74b4d --- /dev/null +++ b/sequencer/src/block/full_payload/ns_table/test.rs @@ -0,0 +1,251 @@ +use super::{ + NsTable, NsTableBuilder, NsTableValidationError, NS_ID_BYTE_LEN, NS_OFFSET_BYTE_LEN, + NUM_NSS_BYTE_LEN, +}; +use crate::{ + block::{ + test::ValidTest, + uint_bytes::{u32_max_from_byte_len, usize_max_from_byte_len, usize_to_bytes}, + }, + NamespaceId, Payload, +}; +use async_compatibility_layer::logging::{setup_backtrace, setup_logging}; +use hotshot::traits::BlockPayload; +use rand::{Rng, RngCore}; +use NsTableValidationError::*; + +#[test] +fn random_valid() { + setup_logging(); + setup_backtrace(); + let mut rng = jf_utils::test_rng(); + + for num_entries in 0..20 { + expect_valid(&random_valid_ns_table(num_entries, &mut rng)); + } +} + +#[test] +fn ns_table_byte_len() { + setup_logging(); + setup_backtrace(); + let mut rng = jf_utils::test_rng(); + + // Extremely small byte lengths should get rejected. + { + let mut ns_table = NsTable { bytes: Vec::new() }; + expect_invalid(&ns_table, InvalidByteLen); + expect_num_bytes_invalid(&mut ns_table, NsTableBuilder::header_byte_len(), &mut rng); + } + + // Add enough bytes for a new entry. + { + let mut ns_table = random_valid_ns_table(20, &mut rng); + expect_num_bytes_invalid(&mut ns_table, NsTableBuilder::entry_byte_len(), &mut rng); + } + + // Helper fn: add 1 byte to the `ns_table` `num_bytes` times. Expect + // invalidity in all but the final time. + fn expect_num_bytes_invalid(ns_table: &mut NsTable, num_bytes: usize, rng: &mut R) + where + R: RngCore, + { + for i in 0..num_bytes { + ns_table.bytes.push(rng.gen()); + if i == num_bytes - 1 { + break; // final iteration: no error expected + } + expect_invalid(ns_table, InvalidByteLen); + } + expect_invalid(ns_table, InvalidHeader); + } +} + +#[async_std::test] +async fn payload_byte_len() { + setup_logging(); + setup_backtrace(); + let test_case = vec![vec![5, 8, 8], vec![7, 9, 11], vec![10, 5, 8]]; + let mut rng = jf_utils::test_rng(); + let test = ValidTest::from_tx_lengths(test_case, &mut rng); + let mut block = + Payload::from_transactions(test.all_txs(), &Default::default(), &Default::default()) + .await + .unwrap() + .0; + let payload_byte_len = block.byte_len(); + let final_offset = block + .ns_table() + .read_ns_offset_unchecked(&block.ns_table().iter().last().unwrap()); + + // final offset matches payload byte len + block.ns_table().validate(&payload_byte_len).unwrap(); + + // Helper closure fn: modify the final offset of `block`'s namespace table + // by adding `diff` to it. Assert failure. + let mut modify_final_offset = |diff: isize| { + let ns_table_byte_len = block.ns_table().bytes.len(); + let old_final_offset: isize = final_offset.try_into().unwrap(); + let new_final_offset: usize = (old_final_offset + diff).try_into().unwrap(); + + block.ns_table_mut().bytes[ns_table_byte_len - NS_OFFSET_BYTE_LEN..] + .copy_from_slice(&usize_to_bytes::(new_final_offset)); + assert_eq!( + block.ns_table().validate(&payload_byte_len).unwrap_err(), + InvalidFinalOffset + ); + }; + + // final offset exceeds payload byte len + modify_final_offset(1); + + // final offset less than payload byte len + modify_final_offset(-1); + + // zero-length payload + let empty_block = Payload::from_transactions([], &Default::default(), &Default::default()) + .await + .unwrap() + .0; + assert_eq!(empty_block.ns_table().len().0, 0); + assert_eq!( + empty_block.ns_table().bytes, + usize_to_bytes::(0) + ); + empty_block + .ns_table() + .validate(&empty_block.byte_len()) + .unwrap(); + + // empty namespace table with nonempty payload + *block.ns_table_mut() = empty_block.ns_table().clone(); + assert_eq!( + block.ns_table().validate(&payload_byte_len).unwrap_err(), + ExpectNonemptyNsTable + ); +} + +#[test] +fn monotonic_increase() { + setup_logging(); + setup_backtrace(); + + // Duplicate namespace ID + two_entries_ns_table((5, 5), (5, 6), Some(DuplicateNamespaceId)); + + // Decreasing namespace ID + two_entries_ns_table((5, 5), (4, 6), None); + + // Duplicate offset + two_entries_ns_table((5, 5), (6, 5), Some(NonIncreasingEntries)); + + // Decreasing offset + two_entries_ns_table((5, 5), (6, 4), Some(NonIncreasingEntries)); + + // Zero namespace ID + two_entries_ns_table((0, 5), (6, 6), None); + + // Zero offset + two_entries_ns_table((5, 0), (6, 6), Some(NonIncreasingEntries)); + + // Helper fn: build a 2-entry NsTable, assert failure + fn two_entries_ns_table( + entry1: (u32, usize), + entry2: (u32, usize), + expect_err: Option, + ) { + let mut ns_table_builder = NsTableBuilder::new(); + ns_table_builder.append_entry(NamespaceId::from(entry1.0), entry1.1); + ns_table_builder.append_entry(NamespaceId::from(entry2.0), entry2.1); + let ns_table = ns_table_builder.into_ns_table(); + if let Some(err) = expect_err { + expect_invalid(&ns_table, err); + } else { + expect_valid(&ns_table); + } + } +} + +// TODO this test obsolete after +// https://github.com/EspressoSystems/espresso-sequencer/issues/1604 +#[test] +fn header() { + setup_logging(); + setup_backtrace(); + let mut rng = jf_utils::test_rng(); + + for num_entries in 0..20 { + let mut ns_table = random_valid_ns_table(num_entries, &mut rng); + if num_entries != 0 { + set_header(&mut ns_table, 0); + set_header(&mut ns_table, num_entries - 1); + } + set_header(&mut ns_table, num_entries + 1); + set_header(&mut ns_table, usize_max_from_byte_len(NUM_NSS_BYTE_LEN)); + } + + // Helper fn: set the header of `ns_table` to declare `num_nss` entries, + // assert failure. + fn set_header(ns_table: &mut NsTable, num_nss: usize) { + ns_table.bytes[..NUM_NSS_BYTE_LEN] + .copy_from_slice(&usize_to_bytes::(num_nss)); + expect_invalid(ns_table, InvalidHeader); + } +} + +fn random_valid_ns_table(num_entries: usize, rng: &mut R) -> NsTable +where + R: RngCore, +{ + let (offset_max_increment, ns_id_max_increment) = if num_entries == 0 { + (0, 0) + } else { + let num_entries_u32: u32 = num_entries.try_into().unwrap(); + ( + usize_max_from_byte_len(NS_OFFSET_BYTE_LEN) / num_entries, + u32_max_from_byte_len(NS_ID_BYTE_LEN) / num_entries_u32, + ) + }; + + let mut ns_id = 0; + let mut offset = 0; + let mut ns_table_builder = NsTableBuilder::new(); + for _ in 0..num_entries { + // ns_id, offset must increase monotonically + ns_id += rng.gen_range(1..=ns_id_max_increment); + offset += rng.gen_range(1..=offset_max_increment); + ns_table_builder.append_entry(NamespaceId::from(ns_id), offset); + } + ns_table_builder.into_ns_table() +} + +fn expect_valid(ns_table: &NsTable) { + // `validate` should succeed + ns_table.validate_deserialization_invariants().unwrap(); + + // serde round-trip should succeed + let serde_bytes = bincode::serialize(ns_table).unwrap(); + let ns_table_serde: NsTable = bincode::deserialize(&serde_bytes).unwrap(); + assert_eq!(&ns_table_serde, ns_table); +} + +fn expect_invalid(ns_table: &NsTable, err: NsTableValidationError) { + use serde::de::Error; + + // `validate` should fail + assert_eq!( + ns_table.validate_deserialization_invariants().unwrap_err(), + err + ); + + // serde round-trip should fail + // + // need to use `to_string` because `bincode::Error`` is not `Eq` + let serde_bytes = bincode::serialize(ns_table).unwrap(); + assert_eq!( + bincode::deserialize::(&serde_bytes) + .unwrap_err() + .to_string(), + bincode::Error::custom(err).to_string(), + ); +} diff --git a/sequencer/src/block/full_payload/payload.rs b/sequencer/src/block/full_payload/payload.rs new file mode 100644 index 0000000000..b0078ff092 --- /dev/null +++ b/sequencer/src/block/full_payload/payload.rs @@ -0,0 +1,319 @@ +use crate::{ + block::{ + full_payload::ns_table::{NsIndex, NsTable, NsTableBuilder}, + namespace_payload::{Index, Iter, NsPayload, NsPayloadBuilder, NsPayloadRange, TxProof}, + }, + ChainConfig, NamespaceId, NodeState, SeqTypes, Transaction, ValidatedState, +}; + +use async_trait::async_trait; +use committable::Committable; +use derive_more::Display; +use hotshot_query_service::availability::QueryablePayload; +use hotshot_types::{ + traits::{BlockPayload, EncodeBytes}, + utils::BuilderCommitment, + vid::{VidCommon, VidSchemeType}, +}; +use jf_vid::VidScheme; +use serde::{Deserialize, Serialize}; +use sha2::Digest; +use std::{collections::BTreeMap, sync::Arc}; + +/// Raw payload data for an entire block. +/// +/// A block consists of two sequences of arbitrary bytes: +/// - `ns_table`: namespace table +/// - `ns_payloads`: namespace payloads +/// +/// Any sequence of bytes is a valid `ns_table`. Any sequence of bytes is a +/// valid `ns_payloads`. The contents of `ns_table` determine how to interpret +/// `ns_payload`. +/// +/// # Namespace table +/// +/// See [`NsTable`] for the format of a namespace table. +/// +/// # Namespace payloads +/// +/// A concatenation of payload bytes for multiple individual namespaces. +/// Namespace boundaries are dictated by `ns_table`. See [`NsPayload`] for the +/// format of a namespace payload. +#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] +pub struct Payload { + // Concatenated payload bytes for each namespace + // + // TODO want to rename thisfield to `ns_payloads`, but can't due to + // serialization compatibility. + #[serde(with = "base64_bytes")] + raw_payload: Vec, + + ns_table: NsTable, +} + +impl Payload { + pub fn ns_table(&self) -> &NsTable { + &self.ns_table + } + + /// Like [`QueryablePayload::transaction_with_proof`] except without the + /// proof. + pub fn transaction(&self, index: &Index) -> Option { + let ns_id = self.ns_table.read_ns_id(index.ns())?; + let ns_payload = self.ns_payload(index.ns()); + ns_payload.export_tx(&ns_id, index.tx()) + } + + // CRATE-VISIBLE HELPERS START HERE + + pub(in crate::block) fn read_ns_payload(&self, range: &NsPayloadRange) -> &NsPayload { + NsPayload::from_bytes_slice(&self.raw_payload[range.as_block_range()]) + } + + /// Convenience wrapper for [`Self::read_ns_payload`]. + /// + /// `index` is not checked. Use `self.ns_table().in_bounds()` as needed. + pub(in crate::block) fn ns_payload(&self, index: &NsIndex) -> &NsPayload { + let ns_payload_range = self.ns_table().ns_range(index, &self.byte_len()); + self.read_ns_payload(&ns_payload_range) + } + + pub(in crate::block) fn byte_len(&self) -> PayloadByteLen { + PayloadByteLen(self.raw_payload.len()) + } + + // PRIVATE HELPERS START HERE + + /// Need a sync version of [`BlockPayload::from_transactions`] in order to impl [`BlockPayload::empty`]. + fn from_transactions_sync( + transactions: impl IntoIterator>::Transaction> + Send, + chain_config: ChainConfig, + _instance_state: &>::Instance, + ) -> Result< + (Self, >::Metadata), + >::Error, + > { + // accounting for block byte length limit + let max_block_byte_len: usize = u64::from(chain_config.max_block_size) + .try_into() + .map_err(|_| >::Error::BlockBuilding)?; + let mut block_byte_len = NsTableBuilder::header_byte_len(); + + // add each tx to its namespace + let mut ns_builders = BTreeMap::::new(); + for tx in transactions.into_iter() { + // accounting for block byte length limit + block_byte_len += tx.payload().len() + NsPayloadBuilder::tx_table_entry_byte_len(); + if !ns_builders.contains_key(&tx.namespace()) { + // each new namespace adds overhead + block_byte_len += + NsTableBuilder::entry_byte_len() + NsPayloadBuilder::tx_table_header_byte_len(); + } + if block_byte_len > max_block_byte_len { + tracing::warn!("transactions truncated to fit in maximum block byte length {max_block_byte_len}"); + break; + } + + let ns_builder = ns_builders.entry(tx.namespace()).or_default(); + ns_builder.append_tx(tx); + } + + // build block payload and namespace table + let mut payload = Vec::new(); + let mut ns_table_builder = NsTableBuilder::new(); + for (ns_id, ns_builder) in ns_builders { + payload.extend(ns_builder.into_bytes()); + ns_table_builder.append_entry(ns_id, payload.len()); + } + let ns_table = ns_table_builder.into_ns_table(); + let metadata = ns_table.clone(); + Ok(( + Self { + raw_payload: payload, + ns_table, + }, + metadata, + )) + } +} + +#[async_trait] +impl BlockPayload for Payload { + // TODO BlockPayload trait eliminate unneeded args, return vals of type + // `Self::Metadata` https://github.com/EspressoSystems/HotShot/issues/3300 + type Error = crate::Error; + type Transaction = Transaction; + type Instance = NodeState; + type Metadata = NsTable; + type ValidatedState = ValidatedState; + + async fn from_transactions( + transactions: impl IntoIterator + Send, + validated_state: &Self::ValidatedState, + instance_state: &Self::Instance, + ) -> Result<(Self, Self::Metadata), Self::Error> { + let validated_state_cf = validated_state.chain_config; + let instance_state_cf = instance_state.chain_config; + + let chain_config = if validated_state_cf.commit() == instance_state_cf.commit() { + instance_state_cf + } else { + match validated_state_cf.resolve() { + Some(cf) => cf, + None => { + instance_state + .peers + .as_ref() + .fetch_chain_config(validated_state_cf.commit()) + .await + } + } + }; + + Self::from_transactions_sync(transactions, chain_config, instance_state) + } + + // TODO avoid cloning the entire payload here? + fn from_bytes(block_payload_bytes: &[u8], ns_table: &Self::Metadata) -> Self { + Self { + raw_payload: block_payload_bytes.to_vec(), + ns_table: ns_table.clone(), + } + } + + fn empty() -> (Self, Self::Metadata) { + let payload = Self::from_transactions_sync(vec![], Default::default(), &Default::default()) + .unwrap() + .0; + let ns_table = payload.ns_table().clone(); + (payload, ns_table) + } + + fn builder_commitment(&self, metadata: &Self::Metadata) -> BuilderCommitment { + let ns_table_bytes = self.ns_table.encode(); + + // TODO `metadata_bytes` equals `ns_table_bytes`, so we are + // double-hashing the ns_table. Why? To maintain serialization + // compatibility. + // https://github.com/EspressoSystems/espresso-sequencer/issues/1576 + let metadata_bytes = metadata.encode(); + + let mut digest = sha2::Sha256::new(); + digest.update((self.raw_payload.len() as u64).to_le_bytes()); + digest.update((ns_table_bytes.len() as u64).to_le_bytes()); + digest.update((metadata_bytes.len() as u64).to_le_bytes()); // https://github.com/EspressoSystems/espresso-sequencer/issues/1576 + digest.update(&self.raw_payload); + digest.update(ns_table_bytes); + digest.update(metadata_bytes); // https://github.com/EspressoSystems/espresso-sequencer/issues/1576 + BuilderCommitment::from_raw_digest(digest.finalize()) + } + + fn transactions<'a>( + &'a self, + metadata: &'a Self::Metadata, + ) -> impl 'a + Iterator { + self.enumerate(metadata).map(|(_, t)| t) + } +} + +impl QueryablePayload for Payload { + // TODO changes to QueryablePayload trait: + // https://github.com/EspressoSystems/hotshot-query-service/issues/639 + type TransactionIndex = Index; + type Iter<'a> = Iter<'a>; + type InclusionProof = TxProof; + + fn len(&self, _meta: &Self::Metadata) -> usize { + // Counting txs is nontrivial. The easiest solution is to consume an + // iterator. If performance is a concern then we could cache this count + // on construction of `Payload`. + self.iter(_meta).count() + } + + fn iter<'a>(&'a self, _meta: &'a Self::Metadata) -> Self::Iter<'a> { + Iter::new(self) + } + + fn transaction_with_proof( + &self, + _meta: &Self::Metadata, + index: &Self::TransactionIndex, + ) -> Option<(Self::Transaction, Self::InclusionProof)> { + // TODO HACK! THE RETURNED PROOF MIGHT FAIL VERIFICATION. + // https://github.com/EspressoSystems/hotshot-query-service/issues/639 + // + // Need a `VidCommon` to proceed. Need to modify `QueryablePayload` + // trait to add a `VidCommon` arg. In the meantime tests fail if I leave + // it `todo!()`, so this hack allows tests to pass. + let common = hotshot_types::vid::vid_scheme(10) + .disperse(&self.raw_payload) + .unwrap() + .common; + + TxProof::new(index, self, &common) + } +} + +impl std::fmt::Display for Payload { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{self:#?}") + } +} + +impl EncodeBytes for Payload { + fn encode(&self) -> Arc<[u8]> { + Arc::from(self.raw_payload.as_ref()) + } +} + +/// Byte length of a block payload, which includes all namespaces but *not* the +/// namespace table. +#[derive(Clone, Debug, Display, Eq, Hash, PartialEq)] +pub struct PayloadByteLen(usize); + +impl PayloadByteLen { + /// Extract payload byte length from a [`VidCommon`] and construct a new [`Self`] from it. + pub fn from_vid_common(common: &VidCommon) -> Self { + Self(usize::try_from(VidSchemeType::get_payload_byte_len(common)).unwrap()) + } + + /// Is the payload byte length declared in a [`VidCommon`] equal [`Self`]? + pub fn is_consistent(&self, common: &VidCommon) -> bool { + // failure to convert to usize implies that `common` cannot be + // consistent with `self`. + let expected = match usize::try_from(VidSchemeType::get_payload_byte_len(common)) { + Ok(n) => n, + Err(_) => { + tracing::warn!( + "VidCommon byte len u32 {} should convert to usize", + VidSchemeType::get_payload_byte_len(common) + ); + return false; + } + }; + + self.0 == expected + } + + pub(in crate::block::full_payload) fn as_usize(&self) -> usize { + self.0 + } +} + +#[cfg(any(test, feature = "testing"))] +impl hotshot_types::traits::block_contents::TestableBlock for Payload { + fn genesis() -> Self { + BlockPayload::empty().0 + } + + fn txn_count(&self) -> u64 { + self.len(&self.ns_table) as u64 + } +} + +#[cfg(any(test, feature = "testing"))] +impl Payload { + pub fn ns_table_mut(&mut self) -> &mut NsTable { + &mut self.ns_table + } +} diff --git a/sequencer/src/block/namespace_payload.rs b/sequencer/src/block/namespace_payload.rs new file mode 100644 index 0000000000..ecd894f86e --- /dev/null +++ b/sequencer/src/block/namespace_payload.rs @@ -0,0 +1,12 @@ +mod iter; +mod ns_payload; +mod ns_payload_range; +mod tx_proof; +mod types; + +pub use iter::{Index, Iter}; +pub use tx_proof::TxProof; + +pub(in crate::block) use ns_payload::{NsPayload, NsPayloadOwned}; +pub(in crate::block) use ns_payload_range::NsPayloadRange; +pub(in crate::block) use types::NsPayloadBuilder; diff --git a/sequencer/src/block/namespace_payload/iter.rs b/sequencer/src/block/namespace_payload/iter.rs new file mode 100644 index 0000000000..09da31b9ad --- /dev/null +++ b/sequencer/src/block/namespace_payload/iter.rs @@ -0,0 +1,81 @@ +use crate::block::{ + full_payload::{NsIndex, NsIter, Payload}, + namespace_payload::types::{TxIndex, TxIter}, +}; +use serde::{Deserialize, Serialize}; +use std::iter::Peekable; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct Index { + ns_index: NsIndex, + tx_index: TxIndex, +} + +impl Index { + pub fn ns(&self) -> &NsIndex { + &self.ns_index + } + pub(in crate::block) fn tx(&self) -> &TxIndex { + &self.tx_index + } +} + +// TODO don't impl `PartialOrd` +// It's needed only for `QueryablePayload` trait: +// https://github.com/EspressoSystems/hotshot-query-service/issues/639 +impl PartialOrd for Index { + fn partial_cmp(&self, _other: &Self) -> Option { + Some(self.cmp(_other)) + } +} +// TODO don't impl `Ord` +// It's needed only for `QueryablePayload` trait: +// https://github.com/EspressoSystems/hotshot-query-service/issues/639 +impl Ord for Index { + fn cmp(&self, _other: &Self) -> std::cmp::Ordering { + unimplemented!() + } +} + +/// Cartesian product of [`NsIter`], [`TxIter`]. +pub struct Iter<'a> { + ns_iter: Peekable, + tx_iter: Option, + block: &'a Payload, +} + +impl<'a> Iter<'a> { + pub fn new(block: &'a Payload) -> Self { + Self { + ns_iter: NsIter::new(&block.ns_table().len()).peekable(), + tx_iter: None, + block, + } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = Index; + + fn next(&mut self) -> Option { + loop { + let Some(ns_index) = self.ns_iter.peek() else { + break None; // ns_iter consumed + }; + + if let Some(tx_index) = self + .tx_iter + .get_or_insert_with(|| self.block.ns_payload(ns_index).iter()) + .next() + { + break Some(Index { + ns_index: ns_index.clone(), + tx_index, + }); + } + + self.tx_iter = None; // unset `tx_iter`; it's consumed for this namespace + self.ns_iter.next(); + } + } +} diff --git a/sequencer/src/block/namespace_payload/ns_payload.rs b/sequencer/src/block/namespace_payload/ns_payload.rs new file mode 100644 index 0000000000..f2997839df --- /dev/null +++ b/sequencer/src/block/namespace_payload/ns_payload.rs @@ -0,0 +1,137 @@ +use crate::{ + block::namespace_payload::types::{ + FromNsPayloadBytes, NsPayloadByteLen, NsPayloadBytesRange, NumTxs, NumTxsRange, + NumTxsUnchecked, TxIndex, TxIter, TxPayloadRange, TxTableEntriesRange, + }, + NamespaceId, Transaction, +}; +use serde::{Deserialize, Serialize}; + +/// Raw binary data for a single namespace's payload. +/// +/// Any sequence of bytes is a valid [`NsPayload`]. +/// +/// See module-level documentation [`types`](super::types) for a full +/// specification of the binary format of a namespace. +pub(in crate::block) struct NsPayload([u8]); + +impl NsPayload { + pub fn from_bytes_slice(bytes: &[u8]) -> &NsPayload { + NsPayload::new_private(bytes) + } + pub fn as_bytes_slice(&self) -> &[u8] { + &self.0 + } + pub fn byte_len(&self) -> NsPayloadByteLen { + NsPayloadByteLen::from_usize(self.0.len()) + } + + /// Read and parse bytes from the ns payload. + /// + /// Arg `range: &R` is convertible into a `Range` via + /// [`NsPayloadBytesRange`]. The payload bytes are parsed into a `R::Output` + /// via [`FromNsPayloadBytes`]. + pub fn read<'a, R>(&'a self, range: &R) -> R::Output + where + R: NsPayloadBytesRange<'a>, + { + >::from_payload_bytes(&self.0[range.ns_payload_range()]) + } + + /// Iterator over all transactions in this namespace. + pub fn iter(&self) -> TxIter { + self.iter_from_num_txs(&self.read_num_txs()) + } + + /// Return all transactions in this namespace. The namespace ID for each + /// returned [`Transaction`] is set to `ns_id`. + pub fn export_all_txs(&self, ns_id: &NamespaceId) -> Vec { + let num_txs = self.read_num_txs(); + self.iter_from_num_txs(&num_txs) + .map(|i| self.tx_from_num_txs(ns_id, &i, &num_txs)) + .collect() + } + + /// Return a transaction from this namespace. Set its namespace ID to + /// `ns_id`. + /// + /// Return `None` if `index` is out of bounds. + pub fn export_tx(&self, ns_id: &NamespaceId, index: &TxIndex) -> Option { + let num_txs_unchecked = self.read_num_txs(); + let num_txs = NumTxs::new(&num_txs_unchecked, &self.byte_len()); + if !num_txs.in_bounds(index) { + return None; // error: tx index out of bounds + } + Some(self.tx_from_num_txs(ns_id, index, &num_txs_unchecked)) + } + + /// Private helper. (Could be pub if desired.) + fn read_num_txs(&self) -> NumTxsUnchecked { + self.read(&NumTxsRange::new(&self.byte_len())) + } + + /// Private helper + fn iter_from_num_txs(&self, num_txs: &NumTxsUnchecked) -> TxIter { + let num_txs = NumTxs::new(num_txs, &self.byte_len()); + TxIter::new(&num_txs) + } + + /// Private helper + fn tx_from_num_txs( + &self, + ns_id: &NamespaceId, + index: &TxIndex, + num_txs_unchecked: &NumTxsUnchecked, + ) -> Transaction { + let tx_table_entries = self.read(&TxTableEntriesRange::new(index)); + let tx_range = TxPayloadRange::new(num_txs_unchecked, &tx_table_entries, &self.byte_len()); + + // TODO don't copy the tx bytes into the return value + // https://github.com/EspressoSystems/hotshot-query-service/issues/267 + let tx_payload = self.read(&tx_range).to_payload_bytes().to_vec(); + Transaction::new(*ns_id, tx_payload) + } +} + +#[repr(transparent)] +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +#[serde(transparent)] +pub(in crate::block) struct NsPayloadOwned(#[serde(with = "base64_bytes")] Vec); + +/// Crazy boilerplate code to make it so that [`NsPayloadOwned`] is to +/// [`NsPayload`] as [`Vec`] is to `[T]`. See [How can I create newtypes for +/// an unsized type and its owned counterpart (like `str` and `String`) in safe +/// Rust? - Stack Overflow](https://stackoverflow.com/q/64977525) +mod ns_payload_owned { + use super::{NsPayload, NsPayloadOwned}; + use std::borrow::Borrow; + use std::ops::Deref; + + impl NsPayload { + // pub(super) because I want it visible everywhere in this file but I + // also want this boilerplate code quarrantined in `ns_payload_owned`. + pub(super) fn new_private(p: &[u8]) -> &NsPayload { + unsafe { &*(p as *const [u8] as *const NsPayload) } + } + } + + impl Deref for NsPayloadOwned { + type Target = NsPayload; + fn deref(&self) -> &NsPayload { + NsPayload::new_private(&self.0) + } + } + + impl Borrow for NsPayloadOwned { + fn borrow(&self) -> &NsPayload { + self.deref() + } + } + + impl ToOwned for NsPayload { + type Owned = NsPayloadOwned; + fn to_owned(&self) -> NsPayloadOwned { + NsPayloadOwned(self.0.to_owned()) + } + } +} diff --git a/sequencer/src/block/namespace_payload/ns_payload_range.rs b/sequencer/src/block/namespace_payload/ns_payload_range.rs new file mode 100644 index 0000000000..f2812f6fd9 --- /dev/null +++ b/sequencer/src/block/namespace_payload/ns_payload_range.rs @@ -0,0 +1,34 @@ +use super::types::{NsPayloadByteLen, NsPayloadBytesRange}; +use std::ops::Range; + +/// Index range for a namespace payload inside a block payload. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub(in crate::block) struct NsPayloadRange(Range); + +impl NsPayloadRange { + /// TODO restrict visibility? + pub fn new(start: usize, end: usize) -> Self { + Self(start..end) + } + + /// Access the underlying index range for this namespace inside a block + /// payload. + pub fn as_block_range(&self) -> Range { + self.0.clone() + } + + /// Return the byte length of this namespace. + pub fn byte_len(&self) -> NsPayloadByteLen { + NsPayloadByteLen::from_usize(self.0.len()) + } + + /// Convert a [`NsPayloadBytesRange`] into a range that's relative to the + /// entire block payload. + pub fn block_range<'a, R>(&self, range: &R) -> Range + where + R: NsPayloadBytesRange<'a>, + { + let range = range.ns_payload_range(); + range.start + self.0.start..range.end + self.0.start + } +} diff --git a/sequencer/src/block/namespace_payload/tx_proof.rs b/sequencer/src/block/namespace_payload/tx_proof.rs new file mode 100644 index 0000000000..ee025c0f4b --- /dev/null +++ b/sequencer/src/block/namespace_payload/tx_proof.rs @@ -0,0 +1,253 @@ +use crate::{ + block::{ + full_payload::{ + NsTable, {Payload, PayloadByteLen}, + }, + namespace_payload::{ + iter::Index, + types::{ + NumTxs, NumTxsRange, NumTxsUnchecked, TxIndex, TxPayloadRange, TxTableEntries, + TxTableEntriesRange, + }, + }, + }, + Transaction, +}; +use hotshot_query_service::{VidCommitment, VidCommon}; +use hotshot_types::{ + traits::EncodeBytes, + vid::{vid_scheme, SmallRangeProofType, VidSchemeType}, +}; +use jf_vid::{ + payload_prover::{PayloadProver, Statement}, + VidScheme, +}; +use serde::{Deserialize, Serialize}; + +/// Proof of correctness for transaction bytes in a block. +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TxProof { + // Naming conventions for this struct's fields: + // - `payload_x`: bytes from the payload + // - `payload_proof_x`: a proof of those bytes from the payload + tx_index: TxIndex, + + // Number of txs declared in the tx table + payload_num_txs: NumTxsUnchecked, + payload_proof_num_txs: SmallRangeProofType, + + // Tx table entries for this tx + payload_tx_table_entries: TxTableEntries, + payload_proof_tx_table_entries: SmallRangeProofType, + + // This tx's payload bytes. + // `None` if this tx has zero length. + payload_proof_tx: Option, +} + +impl TxProof { + /// Returns the [`Transaction`] indicated by `index`, along with a proof of + /// correctness for that transaction. Returns `None` on error. + pub fn new( + index: &Index, + payload: &Payload, + common: &VidCommon, + ) -> Option<(Transaction, Self)> { + let payload_byte_len = payload.byte_len(); + if !payload_byte_len.is_consistent(common) { + tracing::warn!( + "payload byte len {} inconsistent with common {}", + payload_byte_len, + VidSchemeType::get_payload_byte_len(common) + ); + return None; // error: payload byte len inconsistent with common + } + if !payload.ns_table().in_bounds(index.ns()) { + tracing::warn!("ns_index {:?} out of bounds", index.ns()); + return None; // error: ns index out of bounds + } + // check tx index below + + let payload_bytes_arc = payload.encode(); // pacify borrow checker + let payload_bytes = payload_bytes_arc.as_ref(); + let ns_range = payload.ns_table().ns_range(index.ns(), &payload_byte_len); + let ns_byte_len = ns_range.byte_len(); + let ns_payload = payload.read_ns_payload(&ns_range); + let vid = vid_scheme( + VidSchemeType::get_num_storage_nodes(common) + .try_into() + .unwrap(), + ); + + // Read the tx table len from this namespace's tx table and compute a + // proof of correctness. + let num_txs_range = NumTxsRange::new(&ns_byte_len); + let payload_num_txs = ns_payload.read(&num_txs_range); + + // Check tx index. + // + // TODO the next line of code (and other code) could be easier to read + // if we make a helpers that repeat computation we've already done. + if !NumTxs::new(&payload_num_txs, &ns_byte_len).in_bounds(index.tx()) { + return None; // error: tx index out of bounds + } + + let payload_proof_num_txs = vid + .payload_proof(payload_bytes, ns_range.block_range(&num_txs_range)) + .ok()?; + + // Read the tx table entries for this tx and compute a proof of + // correctness. + let tx_table_entries_range = TxTableEntriesRange::new(index.tx()); + let payload_tx_table_entries = ns_payload.read(&tx_table_entries_range); + let payload_proof_tx_table_entries = { + vid.payload_proof(payload_bytes, ns_range.block_range(&tx_table_entries_range)) + .ok()? + }; + + // Read the tx payload and compute a proof of correctness. + let tx_payload_range = + TxPayloadRange::new(&payload_num_txs, &payload_tx_table_entries, &ns_byte_len); + let payload_proof_tx = { + let range = ns_range.block_range(&tx_payload_range); + if range.is_empty() { + None + } else { + Some(vid.payload_proof(payload_bytes, range).ok()?) + } + }; + + let tx = { + let ns_id = payload.ns_table().read_ns_id_unchecked(index.ns()); + let tx_payload = ns_payload + .read(&tx_payload_range) + .to_payload_bytes() + .to_vec(); + Transaction::new(ns_id, tx_payload) + }; + + Some(( + tx, + TxProof { + tx_index: index.tx().clone(), + payload_num_txs, + payload_proof_num_txs, + payload_tx_table_entries, + payload_proof_tx_table_entries, + payload_proof_tx, + }, + )) + } + + /// Verify a [`TxProof`] for `tx` against a payload commitment. Returns + /// `None` on error. + pub fn verify( + &self, + ns_table: &NsTable, + tx: &Transaction, + commit: &VidCommitment, + common: &VidCommon, + ) -> Option { + VidSchemeType::is_consistent(commit, common).ok()?; + let Some(ns_index) = ns_table.find_ns_id(&tx.namespace()) else { + tracing::info!("ns id {} does not exist", tx.namespace()); + return None; // error: ns id does not exist + }; + let ns_range = ns_table.ns_range(&ns_index, &PayloadByteLen::from_vid_common(common)); + let ns_byte_len = ns_range.byte_len(); + + if !NumTxs::new(&self.payload_num_txs, &ns_byte_len).in_bounds(&self.tx_index) { + tracing::info!("tx index {:?} out of bounds", self.tx_index); + return None; // error: tx index out of bounds + } + + let vid = vid_scheme( + VidSchemeType::get_num_storage_nodes(common) + .try_into() + .unwrap(), + ); + + // Verify proof for tx table len + { + let range = ns_range.block_range(&NumTxsRange::new(&ns_byte_len)); + if vid + .payload_verify( + Statement { + payload_subslice: &self.payload_num_txs.to_payload_bytes(), + range, + commit, + common, + }, + &self.payload_proof_num_txs, + ) + .ok()? + .is_err() + { + return Some(false); + } + } + + // Verify proof for tx table entries + { + let range = ns_range.block_range(&TxTableEntriesRange::new(&self.tx_index)); + if vid + .payload_verify( + Statement { + payload_subslice: &self.payload_tx_table_entries.to_payload_bytes(), + range, + commit, + common, + }, + &self.payload_proof_tx_table_entries, + ) + .ok()? + .is_err() + { + return Some(false); + } + } + + // Verify proof for tx payload + { + let range = ns_range.block_range(&TxPayloadRange::new( + &self.payload_num_txs, + &self.payload_tx_table_entries, + &ns_byte_len, + )); + + match (&self.payload_proof_tx, range.is_empty()) { + (Some(proof), false) => { + if vid + .payload_verify( + Statement { + payload_subslice: tx.payload(), + range, + commit, + common, + }, + proof, + ) + .ok()? + .is_err() + { + return Some(false); + } + } + (None, true) => {} // 0-length tx, nothing to verify + (None, false) => { + tracing::error!( + "tx verify: missing proof for nonempty tx payload range {:?}", + range + ); + return None; + } + (Some(_), true) => { + tracing::error!("tx verify: unexpected proof for empty tx payload range"); + return None; + } + } + } + + Some(true) + } +} diff --git a/sequencer/src/block/namespace_payload/types.rs b/sequencer/src/block/namespace_payload/types.rs new file mode 100644 index 0000000000..09860f80bd --- /dev/null +++ b/sequencer/src/block/namespace_payload/types.rs @@ -0,0 +1,429 @@ +//! Types related to a namespace payload and its transaction table. +//! +//! All code that needs to know the binary format of a namespace payload and its +//! transaction table is restricted to this file. +//! +//! There are many newtypes in this file to facilitate transaction proofs. +//! +//! # Binary format of a namespace payload +//! +//! Any sequence of bytes is a valid [`NsPayload`]. +//! +//! A namespace payload consists of two concatenated byte sequences: +//! - `tx_table`: transaction table +//! - `tx_payloads`: transaction payloads +//! +//! # Transaction table +//! +//! Byte lengths for the different items that could appear in a `tx_table` are +//! specified in local private constants [`NUM_TXS_BYTE_LEN`], +//! [`TX_OFFSET_BYTE_LEN`]. +//! +//! ## Number of entries in the transaction table +//! +//! The first [`NUM_TXS_BYTE_LEN`] bytes of the `tx_table` indicate the number +//! `n` of entries in the table as a little-endian unsigned integer. If the +//! entire namespace payload byte length is smaller than [`NUM_TXS_BYTE_LEN`] +//! then the missing bytes are zero-padded. +//! +//! The bytes in the namespace payload beyond the first [`NUM_TXS_BYTE_LEN`] +//! bytes encode entries in the `tx_table`. Each entry consumes exactly +//! [`TX_OFFSET_BYTE_LEN`] bytes. +//! +//! The number `n` could be anything, including a number much larger than the +//! number of entries that could fit in the namespace payload. As such, the +//! actual number of entries in the `tx_table` is defined as the minimum of `n` +//! and the maximum number of whole `tx_table` entries that could fit in the +//! namespace payload. +//! +//! The `tx_payloads` consist of any bytes in the namespace payload beyond the +//! `tx_table`. +//! +//! ## Transaction table entry +//! +//! Each entry in the `tx_table` is exactly [`TX_OFFSET_BYTE_LEN`] bytes. These +//! bytes indicate the end-index of a transaction in the namespace payload +//! bytes. This end-index is a little-endian unsigned integer. +//! +//! This offset is relative to the end of the `tx_table` within the current +//! namespace. +//! +//! ### Example +//! +//! Suppose a block payload has 3000 bytes and 3 namespaces of 1000 bytes each. +//! Suppose the `tx_table` for final namespace in the block has byte length 100, +//! and suppose an entry in that `tx_table` indicates an end-index of `10`. The +//! actual end-index of that transaction relative to the current namespace is +//! `110`: `10` bytes for the offset plus `100` bytes for the `tx_table`. +//! Relative to the entire block payload, the end-index of that transaction is +//! `2110`: `10` bytes for the offset plus `100` bytes for the `tx_table` plus +//! `2000` bytes for this namespace. +//! +//! # How to deduce a transaction's byte range +//! +//! In order to extract the payload bytes of a single transaction `T` from the +//! namespace payload one needs both the start- and end-indices for `T`. +//! +//! See [`TxPayloadRange::new`] for clarification. What follows is a description +//! of what's implemented in [`TxPayloadRange::new`]. +//! +//! If `T` occupies the `i`th entry in the `tx_table` for `i>0` then the +//! start-index for `T` is defined as the end-index of the `(i-1)`th entry in +//! the table. +//! +//! Thus, both start- and end-indices for any transaction `T` can be read from a +//! contiguous, constant-size byte range in the `tx_table`. This property +//! facilitates transaction proofs. +//! +//! The start-index of the 0th entry in the table is implicitly defined to be +//! `0`. +//! +//! The start- and end-indices `(declared_start, declared_end)` declared in the +//! `tx_table` could be anything. As such, the actual start- and end-indices +//! `(start, end)` are defined so as to ensure that the byte range is +//! well-defined and in-bounds for the namespace payload: +//! ```ignore +//! end = min(declared_end, namespace_payload_byte_length) +//! start = min(declared_start, end) +//! ``` +//! +//! To get the byte range for `T` relative to the current namespace, the above +//! range is translated by the byte length of the `tx_table` *as declared in the +//! `tx_table` itself*, suitably truncated to fit within the current namespace. +//! +//! In particular, if the `tx_table` declares a huge number `n` of entries that +//! cannot fit into the namespace payload then all transactions in this +//! namespace have a zero-length byte range whose start- and end-indices are +//! both `namespace_payload_byte_length`. +//! +//! In a "honestly-prepared" `tx_table` the end-index of the final transaction +//! equals the byte length of the namespace payload minus the byte length of the +//! `tx_table`. (Otherwise the namespace payload might have bytes that are not +//! included in any transaction.) +//! +//! It is possible that a `tx_table` table could indicate two distinct +//! transactions whose byte ranges overlap, though no "honestly-prepared" +//! `tx_table` would do this. +use crate::block::uint_bytes::{bytes_serde_impl, usize_from_bytes, usize_to_bytes}; +use crate::Transaction; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::ops::Range; + +/// Byte lengths for the different items that could appear in a tx table. +const NUM_TXS_BYTE_LEN: usize = 4; +const TX_OFFSET_BYTE_LEN: usize = 4; + +/// Data that can be deserialized from a subslice of namespace payload bytes. +/// +/// Companion trait for [`NsPayloadBytesRange`], which specifies the subslice of +/// namespace payload bytes to read. +pub trait FromNsPayloadBytes<'a> { + /// Deserialize `Self` from namespace payload bytes. + fn from_payload_bytes(bytes: &'a [u8]) -> Self; +} + +/// Specifies a subslice of namespace payload bytes to read. +/// +/// Companion trait for [`FromNsPayloadBytes`], which holds data that can be +/// deserialized from that subslice of bytes. +pub trait NsPayloadBytesRange<'a> { + type Output: FromNsPayloadBytes<'a>; + + /// Range relative to this ns payload + fn ns_payload_range(&self) -> Range; +} + +/// Number of txs in a namespace. +/// +/// Like [`NumTxsUnchecked`] but checked against a [`NsPayloadByteLen`]. +pub struct NumTxs(usize); + +impl NumTxs { + /// Returns the minimum of: + /// - `num_txs` + /// - The maximum number of tx table entries that could fit in a namespace + /// whose byte length is `byte_len`. + pub fn new(num_txs: &NumTxsUnchecked, byte_len: &NsPayloadByteLen) -> Self { + Self(std::cmp::min( + // Number of txs declared in the tx table + num_txs.0, + // Max number of tx table entries that could fit in the namespace payload + byte_len.0.saturating_sub(NUM_TXS_BYTE_LEN) / TX_OFFSET_BYTE_LEN, + )) + } + + pub fn in_bounds(&self, index: &TxIndex) -> bool { + index.0 < self.0 + } +} + +/// Byte length of a namespace payload. +pub struct NsPayloadByteLen(usize); + +impl NsPayloadByteLen { + // TODO restrict visibility? + pub fn from_usize(n: usize) -> Self { + Self(n) + } +} + +/// The part of a tx table that declares the number of txs in the payload. +/// +/// "Unchecked" because this quantity might exceed the number of tx table +/// entries that could fit into the namespace that contains it. +/// +/// Use [`NumTxs`] for the actual number of txs in this namespace. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct NumTxsUnchecked(usize); +bytes_serde_impl!( + NumTxsUnchecked, + to_payload_bytes, + [u8; NUM_TXS_BYTE_LEN], + from_payload_bytes +); + +impl NumTxsUnchecked { + pub fn to_payload_bytes(&self) -> [u8; NUM_TXS_BYTE_LEN] { + usize_to_bytes::(self.0) + } +} + +impl FromNsPayloadBytes<'_> for NumTxsUnchecked { + fn from_payload_bytes(bytes: &[u8]) -> Self { + Self(usize_from_bytes::(bytes)) + } +} + +/// Byte range for the part of a tx table that declares the number of txs in the +/// payload. +pub struct NumTxsRange(Range); + +impl NumTxsRange { + pub fn new(byte_len: &NsPayloadByteLen) -> Self { + Self(0..NUM_TXS_BYTE_LEN.min(byte_len.0)) + } +} + +impl NsPayloadBytesRange<'_> for NumTxsRange { + type Output = NumTxsUnchecked; + + fn ns_payload_range(&self) -> Range { + self.0.clone() + } +} + +/// Entries from a tx table in a namespace for use in a transaction proof. +/// +/// Contains either one or two entries according to whether it was derived from +/// the first transaction in the namespace. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct TxTableEntries { + cur: usize, + prev: Option, // `None` if derived from the first transaction +} + +// This serde impl uses Vec. We could save space by using an array of +// length `TWO_ENTRIES_BYTE_LEN`, but then we need a way to distinguish +// `prev=Some(0)` from `prev=None`. +bytes_serde_impl!( + TxTableEntries, + to_payload_bytes, + Vec, + from_payload_bytes +); + +impl TxTableEntries { + const TWO_ENTRIES_BYTE_LEN: usize = 2 * TX_OFFSET_BYTE_LEN; + + pub fn to_payload_bytes(&self) -> Vec { + let mut bytes = Vec::with_capacity(Self::TWO_ENTRIES_BYTE_LEN); + if let Some(prev) = self.prev { + bytes.extend(usize_to_bytes::(prev)); + } + bytes.extend(usize_to_bytes::(self.cur)); + bytes + } +} + +impl FromNsPayloadBytes<'_> for TxTableEntries { + fn from_payload_bytes(bytes: &[u8]) -> Self { + match bytes.len() { + TX_OFFSET_BYTE_LEN => Self { + cur: usize_from_bytes::(bytes), + prev: None, + }, + Self::TWO_ENTRIES_BYTE_LEN => Self { + cur: usize_from_bytes::(&bytes[TX_OFFSET_BYTE_LEN..]), + prev: Some(usize_from_bytes::( + &bytes[..TX_OFFSET_BYTE_LEN], + )), + }, + len => panic!( + "unexpected bytes len {} should be either {} or {}", + len, + TX_OFFSET_BYTE_LEN, + Self::TWO_ENTRIES_BYTE_LEN + ), + } + } +} + +/// Byte range for entries from a tx table for use in a transaction proof. +/// +/// This range covers either one or two entries from a tx table according to +/// whether it was derived from the first transaction in the namespace. +pub struct TxTableEntriesRange(Range); + +impl TxTableEntriesRange { + pub fn new(index: &TxIndex) -> Self { + let start = if index.0 == 0 { + // Special case: the desired range includes only one entry from + // the tx table: the first entry. This entry starts immediately + // following the bytes that encode the tx table length. + NUM_TXS_BYTE_LEN + } else { + // The desired range starts at the beginning of the previous tx + // table entry. + (index.0 - 1) + .saturating_mul(TX_OFFSET_BYTE_LEN) + .saturating_add(NUM_TXS_BYTE_LEN) + }; + // The desired range ends at the end of this transaction's tx table entry + let end = index + .0 + .saturating_add(1) + .saturating_mul(TX_OFFSET_BYTE_LEN) + .saturating_add(NUM_TXS_BYTE_LEN); + Self(start..end) + } +} + +impl NsPayloadBytesRange<'_> for TxTableEntriesRange { + type Output = TxTableEntries; + + fn ns_payload_range(&self) -> Range { + self.0.clone() + } +} + +/// A transaction's payload data. +pub struct TxPayload<'a>(&'a [u8]); + +impl<'a> TxPayload<'a> { + pub fn to_payload_bytes(&self) -> &'a [u8] { + self.0 + } +} + +impl<'a> FromNsPayloadBytes<'a> for TxPayload<'a> { + fn from_payload_bytes(bytes: &'a [u8]) -> Self { + Self(bytes) + } +} + +/// Byte range for a transaction's payload data. +pub struct TxPayloadRange(Range); + +impl TxPayloadRange { + pub fn new( + num_txs: &NumTxsUnchecked, + tx_table_entries: &TxTableEntries, + byte_len: &NsPayloadByteLen, + ) -> Self { + let tx_table_byte_len = num_txs + .0 + .saturating_mul(TX_OFFSET_BYTE_LEN) + .saturating_add(NUM_TXS_BYTE_LEN); + let end = tx_table_entries + .cur + .saturating_add(tx_table_byte_len) + .min(byte_len.0); + let start = tx_table_entries + .prev + .unwrap_or(0) + .saturating_add(tx_table_byte_len) + .min(end); + Self(start..end) + } +} + +impl<'a> NsPayloadBytesRange<'a> for TxPayloadRange { + type Output = TxPayload<'a>; + + fn ns_payload_range(&self) -> Range { + self.0.clone() + } +} + +/// Index for an entry in a tx table. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub(in crate::block) struct TxIndex(usize); +bytes_serde_impl!(TxIndex, to_bytes, [u8; NUM_TXS_BYTE_LEN], from_bytes); + +impl TxIndex { + pub fn to_bytes(&self) -> [u8; NUM_TXS_BYTE_LEN] { + usize_to_bytes::(self.0) + } + fn from_bytes(bytes: &[u8]) -> Self { + Self(usize_from_bytes::(bytes)) + } +} + +pub(in crate::block) struct TxIter(Range); + +impl TxIter { + pub fn new(num_txs: &NumTxs) -> Self { + Self(0..num_txs.0) + } +} + +// Simple `impl Iterator` delegates to `Range`. +impl Iterator for TxIter { + type Item = TxIndex; + + fn next(&mut self) -> Option { + self.0.next().map(TxIndex) + } +} + +/// Build an individual namespace payload one transaction at a time. +/// +/// Use [`Self::append_tx`] to add each transaction. Use [`Self::into_bytes`] +/// when you're done. The returned bytes include a well-formed tx table and all +/// tx payloads. +#[derive(Default)] +pub(in crate::block) struct NsPayloadBuilder { + tx_table_entries: Vec, + tx_bodies: Vec, +} + +impl NsPayloadBuilder { + /// Add a transaction's payload to this namespace + pub fn append_tx(&mut self, tx: Transaction) { + self.tx_bodies.extend(tx.into_payload()); + self.tx_table_entries + .extend(usize_to_bytes::(self.tx_bodies.len())); + } + + /// Serialize to bytes and consume self. + pub fn into_bytes(self) -> Vec { + let mut result = Vec::with_capacity( + NUM_TXS_BYTE_LEN + self.tx_table_entries.len() + self.tx_bodies.len(), + ); + let num_txs = NumTxsUnchecked(self.tx_table_entries.len() / TX_OFFSET_BYTE_LEN); + result.extend(num_txs.to_payload_bytes()); + result.extend(self.tx_table_entries); + result.extend(self.tx_bodies); + result + } + + /// Byte length of a tx table header. + pub const fn tx_table_header_byte_len() -> usize { + NUM_TXS_BYTE_LEN + } + + /// Byte length of a single tx table entry. + pub const fn tx_table_entry_byte_len() -> usize { + TX_OFFSET_BYTE_LEN + } +} diff --git a/sequencer/src/block/test.rs b/sequencer/src/block/test.rs new file mode 100644 index 0000000000..233dec23d0 --- /dev/null +++ b/sequencer/src/block/test.rs @@ -0,0 +1,207 @@ +use crate::{ + block::{ + full_payload::{NsProof, Payload}, + namespace_payload::TxProof, + }, + chain_config::BlockSize, + ChainConfig, NamespaceId, NodeState, Transaction, ValidatedState, +}; +use async_compatibility_layer::logging::{setup_backtrace, setup_logging}; +use hotshot::traits::BlockPayload; +use hotshot_query_service::availability::QueryablePayload; +use hotshot_types::{traits::EncodeBytes, vid::vid_scheme}; +use jf_vid::VidScheme; +use rand::RngCore; +use std::collections::HashMap; + +#[async_std::test] +async fn basic_correctness() { + // play with this + let test_cases = vec![ + vec![vec![5, 8, 8], vec![7, 9, 11], vec![10, 5, 8]], // 3 non-empty namespaces + ]; + + setup_logging(); + setup_backtrace(); + let mut rng = jf_utils::test_rng(); + let valid_tests = ValidTest::many_from_tx_lengths(test_cases, &mut rng); + + let mut vid = vid_scheme(10); + + for mut test in valid_tests { + let mut all_txs = test.all_txs(); + tracing::info!("test case {} nss {} txs", test.nss.len(), all_txs.len()); + + let block = + Payload::from_transactions(test.all_txs(), &Default::default(), &Default::default()) + .await + .unwrap() + .0; + tracing::info!( + "ns_table {:?}, payload {:?}", + block.ns_table().encode(), + block.encode() + ); + + // test correct number of nss, txs + assert_eq!(block.ns_table().iter().count(), test.nss.len()); + assert_eq!(block.len(block.ns_table()), all_txs.len()); + assert_eq!(block.iter(block.ns_table()).count(), all_txs.len()); + + tracing::info!("all_txs {:?}", all_txs); + + let (vid_commit, vid_common) = { + let disperse_data = vid.disperse(block.encode()).unwrap(); + (disperse_data.commit, disperse_data.common) + }; + + // test iterate over all txs + for tx_index in block.iter(block.ns_table()) { + let tx = block.transaction(&tx_index).unwrap(); + tracing::info!("tx {:?}, {:?}", tx_index, tx); + + // warning: linear search for a tx + let test_tx = all_txs.remove(all_txs.iter().position(|t| t == &tx).unwrap()); + assert_eq!(tx, test_tx); + + let tx_proof2 = { + let (tx2, tx_proof) = TxProof::new(&tx_index, &block, &vid_common).unwrap(); + assert_eq!(tx, tx2); + tx_proof + }; + assert!(tx_proof2 + .verify(block.ns_table(), &tx, &vid_commit, &vid_common) + .unwrap()); + } + assert!( + all_txs.is_empty(), + "not all test txs consumed by block.iter" + ); + + // test iterate over all namespaces + for ns_index in block.ns_table().iter() { + let ns_id = block.ns_table().read_ns_id(&ns_index).unwrap(); + tracing::info!("test ns_id {ns_id}"); + + let txs = test + .nss + .remove(&ns_id) + .expect("block ns_id missing from test"); + + let ns_proof = NsProof::new(&block, &ns_index, &vid_common) + .expect("namespace_with_proof should succeed"); + + let (ns_proof_txs, ns_proof_ns_id) = ns_proof + .verify(block.ns_table(), &vid_commit, &vid_common) + .unwrap_or_else(|| panic!("namespace {} proof verification failure", ns_id)); + + assert_eq!(ns_proof_ns_id, ns_id); + assert_eq!(ns_proof_txs, txs); + } + assert!( + test.nss.is_empty(), + "not all test namespaces consumed by ns_iter" + ); + } +} + +#[async_std::test] +async fn enforce_max_block_size() { + setup_logging(); + setup_backtrace(); + let test_case = vec![vec![5, 8, 8], vec![7, 9, 11], vec![10, 5, 8]]; + let payload_byte_len_expected: usize = 119; + let ns_table_byte_len_expected: usize = 28; + + let mut rng = jf_utils::test_rng(); + let test = ValidTest::from_tx_lengths(test_case, &mut rng); + let tx_count_expected = test.all_txs().len(); + + let chain_config = ChainConfig { + max_block_size: BlockSize::from( + (payload_byte_len_expected + ns_table_byte_len_expected) as u64, + ), + ..Default::default() + }; + + // test: actual block size equals max block size + let instance_state = NodeState::default().with_chain_config(chain_config); + + let validated_state = ValidatedState { + chain_config: chain_config.into(), + ..Default::default() + }; + let block = Payload::from_transactions(test.all_txs(), &validated_state, &instance_state) + .await + .unwrap() + .0; + assert_eq!(block.encode().len(), payload_byte_len_expected); + assert_eq!(block.ns_table().encode().len(), ns_table_byte_len_expected); + assert_eq!(block.len(block.ns_table()), tx_count_expected); + + // test: actual block size exceeds max block size, so 1 tx is dropped + // WARN log should be emitted + + let chain_config = ChainConfig { + max_block_size: BlockSize::from( + (payload_byte_len_expected + ns_table_byte_len_expected - 1) as u64, + ), + ..Default::default() + }; + let instance_state = NodeState::default().with_chain_config(chain_config); + + let validated_state = ValidatedState { + chain_config: chain_config.into(), + ..Default::default() + }; + + let block = Payload::from_transactions(test.all_txs(), &validated_state, &instance_state) + .await + .unwrap() + .0; + assert!(block.encode().len() < payload_byte_len_expected); + assert_eq!(block.ns_table().encode().len(), ns_table_byte_len_expected); + assert_eq!(block.len(block.ns_table()), tx_count_expected - 1); +} + +// TODO lots of infra here that could be reused in other tests. +pub struct ValidTest { + nss: HashMap>, +} + +impl ValidTest { + pub fn from_tx_lengths(tx_lengths: Vec>, rng: &mut R) -> Self + where + R: RngCore, + { + let mut nss = HashMap::new(); + for tx_lens in tx_lengths.into_iter() { + let ns_id = NamespaceId::random(rng); + for len in tx_lens { + let ns: &mut Vec<_> = nss.entry(ns_id).or_default(); + ns.push(Transaction::new(ns_id, random_bytes(len, rng))); + } + } + Self { nss } + } + + pub fn many_from_tx_lengths(test_cases: Vec>>, rng: &mut R) -> Vec + where + R: RngCore, + { + test_cases + .into_iter() + .map(|t| Self::from_tx_lengths(t, rng)) + .collect() + } + + pub fn all_txs(&self) -> Vec { + self.nss.iter().flat_map(|(_, txs)| txs.clone()).collect() + } +} + +fn random_bytes(len: usize, rng: &mut R) -> Vec { + let mut result = vec![0; len]; + rng.fill_bytes(&mut result); + result +} diff --git a/sequencer/src/block/uint_bytes.rs b/sequencer/src/block/uint_bytes.rs new file mode 100644 index 0000000000..2296a8182a --- /dev/null +++ b/sequencer/src/block/uint_bytes.rs @@ -0,0 +1,231 @@ +//! Serialization (and deserialization) of primitive unsigned integer types to +//! (and from) an arbitrary fixed-length byte array. +//! +use paste::paste; +use std::mem::size_of; + +// Use an ugly macro because it's difficult or impossible to be generic over +// primitive types such as `usize`, `u64`. +macro_rules! uint_bytes_impl { + ($T:ty) => { + paste! { + /// Serialize `n` into `BYTE_LEN` bytes in little-endian form, padding with + /// 0 as needed. + /// + /// # Panics + /// If `n` cannot fit into `BYTE_LEN` bytes. + pub fn [<$T _to_bytes>](n: $T) -> [u8; BYTE_LEN] { + if size_of::<$T>() > BYTE_LEN { + assert!( + [<$T _fits>](n, BYTE_LEN), + "n {n} cannot fit into {BYTE_LEN} bytes" + ); + n.to_le_bytes()[..BYTE_LEN].try_into().unwrap() // panic is impossible + } else { + // convert `n` to bytes and pad with 0 + let mut result = [0; BYTE_LEN]; + result[..size_of::<$T>()].copy_from_slice(&n.to_le_bytes()[..]); + result + } + } + + /// Deserialize `bytes` in little-endian form into a `$T`, padding with 0 + /// as needed. + /// + /// # Panics + /// If `bytes.len()` is too large to fit into a `$T`. + pub fn [<$T _from_bytes>](bytes: &[u8]) -> $T { + assert!(bytes.len() <= BYTE_LEN, "bytes len {} exceeds BYTE_LEN {BYTE_LEN}", bytes.len()); + assert!( + BYTE_LEN <= size_of::<$T>(), + "BYTE_LEN {BYTE_LEN} cannot fit into {}", + stringify!($T) + ); + let mut [<$T _bytes>] = [0; size_of::<$T>()]; + [<$T _bytes>][..bytes.len()].copy_from_slice(bytes); + $T::from_le_bytes([<$T _bytes>]) + } + + /// Return the largest `$T` value that can fit into `byte_len` bytes. + pub const fn [<$T _max_from_byte_len>](byte_len: usize) -> $T { + if byte_len >= size_of::<$T>() { + $T::MAX + } else { + // overflow cannot occur because `byte_len < size_of::<$T>()` + (1 << (byte_len * 8)) - 1 + } + } + + /// Can `n` fit into `byte_len` bytes? + pub const fn [<$T _fits>](n: $T, byte_len: usize) -> bool { + n <= [<$T _max_from_byte_len>](byte_len) + } + } + }; + } + +uint_bytes_impl!(usize); +uint_bytes_impl!(u32); + +/// Impl [`serde`] for type `$T` with methods named `$to_bytes`, `$from_bytes` +/// of the form +/// ```ignore +/// $T::$to_bytes(&self) -> $B +/// $T::$from_bytes(bytes: &[u8]) -> Self +/// ``` +/// where `$B` is any type that impls [`serde::Deserialize`] and has a method +/// `as_ref` of the form +/// ```ignore +/// $B::as_ref(&self) -> &[u8] +/// ``` +/// Typical examples of `$B` include array `[u8; N]`, slice `&[u8]`, or +/// `Vec`. +macro_rules! bytes_serde_impl { + ($T:ty, $to_bytes:ident, $B:ty, $from_bytes:ident) => { + impl Serialize for $T { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + self.$to_bytes().serialize(serializer) + } + } + + impl<'de> Deserialize<'de> for $T { + fn deserialize(deserializer: D) -> Result<$T, D::Error> + where + D: Deserializer<'de>, + { + <$B as Deserialize>::deserialize(deserializer) + .map(|bytes| <$T>::$from_bytes(bytes.as_ref())) + } + } + }; +} + +pub(super) use bytes_serde_impl; + +#[cfg(test)] +mod test { + use fluent_asserter::prelude::*; + use paste::paste; + use std::mem::size_of; + + macro_rules! uint_bytes_test_impl { + ($T:ty) => { + paste! { + use super::{[<$T _max_from_byte_len>], [<$T _to_bytes>], [<$T _from_bytes>]}; + + #[test] + fn [<$T _max_from_byte_len_correctness>]() { + // test byte lengths 0 to size_of::<$T>() + let mut bytes = [0; size_of::<$T>()]; + assert_eq!([<$T _max_from_byte_len>](0), 0); + for i in 0..bytes.len() { + bytes[i] = 0xff; + assert_eq!([<$T _max_from_byte_len>](i + 1).to_le_bytes(), bytes); + } + + // test byte lengths size_of::<$T>() to twice that length + for i in size_of::<$T>()..2 * size_of::<$T>() { + assert_eq!([<$T _max_from_byte_len>](i + 1), $T::MAX); + } + } + + #[test] + fn [<$T _to_bytes_correctness>]() { + // byte length 0 + assert_eq!([<$T _to_bytes>](0), [0; 0]); + assert_that_code!(|| [<$T _to_bytes>]::<0>(1)).panics(); + + // byte length 1 + assert_eq!([<$T _to_bytes>](0), [0; 1]); + assert_eq!([<$T _to_bytes>](255), [255; 1]); + assert_that_code!(|| [<$T _to_bytes>]::<1>(256)).panics(); + + // byte length 2 + assert_eq!([<$T _to_bytes>](0), [0; 2]); + assert_eq!([<$T _to_bytes>](65535), [255; 2]); + assert_that_code!(|| [<$T _to_bytes>]::<2>(65536)).panics(); + + // byte length size_of::<$T>() + assert_eq!([<$T _to_bytes>](0), [0; size_of::<$T>()]); + assert_eq!([<$T _to_bytes>]($T::MAX), [255; size_of::<$T>()]); + + // byte length size_of::<$T>() + 1 + assert_eq!([<$T _to_bytes>](0), [0; size_of::<$T>() + 1]); + let [<$T _max_bytes>] = { + let mut bytes = [255; size_of::<$T>() + 1]; + bytes[bytes.len() - 1] = 0; + bytes + }; + assert_eq!([<$T _to_bytes>]($T::MAX), [<$T _max_bytes>]); + } + + #[test] + fn [<$T _from_bytes_correctness>]() { + let bytes = [255; size_of::<$T>() + 1]; + + // It would be nice to iterate through + // `0..size_of::<$T>()` but this is not possible with + // const generics for `[<$T _from_bytes>]`. We could + // use `seq-macro` crate but it requires an integer + // literal whereas our range includes `size_of::<$T>()`. + // + // Instead we just hard code four constants: + // `0`, `1`, `size_of::<$T>() - 1`, `size_of::<$T>()`. + assert_eq!( + [<$T _from_bytes>]::<0>(&bytes[..0]), + [<$T _max_from_byte_len>](0) + ); + assert_eq!( + [<$T _from_bytes>]::<1>(&bytes[..1]), + [<$T _max_from_byte_len>](1) + ); + assert_eq!( + [<$T _from_bytes>]::<{size_of::<$T>() - 1}>(&bytes[..size_of::<$T>() - 1]), + [<$T _max_from_byte_len>](size_of::<$T>() - 1) + ); + assert_eq!( + [<$T _from_bytes>]::<{size_of::<$T>()}>(&bytes[..size_of::<$T>()]), + [<$T _max_from_byte_len>](size_of::<$T>()) + ); + + assert_that_code!(|| [<$T _from_bytes>]::<{size_of::<$T>() + 1}>(&bytes[..])).panics(); + } + + #[test] + fn [<$T _from_bytes_allows_smaller_byte_lens>]() { + // This test same as `xxx_from_bytes_correctness` except + // we set the const param `BYTE_LEN` to + // `size_of::<$T>()` in all cases. Why? To ensure that + // `xxx_from_bytes` allows its arg to have length + // smaller than `BYTE_LEN`. + let bytes = [255; size_of::<$T>() + 1]; + + assert_eq!( + [<$T _from_bytes>]::<{size_of::<$T>()}>(&bytes[..0]), + [<$T _max_from_byte_len>](0) + ); + assert_eq!( + [<$T _from_bytes>]::<{size_of::<$T>()}>(&bytes[..1]), + [<$T _max_from_byte_len>](1) + ); + assert_eq!( + [<$T _from_bytes>]::<{size_of::<$T>()}>(&bytes[..size_of::<$T>() - 1]), + [<$T _max_from_byte_len>](size_of::<$T>() - 1) + ); + assert_eq!( + [<$T _from_bytes>]::<{size_of::<$T>()}>(&bytes[..size_of::<$T>()]), + [<$T _max_from_byte_len>](size_of::<$T>()) + ); + + assert_that_code!(|| [<$T _from_bytes>]::<{size_of::<$T>()}>(&bytes[..])).panics(); + } + } + }; + } + + uint_bytes_test_impl!(usize); + uint_bytes_test_impl!(u32); +} diff --git a/sequencer/src/reference_tests.rs b/sequencer/src/reference_tests.rs new file mode 100644 index 0000000000..0bc43bb0ba --- /dev/null +++ b/sequencer/src/reference_tests.rs @@ -0,0 +1,337 @@ +#![cfg(test)] +//! Reference data types. +//! +//! This module provides some reference instantiations of various data types which have an external, +//! language-independent interface (e.g. serialization or commitment scheme). Ports of the sequencer +//! to other languages, as well as downstream packages written in other languages, can use these +//! references objects and their known serializations and commitments to check that their +//! implementations are compatible with this reference implementation. +//! +//! The serialized form of each reference object, in both JSON and binary forms, is available in the +//! `data` directory of the repo for this crate. These files checked against the reference objects +//! in this module to prevent unintentional changes to the serialization format. Thus, these +//! serialized files can be used as test vectors for a port of the serialiation scheme to another +//! language or framework. +//! +//! To get the byte representation or U256 representation of a commitment for testing in other +//! packages, run the tests and look for "commitment bytes" or "commitment U256" in the logs. +//! +//! These tests may fail if you make a breaking change to a commitment scheme, serialization, etc. +//! If this happens, be sure you _want_ to break the API, and, if so, simply replace the relevant +//! constant in this module with the "actual" value that can be found in the logs of the failing +//! test. + +use crate::{ + block::NsTable, state::FeeInfo, ChainConfig, FeeAccount, Header, L1BlockInfo, NamespaceId, + Payload, SeqTypes, Transaction, ValidatedState, +}; +use async_compatibility_layer::logging::{setup_backtrace, setup_logging}; +use committable::Committable; +use es_version::SequencerVersion; +use hotshot_query_service::availability::QueryablePayload; +use hotshot_types::traits::{ + block_contents::vid_commitment, signature_key::BuilderSignatureKey, BlockPayload, EncodeBytes, +}; +use jf_merkle_tree::MerkleTreeScheme; +use pretty_assertions::assert_eq; +use rand::{Rng, RngCore}; +use sequencer_utils::commitment_to_u256; +use serde::{de::DeserializeOwned, Serialize}; +use serde_json::Value; +use std::{fmt::Debug, path::Path, str::FromStr}; +use tagged_base64::TaggedBase64; +use vbs::BinarySerializer; + +type Serializer = vbs::Serializer; + +async fn reference_payload() -> Payload { + const NUM_NS_IDS: usize = 3; + let ns_ids: [NamespaceId; NUM_NS_IDS] = [12648430.into(), 314159265.into(), 2718281828.into()]; + + let mut rng = jf_utils::test_rng(); + let txs = { + const NUM_TXS: usize = 20; + let mut txs = Vec::with_capacity(NUM_TXS); + for _ in 0..NUM_TXS { + let ns_id = ns_ids[rng.gen_range(0..NUM_NS_IDS)]; + txs.push(reference_transaction(ns_id, &mut rng)); + } + txs + }; + + Payload::from_transactions(txs, &Default::default(), &Default::default()) + .await + .unwrap() + .0 +} + +async fn reference_ns_table() -> NsTable { + reference_payload().await.ns_table().clone() +} + +const REFERENCE_NS_TABLE_COMMITMENT: &str = "NSTABLE~tMW0-hGn0563bgYgvsO9r95f2AUiTD_2tvjDOuGRwNA5"; + +fn reference_l1_block() -> L1BlockInfo { + L1BlockInfo { + number: 123, + timestamp: 0x456.into(), + hash: "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + .parse() + .unwrap(), + } +} + +const REFERENCE_L1_BLOCK_COMMITMENT: &str = "L1BLOCK~4HpzluLK2Isz3RdPNvNrDAyQcWOF2c9JeLZzVNLmfpQ9"; + +fn reference_chain_config() -> ChainConfig { + ChainConfig { + chain_id: 0x8a19.into(), + max_block_size: 10240.into(), + base_fee: 0.into(), + fee_contract: Some(Default::default()), + fee_recipient: Default::default(), + } +} + +const REFERENCE_CHAIN_CONFIG_COMMITMENT: &str = + "CHAIN_CONFIG~L6HmMktJbvnEGgpmRrsiYvQmIBstSj9UtDM7eNFFqYFO"; + +fn reference_fee_info() -> FeeInfo { + FeeInfo::new( + FeeAccount::from_str("0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266").unwrap(), + 0, + ) +} + +const REFERENCE_FEE_INFO_COMMITMENT: &str = "FEE_INFO~xCCeTjJClBtwtOUrnAmT65LNTQGceuyjSJHUFfX6VRXR"; + +async fn reference_header() -> Header { + let builder_key = FeeAccount::generated_from_seed_indexed(Default::default(), 0).1; + let fee_info = reference_fee_info(); + let payload = reference_payload().await; + let ns_table = payload.ns_table().clone(); + let payload_commitment = vid_commitment(&payload.encode(), 1); + let builder_commitment = payload.builder_commitment(&ns_table); + let builder_signature = FeeAccount::sign_fee( + &builder_key, + fee_info.amount().as_u64().unwrap(), + &ns_table, + &payload_commitment, + ) + .unwrap(); + + let state = ValidatedState::default(); + + Header { + height: 42, + timestamp: 789, + l1_head: 124, + l1_finalized: Some(reference_l1_block()), + payload_commitment, + builder_commitment, + ns_table, + block_merkle_tree_root: state.block_merkle_tree.commitment(), + fee_merkle_tree_root: state.fee_merkle_tree.commitment(), + fee_info, + chain_config: reference_chain_config().into(), + builder_signature: Some(builder_signature), + } +} + +const REFERENCE_HEADER_COMMITMENT: &str = "BLOCK~dh1KpdvvxSvnnPpOi2yI3DOg8h6ltr2Kv13iRzbQvtN2"; + +fn reference_transaction(ns_id: NamespaceId, rng: &mut R) -> Transaction +where + R: RngCore, +{ + let mut tx_payload = vec![0u8; 256]; + rng.fill_bytes(&mut tx_payload); + Transaction::new(ns_id, tx_payload) +} + +const REFERENCE_TRANSACTION_COMMITMENT: &str = "TX~EikfLslj3g6sIWRZYpN6ZuU1gadN77AHXmRA56yNnPrQ"; + +async fn reference_tx_index() -> >::TransactionIndex { + let payload = reference_payload().await; + payload.iter(payload.ns_table()).last().unwrap() +} + +fn reference_test_without_committable( + name: &str, + reference: &T, +) { + setup_logging(); + setup_backtrace(); + + // Load the expected serialization from the repo. + let data_dir = Path::new(env!("CARGO_MANIFEST_DIR")).join("../data"); + let expected_bytes = std::fs::read(data_dir.join(format!("{name}.json"))).unwrap(); + let expected: Value = serde_json::from_slice(&expected_bytes).unwrap(); + + // Check that the reference object matches the expected serialized form. + let actual = serde_json::to_value(reference).unwrap(); + + if actual != expected { + let actual_pretty = serde_json::to_string_pretty(&actual).unwrap(); + let expected_pretty = serde_json::to_string_pretty(&expected).unwrap(); + + // Write the actual output to a file to make it easier to compare with/replace the expected + // file if the serialization change was actually intended. + let actual_path = data_dir.join(format!("{name}-actual.json")); + std::fs::write(&actual_path, actual_pretty.as_bytes()).unwrap(); + + // Fail the test with an assertion that outputs a nice diff between the prettified JSON + // objects. + assert_eq!( + expected_pretty, + actual_pretty, + r#" +Serialized {name} does not match expected JSON. The actual serialization has been written to {}. If +you intended to make a breaking change to the API, you may replace the reference JSON file in +/data/{name}.json with /data/{name}-actual.json. Otherwise, revert your changes which have caused a +change in the serialization of this data structure. +"#, + actual_path.display() + ); + } + + // Check that we can deserialize from the reference JSON object. + let parsed: T = serde_json::from_value(expected).unwrap(); + assert_eq!( + *reference, + parsed, + "Reference object commitment does not match commitment of parsed JSON. This is indicative of + inconsistency or non-determinism in the commitment scheme.", + ); + + // Check that the reference object matches the expected binary form. + let expected = std::fs::read(data_dir.join(format!("{name}.bin"))).unwrap(); + let actual = Serializer::serialize(&reference).unwrap(); + if actual != expected { + // Write the actual output to a file to make it easier to compare with/replace the expected + // file if the serialization change was actually intended. + let actual_path = data_dir.join(format!("{name}-actual.bin")); + std::fs::write(&actual_path, &actual).unwrap(); + + // Fail the test with an assertion that outputs a diff. + // Use TaggedBase64 for compact console output. + assert_eq!( + TaggedBase64::encode_raw(&expected), + TaggedBase64::encode_raw(&actual), + r#" +Serialized {name} does not match expected binary file. The actual serialization has been written to +{}. If you intended to make a breaking change to the API, you may replace the reference file in +/data/{name}.bin with /data/{name}-actual.bin. Otherwise, revert your changes which have caused a +change in the serialization of this data structure. +"#, + actual_path.display() + ); + } + + // Check that we can deserialize from the reference binary object. + let parsed: T = Serializer::deserialize(&expected).unwrap(); + assert_eq!( + *reference, parsed, + "Reference object commitment does not match commitment of parsed binary object. This is + indicative of inconsistency or non-determinism in the commitment scheme.", + ); +} + +fn reference_test( + name: &str, + reference: T, + commitment: &str, +) { + setup_logging(); + setup_backtrace(); + + reference_test_without_committable(name, &reference); + + // Print information about the commitment that might be useful in generating tests for other + // languages. + let actual = reference.commit(); + let bytes: &[u8] = actual.as_ref(); + let u256 = commitment_to_u256(actual); + tracing::info!("actual commitment: {}", actual); + tracing::info!("commitment bytes: {:?}", bytes); + tracing::info!("commitment U256: {}", u256); + + // Check that the reference object matches the expected serialized object. + let expected = commitment.parse().unwrap(); + assert_eq!( + actual, expected, + r#" +Commitment of serialized object does not match commitment of reference object. If you intended to +make a breaking change to the API, you may replace the reference commitment constant in the +reference_tests module with the "actual" commitment below. Otherwise, revert your changes which +have caused a change to the commitment scheme. + +Expected: {expected} +Actual: {actual} +"# + ); +} + +#[async_std::test] +async fn test_reference_payload() { + reference_test_without_committable("payload", &reference_payload().await); +} + +#[async_std::test] +async fn test_reference_tx_index() { + reference_test_without_committable("tx_index", &reference_tx_index().await); +} + +#[async_std::test] +async fn test_reference_ns_table() { + reference_test( + "ns_table", + reference_ns_table().await, + REFERENCE_NS_TABLE_COMMITMENT, + ); +} + +#[test] +fn test_reference_l1_block() { + reference_test( + "l1_block", + reference_l1_block(), + REFERENCE_L1_BLOCK_COMMITMENT, + ); +} + +#[test] +fn test_reference_chain_config() { + reference_test( + "chain_config", + reference_chain_config(), + REFERENCE_CHAIN_CONFIG_COMMITMENT, + ); +} + +#[test] +fn test_reference_fee_info() { + reference_test( + "fee_info", + reference_fee_info(), + REFERENCE_FEE_INFO_COMMITMENT, + ); +} + +#[async_std::test] +async fn test_reference_header() { + reference_test( + "header", + reference_header().await, + REFERENCE_HEADER_COMMITMENT, + ); +} + +#[test] +fn test_reference_transaction() { + reference_test( + "transaction", + reference_transaction(12648430.into(), &mut jf_utils::test_rng()), + REFERENCE_TRANSACTION_COMMITMENT, + ); +} diff --git a/utils/src/deployer.rs b/utils/src/deployer.rs index 788e572f4e..330d0089a4 100644 --- a/utils/src/deployer.rs +++ b/utils/src/deployer.rs @@ -1,5 +1,3 @@ -use std::{collections::HashMap, io::Write, ops::Deref}; - use anyhow::{ensure, Context}; use async_std::sync::Arc; use clap::{builder::OsStr, Parser, ValueEnum}; @@ -11,12 +9,13 @@ use contract_bindings::{ light_client_mock::LIGHTCLIENTMOCK_ABI, light_client_state_update_vk::LightClientStateUpdateVK, light_client_state_update_vk_mock::LightClientStateUpdateVKMock, - plonk_verifier::PlonkVerifier, + plonk_verifier_2::PlonkVerifier2, }; use derive_more::Display; use ethers::{prelude::*, signers::coins_bip39::English, solc::artifacts::BytecodeObject}; use futures::future::{BoxFuture, FutureExt}; use hotshot_contract_adapter::light_client::{LightClientConstructorArgs, ParsedLightClientState}; +use std::{collections::HashMap, io::Write, ops::Deref}; use url::Url; /// Set of predeployed contracts. @@ -187,7 +186,7 @@ pub async fn deploy_light_client_contract( let plonk_verifier = contracts .deploy_tx( Contract::PlonkVerifier, - PlonkVerifier::deploy(l1.clone(), ())?, + PlonkVerifier2::deploy(l1.clone(), ())?, ) .await?; let vk = contracts @@ -250,7 +249,7 @@ pub async fn deploy_mock_light_client_contract( let plonk_verifier = contracts .deploy_tx( Contract::PlonkVerifier, - PlonkVerifier::deploy(l1.clone(), ())?, + PlonkVerifier2::deploy(l1.clone(), ())?, ) .await?; let vk = contracts